option parsing buffer overflow vulnerability
[aNetHack.git] / src / invent.c
blob8859bb7b3dbdc5923961ebd9b24ec6254f6294fd
1 /* NetHack 3.6 invent.c $NHDT-Date: 1461967848 2016/04/29 22:10:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.208 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 #define NOINVSYM '#'
8 #define CONTAINED_SYM '>' /* designator for inside a container */
9 #define HANDS_SYM '-'
11 STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
12 const genericptr));
13 STATIC_DCL void NDECL(reorder_invent);
14 STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
15 STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
16 STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
17 STATIC_DCL boolean FDECL(only_here, (struct obj *));
18 STATIC_DCL void FDECL(compactify, (char *));
19 STATIC_DCL boolean FDECL(taking_off, (const char *));
20 STATIC_DCL boolean FDECL(putting_on, (const char *));
21 STATIC_PTR int FDECL(ckunpaid, (struct obj *));
22 STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
23 STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
24 STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
25 STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
26 BOOLEAN_P, long *));
27 STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
28 STATIC_DCL void FDECL(tally_BUCX, (struct obj *,
29 int *, int *, int *, int *, int *));
30 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
31 STATIC_DCL void NDECL(dounpaid);
32 STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
33 STATIC_DCL void FDECL(menu_identify, (int));
34 STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
35 STATIC_DCL char FDECL(obj_to_let, (struct obj *));
37 static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
39 /* wizards can wish for venom, which will become an invisible inventory
40 * item without this. putting it in inv_order would mean venom would
41 * suddenly become a choice for all the inventory-class commands, which
42 * would probably cause mass confusion. the test for inventory venom
43 * is only WIZARD and not wizard because the wizard can leave venom lying
44 * around on a bones level for normal players to find. [Note to the
45 * confused: 'WIZARD' used to be a compile-time conditional so this was
46 * guarded by #ifdef WIZARD/.../#endif.]
48 static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
50 struct sortloot_item {
51 struct obj *obj;
52 int indx;
54 unsigned sortlootmode = 0;
56 /* qsort comparison routine for sortloot() */
57 STATIC_OVL int CFDECLSPEC
58 sortloot_cmp(vptr1, vptr2)
59 const genericptr vptr1;
60 const genericptr vptr2;
62 struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
63 *sli2 = (struct sortloot_item *) vptr2;
64 struct obj *obj1 = sli1->obj,
65 *obj2 = sli2->obj,
66 sav1, sav2;
67 char *cls1, *cls2, nam1[BUFSZ], nam2[BUFSZ];
68 int val1, val2, c, namcmp;
70 /* order by object class like inventory display */
71 if ((sortlootmode & SORTLOOT_PACK) != 0) {
72 cls1 = index(flags.inv_order, obj1->oclass);
73 cls2 = index(flags.inv_order, obj2->oclass);
74 if (cls1 != cls2)
75 return (int) (cls1 - cls2);
77 if ((sortlootmode & SORTLOOT_INVLET) != 0) {
78 ; /* skip sub-classes when sorting by packorder+invlet */
80 /* for armor, group by sub-category */
81 } else if (obj1->oclass == ARMOR_CLASS) {
82 static int armcat[7 + 1];
84 if (!armcat[7]) {
85 /* one-time init; we want to control the order */
86 armcat[ARM_HELM] = 1; /* [2] */
87 armcat[ARM_GLOVES] = 2; /* [3] */
88 armcat[ARM_BOOTS] = 3; /* [4] */
89 armcat[ARM_SHIELD] = 4; /* [1] */
90 armcat[ARM_CLOAK] = 5; /* [5] */
91 armcat[ARM_SHIRT] = 6; /* [6] */
92 armcat[ARM_SUIT] = 7; /* [0] */
93 armcat[7] = 8;
95 val1 = armcat[objects[obj1->otyp].oc_armcat];
96 val2 = armcat[objects[obj2->otyp].oc_armcat];
97 if (val1 != val2)
98 return val1 - val2;
100 /* for weapons, group by ammo (arrows, bolts), launcher (bows),
101 missile (dart, boomerang), stackable (daggers, knives, spears),
102 'other' (swords, axes, &c), polearm */
103 } else if (obj1->oclass == WEAPON_CLASS) {
104 val1 = objects[obj1->otyp].oc_skill;
105 val1 = (val1 < 0)
106 ? (val1 >= -P_CROSSBOW && val1 <= -P_BOW) ? 1 : 3
107 : (val1 >= P_BOW && val1 <= P_CROSSBOW) ? 2
108 : (val1 == P_SPEAR || val1 == P_DAGGER
109 || val1 == P_KNIFE) ? 4 : !is_pole(obj1) ? 5 : 6;
110 val2 = objects[obj2->otyp].oc_skill;
111 val2 = (val2 < 0)
112 ? (val2 >= -P_CROSSBOW && val2 <= -P_BOW) ? 1 : 3
113 : (val2 >= P_BOW && val2 <= P_CROSSBOW) ? 2
114 : (val2 == P_SPEAR || val2 == P_DAGGER
115 || val2 == P_KNIFE) ? 4 : !is_pole(obj2) ? 5 : 6;
116 if (val1 != val2)
117 return val1 - val2;
121 /* order by assigned inventory letter */
122 if ((sortlootmode & SORTLOOT_INVLET) != 0) {
123 c = obj1->invlet;
124 val1 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
125 : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
126 : (c == '$') ? 1
127 : (c == '#') ? 1 + 52 + 1
128 : 1 + 52 + 1 + 1; /* none of the above */
129 c = obj2->invlet;
130 val2 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
131 : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
132 : (c == '$') ? 1
133 : (c == '#') ? 1 + 52 + 1
134 : 1 + 52 + 1 + 1; /* none of the above */
135 if (val1 != val2)
136 return val1 - val2;
139 if ((sortlootmode & SORTLOOT_LOOT) == 0)
140 goto tiebreak;
143 * Sort object names in lexicographical order, ignoring quantity.
145 /* Force diluted potions to come out after undiluted of same type;
146 obj->odiluted overloads obj->oeroded. */
147 sav1.odiluted = obj1->odiluted;
148 sav2.odiluted = obj2->odiluted;
149 if (obj1->oclass == POTION_CLASS)
150 obj1->odiluted = 0;
151 if (obj1->oclass == POTION_CLASS)
152 obj2->odiluted = 0;
153 /* Force holy and unholy water to sort adjacent to water rather
154 than among 'h's and 'u's. BUCX order will keep them distinct. */
155 Strcpy(nam1, cxname_singular(obj1));
156 if (obj1->otyp == POT_WATER && obj1->bknown
157 && (obj1->blessed || obj1->cursed))
158 (void) strsubst(nam1, obj1->blessed ? "holy " : "unholy ", "");
159 Strcpy(nam2, cxname_singular(obj2));
160 if (obj2->otyp == POT_WATER && obj2->bknown
161 && (obj2->blessed || obj2->cursed))
162 (void) strsubst(nam2, obj2->blessed ? "holy " : "unholy ", "");
163 obj1->odiluted = sav1.odiluted;
164 obj2->odiluted = sav2.odiluted;
166 if ((namcmp = strcmpi(nam1, nam2)) != 0)
167 return namcmp;
169 /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and
170 unknown to 0. */
171 val1 = obj1->bknown
172 ? (obj1->blessed << 2)
173 + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
174 : 0;
175 val2 = obj2->bknown
176 ? (obj2->blessed << 2)
177 + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
178 : 0;
179 if (val1 != val2)
180 return val2 - val1; /* bigger is better */
182 /* Sort by greasing. This will put the objects in degreasing order. */
183 val1 = obj1->greased;
184 val2 = obj2->greased;
185 if (val1 != val2)
186 return val2 - val1; /* bigger is better */
188 /* Sort by erosion. The effective amount is what matters. */
189 val1 = greatest_erosion(obj1);
190 val2 = greatest_erosion(obj2);
191 if (val1 != val2)
192 return val1 - val2; /* bigger is WORSE */
194 /* Sort by erodeproofing. Map known-invulnerable to 1, and both
195 known-vulnerable and unknown-vulnerability to 0, because that's
196 how they're displayed. */
197 val1 = obj1->rknown && obj1->oerodeproof;
198 val2 = obj2->rknown && obj2->oerodeproof;
199 if (val1 != val2)
200 return val2 - val1; /* bigger is better */
202 /* Sort by enchantment. Map unknown to -1000, which is comfortably
203 below the range of obj->spe. oc_uses_known means that obj->known
204 matters, which usually indirectly means that obj->spe is relevant.
205 Lots of objects use obj->spe for some other purpose (see obj.h). */
206 if (objects[obj1->otyp].oc_uses_known
207 /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
208 && obj1->oclass != FOOD_CLASS) {
209 val1 = obj1->known ? obj1->spe : -1000;
210 val2 = obj2->known ? obj2->spe : -1000;
211 if (val1 != val2)
212 return val2 - val1; /* bigger is better */
215 tiebreak:
216 /* They're identical, as far as we're concerned. We want
217 to force a deterministic order, and do so by producing a
218 stable sort: maintain the original order of equal items. */
219 return (sli2->indx - sli1->indx);
222 void
223 sortloot(olist, mode, by_nexthere)
224 struct obj **olist;
225 unsigned mode; /* flags for sortloot_cmp() */
226 boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
228 struct sortloot_item *sliarray, osli, nsli;
229 struct obj *o, **nxt_p;
230 unsigned n, i;
231 boolean already_sorted = TRUE;
233 sortlootmode = mode; /* extra input for sortloot_cmp() */
234 for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0;
235 osli = nsli) {
236 nsli.obj = by_nexthere ? o->nexthere : o->nobj;
237 nsli.indx = (int) ++n;
238 if (nsli.obj && already_sorted
239 && sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0)
240 already_sorted = FALSE;
242 if (n > 1 && !already_sorted) {
243 sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray);
244 for (i = 0, o = *olist; o;
245 ++i, o = by_nexthere ? o->nexthere : o->nobj)
246 sliarray[i].obj = o, sliarray[i].indx = (int) i;
248 qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
249 for (i = 0; i < n; ++i) {
250 o = sliarray[i].obj;
251 nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj);
252 *nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0;
254 *olist = sliarray[0].obj;
255 free((genericptr_t) sliarray);
257 sortlootmode = 0;
260 void
261 assigninvlet(otmp)
262 register struct obj *otmp;
264 boolean inuse[52];
265 register int i;
266 register struct obj *obj;
268 /* there should be at most one of these in inventory... */
269 if (otmp->oclass == COIN_CLASS) {
270 otmp->invlet = GOLD_SYM;
271 return;
274 for (i = 0; i < 52; i++)
275 inuse[i] = FALSE;
276 for (obj = invent; obj; obj = obj->nobj)
277 if (obj != otmp) {
278 i = obj->invlet;
279 if ('a' <= i && i <= 'z')
280 inuse[i - 'a'] = TRUE;
281 else if ('A' <= i && i <= 'Z')
282 inuse[i - 'A' + 26] = TRUE;
283 if (i == otmp->invlet)
284 otmp->invlet = 0;
286 if ((i = otmp->invlet)
287 && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
288 return;
289 for (i = lastinvnr + 1; i != lastinvnr; i++) {
290 if (i == 52) {
291 i = -1;
292 continue;
294 if (!inuse[i])
295 break;
297 otmp->invlet =
298 (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26));
299 lastinvnr = i;
302 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
303 #define inv_rank(o) ((o)->invlet ^ 040)
305 /* sort the inventory; used by addinv() and doorganize() */
306 STATIC_OVL void
307 reorder_invent()
309 struct obj *otmp, *prev, *next;
310 boolean need_more_sorting;
312 do {
314 * We expect at most one item to be out of order, so this
315 * isn't nearly as inefficient as it may first appear.
317 need_more_sorting = FALSE;
318 for (otmp = invent, prev = 0; otmp;) {
319 next = otmp->nobj;
320 if (next && inv_rank(next) < inv_rank(otmp)) {
321 need_more_sorting = TRUE;
322 if (prev)
323 prev->nobj = next;
324 else
325 invent = next;
326 otmp->nobj = next->nobj;
327 next->nobj = otmp;
328 prev = next;
329 } else {
330 prev = otmp;
331 otmp = next;
334 } while (need_more_sorting);
337 #undef inv_rank
339 /* scan a list of objects to see whether another object will merge with
340 one of them; used in pickup.c when all 52 inventory slots are in use,
341 to figure out whether another object could still be picked up */
342 struct obj *
343 merge_choice(objlist, obj)
344 struct obj *objlist, *obj;
346 struct monst *shkp;
347 int save_nocharge;
349 if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
350 return (struct obj *) 0;
351 /* if this is an item on the shop floor, the attributes it will
352 have when carried are different from what they are now; prevent
353 that from eliciting an incorrect result from mergable() */
354 save_nocharge = obj->no_charge;
355 if (objlist == invent && obj->where == OBJ_FLOOR
356 && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
357 if (obj->no_charge)
358 obj->no_charge = 0;
359 /* A billable object won't have its `unpaid' bit set, so would
360 erroneously seem to be a candidate to merge with a similar
361 ordinary object. That's no good, because once it's really
362 picked up, it won't merge after all. It might merge with
363 another unpaid object, but we can't check that here (depends
364 too much upon shk's bill) and if it doesn't merge it would
365 end up in the '#' overflow inventory slot, so reject it now. */
366 else if (inhishop(shkp))
367 return (struct obj *) 0;
369 while (objlist) {
370 if (mergable(objlist, obj))
371 break;
372 objlist = objlist->nobj;
374 obj->no_charge = save_nocharge;
375 return objlist;
378 /* merge obj with otmp and delete obj if types agree */
380 merged(potmp, pobj)
381 struct obj **potmp, **pobj;
383 register struct obj *otmp = *potmp, *obj = *pobj;
385 if (mergable(otmp, obj)) {
386 /* Approximate age: we do it this way because if we were to
387 * do it "accurately" (merge only when ages are identical)
388 * we'd wind up never merging any corpses.
389 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
391 * Don't do the age manipulation if lit. We would need
392 * to stop the burn on both items, then merge the age,
393 * then restart the burn. Glob ages are averaged in the
394 * absorb routine, which uses weight rather than quantity
395 * to adjust for proportion (glob quantity is always 1).
397 if (!obj->lamplit && !obj->globby)
398 otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
399 / (otmp->quan + obj->quan);
401 otmp->quan += obj->quan;
402 /* temporary special case for gold objects!!!! */
403 if (otmp->oclass == COIN_CLASS)
404 otmp->owt = weight(otmp);
405 /* and puddings!!!1!!one! */
406 else if (!Is_pudding(otmp))
407 otmp->owt += obj->owt;
408 if (!has_oname(otmp) && has_oname(obj))
409 otmp = *potmp = oname(otmp, ONAME(obj));
410 obj_extract_self(obj);
412 /* really should merge the timeouts */
413 if (obj->lamplit)
414 obj_merge_light_sources(obj, otmp);
415 if (obj->timed)
416 obj_stop_timers(obj); /* follows lights */
418 /* fixup for `#adjust' merging wielded darts, daggers, &c */
419 if (obj->owornmask && carried(otmp)) {
420 long wmask = otmp->owornmask | obj->owornmask;
422 /* Both the items might be worn in competing slots;
423 merger preference (regardless of which is which):
424 primary weapon + alternate weapon -> primary weapon;
425 primary weapon + quiver -> primary weapon;
426 alternate weapon + quiver -> alternate weapon.
427 (Prior to 3.3.0, it was not possible for the two
428 stacks to be worn in different slots and `obj'
429 didn't need to be unworn when merging.) */
430 if (wmask & W_WEP)
431 wmask = W_WEP;
432 else if (wmask & W_SWAPWEP)
433 wmask = W_SWAPWEP;
434 else if (wmask & W_QUIVER)
435 wmask = W_QUIVER;
436 else {
437 impossible("merging strangely worn items (%lx)", wmask);
438 wmask = otmp->owornmask;
440 if ((otmp->owornmask & ~wmask) != 0L)
441 setnotworn(otmp);
442 setworn(otmp, wmask);
443 setnotworn(obj);
444 #if 0
445 /* (this should not be necessary, since items
446 already in a monster's inventory don't ever get
447 merged into other objects [only vice versa]) */
448 } else if (obj->owornmask && mcarried(otmp)) {
449 if (obj == MON_WEP(otmp->ocarry)) {
450 MON_WEP(otmp->ocarry) = otmp;
451 otmp->owornmask = W_WEP;
453 #endif /*0*/
456 /* handle puddings a bit differently; absorption will free the
457 other object automatically so we can just return out from here */
458 if (obj->globby) {
459 pudding_merge_message(otmp, obj);
460 obj_absorb(potmp, pobj);
461 return 1;
464 obfree(obj, otmp); /* free(obj), bill->otmp */
465 return 1;
467 return 0;
471 * Adjust hero intrinsics as if this object was being added to the hero's
472 * inventory. Called _before_ the object has been added to the hero's
473 * inventory.
475 * This is called when adding objects to the hero's inventory normally (via
476 * addinv) or when an object in the hero's inventory has been polymorphed
477 * in-place.
479 * It may be valid to merge this code with with addinv_core2().
481 void
482 addinv_core1(obj)
483 struct obj *obj;
485 if (obj->oclass == COIN_CLASS) {
486 context.botl = 1;
487 } else if (obj->otyp == AMULET_OF_YENDOR) {
488 if (u.uhave.amulet)
489 impossible("already have amulet?");
490 u.uhave.amulet = 1;
491 u.uachieve.amulet = 1;
492 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
493 if (u.uhave.menorah)
494 impossible("already have candelabrum?");
495 u.uhave.menorah = 1;
496 u.uachieve.menorah = 1;
497 } else if (obj->otyp == BELL_OF_OPENING) {
498 if (u.uhave.bell)
499 impossible("already have silver bell?");
500 u.uhave.bell = 1;
501 u.uachieve.bell = 1;
502 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
503 if (u.uhave.book)
504 impossible("already have the book?");
505 u.uhave.book = 1;
506 u.uachieve.book = 1;
507 } else if (obj->oartifact) {
508 if (is_quest_artifact(obj)) {
509 if (u.uhave.questart)
510 impossible("already have quest artifact?");
511 u.uhave.questart = 1;
512 artitouch(obj);
514 set_artifact_intrinsic(obj, 1, W_ART);
516 if (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
517 u.uachieve.mines_luckstone = 1;
518 obj->record_achieve_special = 0;
519 } else if ((obj->otyp == AMULET_OF_REFLECTION
520 || obj->otyp == BAG_OF_HOLDING)
521 && obj->record_achieve_special) {
522 u.uachieve.finish_sokoban = 1;
523 obj->record_achieve_special = 0;
528 * Adjust hero intrinsics as if this object was being added to the hero's
529 * inventory. Called _after_ the object has been added to the hero's
530 * inventory.
532 * This is called when adding objects to the hero's inventory normally (via
533 * addinv) or when an object in the hero's inventory has been polymorphed
534 * in-place.
536 void
537 addinv_core2(obj)
538 struct obj *obj;
540 if (confers_luck(obj)) {
541 /* new luckstone must be in inventory by this point
542 * for correct calculation */
543 set_moreluck();
548 * Add obj to the hero's inventory. Make sure the object is "free".
549 * Adjust hero attributes as necessary.
551 struct obj *
552 addinv(obj)
553 struct obj *obj;
555 struct obj *otmp, *prev;
556 int saved_otyp = (int) obj->otyp; /* for panic */
557 boolean obj_was_thrown;
559 if (obj->where != OBJ_FREE)
560 panic("addinv: obj not free");
561 /* normally addtobill() clears no_charge when items in a shop are
562 picked up, but won't do so if the shop has become untended */
563 obj->no_charge = 0; /* should not be set in hero's invent */
564 if (Has_contents(obj))
565 picked_container(obj); /* clear no_charge */
566 obj_was_thrown = obj->was_thrown;
567 obj->was_thrown = 0; /* not meaningful for invent */
569 addinv_core1(obj);
571 /* merge with quiver in preference to any other inventory slot
572 in case quiver and wielded weapon are both eligible; adding
573 extra to quivered stack is more useful than to wielded one */
574 if (uquiver && merged(&uquiver, &obj)) {
575 obj = uquiver;
576 if (!obj)
577 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
578 goto added;
580 /* merge if possible; find end of chain in the process */
581 for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
582 if (merged(&otmp, &obj)) {
583 obj = otmp;
584 if (!obj)
585 panic("addinv: null obj after merge otyp=%d", saved_otyp);
586 goto added;
588 /* didn't merge, so insert into chain */
589 assigninvlet(obj);
590 if (flags.invlet_constant || !prev) {
591 obj->nobj = invent; /* insert at beginning */
592 invent = obj;
593 if (flags.invlet_constant)
594 reorder_invent();
595 } else {
596 prev->nobj = obj; /* insert at end */
597 obj->nobj = 0;
599 obj->where = OBJ_INVENT;
601 /* fill empty quiver if obj was thrown */
602 if (flags.pickup_thrown && !uquiver && obj_was_thrown
603 && (throwing_weapon(obj) || is_ammo(obj)))
604 setuqwep(obj);
605 added:
606 addinv_core2(obj);
607 carry_obj_effects(obj); /* carrying affects the obj */
608 update_inventory();
609 return obj;
613 * Some objects are affected by being carried.
614 * Make those adjustments here. Called _after_ the object
615 * has been added to the hero's or monster's inventory,
616 * and after hero's intrinsics have been updated.
618 void
619 carry_obj_effects(obj)
620 struct obj *obj;
622 /* Cursed figurines can spontaneously transform
623 when carried. */
624 if (obj->otyp == FIGURINE) {
625 if (obj->cursed && obj->corpsenm != NON_PM
626 && !dead_species(obj->corpsenm, TRUE)) {
627 attach_fig_transform_timeout(obj);
632 /* Add an item to the inventory unless we're fumbling or it refuses to be
633 * held (via touch_artifact), and give a message.
634 * If there aren't any free inventory slots, we'll drop it instead.
635 * If both success and failure messages are NULL, then we're just doing the
636 * fumbling/slot-limit checking for a silent grab. In any case,
637 * touch_artifact will print its own messages if they are warranted.
639 struct obj *
640 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
641 struct obj *obj;
642 const char *drop_fmt, *drop_arg, *hold_msg;
644 char buf[BUFSZ];
646 if (!Blind)
647 obj->dknown = 1; /* maximize mergibility */
648 if (obj->oartifact) {
649 /* place_object may change these */
650 boolean crysknife = (obj->otyp == CRYSKNIFE);
651 int oerode = obj->oerodeproof;
652 boolean wasUpolyd = Upolyd;
654 /* in case touching this object turns out to be fatal */
655 place_object(obj, u.ux, u.uy);
657 if (!touch_artifact(obj, &youmonst)) {
658 obj_extract_self(obj); /* remove it from the floor */
659 dropy(obj); /* now put it back again :-) */
660 return obj;
661 } else if (wasUpolyd && !Upolyd) {
662 /* loose your grip if you revert your form */
663 if (drop_fmt)
664 pline(drop_fmt, drop_arg);
665 obj_extract_self(obj);
666 dropy(obj);
667 return obj;
669 obj_extract_self(obj);
670 if (crysknife) {
671 obj->otyp = CRYSKNIFE;
672 obj->oerodeproof = oerode;
675 if (Fumbling) {
676 if (drop_fmt)
677 pline(drop_fmt, drop_arg);
678 dropy(obj);
679 } else {
680 long oquan = obj->quan;
681 int prev_encumbr = near_capacity(); /* before addinv() */
683 /* encumbrance only matters if it would now become worse
684 than max( current_value, stressed ) */
685 if (prev_encumbr < MOD_ENCUMBER)
686 prev_encumbr = MOD_ENCUMBER;
687 /* addinv() may redraw the entire inventory, overwriting
688 drop_arg when it comes from something like doname() */
689 if (drop_arg)
690 drop_arg = strcpy(buf, drop_arg);
692 obj = addinv(obj);
693 if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
694 && near_capacity() > prev_encumbr)) {
695 if (drop_fmt)
696 pline(drop_fmt, drop_arg);
697 /* undo any merge which took place */
698 if (obj->quan > oquan)
699 obj = splitobj(obj, oquan);
700 dropx(obj);
701 } else {
702 if (flags.autoquiver && !uquiver && !obj->owornmask
703 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
704 || ammo_and_launcher(obj, uswapwep)))
705 setuqwep(obj);
706 if (hold_msg || drop_fmt)
707 prinv(hold_msg, obj, oquan);
710 return obj;
713 /* useup() all of an item regardless of its quantity */
714 void
715 useupall(obj)
716 struct obj *obj;
718 setnotworn(obj);
719 freeinv(obj);
720 obfree(obj, (struct obj *) 0); /* deletes contents also */
723 void
724 useup(obj)
725 register struct obj *obj;
727 /* Note: This works correctly for containers because they (containers)
728 don't merge. */
729 if (obj->quan > 1L) {
730 obj->in_use = FALSE; /* no longer in use */
731 obj->quan--;
732 obj->owt = weight(obj);
733 update_inventory();
734 } else {
735 useupall(obj);
739 /* use one charge from an item and possibly incur shop debt for it */
740 void
741 consume_obj_charge(obj, maybe_unpaid)
742 struct obj *obj;
743 boolean maybe_unpaid; /* false if caller handles shop billing */
745 if (maybe_unpaid)
746 check_unpaid(obj);
747 obj->spe -= 1;
748 if (obj->known)
749 update_inventory();
753 * Adjust hero's attributes as if this object was being removed from the
754 * hero's inventory. This should only be called from freeinv() and
755 * where we are polymorphing an object already in the hero's inventory.
757 * Should think of a better name...
759 void
760 freeinv_core(obj)
761 struct obj *obj;
763 if (obj->oclass == COIN_CLASS) {
764 context.botl = 1;
765 return;
766 } else if (obj->otyp == AMULET_OF_YENDOR) {
767 if (!u.uhave.amulet)
768 impossible("don't have amulet?");
769 u.uhave.amulet = 0;
770 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
771 if (!u.uhave.menorah)
772 impossible("don't have candelabrum?");
773 u.uhave.menorah = 0;
774 } else if (obj->otyp == BELL_OF_OPENING) {
775 if (!u.uhave.bell)
776 impossible("don't have silver bell?");
777 u.uhave.bell = 0;
778 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
779 if (!u.uhave.book)
780 impossible("don't have the book?");
781 u.uhave.book = 0;
782 } else if (obj->oartifact) {
783 if (is_quest_artifact(obj)) {
784 if (!u.uhave.questart)
785 impossible("don't have quest artifact?");
786 u.uhave.questart = 0;
788 set_artifact_intrinsic(obj, 0, W_ART);
791 if (obj->otyp == LOADSTONE) {
792 curse(obj);
793 } else if (confers_luck(obj)) {
794 set_moreluck();
795 context.botl = 1;
796 } else if (obj->otyp == FIGURINE && obj->timed) {
797 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
801 /* remove an object from the hero's inventory */
802 void
803 freeinv(obj)
804 register struct obj *obj;
806 extract_nobj(obj, &invent);
807 freeinv_core(obj);
808 update_inventory();
811 void
812 delallobj(x, y)
813 int x, y;
815 struct obj *otmp, *otmp2;
817 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
818 if (otmp == uball)
819 unpunish();
820 /* after unpunish(), or might get deallocated chain */
821 otmp2 = otmp->nexthere;
822 if (otmp == uchain)
823 continue;
824 delobj(otmp);
828 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
829 void
830 delobj(obj)
831 register struct obj *obj;
833 boolean update_map;
835 if (obj->otyp == AMULET_OF_YENDOR
836 || obj->otyp == CANDELABRUM_OF_INVOCATION
837 || obj->otyp == BELL_OF_OPENING
838 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
839 /* player might be doing something stupid, but we
840 * can't guarantee that. assume special artifacts
841 * are indestructible via drawbridges, and exploding
842 * chests, and golem creation, and ...
844 return;
846 update_map = (obj->where == OBJ_FLOOR);
847 obj_extract_self(obj);
848 if (update_map)
849 newsym(obj->ox, obj->oy);
850 obfree(obj, (struct obj *) 0); /* frees contents also */
853 /* try to find a particular type of object at designated map location */
854 struct obj *
855 sobj_at(otyp, x, y)
856 int otyp;
857 int x, y;
859 register struct obj *otmp;
861 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
862 if (otmp->otyp == otyp)
863 break;
865 return otmp;
868 /* sobj_at(&c) traversal -- find next object of specified type */
869 struct obj *
870 nxtobj(obj, type, by_nexthere)
871 struct obj *obj;
872 int type;
873 boolean by_nexthere;
875 register struct obj *otmp;
877 otmp = obj; /* start with the object after this one */
878 do {
879 otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
880 if (!otmp)
881 break;
882 } while (otmp->otyp != type);
884 return otmp;
887 struct obj *
888 carrying(type)
889 register int type;
891 register struct obj *otmp;
893 for (otmp = invent; otmp; otmp = otmp->nobj)
894 if (otmp->otyp == type)
895 return otmp;
896 return (struct obj *) 0;
899 /* Fictional and not-so-fictional currencies.
900 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
902 static const char *const currencies[] = {
903 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
904 "Ankh-Morpork Dollar", /* Discworld */
905 "auric", /* The Domination of Draka */
906 "buckazoid", /* Space Quest */
907 "cirbozoid", /* Starslip */
908 "credit chit", /* Deus Ex */
909 "cubit", /* Battlestar Galactica */
910 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
911 "fretzer", /* Jules Verne */
912 "imperial credit", /* Star Wars */
913 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
914 "kongbuck", /* Snow Crash */
915 "nanite", /* System Shock 2 */
916 "quatloo", /* Star Trek, Sim City */
917 "simoleon", /* Sim City */
918 "solari", /* Spaceballs */
919 "spacebuck", /* Spaceballs */
920 "sporebuck", /* Spore */
921 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
922 "woolong", /* Cowboy Bebop */
923 "zorkmid", /* Zork, NetHack */
926 const char *
927 currency(amount)
928 long amount;
930 const char *res;
932 res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
933 if (amount != 1L)
934 res = makeplural(res);
935 return res;
938 boolean
939 have_lizard()
941 register struct obj *otmp;
943 for (otmp = invent; otmp; otmp = otmp->nobj)
944 if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
945 return TRUE;
946 return FALSE;
949 /* 3.6 tribute */
950 struct obj *
951 u_have_novel()
953 register struct obj *otmp;
955 for (otmp = invent; otmp; otmp = otmp->nobj)
956 if (otmp->otyp == SPE_NOVEL)
957 return otmp;
958 return (struct obj *) 0;
961 struct obj *
962 o_on(id, objchn)
963 unsigned int id;
964 register struct obj *objchn;
966 struct obj *temp;
968 while (objchn) {
969 if (objchn->o_id == id)
970 return objchn;
971 if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
972 return temp;
973 objchn = objchn->nobj;
975 return (struct obj *) 0;
978 boolean
979 obj_here(obj, x, y)
980 register struct obj *obj;
981 int x, y;
983 register struct obj *otmp;
985 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
986 if (obj == otmp)
987 return TRUE;
988 return FALSE;
991 struct obj *
992 g_at(x, y)
993 register int x, y;
995 register struct obj *obj = level.objects[x][y];
997 while (obj) {
998 if (obj->oclass == COIN_CLASS)
999 return obj;
1000 obj = obj->nexthere;
1002 return (struct obj *) 0;
1005 /* compact a string of inventory letters by dashing runs of letters */
1006 STATIC_OVL void
1007 compactify(buf)
1008 register char *buf;
1010 register int i1 = 1, i2 = 1;
1011 register char ilet, ilet1, ilet2;
1013 ilet2 = buf[0];
1014 ilet1 = buf[1];
1015 buf[++i2] = buf[++i1];
1016 ilet = buf[i1];
1017 while (ilet) {
1018 if (ilet == ilet1 + 1) {
1019 if (ilet1 == ilet2 + 1)
1020 buf[i2 - 1] = ilet1 = '-';
1021 else if (ilet2 == '-') {
1022 buf[i2 - 1] = ++ilet1;
1023 buf[i2] = buf[++i1];
1024 ilet = buf[i1];
1025 continue;
1027 } else if (ilet == NOINVSYM) {
1028 /* compact three or more consecutive '#'
1029 characters into "#-#" */
1030 if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
1031 buf[i2 - 1] = '-';
1032 else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
1033 && buf[i2 - 1] == NOINVSYM)
1034 --i2;
1036 ilet2 = ilet1;
1037 ilet1 = ilet;
1038 buf[++i2] = buf[++i1];
1039 ilet = buf[i1];
1043 /* some objects shouldn't be split when count given to getobj or askchain */
1044 boolean
1045 splittable(obj)
1046 struct obj *obj;
1048 return !((obj->otyp == LOADSTONE && obj->cursed)
1049 || (obj == uwep && welded(uwep)));
1052 /* match the prompt for either 'T' or 'R' command */
1053 STATIC_OVL boolean
1054 taking_off(action)
1055 const char *action;
1057 return !strcmp(action, "take off") || !strcmp(action, "remove");
1060 /* match the prompt for either 'W' or 'P' command */
1061 STATIC_OVL boolean
1062 putting_on(action)
1063 const char *action;
1065 return !strcmp(action, "wear") || !strcmp(action, "put on");
1069 * getobj returns:
1070 * struct obj *xxx: object to do something with.
1071 * (struct obj *) 0 error return: no object.
1072 * &zeroobj explicitly no object (as in w-).
1073 !!!! test if gold can be used in unusual ways (eaten etc.)
1074 !!!! may be able to remove "usegold"
1076 struct obj *
1077 getobj(let, word)
1078 register const char *let, *word;
1080 register struct obj *otmp;
1081 register char ilet;
1082 char buf[BUFSZ], qbuf[QBUFSZ];
1083 char lets[BUFSZ], altlets[BUFSZ], *ap;
1084 register int foo = 0;
1085 register char *bp = buf;
1086 xchar allowcnt = 0; /* 0, 1 or 2 */
1087 boolean usegold = FALSE; /* can't use gold because its illegal */
1088 boolean allowall = FALSE;
1089 boolean allownone = FALSE;
1090 boolean useboulder = FALSE;
1091 xchar foox = 0;
1092 long cnt;
1093 boolean cntgiven = FALSE;
1094 long dummymask;
1096 if (*let == ALLOW_COUNT)
1097 let++, allowcnt = 1;
1098 if (*let == COIN_CLASS)
1099 let++, usegold = TRUE;
1101 /* Equivalent of an "ugly check" for gold */
1102 if (usegold && !strcmp(word, "eat")
1103 && (!metallivorous(youmonst.data)
1104 || youmonst.data == &mons[PM_RUST_MONSTER]))
1105 usegold = FALSE;
1107 if (*let == ALL_CLASSES)
1108 let++, allowall = TRUE;
1109 if (*let == ALLOW_NONE)
1110 let++, allownone = TRUE;
1111 /* "ugly check" for reading fortune cookies, part 1.
1112 * The normal 'ugly check' keeps the object on the inventory list.
1113 * We don't want to do that for shirts/cookies, so the check for
1114 * them is handled a bit differently (and also requires that we set
1115 * allowall in the caller).
1117 if (allowall && !strcmp(word, "read"))
1118 allowall = FALSE;
1120 /* another ugly check: show boulders (not statues) */
1121 if (*let == WEAPON_CLASS && !strcmp(word, "throw")
1122 && throws_rocks(youmonst.data))
1123 useboulder = TRUE;
1125 if (allownone)
1126 *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
1127 ap = altlets;
1129 if (!flags.invlet_constant)
1130 reassign();
1131 else
1132 /* in case invent is in packorder, force it to be in invlet
1133 order before collecing candidate inventory letters;
1134 if player responds with '?' or '*' it will be changed
1135 back by display_pickinv(), but by then we'll have 'lets'
1136 and so won't have to re-sort in the for(;;) loop below */
1137 sortloot(&invent, SORTLOOT_INVLET, FALSE);
1139 for (otmp = invent; otmp; otmp = otmp->nobj) {
1140 if (&bp[foo] == &buf[sizeof buf - 1]
1141 || ap == &altlets[sizeof altlets - 1]) {
1142 /* we must have a huge number of NOINVSYM items somehow */
1143 impossible("getobj: inventory overflow");
1144 break;
1147 if (!*let || index(let, otmp->oclass)
1148 || (usegold && otmp->invlet == GOLD_SYM)
1149 || (useboulder && otmp->otyp == BOULDER)) {
1150 register int otyp = otmp->otyp;
1152 bp[foo++] = otmp->invlet;
1153 /* clang-format off */
1154 /* *INDENT-OFF* */
1155 /* ugly check: remove inappropriate things */
1156 if (
1157 (taking_off(word) /* exclude if not worn */
1158 && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1159 || (putting_on(word) /* exclude if already worn */
1160 && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1161 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1162 || (!strcmp(word, "wield")
1163 && (otmp->owornmask & W_WEP))
1164 #endif
1165 || (!strcmp(word, "ready") /* exclude when wielded... */
1166 && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
1167 && otmp->quan == 1L)) /* ...unless more than one */
1168 || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1169 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1171 foo--;
1172 foox++;
1174 /* Second ugly check; unlike the first it won't trigger an
1175 * "else" in "you don't have anything else to ___".
1177 else if (
1178 (putting_on(word)
1179 && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1180 || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1181 && otyp != TOWEL && otyp != LENSES)))
1182 || (!strcmp(word, "wield")
1183 && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1184 || (!strcmp(word, "eat") && !is_edible(otmp))
1185 || (!strcmp(word, "sacrifice")
1186 && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1187 && otyp != FAKE_AMULET_OF_YENDOR))
1188 || (!strcmp(word, "write with")
1189 && (otmp->oclass == TOOL_CLASS
1190 && otyp != MAGIC_MARKER && otyp != TOWEL))
1191 || (!strcmp(word, "tin")
1192 && (otyp != CORPSE || !tinnable(otmp)))
1193 || (!strcmp(word, "rub")
1194 && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1195 && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1196 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1197 || (!strcmp(word, "use or apply")
1198 /* Picks, axes, pole-weapons, bullwhips */
1199 && ((otmp->oclass == WEAPON_CLASS
1200 && !is_pick(otmp) && !is_axe(otmp)
1201 && !is_pole(otmp) && otyp != BULLWHIP)
1202 || (otmp->oclass == POTION_CLASS
1203 /* only applicable potion is oil, and it will only
1204 be offered as a choice when already discovered */
1205 && (otyp != POT_OIL || !otmp->dknown
1206 || !objects[POT_OIL].oc_name_known))
1207 || (otmp->oclass == FOOD_CLASS
1208 && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1209 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1210 || (!strcmp(word, "invoke")
1211 && !otmp->oartifact
1212 && !objects[otyp].oc_unique
1213 && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1214 && otyp != CRYSTAL_BALL /* synonym for apply */
1215 /* note: presenting the possibility of invoking non-artifact
1216 mirrors and/or lamps is simply a cruel deception... */
1217 && otyp != MIRROR
1218 && otyp != MAGIC_LAMP
1219 && (otyp != OIL_LAMP /* don't list known oil lamp */
1220 || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1221 || (!strcmp(word, "untrap with")
1222 && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1223 || (otmp->oclass == POTION_CLASS
1224 /* only applicable potion is oil, and it will only
1225 be offered as a choice when already discovered */
1226 && (otyp != POT_OIL || !otmp->dknown
1227 || !objects[POT_OIL].oc_name_known))))
1228 || (!strcmp(word, "tip") && !Is_container(otmp)
1229 /* include horn of plenty if sufficiently discovered */
1230 && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1231 || !objects[HORN_OF_PLENTY].oc_name_known))
1232 || (!strcmp(word, "charge") && !is_chargeable(otmp))
1233 || (!strcmp(word, "open") && otyp != TIN)
1234 || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1236 foo--;
1238 /* Third ugly check: acceptable but not listed as likely
1239 * candidates in the prompt or in the inventory subset if
1240 * player responds with '?'.
1242 else if (
1243 /* ugly check for unworn armor that can't be worn */
1244 (putting_on(word) && *let == ARMOR_CLASS
1245 && !canwearobj(otmp, &dummymask, FALSE))
1246 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1247 || ((putting_on(word) || taking_off(word))
1248 && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1249 /* or unsuitable items rubbed on known touchstone */
1250 || (!strncmp(word, "rub on the stone", 16)
1251 && *let == GEM_CLASS && otmp->dknown
1252 && objects[otyp].oc_name_known)
1253 /* suppress corpses on astral, amulets elsewhere */
1254 || (!strcmp(word, "sacrifice")
1255 /* (!astral && amulet) || (astral && !amulet) */
1256 && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1257 /* suppress container being stashed into */
1258 || (!strcmp(word, "stash") && !ck_bag(otmp))
1259 /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1260 or accessory (ring) covered by cursed worn armor (gloves) */
1261 || (taking_off(word)
1262 && inaccessible_equipment(otmp, (const char *) 0,
1263 (boolean) (otmp->oclass == RING_CLASS)))
1264 || (!strcmp(word, "write on")
1265 && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
1266 || !otmp->dknown || !objects[otyp].oc_name_known))
1268 /* acceptable but not listed as likely candidate */
1269 foo--;
1270 allowall = TRUE;
1271 *ap++ = otmp->invlet;
1273 /* *INDENT-ON* */
1274 /* clang-format on */
1275 } else {
1276 /* "ugly check" for reading fortune cookies, part 2 */
1277 if ((!strcmp(word, "read") && is_readable(otmp)))
1278 allowall = usegold = TRUE;
1282 bp[foo] = 0;
1283 if (foo == 0 && bp > buf && bp[-1] == ' ')
1284 *--bp = 0;
1285 Strcpy(lets, bp); /* necessary since we destroy buf */
1286 if (foo > 5) /* compactify string */
1287 compactify(bp);
1288 *ap = '\0';
1290 if (!foo && !allowall && !allownone) {
1291 You("don't have anything %sto %s.", foox ? "else " : "", word);
1292 return (struct obj *) 0;
1293 } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
1294 /* we wanted all scrolls and books in altlets[], but that came with
1295 'allowall' which we don't want since it prevents "silly thing"
1296 result if anything other than scroll or spellbook is chosen */
1297 allowall = FALSE;
1299 for (;;) {
1300 cnt = 0;
1301 cntgiven = FALSE;
1302 if (!buf[0]) {
1303 Sprintf(qbuf, "What do you want to %s? [*]", word);
1304 } else {
1305 Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
1307 if (in_doagain)
1308 ilet = readchar();
1309 else
1310 ilet = yn_function(qbuf, (char *) 0, '\0');
1311 if (digit(ilet)) {
1312 long tmpcnt = 0;
1314 if (!allowcnt) {
1315 pline("No count allowed with this command.");
1316 continue;
1318 ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt);
1319 if (tmpcnt) {
1320 cnt = tmpcnt;
1321 cntgiven = TRUE;
1324 if (index(quitchars, ilet)) {
1325 if (flags.verbose)
1326 pline1(Never_mind);
1327 return (struct obj *) 0;
1329 if (ilet == HANDS_SYM) { /* '-' */
1330 if (!allownone) {
1331 char *suf = (char *) 0;
1333 strcpy(buf, word);
1334 if ((bp = strstr(buf, " on the ")) != 0) {
1335 /* rub on the stone[s] */
1336 *bp = '\0';
1337 suf = (bp + 1);
1339 if ((bp = strstr(buf, " or ")) != 0) {
1340 *bp = '\0';
1341 bp = (rn2(2) ? buf : (bp + 4));
1342 } else
1343 bp = buf;
1344 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1345 suf ? suf : "");
1347 return (allownone ? &zeroobj : (struct obj *) 0);
1349 /* since gold is now kept in inventory, we need to do processing for
1350 select-from-invent before checking whether gold has been picked */
1351 if (ilet == '?' || ilet == '*') {
1352 char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1353 long ctmp = 0;
1355 qbuf[0] = '\0';
1356 if (!strcmp(word, "grease"))
1357 Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
1358 else if (!strcmp(word, "write with"))
1359 Sprintf(qbuf, "your %s", body_part(FINGERTIP));
1360 else if (!strcmp(word, "wield"))
1361 Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
1362 makeplural(body_part(HAND)),
1363 !uwep ? " (wielded)" : "");
1364 else if (!strcmp(word, "ready"))
1365 Sprintf(qbuf, "empty quiver%s",
1366 !uquiver ? " (nothing readied)" : "");
1368 if (ilet == '?' && !*lets && *altlets)
1369 allowed_choices = altlets;
1370 ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
1371 TRUE, allowcnt ? &ctmp : (long *) 0);
1372 if (!ilet)
1373 continue;
1374 if (ilet == HANDS_SYM)
1375 return &zeroobj;
1376 if (ilet == '\033') {
1377 if (flags.verbose)
1378 pline1(Never_mind);
1379 return (struct obj *) 0;
1381 if (allowcnt && ctmp >= 0) {
1382 cnt = ctmp;
1383 cntgiven = TRUE;
1385 /* they typed a letter (not a space) at the prompt */
1387 /* find the item which was picked */
1388 for (otmp = invent; otmp; otmp = otmp->nobj)
1389 if (otmp->invlet == ilet)
1390 break;
1391 /* some items have restrictions */
1392 if (ilet == def_oc_syms[COIN_CLASS].sym
1393 /* guard against the [hypothetical] chace of having more
1394 than one invent slot of gold and picking the non-'$' one */
1395 || (otmp && otmp->oclass == COIN_CLASS)) {
1396 if (!usegold) {
1397 You("cannot %s gold.", word);
1398 return (struct obj *) 0;
1400 /* Historic note: early Nethack had a bug which was
1401 * first reported for Larn, where trying to drop 2^32-n
1402 * gold pieces was allowed, and did interesting things
1403 * to your money supply. The LRS is the tax bureau
1404 * from Larn.
1406 if (cntgiven && cnt <= 0) {
1407 if (cnt < 0)
1408 pline_The(
1409 "LRS would be very interested to know you have that much.");
1410 return (struct obj *) 0;
1413 if (cntgiven && !strcmp(word, "throw")) {
1414 /* permit counts for throwing gold, but don't accept
1415 * counts for other things since the throw code will
1416 * split off a single item anyway */
1417 if (cnt == 0)
1418 return (struct obj *) 0;
1419 if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
1420 && !(otmp && otmp->oclass == COIN_CLASS))) {
1421 You("can only throw one item at a time.");
1422 continue;
1425 context.botl = 1; /* May have changed the amount of money */
1426 savech(ilet);
1427 /* [we used to set otmp (by finding ilet in invent) here, but
1428 that's been moved above so that otmp can be checked earlier] */
1429 /* verify the chosen object */
1430 if (!otmp) {
1431 You("don't have that object.");
1432 if (in_doagain)
1433 return (struct obj *) 0;
1434 continue;
1435 } else if (cnt < 0 || otmp->quan < cnt) {
1436 You("don't have that many! You have only %ld.", otmp->quan);
1437 if (in_doagain)
1438 return (struct obj *) 0;
1439 continue;
1441 break;
1443 if (!allowall && let && !index(let, otmp->oclass)
1444 && !(usegold && otmp->oclass == COIN_CLASS)) {
1445 silly_thing(word, otmp);
1446 return (struct obj *) 0;
1448 if (cntgiven) {
1449 if (cnt == 0)
1450 return (struct obj *) 0;
1451 if (cnt != otmp->quan) {
1452 /* don't split a stack of cursed loadstones */
1453 if (splittable(otmp))
1454 otmp = splitobj(otmp, cnt);
1455 else if (otmp->otyp == LOADSTONE && otmp->cursed)
1456 /* kludge for canletgo()'s can't-drop-this message */
1457 otmp->corpsenm = (int) cnt;
1460 return otmp;
1463 void
1464 silly_thing(word, otmp)
1465 const char *word;
1466 struct obj *otmp;
1468 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1469 nhUse(otmp);
1470 #else
1471 const char *s1, *s2, *s3;
1472 int ocls = otmp->oclass, otyp = otmp->otyp;
1474 s1 = s2 = s3 = 0;
1475 /* check for attempted use of accessory commands ('P','R') on armor
1476 and for corresponding armor commands ('W','T') on accessories */
1477 if (ocls == ARMOR_CLASS) {
1478 if (!strcmp(word, "put on"))
1479 s1 = "W", s2 = "wear", s3 = "";
1480 else if (!strcmp(word, "remove"))
1481 s1 = "T", s2 = "take", s3 = " off";
1482 } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1483 || ocls == AMULET_CLASS
1484 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1485 if (!strcmp(word, "wear"))
1486 s1 = "P", s2 = "put", s3 = " on";
1487 else if (!strcmp(word, "take off"))
1488 s1 = "R", s2 = "remove", s3 = "";
1490 if (s1)
1491 pline("Use the '%s' command to %s %s%s.", s1, s2,
1492 !is_plural(otmp) ? "that" : "those", s3);
1493 else
1494 #endif
1495 pline(silly_thing_to, word);
1498 STATIC_PTR int
1499 ckvalidcat(otmp)
1500 struct obj *otmp;
1502 /* use allow_category() from pickup.c */
1503 return (int) allow_category(otmp);
1506 STATIC_PTR int
1507 ckunpaid(otmp)
1508 struct obj *otmp;
1510 return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1513 boolean
1514 wearing_armor()
1516 return (boolean) (uarm || uarmc || uarmf || uarmg
1517 || uarmh || uarms || uarmu);
1520 boolean
1521 is_worn(otmp)
1522 struct obj *otmp;
1524 return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
1525 ? TRUE
1526 : FALSE;
1529 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1530 STATIC_VAR struct xprnctx {
1531 char let;
1532 boolean dot;
1533 } safeq_xprn_ctx;
1535 /* safe_qbuf() -> short_oname() callback */
1536 STATIC_PTR char *
1537 safeq_xprname(obj)
1538 struct obj *obj;
1540 return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1541 0L, 0L);
1544 /* alternate safe_qbuf() -> short_oname() callback */
1545 STATIC_PTR char *
1546 safeq_shortxprname(obj)
1547 struct obj *obj;
1549 return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1550 safeq_xprn_ctx.dot, 0L, 0L);
1553 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1554 RING_CLASS, AMULET_CLASS,
1555 TOOL_CLASS, 0 };
1557 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1558 Return the number of times fn was called successfully.
1559 If combo is TRUE, we just use this to get a category list. */
1561 ggetobj(word, fn, mx, combo, resultflags)
1562 const char *word;
1563 int FDECL((*fn), (OBJ_P)), mx;
1564 boolean combo; /* combination menu flag */
1565 unsigned *resultflags;
1567 int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1568 boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1569 boolean takeoff, ident, allflag, m_seen;
1570 int itemcount;
1571 int oletct, iletct, unpaid, oc_of_sym;
1572 char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
1573 char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1574 char buf[BUFSZ], qbuf[QBUFSZ];
1576 if (resultflags)
1577 *resultflags = 0;
1578 takeoff = ident = allflag = m_seen = FALSE;
1579 if (!invent) {
1580 You("have nothing to %s.", word);
1581 return 0;
1583 add_valid_menu_class(0); /* reset */
1584 if (taking_off(word)) {
1585 takeoff = TRUE;
1586 ofilter = is_worn;
1587 } else if (!strcmp(word, "identify")) {
1588 ident = TRUE;
1589 ofilter = not_fully_identified;
1592 iletct = collect_obj_classes(ilets, invent, FALSE, ofilter, &itemcount);
1593 unpaid = count_unpaid(invent);
1595 if (ident && !iletct) {
1596 return -1; /* no further identifications */
1597 } else if (!takeoff && (unpaid || invent)) {
1598 ilets[iletct++] = ' ';
1599 if (unpaid)
1600 ilets[iletct++] = 'u';
1601 if (count_buc(invent, BUC_BLESSED))
1602 ilets[iletct++] = 'B';
1603 if (count_buc(invent, BUC_UNCURSED))
1604 ilets[iletct++] = 'U';
1605 if (count_buc(invent, BUC_CURSED))
1606 ilets[iletct++] = 'C';
1607 if (count_buc(invent, BUC_UNKNOWN))
1608 ilets[iletct++] = 'X';
1609 if (invent)
1610 ilets[iletct++] = 'a';
1611 } else if (takeoff && invent) {
1612 ilets[iletct++] = ' ';
1614 ilets[iletct++] = 'i';
1615 if (!combo)
1616 ilets[iletct++] = 'm'; /* allow menu presentation on request */
1617 ilets[iletct] = '\0';
1619 for (;;) {
1620 Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
1621 word, ilets);
1622 getlin(qbuf, buf);
1623 if (buf[0] == '\033')
1624 return 0;
1625 if (index(buf, 'i')) {
1626 char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
1627 struct obj *otmp;
1629 /* applicable inventory letters; if empty, show entire invent */
1630 ailets[0] = '\0';
1631 if (ofilter)
1632 for (otmp = invent; otmp; otmp = otmp->nobj)
1633 /* index() check: limit overflow items to one '#' */
1634 if ((*ofilter)(otmp) && !index(ailets, otmp->invlet))
1635 (void) strkitten(ailets, otmp->invlet);
1636 if (display_inventory(ailets, TRUE) == '\033')
1637 return 0;
1638 } else
1639 break;
1642 extra_removeables[0] = '\0';
1643 if (takeoff) {
1644 /* arbitrary types of items can be placed in the weapon slots
1645 [any duplicate entries in extra_removeables[] won't matter] */
1646 if (uwep)
1647 (void) strkitten(extra_removeables, uwep->oclass);
1648 if (uswapwep)
1649 (void) strkitten(extra_removeables, uswapwep->oclass);
1650 if (uquiver)
1651 (void) strkitten(extra_removeables, uquiver->oclass);
1654 ip = buf;
1655 olets[oletct = 0] = '\0';
1656 while ((sym = *ip++) != '\0') {
1657 if (sym == ' ')
1658 continue;
1659 oc_of_sym = def_char_to_objclass(sym);
1660 if (takeoff && oc_of_sym != MAXOCLASSES) {
1661 if (index(extra_removeables, oc_of_sym)) {
1662 ; /* skip rest of takeoff checks */
1663 } else if (!index(removeables, oc_of_sym)) {
1664 pline("Not applicable.");
1665 return 0;
1666 } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1667 noarmor(FALSE);
1668 return 0;
1669 } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
1670 && !uquiver) {
1671 You("are not wielding anything.");
1672 return 0;
1673 } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1674 You("are not wearing rings.");
1675 return 0;
1676 } else if (oc_of_sym == AMULET_CLASS && !uamul) {
1677 You("are not wearing an amulet.");
1678 return 0;
1679 } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1680 You("are not wearing a blindfold.");
1681 return 0;
1685 if (oc_of_sym == COIN_CLASS && !combo) {
1686 context.botl = 1;
1687 } else if (sym == 'a') {
1688 allflag = TRUE;
1689 } else if (sym == 'A') {
1690 /* same as the default */;
1691 } else if (sym == 'u') {
1692 add_valid_menu_class('u');
1693 ckfn = ckunpaid;
1694 } else if (sym == 'B') {
1695 add_valid_menu_class('B');
1696 ckfn = ckvalidcat;
1697 } else if (sym == 'U') {
1698 add_valid_menu_class('U');
1699 ckfn = ckvalidcat;
1700 } else if (sym == 'C') {
1701 add_valid_menu_class('C');
1702 ckfn = ckvalidcat;
1703 } else if (sym == 'X') {
1704 add_valid_menu_class('X');
1705 ckfn = ckvalidcat;
1706 } else if (sym == 'm') {
1707 m_seen = TRUE;
1708 } else if (oc_of_sym == MAXOCLASSES) {
1709 You("don't have any %c's.", sym);
1710 } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
1711 if (!index(olets, oc_of_sym)) {
1712 add_valid_menu_class(oc_of_sym);
1713 olets[oletct++] = oc_of_sym;
1714 olets[oletct] = 0;
1719 if (m_seen) {
1720 return (allflag
1721 || (!oletct && ckfn != ckunpaid && ckfn != ckvalidcat))
1722 ? -2 : -3;
1723 } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
1724 return 0;
1725 #if 0
1726 /* !!!! test gold dropping */
1727 } else if (allowgold == 2 && !oletct) {
1728 return 1; /* you dropped gold (or at least tried to) */
1729 #endif
1730 } else {
1731 int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1733 * askchain() has already finished the job in this case
1734 * so set a special flag to convey that back to the caller
1735 * so that it won't continue processing.
1736 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1738 if (combo && allflag && resultflags)
1739 *resultflags |= ALL_FINISHED;
1740 return cnt;
1745 * Walk through the chain starting at objchn and ask for all objects
1746 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1747 * whether the action in question (i.e., fn) has to be performed.
1748 * If allflag then no questions are asked. Mx gives the max number
1749 * of objects to be treated. Return the number of objects treated.
1752 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1753 struct obj **objchn;
1754 int allflag, mx;
1755 const char *olets, *word; /* olets is an Obj Class char array */
1756 int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
1758 struct obj *otmp, *otmpo;
1759 register char sym, ilet;
1760 register int cnt = 0, dud = 0, tmp;
1761 boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
1762 char qbuf[QBUFSZ], qpfx[QBUFSZ];
1764 takeoff = taking_off(word);
1765 ident = !strcmp(word, "identify");
1766 take_out = !strcmp(word, "take out");
1767 put_in = !strcmp(word, "put in");
1768 nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
1769 || takeoff || take_out || put_in);
1770 ininv = (*objchn == invent);
1772 /* someday maybe we'll sort by 'olets' too (temporarily replace
1773 flags.packorder and pass SORTLOOT_PACK), but not yet... */
1774 sortloot(objchn, SORTLOOT_INVLET, FALSE);
1776 first = TRUE;
1778 * Interrogate in the object class order specified.
1779 * For example, if a person specifies =/ then first all rings
1780 * will be asked about followed by all wands. -dgk
1782 nextclass:
1783 ilet = 'a' - 1;
1784 if (*objchn && (*objchn)->oclass == COIN_CLASS)
1785 ilet--; /* extra iteration */
1787 * Multiple Drop can change the invent chain while it operates
1788 * (dropping a burning potion of oil while levitating creates
1789 * an explosion which can destroy inventory items), so simple
1790 * list traversal
1791 * for (otmp = *objchn; otmp; otmp = otmp2) {
1792 * otmp2 = otmp->nobj;
1793 * ...
1795 * is inadequate here. Use each object's bypass bit to keep
1796 * track of which list elements have already been processed.
1798 bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
1799 while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
1800 if (ilet == 'z')
1801 ilet = 'A';
1802 else
1803 ilet++;
1804 if (olets && *olets && otmp->oclass != *olets)
1805 continue;
1806 if (takeoff && !is_worn(otmp))
1807 continue;
1808 if (ident && !not_fully_identified(otmp))
1809 continue;
1810 if (ckfn && !(*ckfn)(otmp))
1811 continue;
1812 if (!allflag) {
1813 safeq_xprn_ctx.let = ilet;
1814 safeq_xprn_ctx.dot = !nodot;
1815 *qpfx = '\0';
1816 if (first) {
1817 /* traditional_loot() skips prompting when only one
1818 class of objects is involved, so prefix the first
1819 object being queried here with an explanation why */
1820 if (take_out || put_in)
1821 Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
1822 first = FALSE;
1824 (void) safe_qbuf(qbuf, qpfx, "?", otmp,
1825 ininv ? safeq_xprname : doname,
1826 ininv ? safeq_shortxprname : ansimpleoname,
1827 "item");
1828 sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
1829 : nyNaq(qbuf);
1830 } else
1831 sym = 'y';
1833 otmpo = otmp;
1834 if (sym == '#') {
1835 /* Number was entered; split the object unless it corresponds
1836 to 'none' or 'all'. 2 special cases: cursed loadstones and
1837 welded weapons (eg, multiple daggers) will remain as merged
1838 unit; done to avoid splitting an object that won't be
1839 droppable (even if we're picking up rather than dropping). */
1840 if (!yn_number) {
1841 sym = 'n';
1842 } else {
1843 sym = 'y';
1844 if (yn_number < otmp->quan && splittable(otmp))
1845 otmp = splitobj(otmp, yn_number);
1848 switch (sym) {
1849 case 'a':
1850 allflag = 1;
1851 case 'y':
1852 tmp = (*fn)(otmp);
1853 if (tmp < 0) {
1854 if (container_gone(fn)) {
1855 /* otmp caused magic bag to explode;
1856 both are now gone */
1857 otmp = 0; /* and return */
1858 } else if (otmp && otmp != otmpo) {
1859 /* split occurred, merge again */
1860 (void) merged(&otmpo, &otmp);
1862 goto ret;
1864 cnt += tmp;
1865 if (--mx == 0)
1866 goto ret;
1867 case 'n':
1868 if (nodot)
1869 dud++;
1870 default:
1871 break;
1872 case 'q':
1873 /* special case for seffects() */
1874 if (ident)
1875 cnt = -1;
1876 goto ret;
1879 if (olets && *olets && *++olets)
1880 goto nextclass;
1881 if (!takeoff && (dud || cnt))
1882 pline("That was all.");
1883 else if (!dud && !cnt)
1884 pline("No applicable objects.");
1885 ret:
1886 bypass_objlist(*objchn, FALSE);
1887 return cnt;
1891 * Object identification routines:
1894 /* make an object actually be identified; no display updating */
1895 void
1896 fully_identify_obj(otmp)
1897 struct obj *otmp;
1899 makeknown(otmp->otyp);
1900 if (otmp->oartifact)
1901 discover_artifact((xchar) otmp->oartifact);
1902 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1903 if (Is_container(otmp) || otmp->otyp == STATUE)
1904 otmp->cknown = otmp->lknown = 1;
1905 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1906 learn_egg_type(otmp->corpsenm);
1909 /* ggetobj callback routine; identify an object and give immediate feedback */
1911 identify(otmp)
1912 struct obj *otmp;
1914 fully_identify_obj(otmp);
1915 prinv((char *) 0, otmp, 0L);
1916 return 1;
1919 /* menu of unidentified objects; select and identify up to id_limit of them */
1920 STATIC_OVL void
1921 menu_identify(id_limit)
1922 int id_limit;
1924 menu_item *pick_list;
1925 int n, i, first = 1, tryct = 5;
1926 char buf[BUFSZ];
1927 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1929 while (id_limit) {
1930 Sprintf(buf, "What would you like to identify %s?",
1931 first ? "first" : "next");
1932 n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
1933 | USE_INVLET | INVORDER_SORT),
1934 &pick_list, PICK_ANY, not_fully_identified);
1936 if (n > 0) {
1937 if (n > id_limit)
1938 n = id_limit;
1939 for (i = 0; i < n; i++, id_limit--)
1940 (void) identify(pick_list[i].item.a_obj);
1941 free((genericptr_t) pick_list);
1942 mark_synch(); /* Before we loop to pop open another menu */
1943 first = 0;
1944 } else if (n == -2) { /* player used ESC to quit menu */
1945 break;
1946 } else if (n == -1) { /* no eligible items found */
1947 pline("That was all.");
1948 break;
1949 } else if (!--tryct) { /* stop re-prompting */
1950 pline1(thats_enough_tries);
1951 break;
1952 } else { /* try again */
1953 pline("Choose an item; use ESC to decline.");
1958 /* dialog with user to identify a given number of items; 0 means all */
1959 void
1960 identify_pack(id_limit, learning_id)
1961 int id_limit;
1962 boolean learning_id; /* true if we just read unknown identify scroll */
1964 struct obj *obj, *the_obj;
1965 int n, unid_cnt;
1967 unid_cnt = 0;
1968 the_obj = 0; /* if unid_cnt ends up 1, this will be it */
1969 for (obj = invent; obj; obj = obj->nobj)
1970 if (not_fully_identified(obj))
1971 ++unid_cnt, the_obj = obj;
1973 if (!unid_cnt) {
1974 You("have already identified all %sof your possessions.",
1975 learning_id ? "the rest " : "");
1976 } else if (!id_limit || id_limit >= unid_cnt) {
1977 /* identify everything */
1978 if (unid_cnt == 1) {
1979 (void) identify(the_obj);
1980 } else {
1981 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1983 for (obj = invent; obj; obj = obj->nobj)
1984 if (not_fully_identified(obj))
1985 (void) identify(obj);
1987 } else {
1988 /* identify up to `id_limit' items */
1989 n = 0;
1990 if (flags.menu_style == MENU_TRADITIONAL)
1991 do {
1992 n = ggetobj("identify", identify, id_limit, FALSE,
1993 (unsigned *) 0);
1994 if (n < 0)
1995 break; /* quit or no eligible items */
1996 } while ((id_limit -= n) > 0);
1997 if (n == 0 || n < -1)
1998 menu_identify(id_limit);
2000 update_inventory();
2003 /* called when regaining sight; mark inventory objects which were picked
2004 up while blind as now having been seen */
2005 void
2006 learn_unseen_invent()
2008 struct obj *otmp;
2010 if (Blind)
2011 return; /* sanity check */
2013 for (otmp = invent; otmp; otmp = otmp->nobj) {
2014 if (otmp->dknown)
2015 continue; /* already seen */
2016 /* set dknown, perhaps bknown (for priest[ess]) */
2017 (void) xname(otmp);
2019 * If object->eknown gets implemented (see learnwand(zap.c)),
2020 * handle deferred discovery here.
2023 update_inventory();
2026 /* should of course only be called for things in invent */
2027 STATIC_OVL char
2028 obj_to_let(obj)
2029 struct obj *obj;
2031 if (!flags.invlet_constant) {
2032 obj->invlet = NOINVSYM;
2033 reassign();
2035 return obj->invlet;
2039 * Print the indicated quantity of the given object. If quan == 0L then use
2040 * the current quantity.
2042 void
2043 prinv(prefix, obj, quan)
2044 const char *prefix;
2045 struct obj *obj;
2046 long quan;
2048 if (!prefix)
2049 prefix = "";
2050 pline("%s%s%s", prefix, *prefix ? " " : "",
2051 xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
2054 char *
2055 xprname(obj, txt, let, dot, cost, quan)
2056 struct obj *obj;
2057 const char *txt; /* text to print instead of obj */
2058 char let; /* inventory letter */
2059 boolean dot; /* append period; (dot && cost => Iu) */
2060 long cost; /* cost (for inventory of unpaid or expended items) */
2061 long quan; /* if non-0, print this quantity, not obj->quan */
2063 #ifdef LINT /* handle static char li[BUFSZ]; */
2064 char li[BUFSZ];
2065 #else
2066 static char li[BUFSZ];
2067 #endif
2068 boolean use_invlet = (flags.invlet_constant
2069 && let != CONTAINED_SYM && let != HANDS_SYM);
2070 long savequan = 0;
2072 if (quan && obj) {
2073 savequan = obj->quan;
2074 obj->quan = quan;
2077 * If let is:
2078 * - Then obj == null and 'txt' refers to hands or fingers.
2079 * * Then obj == null and we are printing a total amount.
2080 * > Then the object is contained and doesn't have an inventory letter.
2082 if (cost != 0 || let == '*') {
2083 /* if dot is true, we're doing Iu, otherwise Ix */
2084 Sprintf(li,
2085 iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
2086 : "%c - %-45s %6ld %s",
2087 (dot && use_invlet ? obj->invlet : let),
2088 (txt ? txt : doname(obj)), cost, currency(cost));
2089 } else {
2090 /* ordinary inventory display or pickup message */
2091 Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
2092 (txt ? txt : doname(obj)), (dot ? "." : ""));
2094 if (savequan)
2095 obj->quan = savequan;
2097 return li;
2100 /* the 'i' command */
2102 ddoinv()
2104 (void) display_inventory((char *) 0, FALSE);
2105 return 0;
2109 * find_unpaid()
2111 * Scan the given list of objects. If last_found is NULL, return the first
2112 * unpaid object found. If last_found is not NULL, then skip over unpaid
2113 * objects until last_found is reached, then set last_found to NULL so the
2114 * next unpaid object is returned. This routine recursively follows
2115 * containers.
2117 STATIC_OVL struct obj *
2118 find_unpaid(list, last_found)
2119 struct obj *list, **last_found;
2121 struct obj *obj;
2123 while (list) {
2124 if (list->unpaid) {
2125 if (*last_found) {
2126 /* still looking for previous unpaid object */
2127 if (list == *last_found)
2128 *last_found = (struct obj *) 0;
2129 } else
2130 return ((*last_found = list));
2132 if (Has_contents(list)) {
2133 if ((obj = find_unpaid(list->cobj, last_found)) != 0)
2134 return obj;
2136 list = list->nobj;
2138 return (struct obj *) 0;
2141 /* for perm_invent when operating on a partial inventory display, so that
2142 the persistent one doesn't get shrunk during filtering for item selection
2143 then regrown to full inventory, possibly being resized in the process */
2144 static winid cached_pickinv_win = WIN_ERR;
2146 void
2147 free_pickinv_cache()
2149 if (cached_pickinv_win != WIN_ERR) {
2150 destroy_nhwindow(cached_pickinv_win);
2151 cached_pickinv_win = WIN_ERR;
2156 * Internal function used by display_inventory and getobj that can display
2157 * inventory and return a count as well as a letter. If out_cnt is not null,
2158 * any count returned from the menu selection is placed here.
2160 STATIC_OVL char
2161 display_pickinv(lets, xtra_choice, want_reply, out_cnt)
2162 register const char *lets;
2163 const char *xtra_choice; /* "fingers", pick hands rather than an object */
2164 boolean want_reply;
2165 long *out_cnt;
2167 struct obj *otmp;
2168 char ilet, ret;
2169 char *invlet = flags.inv_order;
2170 int n, classcount;
2171 winid win; /* windows being used */
2172 anything any;
2173 menu_item *selected;
2175 if (lets && !*lets)
2176 lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
2178 if (flags.perm_invent && (lets || xtra_choice)) {
2179 /* partial inventory in perm_invent setting; don't operate on
2180 full inventory window, use an alternate one instead; create
2181 the first time needed and keep it for re-use as needed later */
2182 if (cached_pickinv_win == WIN_ERR)
2183 cached_pickinv_win = create_nhwindow(NHW_MENU);
2184 win = cached_pickinv_win;
2185 } else
2186 win = WIN_INVEN;
2189 * Exit early if no inventory -- but keep going if we are doing
2190 * a permanent inventory update. We need to keep going so the
2191 * permanent inventory window updates itself to remove the last
2192 * item(s) dropped. One down side: the addition of the exception
2193 * for permanent inventory window updates _can_ pop the window
2194 * up when it's not displayed -- even if it's empty -- because we
2195 * don't know at this level if its up or not. This may not be
2196 * an issue if empty checks are done before hand and the call
2197 * to here is short circuited away.
2199 * 2: our count here is only to distinguish between 0 and 1 and
2200 * more than 1; for the last one, we don't need a precise number.
2201 * For perm_invent update we force 'more than 1'.
2203 n = (flags.perm_invent && !lets && !want_reply) ? 2
2204 : lets ? (int) strlen(lets)
2205 : !invent ? 0 : !invent->nobj ? 1 : 2;
2206 /* for xtra_choice, there's another 'item' not included in initial 'n';
2207 for !lets (full invent) and for override_ID (wizard mode identify),
2208 skip message_menu handling of single item even if item count was 1 */
2209 if (xtra_choice || (n == 1 && (!lets || iflags.override_ID)))
2210 ++n;
2212 if (n == 0) {
2213 pline("Not carrying anything.");
2214 return 0;
2217 /* oxymoron? temporarily assign permanent inventory letters */
2218 if (!flags.invlet_constant)
2219 reassign();
2221 if (n == 1) {
2222 /* when only one item of interest, use pline instead of menus;
2223 we actually use a fake message-line menu in order to allow
2224 the user to perform selection at the --More-- prompt for tty */
2225 ret = '\0';
2226 if (xtra_choice) {
2227 /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2228 "nothing" (ready Quiver), or "fingers" (apply grease) */
2229 ret = message_menu(HANDS_SYM, PICK_ONE,
2230 xprname((struct obj *) 0, xtra_choice,
2231 HANDS_SYM, TRUE, 0L, 0L)); /* '-' */
2232 } else {
2233 for (otmp = invent; otmp; otmp = otmp->nobj)
2234 if (!lets || otmp->invlet == lets[0])
2235 break;
2236 if (otmp)
2237 ret = message_menu(otmp->invlet,
2238 want_reply ? PICK_ONE : PICK_NONE,
2239 xprname(otmp, (char *) 0, lets[0],
2240 TRUE, 0L, 0L));
2242 if (out_cnt)
2243 *out_cnt = -1L; /* select all */
2244 return ret;
2247 sortloot(&invent,
2248 (((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET)
2249 | (flags.sortpack ? SORTLOOT_PACK : 0)),
2250 FALSE);
2252 start_menu(win);
2253 any = zeroany;
2254 if (wizard && iflags.override_ID) {
2255 char prompt[QBUFSZ];
2257 any.a_char = -1;
2258 /* wiz_identify stuffed the wiz_identify command character (^I)
2259 into iflags.override_ID for our use as an accelerator */
2260 Sprintf(prompt, "Debug Identify (%s to permanently identify)",
2261 visctrl(iflags.override_ID));
2262 add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
2263 prompt, MENU_UNSELECTED);
2264 } else if (xtra_choice) {
2265 /* wizard override ID and xtra_choice are mutually exclusive */
2266 if (flags.sortpack)
2267 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2268 "Miscellaneous", MENU_UNSELECTED);
2269 any.a_char = HANDS_SYM; /* '-' */
2270 add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
2271 xtra_choice, MENU_UNSELECTED);
2273 nextclass:
2274 classcount = 0;
2275 for (otmp = invent; otmp; otmp = otmp->nobj) {
2276 if (lets && !index(lets, otmp->invlet))
2277 continue;
2278 if (!flags.sortpack || otmp->oclass == *invlet) {
2279 any = zeroany; /* all bits zero */
2280 ilet = otmp->invlet;
2281 if (flags.sortpack && !classcount) {
2282 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2283 let_to_name(*invlet, FALSE,
2284 (want_reply && iflags.menu_head_objsym)),
2285 MENU_UNSELECTED);
2286 classcount++;
2288 any.a_char = ilet;
2289 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2290 doname(otmp), MENU_UNSELECTED);
2293 if (flags.sortpack) {
2294 if (*++invlet)
2295 goto nextclass;
2296 if (--invlet != venom_inv) {
2297 invlet = venom_inv;
2298 goto nextclass;
2301 end_menu(win, (char *) 0);
2303 n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
2304 if (n > 0) {
2305 ret = selected[0].item.a_char;
2306 if (out_cnt)
2307 *out_cnt = selected[0].count;
2308 free((genericptr_t) selected);
2309 } else
2310 ret = !n ? '\0' : '\033'; /* cancelled */
2312 return ret;
2316 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2317 * list all objects with object classes that match the order in lets.
2319 * Returns the letter identifier of a selected item, or 0 if nothing
2320 * was selected.
2322 char
2323 display_inventory(lets, want_reply)
2324 const char *lets;
2325 boolean want_reply;
2327 return display_pickinv(lets, (char *) 0, want_reply, (long *) 0);
2331 * Show what is current using inventory letters.
2334 STATIC_OVL char
2335 display_used_invlets(avoidlet)
2336 char avoidlet;
2338 struct obj *otmp;
2339 char ilet, ret = 0;
2340 char *invlet = flags.inv_order;
2341 int n, classcount, invdone = 0;
2342 winid win;
2343 anything any;
2344 menu_item *selected;
2346 if (invent) {
2347 win = create_nhwindow(NHW_MENU);
2348 start_menu(win);
2349 while (!invdone) {
2350 any = zeroany; /* set all bits to zero */
2351 classcount = 0;
2352 for (otmp = invent; otmp; otmp = otmp->nobj) {
2353 ilet = otmp->invlet;
2354 if (ilet == avoidlet)
2355 continue;
2356 if (!flags.sortpack || otmp->oclass == *invlet) {
2357 if (flags.sortpack && !classcount) {
2358 any = zeroany; /* zero */
2359 add_menu(win, NO_GLYPH, &any, 0, 0,
2360 iflags.menu_headings,
2361 let_to_name(*invlet, FALSE, FALSE),
2362 MENU_UNSELECTED);
2363 classcount++;
2365 any.a_char = ilet;
2366 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2367 doname(otmp), MENU_UNSELECTED);
2370 if (flags.sortpack && *++invlet)
2371 continue;
2372 invdone = 1;
2374 end_menu(win, "Inventory letters used:");
2376 n = select_menu(win, PICK_ONE, &selected);
2377 if (n > 0) {
2378 ret = selected[0].item.a_char;
2379 free((genericptr_t) selected);
2380 } else
2381 ret = !n ? '\0' : '\033'; /* cancelled */
2382 destroy_nhwindow(win);
2384 return ret;
2388 * Returns the number of unpaid items within the given list. This includes
2389 * contained objects.
2392 count_unpaid(list)
2393 struct obj *list;
2395 int count = 0;
2397 while (list) {
2398 if (list->unpaid)
2399 count++;
2400 if (Has_contents(list))
2401 count += count_unpaid(list->cobj);
2402 list = list->nobj;
2404 return count;
2408 * Returns the number of items with b/u/c/unknown within the given list.
2409 * This does NOT include contained objects.
2411 * Assumes that the hero sees or touches or otherwise senses the objects
2412 * at some point: bknown is forced for priest[ess], like in xname().
2415 count_buc(list, type)
2416 struct obj *list;
2417 int type;
2419 int count = 0;
2421 for (; list; list = list->nobj) {
2422 /* coins are "none of the above" as far as BUCX filtering goes */
2423 if (list->oclass == COIN_CLASS)
2424 continue;
2425 /* priests always know bless/curse state */
2426 if (Role_if(PM_PRIEST))
2427 list->bknown = 1;
2429 /* check whether this object matches the requested type */
2430 if (!list->bknown
2431 ? (type == BUC_UNKNOWN)
2432 : list->blessed ? (type == BUC_BLESSED)
2433 : list->cursed ? (type == BUC_CURSED)
2434 : (type == BUC_UNCURSED))
2435 ++count;
2437 return count;
2440 /* similar to count_buc(), but tallies all states at once
2441 rather than looking for a specific type */
2442 STATIC_OVL void
2443 tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
2444 struct obj *list;
2445 int *bcp, *ucp, *ccp, *xcp, *ocp;
2447 *bcp = *ucp = *ccp = *xcp = *ocp = 0;
2448 for (; list; list = list->nobj) {
2449 if (list->oclass == COIN_CLASS) {
2450 ++(*ocp); /* "other" */
2451 continue;
2453 /* priests always know bless/curse state */
2454 if (Role_if(PM_PRIEST))
2455 list->bknown = 1;
2457 if (!list->bknown)
2458 ++(*xcp);
2459 else if (list->blessed)
2460 ++(*bcp);
2461 else if (list->cursed)
2462 ++(*ccp);
2463 else /* neither blessed nor cursed => uncursed */
2464 ++(*ucp);
2468 long
2469 count_contents(container, nested, quantity, everything)
2470 struct obj *container;
2471 boolean nested, /* include contents of any nested containers */
2472 quantity, /* count all vs count separate stacks */
2473 everything; /* all objects vs only unpaid objects */
2475 struct obj *otmp;
2476 long count = 0L;
2478 for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
2479 if (nested && Has_contents(otmp))
2480 count += count_contents(otmp, nested, quantity, everything);
2481 if (everything || otmp->unpaid)
2482 count += quantity ? otmp->quan : 1L;
2484 return count;
2487 STATIC_OVL void
2488 dounpaid()
2490 winid win;
2491 struct obj *otmp, *marker;
2492 register char ilet;
2493 char *invlet = flags.inv_order;
2494 int classcount, count, num_so_far;
2495 long cost, totcost;
2497 count = count_unpaid(invent);
2499 if (count == 1) {
2500 marker = (struct obj *) 0;
2501 otmp = find_unpaid(invent, &marker);
2502 cost = unpaid_cost(otmp, FALSE);
2503 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2504 pline1(xprname(otmp, distant_name(otmp, doname),
2505 carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
2506 cost, 0L));
2507 iflags.suppress_price--;
2508 return;
2511 win = create_nhwindow(NHW_MENU);
2512 cost = totcost = 0;
2513 num_so_far = 0; /* count of # printed so far */
2514 if (!flags.invlet_constant)
2515 reassign();
2517 do {
2518 classcount = 0;
2519 for (otmp = invent; otmp; otmp = otmp->nobj) {
2520 ilet = otmp->invlet;
2521 if (otmp->unpaid) {
2522 if (!flags.sortpack || otmp->oclass == *invlet) {
2523 if (flags.sortpack && !classcount) {
2524 putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
2525 classcount++;
2528 totcost += cost = unpaid_cost(otmp, FALSE);
2529 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2530 putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
2531 ilet, TRUE, cost, 0L));
2532 iflags.suppress_price--;
2533 num_so_far++;
2537 } while (flags.sortpack && (*++invlet));
2539 if (count > num_so_far) {
2540 /* something unpaid is contained */
2541 if (flags.sortpack)
2542 putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
2544 * Search through the container objects in the inventory for
2545 * unpaid items. The top level inventory items have already
2546 * been listed.
2548 for (otmp = invent; otmp; otmp = otmp->nobj) {
2549 if (Has_contents(otmp)) {
2550 long contcost = 0L;
2552 marker = (struct obj *) 0; /* haven't found any */
2553 while (find_unpaid(otmp->cobj, &marker)) {
2554 totcost += cost = unpaid_cost(marker, FALSE);
2555 contcost += cost;
2556 if (otmp->cknown) {
2557 iflags.suppress_price++; /* suppress "(unpaid)" sfx */
2558 putstr(win, 0,
2559 xprname(marker, distant_name(marker, doname),
2560 CONTAINED_SYM, TRUE, cost, 0L));
2561 iflags.suppress_price--;
2564 if (!otmp->cknown) {
2565 char contbuf[BUFSZ];
2567 /* Shopkeeper knows what to charge for contents */
2568 Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
2569 putstr(win, 0,
2570 xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
2571 TRUE, contcost, 0L));
2577 putstr(win, 0, "");
2578 putstr(win, 0,
2579 xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
2580 display_nhwindow(win, FALSE);
2581 destroy_nhwindow(win);
2584 /* query objlist callback: return TRUE if obj type matches "this_type" */
2585 static int this_type;
2587 STATIC_OVL boolean
2588 this_type_only(obj)
2589 struct obj *obj;
2591 boolean res = (obj->oclass == this_type);
2593 if (obj->oclass != COIN_CLASS) {
2594 switch (this_type) {
2595 case 'B':
2596 res = (obj->bknown && obj->blessed);
2597 break;
2598 case 'U':
2599 res = (obj->bknown && !(obj->blessed || obj->cursed));
2600 break;
2601 case 'C':
2602 res = (obj->bknown && obj->cursed);
2603 break;
2604 case 'X':
2605 res = !obj->bknown;
2606 break;
2607 default:
2608 break; /* use 'res' as-is */
2611 return res;
2614 /* the 'I' command */
2616 dotypeinv()
2618 char c = '\0';
2619 int n, i = 0;
2620 char *extra_types, types[BUFSZ];
2621 int class_count, oclass, unpaid_count, itemcount;
2622 int bcnt, ccnt, ucnt, xcnt, ocnt;
2623 boolean billx = *u.ushops && doinvbill(0);
2624 menu_item *pick_list;
2625 boolean traditional = TRUE;
2626 const char *prompt = "What type of object do you want an inventory of?";
2628 if (!invent && !billx) {
2629 You("aren't carrying anything.");
2630 return 0;
2632 unpaid_count = count_unpaid(invent);
2633 tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
2635 if (flags.menu_style != MENU_TRADITIONAL) {
2636 if (flags.menu_style == MENU_FULL
2637 || flags.menu_style == MENU_PARTIAL) {
2638 traditional = FALSE;
2639 i = UNPAID_TYPES;
2640 if (billx)
2641 i |= BILLED_TYPES;
2642 if (bcnt)
2643 i |= BUC_BLESSED;
2644 if (ucnt)
2645 i |= BUC_UNCURSED;
2646 if (ccnt)
2647 i |= BUC_CURSED;
2648 if (xcnt)
2649 i |= BUC_UNKNOWN;
2650 n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2651 if (!n)
2652 return 0;
2653 this_type = c = pick_list[0].item.a_int;
2654 free((genericptr_t) pick_list);
2657 if (traditional) {
2658 /* collect a list of classes of objects carried, for use as a prompt
2660 types[0] = 0;
2661 class_count =
2662 collect_obj_classes(types, invent, FALSE,
2663 (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
2664 if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
2665 types[class_count++] = ' ';
2666 if (unpaid_count)
2667 types[class_count++] = 'u';
2668 if (billx)
2669 types[class_count++] = 'x';
2670 if (bcnt)
2671 types[class_count++] = 'B';
2672 if (ucnt)
2673 types[class_count++] = 'U';
2674 if (ccnt)
2675 types[class_count++] = 'C';
2676 if (xcnt)
2677 types[class_count++] = 'X';
2678 types[class_count] = '\0';
2679 /* add everything not already included; user won't see these */
2680 extra_types = eos(types);
2681 *extra_types++ = '\033';
2682 if (!unpaid_count)
2683 *extra_types++ = 'u';
2684 if (!billx)
2685 *extra_types++ = 'x';
2686 if (!bcnt)
2687 *extra_types++ = 'B';
2688 if (!ucnt)
2689 *extra_types++ = 'U';
2690 if (!ccnt)
2691 *extra_types++ = 'C';
2692 if (!xcnt)
2693 *extra_types++ = 'X';
2694 *extra_types = '\0'; /* for index() */
2695 for (i = 0; i < MAXOCLASSES; i++)
2696 if (!index(types, def_oc_syms[i].sym)) {
2697 *extra_types++ = def_oc_syms[i].sym;
2698 *extra_types = '\0';
2701 if (class_count > 1) {
2702 c = yn_function(prompt, types, '\0');
2703 savech(c);
2704 if (c == '\0') {
2705 clear_nhwindow(WIN_MESSAGE);
2706 return 0;
2708 } else {
2709 /* only one thing to itemize */
2710 if (unpaid_count)
2711 c = 'u';
2712 else if (billx)
2713 c = 'x';
2714 else
2715 c = types[0];
2718 if (c == 'x' || (c == 'X' && billx && !xcnt)) {
2719 if (billx)
2720 (void) doinvbill(1);
2721 else
2722 pline("No used-up objects%s.",
2723 unpaid_count ? " on your shopping bill" : "");
2724 return 0;
2726 if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
2727 if (unpaid_count)
2728 dounpaid();
2729 else
2730 You("are not carrying any unpaid objects.");
2731 return 0;
2733 if (traditional) {
2734 if (index("BUCX", c))
2735 oclass = c; /* not a class but understood by this_type_only() */
2736 else
2737 oclass = def_char_to_objclass(c); /* change to object class */
2739 if (oclass == COIN_CLASS)
2740 return doprgold();
2741 if (index(types, c) > index(types, '\033')) {
2742 /* '> ESC' => hidden choice, something known not to be carried */
2743 const char *which = 0;
2745 switch (c) {
2746 case 'B':
2747 which = "known to be blessed";
2748 break;
2749 case 'U':
2750 which = "known to be uncursed";
2751 break;
2752 case 'C':
2753 which = "known to be cursed";
2754 break;
2755 case 'X':
2756 You(
2757 "have no objects whose blessed/uncursed/cursed status is unknown.");
2758 break; /* better phrasing is desirable */
2759 default:
2760 which = "such";
2761 break;
2763 if (which)
2764 You("have no %s objects.", which);
2765 return 0;
2767 this_type = oclass;
2769 if (query_objlist((char *) 0, &invent,
2770 ((flags.invlet_constant ? USE_INVLET : 0)
2771 | INVORDER_SORT),
2772 &pick_list, PICK_NONE, this_type_only) > 0)
2773 free((genericptr_t) pick_list);
2774 return 0;
2777 /* return a string describing the dungeon feature at <x,y> if there
2778 is one worth mentioning at that location; otherwise null */
2779 const char *
2780 dfeature_at(x, y, buf)
2781 int x, y;
2782 char *buf;
2784 struct rm *lev = &levl[x][y];
2785 int ltyp = lev->typ, cmap = -1;
2786 const char *dfeature = 0;
2787 static char altbuf[BUFSZ];
2789 if (IS_DOOR(ltyp)) {
2790 switch (lev->doormask) {
2791 case D_NODOOR:
2792 cmap = S_ndoor;
2793 break; /* "doorway" */
2794 case D_ISOPEN:
2795 cmap = S_vodoor;
2796 break; /* "open door" */
2797 case D_BROKEN:
2798 dfeature = "broken door";
2799 break;
2800 default:
2801 cmap = S_vcdoor;
2802 break; /* "closed door" */
2804 /* override door description for open drawbridge */
2805 if (is_drawbridge_wall(x, y) >= 0)
2806 dfeature = "open drawbridge portcullis", cmap = -1;
2807 } else if (IS_FOUNTAIN(ltyp))
2808 cmap = S_fountain; /* "fountain" */
2809 else if (IS_THRONE(ltyp))
2810 cmap = S_throne; /* "opulent throne" */
2811 else if (is_lava(x, y))
2812 cmap = S_lava; /* "molten lava" */
2813 else if (is_ice(x, y))
2814 cmap = S_ice; /* "ice" */
2815 else if (is_pool(x, y))
2816 dfeature = "pool of water";
2817 else if (IS_SINK(ltyp))
2818 cmap = S_sink; /* "sink" */
2819 else if (IS_ALTAR(ltyp)) {
2820 Sprintf(altbuf, "%saltar to %s (%s)",
2821 ((lev->altarmask & AM_SHRINE)
2822 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
2823 ? "high "
2824 : "",
2825 a_gname(),
2826 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2827 dfeature = altbuf;
2828 } else if ((x == xupstair && y == yupstair)
2829 || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2830 cmap = S_upstair; /* "staircase up" */
2831 else if ((x == xdnstair && y == ydnstair)
2832 || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2833 cmap = S_dnstair; /* "staircase down" */
2834 else if (x == xupladder && y == yupladder)
2835 cmap = S_upladder; /* "ladder up" */
2836 else if (x == xdnladder && y == ydnladder)
2837 cmap = S_dnladder; /* "ladder down" */
2838 else if (ltyp == DRAWBRIDGE_DOWN)
2839 cmap = S_vodbridge; /* "lowered drawbridge" */
2840 else if (ltyp == DBWALL)
2841 cmap = S_vcdbridge; /* "raised drawbridge" */
2842 else if (IS_GRAVE(ltyp))
2843 cmap = S_grave; /* "grave" */
2844 else if (ltyp == TREE)
2845 cmap = S_tree; /* "tree" */
2846 else if (ltyp == IRONBARS)
2847 dfeature = "set of iron bars";
2849 if (cmap >= 0)
2850 dfeature = defsyms[cmap].explanation;
2851 if (dfeature)
2852 Strcpy(buf, dfeature);
2853 return dfeature;
2856 /* look at what is here; if there are many objects (pile_limit or more),
2857 don't show them unless obj_cnt is 0 */
2859 look_here(obj_cnt, picked_some)
2860 int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
2861 boolean picked_some;
2863 struct obj *otmp;
2864 struct trap *trap;
2865 const char *verb = Blind ? "feel" : "see";
2866 const char *dfeature = (char *) 0;
2867 char fbuf[BUFSZ], fbuf2[BUFSZ];
2868 winid tmpwin;
2869 boolean skip_objects, felt_cockatrice = FALSE;
2871 /* default pile_limit is 5; a value of 0 means "never skip"
2872 (and 1 effectively forces "always skip") */
2873 skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
2874 if (u.uswallow && u.ustuck) {
2875 struct monst *mtmp = u.ustuck;
2877 Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
2878 mbodypart(mtmp, STOMACH));
2879 /* Skip "Contents of " by using fbuf index 12 */
2880 You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
2881 verb, &fbuf[12]);
2882 otmp = mtmp->minvent;
2883 if (otmp) {
2884 for (; otmp; otmp = otmp->nobj) {
2885 /* If swallower is an animal, it should have become stone
2886 * but... */
2887 if (otmp->otyp == CORPSE)
2888 feel_cockatrice(otmp, FALSE);
2890 if (Blind)
2891 Strcpy(fbuf, "You feel");
2892 Strcat(fbuf, ":");
2893 (void) display_minventory(mtmp, MINV_ALL | PICK_NONE, fbuf);
2894 } else {
2895 You("%s no objects here.", verb);
2897 return !!Blind;
2899 if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
2900 There("is %s here.",
2901 an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2903 otmp = level.objects[u.ux][u.uy];
2904 dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2905 if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2906 dfeature = 0;
2908 if (Blind) {
2909 boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2911 if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2912 /* don't say "altar" twice, dfeature has more info */
2913 You("try to feel what is here.");
2914 } else {
2915 const char *where = (Blind && !can_reach_floor(TRUE))
2916 ? "lying beneath you"
2917 : "lying here on the ",
2918 *onwhat = (Blind && !can_reach_floor(TRUE))
2919 ? ""
2920 : surface(u.ux, u.uy);
2922 You("try to feel what is %s%s.", drift ? "floating here" : where,
2923 drift ? "" : onwhat);
2925 if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
2926 dfeature = 0; /* ice already identified */
2927 if (!can_reach_floor(TRUE)) {
2928 pline("But you can't reach it!");
2929 return 0;
2933 if (dfeature)
2934 Sprintf(fbuf, "There is %s here.", an(dfeature));
2936 if (!otmp || is_lava(u.ux, u.uy)
2937 || (is_pool(u.ux, u.uy) && !Underwater)) {
2938 if (dfeature)
2939 pline1(fbuf);
2940 read_engr_at(u.ux, u.uy); /* Eric Backus */
2941 if (!skip_objects && (Blind || !dfeature))
2942 You("%s no objects here.", verb);
2943 return !!Blind;
2945 /* we know there is something here */
2947 if (skip_objects) {
2948 if (dfeature)
2949 pline1(fbuf);
2950 read_engr_at(u.ux, u.uy); /* Eric Backus */
2951 if (obj_cnt == 1 && otmp->quan == 1L)
2952 There("is %s object here.", picked_some ? "another" : "an");
2953 else
2954 There("are %s%s objects here.",
2955 (obj_cnt < 5)
2956 ? "a few"
2957 : (obj_cnt < 10)
2958 ? "several"
2959 : "many",
2960 picked_some ? " more" : "");
2961 for (; otmp; otmp = otmp->nexthere)
2962 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2963 pline("%s %s%s.",
2964 (obj_cnt > 1)
2965 ? "Including"
2966 : (otmp->quan > 1L)
2967 ? "They're"
2968 : "It's",
2969 corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
2970 poly_when_stoned(youmonst.data)
2971 ? ""
2972 : ", unfortunately");
2973 feel_cockatrice(otmp, FALSE);
2974 break;
2976 } else if (!otmp->nexthere) {
2977 /* only one object */
2978 if (dfeature)
2979 pline1(fbuf);
2980 read_engr_at(u.ux, u.uy); /* Eric Backus */
2981 You("%s here %s.", verb, doname_with_price(otmp));
2982 iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
2983 if (otmp->otyp == CORPSE)
2984 feel_cockatrice(otmp, FALSE);
2985 } else {
2986 char buf[BUFSZ];
2988 display_nhwindow(WIN_MESSAGE, FALSE);
2989 tmpwin = create_nhwindow(NHW_MENU);
2990 if (dfeature) {
2991 putstr(tmpwin, 0, fbuf);
2992 putstr(tmpwin, 0, "");
2994 Sprintf(buf, "%s that %s here:",
2995 picked_some ? "Other things" : "Things",
2996 Blind ? "you feel" : "are");
2997 putstr(tmpwin, 0, buf);
2998 for (; otmp; otmp = otmp->nexthere) {
2999 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
3000 felt_cockatrice = TRUE;
3001 Sprintf(buf, "%s...", doname(otmp));
3002 putstr(tmpwin, 0, buf);
3003 break;
3005 putstr(tmpwin, 0, doname_with_price(otmp));
3007 display_nhwindow(tmpwin, TRUE);
3008 destroy_nhwindow(tmpwin);
3009 if (felt_cockatrice)
3010 feel_cockatrice(otmp, FALSE);
3011 read_engr_at(u.ux, u.uy); /* Eric Backus */
3013 return !!Blind;
3016 /* the ':' command - explicitly look at what is here, including all objects */
3018 dolook()
3020 int res;
3022 /* don't let
3023 MSGTYPE={norep,noshow} "You see here"
3024 interfere with feedback from the look-here command */
3025 hide_unhide_msgtypes(TRUE, MSGTYP_MASK_REP_SHOW);
3026 res = look_here(0, FALSE);
3027 /* restore normal msgtype handling */
3028 hide_unhide_msgtypes(FALSE, MSGTYP_MASK_REP_SHOW);
3029 return res;
3032 boolean
3033 will_feel_cockatrice(otmp, force_touch)
3034 struct obj *otmp;
3035 boolean force_touch;
3037 if ((Blind || force_touch) && !uarmg && !Stone_resistance
3038 && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
3039 return TRUE;
3040 return FALSE;
3043 void
3044 feel_cockatrice(otmp, force_touch)
3045 struct obj *otmp;
3046 boolean force_touch;
3048 char kbuf[BUFSZ];
3050 if (will_feel_cockatrice(otmp, force_touch)) {
3051 /* "the <cockatrice> corpse" */
3052 Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
3054 if (poly_when_stoned(youmonst.data))
3055 You("touched %s with your bare %s.", kbuf,
3056 makeplural(body_part(HAND)));
3057 else
3058 pline("Touching %s is a fatal mistake...", kbuf);
3059 /* normalize body shape here; hand, not body_part(HAND) */
3060 Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
3061 /* will call polymon() for the poly_when_stoned() case */
3062 instapetrify(kbuf);
3066 void
3067 stackobj(obj)
3068 struct obj *obj;
3070 struct obj *otmp;
3072 for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
3073 if (otmp != obj && merged(&obj, &otmp))
3074 break;
3075 return;
3078 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3079 boolean
3080 mergable(otmp, obj)
3081 register struct obj *otmp, *obj;
3083 int objnamelth = 0, otmpnamelth = 0;
3085 if (obj == otmp)
3086 return FALSE; /* already the same object */
3087 if (obj->otyp != otmp->otyp)
3088 return FALSE; /* different types */
3089 if (obj->nomerge) /* explicitly marked to prevent merge */
3090 return FALSE;
3092 /* coins of the same kind will always merge */
3093 if (obj->oclass == COIN_CLASS)
3094 return TRUE;
3096 if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
3097 || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
3098 || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
3099 || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
3100 || obj->bypass != otmp->bypass)
3101 return FALSE;
3103 if (obj->globby)
3104 return TRUE;
3105 /* Checks beyond this point either aren't applicable to globs
3106 * or don't inhibit their merger.
3109 if (obj->oclass == FOOD_CLASS
3110 && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
3111 return FALSE;
3113 if (obj->dknown != otmp->dknown
3114 || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
3115 || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
3116 || obj->greased != otmp->greased)
3117 return FALSE;
3119 if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
3120 && (obj->oerodeproof != otmp->oerodeproof
3121 || obj->rknown != otmp->rknown))
3122 return FALSE;
3124 if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
3125 if (obj->corpsenm != otmp->corpsenm)
3126 return FALSE;
3129 /* hatching eggs don't merge; ditto for revivable corpses */
3130 if ((obj->otyp == EGG && (obj->timed || otmp->timed))
3131 || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
3132 && is_reviver(&mons[otmp->corpsenm])))
3133 return FALSE;
3135 /* allow candle merging only if their ages are close */
3136 /* see begin_burn() for a reference for the magic "25" */
3137 if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
3138 return FALSE;
3140 /* burning potions of oil never merge */
3141 if (obj->otyp == POT_OIL && obj->lamplit)
3142 return FALSE;
3144 /* don't merge surcharged item with base-cost item */
3145 if (obj->unpaid && !same_price(obj, otmp))
3146 return FALSE;
3148 /* if they have names, make sure they're the same */
3149 objnamelth = strlen(safe_oname(obj));
3150 otmpnamelth = strlen(safe_oname(otmp));
3151 if ((objnamelth != otmpnamelth
3152 && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
3153 || (objnamelth && otmpnamelth
3154 && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
3155 return FALSE;
3157 /* for the moment, any additional information is incompatible */
3158 if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
3159 || has_omid(otmp) || has_olong(otmp))
3160 return FALSE;
3162 if (obj->oartifact != otmp->oartifact)
3163 return FALSE;
3165 if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
3166 return (boolean) objects[obj->otyp].oc_merge;
3167 } else
3168 return FALSE;
3171 /* the '$' command */
3173 doprgold()
3175 /* the messages used to refer to "carrying gold", but that didn't
3176 take containers into account */
3177 long umoney = money_cnt(invent);
3178 if (!umoney)
3179 Your("wallet is empty.");
3180 else
3181 Your("wallet contains %ld %s.", umoney, currency(umoney));
3182 shopper_financial_report();
3183 return 0;
3186 /* the ')' command */
3188 doprwep()
3190 if (!uwep) {
3191 You("are empty %s.", body_part(HANDED));
3192 } else {
3193 prinv((char *) 0, uwep, 0L);
3194 if (u.twoweap)
3195 prinv((char *) 0, uswapwep, 0L);
3197 return 0;
3200 /* caller is responsible for checking !wearing_armor() */
3201 STATIC_OVL void
3202 noarmor(report_uskin)
3203 boolean report_uskin;
3205 if (!uskin || !report_uskin) {
3206 You("are not wearing any armor.");
3207 } else {
3208 char *p, *uskinname, buf[BUFSZ];
3210 uskinname = strcpy(buf, simpleonames(uskin));
3211 /* shorten "set of <color> dragon scales" to "<color> scales"
3212 and "<color> dragon scale mail" to "<color> scale mail" */
3213 if (!strncmpi(uskinname, "set of ", 7))
3214 uskinname += 7;
3215 if ((p = strstri(uskinname, " dragon ")) != 0)
3216 while ((p[1] = p[8]) != '\0')
3217 ++p;
3219 You("are not wearing armor but have %s embedded in your skin.",
3220 uskinname);
3224 /* the '[' command */
3226 doprarm()
3228 char lets[8];
3229 register int ct = 0;
3231 * Note: players sometimes get here by pressing a function key which
3232 * transmits ''ESC [ <something>'' rather than by pressing '[';
3233 * there's nothing we can--or should-do about that here.
3236 if (!wearing_armor()) {
3237 noarmor(TRUE);
3238 } else {
3239 if (uarmu)
3240 lets[ct++] = obj_to_let(uarmu);
3241 if (uarm)
3242 lets[ct++] = obj_to_let(uarm);
3243 if (uarmc)
3244 lets[ct++] = obj_to_let(uarmc);
3245 if (uarmh)
3246 lets[ct++] = obj_to_let(uarmh);
3247 if (uarms)
3248 lets[ct++] = obj_to_let(uarms);
3249 if (uarmg)
3250 lets[ct++] = obj_to_let(uarmg);
3251 if (uarmf)
3252 lets[ct++] = obj_to_let(uarmf);
3253 lets[ct] = 0;
3254 (void) display_inventory(lets, FALSE);
3256 return 0;
3259 /* the '=' command */
3261 doprring()
3263 if (!uleft && !uright)
3264 You("are not wearing any rings.");
3265 else {
3266 char lets[3];
3267 register int ct = 0;
3269 if (uleft)
3270 lets[ct++] = obj_to_let(uleft);
3271 if (uright)
3272 lets[ct++] = obj_to_let(uright);
3273 lets[ct] = 0;
3274 (void) display_inventory(lets, FALSE);
3276 return 0;
3279 /* the '"' command */
3281 dopramulet()
3283 if (!uamul)
3284 You("are not wearing an amulet.");
3285 else
3286 prinv((char *) 0, uamul, 0L);
3287 return 0;
3290 STATIC_OVL boolean
3291 tool_in_use(obj)
3292 struct obj *obj;
3294 if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
3295 return TRUE;
3296 if (obj->oclass != TOOL_CLASS)
3297 return FALSE;
3298 return (boolean) (obj == uwep || obj->lamplit
3299 || (obj->otyp == LEASH && obj->leashmon));
3302 /* the '(' command */
3304 doprtool()
3306 struct obj *otmp;
3307 int ct = 0;
3308 char lets[52 + 1];
3310 for (otmp = invent; otmp; otmp = otmp->nobj)
3311 if (tool_in_use(otmp))
3312 lets[ct++] = obj_to_let(otmp);
3313 lets[ct] = '\0';
3314 if (!ct)
3315 You("are not using any tools.");
3316 else
3317 (void) display_inventory(lets, FALSE);
3318 return 0;
3321 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3322 show inventory of all currently wielded, worn, or used objects */
3324 doprinuse()
3326 struct obj *otmp;
3327 int ct = 0;
3328 char lets[52 + 1];
3330 for (otmp = invent; otmp; otmp = otmp->nobj)
3331 if (is_worn(otmp) || tool_in_use(otmp))
3332 lets[ct++] = obj_to_let(otmp);
3333 lets[ct] = '\0';
3334 if (!ct)
3335 You("are not wearing or wielding anything.");
3336 else
3337 (void) display_inventory(lets, FALSE);
3338 return 0;
3342 * uses up an object that's on the floor, charging for it as necessary
3344 void
3345 useupf(obj, numused)
3346 register struct obj *obj;
3347 long numused;
3349 register struct obj *otmp;
3350 boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
3352 /* burn_floor_objects() keeps an object pointer that it tries to
3353 * useupf() multiple times, so obj must survive if plural */
3354 if (obj->quan > numused)
3355 otmp = splitobj(obj, numused);
3356 else
3357 otmp = obj;
3358 if (costly_spot(otmp->ox, otmp->oy)) {
3359 if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
3360 addtobill(otmp, FALSE, FALSE, FALSE);
3361 else
3362 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
3364 delobj(otmp);
3365 if (at_u && u.uundetected && hides_under(youmonst.data))
3366 (void) hideunder(&youmonst);
3370 * Conversion from a class to a string for printing.
3371 * This must match the object class order.
3373 STATIC_VAR NEARDATA const char *names[] = {
3374 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3375 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3376 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3379 static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
3381 static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
3383 static NEARDATA char *invbuf = (char *) 0;
3384 static NEARDATA unsigned invbufsiz = 0;
3386 char *
3387 let_to_name(let, unpaid, showsym)
3388 char let;
3389 boolean unpaid, showsym;
3391 const char *ocsymfmt = " ('%c')";
3392 const int invbuf_sympadding = 8; /* arbitrary */
3393 const char *class_name;
3394 const char *pos;
3395 int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
3396 unsigned len;
3398 if (oclass)
3399 class_name = names[oclass];
3400 else if ((pos = index(oth_symbols, let)) != 0)
3401 class_name = oth_names[pos - oth_symbols];
3402 else
3403 class_name = names[0];
3405 len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
3406 + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
3407 if (len > invbufsiz) {
3408 if (invbuf)
3409 free((genericptr_t) invbuf);
3410 invbufsiz = len + 10; /* add slop to reduce incremental realloc */
3411 invbuf = (char *) alloc(invbufsiz);
3413 if (unpaid)
3414 Strcat(strcpy(invbuf, "Unpaid "), class_name);
3415 else
3416 Strcpy(invbuf, class_name);
3417 if ((oclass != 0) && showsym) {
3418 char *bp = eos(invbuf);
3419 int mlen = invbuf_sympadding - strlen(class_name);
3420 while (--mlen > 0) {
3421 *bp = ' ';
3422 bp++;
3424 *bp = '\0';
3425 Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
3427 return invbuf;
3430 /* release the static buffer used by let_to_name() */
3431 void
3432 free_invbuf()
3434 if (invbuf)
3435 free((genericptr_t) invbuf), invbuf = (char *) 0;
3436 invbufsiz = 0;
3439 /* give consecutive letters to every item in inventory (for !fixinv mode);
3440 gold is always forced to '$' slot at head of list */
3441 void
3442 reassign()
3444 int i;
3445 struct obj *obj, *prevobj, *goldobj;
3447 /* first, remove [first instance of] gold from invent, if present */
3448 prevobj = goldobj = 0;
3449 for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
3450 if (obj->oclass == COIN_CLASS) {
3451 goldobj = obj;
3452 if (prevobj)
3453 prevobj->nobj = goldobj->nobj;
3454 else
3455 invent = goldobj->nobj;
3456 break;
3458 /* second, re-letter the rest of the list */
3459 for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
3460 obj->invlet =
3461 (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
3462 /* third, assign gold the "letter" '$' and re-insert it at head */
3463 if (goldobj) {
3464 goldobj->invlet = GOLD_SYM;
3465 goldobj->nobj = invent;
3466 invent = goldobj;
3468 if (i >= 52)
3469 i = 52 - 1;
3470 lastinvnr = i;
3473 /* #adjust command
3475 * User specifies a 'from' slot for inventory stack to move,
3476 * then a 'to' slot for its destination. Open slots and those
3477 * filled by compatible stacks are listed as likely candidates
3478 * but user can pick any inventory letter (including 'from').
3479 * All compatible items found are gathered into the 'from'
3480 * stack as it is moved. If the 'to' slot isn't empty and
3481 * doesn't merge, then its stack is swapped to the 'from' slot.
3483 * If the user specifies a count when choosing the 'from' slot,
3484 * and that count is less than the full size of the stack,
3485 * then the stack will be split. The 'count' portion is moved
3486 * to the destination, and the only candidate for merging with
3487 * it is the stack already at the 'to' slot, if any. When the
3488 * destination is non-empty but won't merge, whatever is there
3489 * will be moved to an open slot; if there isn't any open slot
3490 * available, the adjustment attempt fails.
3492 * Splitting has one special case: if 'to' slot is non-empty
3493 * and is compatible with 'from' in all respects except for
3494 * user-assigned names, the 'count' portion being moved is
3495 * effectively renamed so that it will merge with 'to' stack.
3498 doorganize() /* inventory organizer by Del Lamb */
3500 struct obj *obj, *otmp, *splitting, *bumped;
3501 int ix, cur, trycnt;
3502 char let;
3503 char alphabet[52 + 1], buf[52 + 1];
3504 char qbuf[QBUFSZ];
3505 char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3506 const char *adj_type;
3508 if (!invent) {
3509 You("aren't carrying anything to adjust.");
3510 return 0;
3513 if (!flags.invlet_constant)
3514 reassign();
3515 /* get object the user wants to organize (the 'from' slot) */
3516 allowall[0] = ALLOW_COUNT;
3517 allowall[1] = ALL_CLASSES;
3518 allowall[2] = '\0';
3519 if (!(obj = getobj(allowall, "adjust")))
3520 return 0;
3522 /* figure out whether user gave a split count to getobj() */
3523 splitting = bumped = 0;
3524 for (otmp = invent; otmp; otmp = otmp->nobj)
3525 if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
3526 if (otmp->invlet == obj->invlet)
3527 splitting = otmp;
3528 break;
3531 /* initialize the list with all lower and upper case letters */
3532 for (ix = 0, let = 'a'; let <= 'z';)
3533 alphabet[ix++] = let++;
3534 for (let = 'A'; let <= 'Z';)
3535 alphabet[ix++] = let++;
3536 alphabet[ix] = '\0';
3537 /* for floating inv letters, truncate list after the first open slot */
3538 if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
3539 alphabet[ix + (splitting ? 0 : 1)] = '\0';
3541 /* blank out all the letters currently in use in the inventory */
3542 /* except those that will be merged with the selected object */
3543 for (otmp = invent; otmp; otmp = otmp->nobj)
3544 if (otmp != obj && !mergable(otmp, obj)) {
3545 let = otmp->invlet;
3546 if (let >= 'a' && let <= 'z')
3547 alphabet[let - 'a'] = ' ';
3548 else if (let >= 'A' && let <= 'Z')
3549 alphabet[let - 'A' + 26] = ' ';
3552 /* compact the list by removing all the blanks */
3553 for (ix = cur = 0; alphabet[ix]; ix++)
3554 if (alphabet[ix] != ' ')
3555 buf[cur++] = alphabet[ix];
3556 if (!cur && obj->invlet == NOINVSYM)
3557 buf[cur++] = NOINVSYM;
3558 buf[cur] = '\0';
3559 /* and by dashing runs of letters */
3560 if (cur > 5)
3561 compactify(buf);
3563 /* get 'to' slot to use as destination */
3564 Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
3565 invent ? " (? see used letters)" : "");
3566 for (trycnt = 1; ; ++trycnt) {
3567 let = yn_function(qbuf, (char *) 0, '\0');
3568 if (let == '?' || let == '*') {
3569 let = display_used_invlets(splitting ? obj->invlet : 0);
3570 if (!let)
3571 continue;
3572 if (let == '\033')
3573 goto noadjust;
3575 if (index(quitchars, let)
3576 /* adjusting to same slot is meaningful since all
3577 compatible stacks get collected along the way,
3578 but splitting to same slot is not */
3579 || (splitting && let == obj->invlet)) {
3580 noadjust:
3581 if (splitting)
3582 (void) merged(&splitting, &obj);
3583 pline1(Never_mind);
3584 return 0;
3586 if ((letter(let) && let != '@') || index(buf, let))
3587 break; /* got one */
3588 if (trycnt == 5)
3589 goto noadjust;
3590 pline("Select an inventory slot letter."); /* else try again */
3593 /* change the inventory and print the resulting item */
3594 adj_type = !splitting ? "Moving:" : "Splitting:";
3597 * don't use freeinv/addinv to avoid double-touching artifacts,
3598 * dousing lamps, losing luck, cursing loadstone, etc.
3600 extract_nobj(obj, &invent);
3602 for (otmp = invent; otmp;) {
3603 if (!splitting) {
3604 if (merged(&otmp, &obj)) {
3605 adj_type = "Merging:";
3606 obj = otmp;
3607 otmp = otmp->nobj;
3608 extract_nobj(obj, &invent);
3609 continue; /* otmp has already been updated */
3610 } else if (otmp->invlet == let) {
3611 adj_type = "Swapping:";
3612 otmp->invlet = obj->invlet;
3614 } else {
3615 /* splitting: don't merge extra compatible stacks;
3616 if destination is compatible, do merge with it,
3617 otherwise bump whatever is there to an open slot */
3618 if (otmp->invlet == let) {
3619 int olth = 0;
3621 if (has_oname(obj))
3622 olth = strlen(ONAME(obj));
3623 /* ugly hack: if these objects aren't going to merge
3624 solely because they have conflicting user-assigned
3625 names, strip off the name of the one being moved */
3626 if (olth && !obj->oartifact && !mergable(otmp, obj)) {
3627 char *holdname = ONAME(obj);
3629 ONAME(obj) = (char *) 0;
3630 /* restore name iff merging is still not possible */
3631 if (!mergable(otmp, obj)) {
3632 ONAME(obj) = holdname;
3633 holdname = (char *) 0;
3634 } else
3635 free((genericptr_t) holdname);
3638 if (merged(&otmp, &obj)) {
3639 obj = otmp;
3640 extract_nobj(obj, &invent);
3641 } else if (inv_cnt(FALSE) >= 52) {
3642 (void) merged(&splitting, &obj); /* undo split */
3643 /* "knapsack cannot accommodate any more items" */
3644 Your("pack is too full.");
3645 return 0;
3646 } else {
3647 bumped = otmp;
3648 extract_nobj(bumped, &invent);
3650 break;
3651 } /* found 'to' slot */
3652 } /* splitting */
3653 otmp = otmp->nobj;
3656 /* inline addinv; insert loose object at beginning of inventory */
3657 obj->invlet = let;
3658 obj->nobj = invent;
3659 obj->where = OBJ_INVENT;
3660 invent = obj;
3661 reorder_invent();
3662 if (bumped) {
3663 /* splitting the 'from' stack is causing an incompatible
3664 stack in the 'to' slot to be moved into an open one;
3665 we need to do another inline insertion to inventory */
3666 assigninvlet(bumped);
3667 bumped->nobj = invent;
3668 bumped->where = OBJ_INVENT;
3669 invent = bumped;
3670 reorder_invent();
3673 /* messages deferred until inventory has been fully reestablished */
3674 prinv(adj_type, obj, 0L);
3675 if (bumped)
3676 prinv("Moving:", bumped, 0L);
3677 if (splitting)
3678 clear_splitobjs(); /* reset splitobj context */
3679 update_inventory();
3680 return 0;
3683 /* common to display_minventory and display_cinventory */
3684 STATIC_OVL void
3685 invdisp_nothing(hdr, txt)
3686 const char *hdr, *txt;
3688 winid win;
3689 anything any;
3690 menu_item *selected;
3692 any = zeroany;
3693 win = create_nhwindow(NHW_MENU);
3694 start_menu(win);
3695 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
3696 MENU_UNSELECTED);
3697 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3698 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
3699 end_menu(win, (char *) 0);
3700 if (select_menu(win, PICK_NONE, &selected) > 0)
3701 free((genericptr_t) selected);
3702 destroy_nhwindow(win);
3703 return;
3706 /* query_objlist callback: return things that are worn or wielded */
3707 STATIC_OVL boolean
3708 worn_wield_only(obj)
3709 struct obj *obj;
3711 #if 1
3712 /* check for things that *are* worn or wielded (only used for monsters,
3713 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3714 return (boolean) (obj->owornmask != 0L);
3715 #else
3716 /* this used to check for things that *might* be worn or wielded,
3717 but that's not particularly interesting */
3718 if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
3719 return TRUE;
3720 return (boolean) (obj->oclass == WEAPON_CLASS
3721 || obj->oclass == ARMOR_CLASS
3722 || obj->oclass == AMULET_CLASS
3723 || obj->oclass == RING_CLASS);
3724 #endif
3728 * Display a monster's inventory.
3729 * Returns a pointer to the object from the monster's inventory selected
3730 * or NULL if nothing was selected.
3732 * By default, only worn and wielded items are displayed. The caller
3733 * can pick one. Modifier flags are:
3735 * PICK_NONE, PICK_ONE - standard menu control
3736 * PICK_ANY - allowed, but we only return a single object
3737 * MINV_NOLET - nothing selectable
3738 * MINV_ALL - display all inventory
3740 struct obj *
3741 display_minventory(mon, dflags, title)
3742 register struct monst *mon;
3743 int dflags;
3744 char *title;
3746 struct obj *ret;
3747 char tmp[QBUFSZ];
3748 int n;
3749 menu_item *selected = 0;
3750 int do_all = (dflags & MINV_ALL) != 0,
3751 incl_hero = (do_all && u.uswallow && mon == u.ustuck),
3752 have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
3753 pickings = (dflags & MINV_PICKMASK);
3755 Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
3756 do_all ? "possessions" : "armament");
3758 if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
3759 /* Fool the 'weapon in hand' routine into
3760 * displaying 'weapon in claw', etc. properly.
3762 youmonst.data = mon->data;
3764 n = query_objlist(title ? title : tmp, &(mon->minvent),
3765 (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
3766 &selected, pickings,
3767 do_all ? allow_all : worn_wield_only);
3768 set_uasmon();
3769 } else {
3770 invdisp_nothing(title ? title : tmp, "(none)");
3771 n = 0;
3774 if (n > 0) {
3775 ret = selected[0].item.a_obj;
3776 free((genericptr_t) selected);
3777 } else
3778 ret = (struct obj *) 0;
3779 return ret;
3783 * Display the contents of a container in inventory style.
3784 * Currently, this is only used for statues, via wand of probing.
3786 struct obj *
3787 display_cinventory(obj)
3788 register struct obj *obj;
3790 struct obj *ret;
3791 char qbuf[QBUFSZ];
3792 int n;
3793 menu_item *selected = 0;
3795 (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
3796 "that");
3798 if (obj->cobj) {
3799 n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
3800 &selected, PICK_NONE, allow_all);
3801 } else {
3802 invdisp_nothing(qbuf, "(empty)");
3803 n = 0;
3805 if (n > 0) {
3806 ret = selected[0].item.a_obj;
3807 free((genericptr_t) selected);
3808 } else
3809 ret = (struct obj *) 0;
3810 obj->cknown = 1;
3811 return ret;
3814 /* query objlist callback: return TRUE if obj is at given location */
3815 static coord only;
3817 STATIC_OVL boolean
3818 only_here(obj)
3819 struct obj *obj;
3821 return (obj->ox == only.x && obj->oy == only.y);
3825 * Display a list of buried items in inventory style. Return a non-zero
3826 * value if there were items at that spot.
3828 * Currently, this is only used with a wand of probing zapped downwards.
3831 display_binventory(x, y, as_if_seen)
3832 int x, y;
3833 boolean as_if_seen;
3835 struct obj *obj;
3836 menu_item *selected = 0;
3837 int n;
3839 /* count # of objects here */
3840 for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
3841 if (obj->ox == x && obj->oy == y) {
3842 if (as_if_seen)
3843 obj->dknown = 1;
3844 n++;
3847 if (n) {
3848 only.x = x;
3849 only.y = y;
3850 if (query_objlist("Things that are buried here:",
3851 &level.buriedobjlist, INVORDER_SORT,
3852 &selected, PICK_NONE, only_here) > 0)
3853 free((genericptr_t) selected);
3854 only.x = only.y = 0;
3856 return n;
3859 /*invent.c*/