Document explicitly what m-prefix does to each command
[aNetHack.git] / src / invent.c
blobfb0099bb8908e4f2b228a9b020fdc609f2f40aa3
1 /* NetHack 3.6 invent.c $NHDT-Date: 1472809075 2016/09/02 09:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.210 $ */
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 (is_mines_prize(obj) && obj->record_achieve_special) {
517 u.uachieve.mines_luckstone = 1;
518 obj->record_achieve_special = 0;
519 } else if (is_soko_prize(obj) && obj->record_achieve_special) {
520 u.uachieve.finish_sokoban = 1;
521 obj->record_achieve_special = 0;
526 * Adjust hero intrinsics as if this object was being added to the hero's
527 * inventory. Called _after_ the object has been added to the hero's
528 * inventory.
530 * This is called when adding objects to the hero's inventory normally (via
531 * addinv) or when an object in the hero's inventory has been polymorphed
532 * in-place.
534 void
535 addinv_core2(obj)
536 struct obj *obj;
538 if (confers_luck(obj)) {
539 /* new luckstone must be in inventory by this point
540 * for correct calculation */
541 set_moreluck();
546 * Add obj to the hero's inventory. Make sure the object is "free".
547 * Adjust hero attributes as necessary.
549 struct obj *
550 addinv(obj)
551 struct obj *obj;
553 struct obj *otmp, *prev;
554 int saved_otyp = (int) obj->otyp; /* for panic */
555 boolean obj_was_thrown;
557 if (obj->where != OBJ_FREE)
558 panic("addinv: obj not free");
559 /* normally addtobill() clears no_charge when items in a shop are
560 picked up, but won't do so if the shop has become untended */
561 obj->no_charge = 0; /* should not be set in hero's invent */
562 if (Has_contents(obj))
563 picked_container(obj); /* clear no_charge */
564 obj_was_thrown = obj->was_thrown;
565 obj->was_thrown = 0; /* not meaningful for invent */
567 addinv_core1(obj);
569 /* merge with quiver in preference to any other inventory slot
570 in case quiver and wielded weapon are both eligible; adding
571 extra to quivered stack is more useful than to wielded one */
572 if (uquiver && merged(&uquiver, &obj)) {
573 obj = uquiver;
574 if (!obj)
575 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
576 goto added;
578 /* merge if possible; find end of chain in the process */
579 for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
580 if (merged(&otmp, &obj)) {
581 obj = otmp;
582 if (!obj)
583 panic("addinv: null obj after merge otyp=%d", saved_otyp);
584 goto added;
586 /* didn't merge, so insert into chain */
587 assigninvlet(obj);
588 if (flags.invlet_constant || !prev) {
589 obj->nobj = invent; /* insert at beginning */
590 invent = obj;
591 if (flags.invlet_constant)
592 reorder_invent();
593 } else {
594 prev->nobj = obj; /* insert at end */
595 obj->nobj = 0;
597 obj->where = OBJ_INVENT;
599 /* fill empty quiver if obj was thrown */
600 if (flags.pickup_thrown && !uquiver && obj_was_thrown
601 && (throwing_weapon(obj) || is_ammo(obj)))
602 setuqwep(obj);
603 added:
604 addinv_core2(obj);
605 carry_obj_effects(obj); /* carrying affects the obj */
606 update_inventory();
607 return obj;
611 * Some objects are affected by being carried.
612 * Make those adjustments here. Called _after_ the object
613 * has been added to the hero's or monster's inventory,
614 * and after hero's intrinsics have been updated.
616 void
617 carry_obj_effects(obj)
618 struct obj *obj;
620 /* Cursed figurines can spontaneously transform
621 when carried. */
622 if (obj->otyp == FIGURINE) {
623 if (obj->cursed && obj->corpsenm != NON_PM
624 && !dead_species(obj->corpsenm, TRUE)) {
625 attach_fig_transform_timeout(obj);
630 /* Add an item to the inventory unless we're fumbling or it refuses to be
631 * held (via touch_artifact), and give a message.
632 * If there aren't any free inventory slots, we'll drop it instead.
633 * If both success and failure messages are NULL, then we're just doing the
634 * fumbling/slot-limit checking for a silent grab. In any case,
635 * touch_artifact will print its own messages if they are warranted.
637 struct obj *
638 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
639 struct obj *obj;
640 const char *drop_fmt, *drop_arg, *hold_msg;
642 char buf[BUFSZ];
644 if (!Blind)
645 obj->dknown = 1; /* maximize mergibility */
646 if (obj->oartifact) {
647 /* place_object may change these */
648 boolean crysknife = (obj->otyp == CRYSKNIFE);
649 int oerode = obj->oerodeproof;
650 boolean wasUpolyd = Upolyd;
652 /* in case touching this object turns out to be fatal */
653 place_object(obj, u.ux, u.uy);
655 if (!touch_artifact(obj, &youmonst)) {
656 obj_extract_self(obj); /* remove it from the floor */
657 dropy(obj); /* now put it back again :-) */
658 return obj;
659 } else if (wasUpolyd && !Upolyd) {
660 /* loose your grip if you revert your form */
661 if (drop_fmt)
662 pline(drop_fmt, drop_arg);
663 obj_extract_self(obj);
664 dropy(obj);
665 return obj;
667 obj_extract_self(obj);
668 if (crysknife) {
669 obj->otyp = CRYSKNIFE;
670 obj->oerodeproof = oerode;
673 if (Fumbling) {
674 if (drop_fmt)
675 pline(drop_fmt, drop_arg);
676 dropy(obj);
677 } else {
678 long oquan = obj->quan;
679 int prev_encumbr = near_capacity(); /* before addinv() */
681 /* encumbrance only matters if it would now become worse
682 than max( current_value, stressed ) */
683 if (prev_encumbr < MOD_ENCUMBER)
684 prev_encumbr = MOD_ENCUMBER;
685 /* addinv() may redraw the entire inventory, overwriting
686 drop_arg when it comes from something like doname() */
687 if (drop_arg)
688 drop_arg = strcpy(buf, drop_arg);
690 obj = addinv(obj);
691 if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
692 && near_capacity() > prev_encumbr)) {
693 if (drop_fmt)
694 pline(drop_fmt, drop_arg);
695 /* undo any merge which took place */
696 if (obj->quan > oquan)
697 obj = splitobj(obj, oquan);
698 dropx(obj);
699 } else {
700 if (flags.autoquiver && !uquiver && !obj->owornmask
701 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
702 || ammo_and_launcher(obj, uswapwep)))
703 setuqwep(obj);
704 if (hold_msg || drop_fmt)
705 prinv(hold_msg, obj, oquan);
708 return obj;
711 /* useup() all of an item regardless of its quantity */
712 void
713 useupall(obj)
714 struct obj *obj;
716 setnotworn(obj);
717 freeinv(obj);
718 obfree(obj, (struct obj *) 0); /* deletes contents also */
721 void
722 useup(obj)
723 register struct obj *obj;
725 /* Note: This works correctly for containers because they (containers)
726 don't merge. */
727 if (obj->quan > 1L) {
728 obj->in_use = FALSE; /* no longer in use */
729 obj->quan--;
730 obj->owt = weight(obj);
731 update_inventory();
732 } else {
733 useupall(obj);
737 /* use one charge from an item and possibly incur shop debt for it */
738 void
739 consume_obj_charge(obj, maybe_unpaid)
740 struct obj *obj;
741 boolean maybe_unpaid; /* false if caller handles shop billing */
743 if (maybe_unpaid)
744 check_unpaid(obj);
745 obj->spe -= 1;
746 if (obj->known)
747 update_inventory();
751 * Adjust hero's attributes as if this object was being removed from the
752 * hero's inventory. This should only be called from freeinv() and
753 * where we are polymorphing an object already in the hero's inventory.
755 * Should think of a better name...
757 void
758 freeinv_core(obj)
759 struct obj *obj;
761 if (obj->oclass == COIN_CLASS) {
762 context.botl = 1;
763 return;
764 } else if (obj->otyp == AMULET_OF_YENDOR) {
765 if (!u.uhave.amulet)
766 impossible("don't have amulet?");
767 u.uhave.amulet = 0;
768 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
769 if (!u.uhave.menorah)
770 impossible("don't have candelabrum?");
771 u.uhave.menorah = 0;
772 } else if (obj->otyp == BELL_OF_OPENING) {
773 if (!u.uhave.bell)
774 impossible("don't have silver bell?");
775 u.uhave.bell = 0;
776 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
777 if (!u.uhave.book)
778 impossible("don't have the book?");
779 u.uhave.book = 0;
780 } else if (obj->oartifact) {
781 if (is_quest_artifact(obj)) {
782 if (!u.uhave.questart)
783 impossible("don't have quest artifact?");
784 u.uhave.questart = 0;
786 set_artifact_intrinsic(obj, 0, W_ART);
789 if (obj->otyp == LOADSTONE) {
790 curse(obj);
791 } else if (confers_luck(obj)) {
792 set_moreluck();
793 context.botl = 1;
794 } else if (obj->otyp == FIGURINE && obj->timed) {
795 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
799 /* remove an object from the hero's inventory */
800 void
801 freeinv(obj)
802 register struct obj *obj;
804 extract_nobj(obj, &invent);
805 freeinv_core(obj);
806 update_inventory();
809 void
810 delallobj(x, y)
811 int x, y;
813 struct obj *otmp, *otmp2;
815 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
816 if (otmp == uball)
817 unpunish();
818 /* after unpunish(), or might get deallocated chain */
819 otmp2 = otmp->nexthere;
820 if (otmp == uchain)
821 continue;
822 delobj(otmp);
826 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
827 void
828 delobj(obj)
829 register struct obj *obj;
831 boolean update_map;
833 if (obj->otyp == AMULET_OF_YENDOR
834 || obj->otyp == CANDELABRUM_OF_INVOCATION
835 || obj->otyp == BELL_OF_OPENING
836 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
837 /* player might be doing something stupid, but we
838 * can't guarantee that. assume special artifacts
839 * are indestructible via drawbridges, and exploding
840 * chests, and golem creation, and ...
842 return;
844 update_map = (obj->where == OBJ_FLOOR);
845 obj_extract_self(obj);
846 if (update_map)
847 newsym(obj->ox, obj->oy);
848 obfree(obj, (struct obj *) 0); /* frees contents also */
851 /* try to find a particular type of object at designated map location */
852 struct obj *
853 sobj_at(otyp, x, y)
854 int otyp;
855 int x, y;
857 register struct obj *otmp;
859 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
860 if (otmp->otyp == otyp)
861 break;
863 return otmp;
866 /* sobj_at(&c) traversal -- find next object of specified type */
867 struct obj *
868 nxtobj(obj, type, by_nexthere)
869 struct obj *obj;
870 int type;
871 boolean by_nexthere;
873 register struct obj *otmp;
875 otmp = obj; /* start with the object after this one */
876 do {
877 otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
878 if (!otmp)
879 break;
880 } while (otmp->otyp != type);
882 return otmp;
885 struct obj *
886 carrying(type)
887 register int type;
889 register struct obj *otmp;
891 for (otmp = invent; otmp; otmp = otmp->nobj)
892 if (otmp->otyp == type)
893 return otmp;
894 return (struct obj *) 0;
897 /* Fictional and not-so-fictional currencies.
898 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
900 static const char *const currencies[] = {
901 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
902 "Ankh-Morpork Dollar", /* Discworld */
903 "auric", /* The Domination of Draka */
904 "buckazoid", /* Space Quest */
905 "cirbozoid", /* Starslip */
906 "credit chit", /* Deus Ex */
907 "cubit", /* Battlestar Galactica */
908 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
909 "fretzer", /* Jules Verne */
910 "imperial credit", /* Star Wars */
911 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
912 "kongbuck", /* Snow Crash */
913 "nanite", /* System Shock 2 */
914 "quatloo", /* Star Trek, Sim City */
915 "simoleon", /* Sim City */
916 "solari", /* Spaceballs */
917 "spacebuck", /* Spaceballs */
918 "sporebuck", /* Spore */
919 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
920 "woolong", /* Cowboy Bebop */
921 "zorkmid", /* Zork, NetHack */
924 const char *
925 currency(amount)
926 long amount;
928 const char *res;
930 res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
931 if (amount != 1L)
932 res = makeplural(res);
933 return res;
936 boolean
937 have_lizard()
939 register struct obj *otmp;
941 for (otmp = invent; otmp; otmp = otmp->nobj)
942 if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
943 return TRUE;
944 return FALSE;
947 /* 3.6 tribute */
948 struct obj *
949 u_have_novel()
951 register struct obj *otmp;
953 for (otmp = invent; otmp; otmp = otmp->nobj)
954 if (otmp->otyp == SPE_NOVEL)
955 return otmp;
956 return (struct obj *) 0;
959 struct obj *
960 o_on(id, objchn)
961 unsigned int id;
962 register struct obj *objchn;
964 struct obj *temp;
966 while (objchn) {
967 if (objchn->o_id == id)
968 return objchn;
969 if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
970 return temp;
971 objchn = objchn->nobj;
973 return (struct obj *) 0;
976 boolean
977 obj_here(obj, x, y)
978 register struct obj *obj;
979 int x, y;
981 register struct obj *otmp;
983 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
984 if (obj == otmp)
985 return TRUE;
986 return FALSE;
989 struct obj *
990 g_at(x, y)
991 register int x, y;
993 register struct obj *obj = level.objects[x][y];
995 while (obj) {
996 if (obj->oclass == COIN_CLASS)
997 return obj;
998 obj = obj->nexthere;
1000 return (struct obj *) 0;
1003 /* compact a string of inventory letters by dashing runs of letters */
1004 STATIC_OVL void
1005 compactify(buf)
1006 register char *buf;
1008 register int i1 = 1, i2 = 1;
1009 register char ilet, ilet1, ilet2;
1011 ilet2 = buf[0];
1012 ilet1 = buf[1];
1013 buf[++i2] = buf[++i1];
1014 ilet = buf[i1];
1015 while (ilet) {
1016 if (ilet == ilet1 + 1) {
1017 if (ilet1 == ilet2 + 1)
1018 buf[i2 - 1] = ilet1 = '-';
1019 else if (ilet2 == '-') {
1020 buf[i2 - 1] = ++ilet1;
1021 buf[i2] = buf[++i1];
1022 ilet = buf[i1];
1023 continue;
1025 } else if (ilet == NOINVSYM) {
1026 /* compact three or more consecutive '#'
1027 characters into "#-#" */
1028 if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
1029 buf[i2 - 1] = '-';
1030 else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
1031 && buf[i2 - 1] == NOINVSYM)
1032 --i2;
1034 ilet2 = ilet1;
1035 ilet1 = ilet;
1036 buf[++i2] = buf[++i1];
1037 ilet = buf[i1];
1041 /* some objects shouldn't be split when count given to getobj or askchain */
1042 boolean
1043 splittable(obj)
1044 struct obj *obj;
1046 return !((obj->otyp == LOADSTONE && obj->cursed)
1047 || (obj == uwep && welded(uwep)));
1050 /* match the prompt for either 'T' or 'R' command */
1051 STATIC_OVL boolean
1052 taking_off(action)
1053 const char *action;
1055 return !strcmp(action, "take off") || !strcmp(action, "remove");
1058 /* match the prompt for either 'W' or 'P' command */
1059 STATIC_OVL boolean
1060 putting_on(action)
1061 const char *action;
1063 return !strcmp(action, "wear") || !strcmp(action, "put on");
1067 * getobj returns:
1068 * struct obj *xxx: object to do something with.
1069 * (struct obj *) 0 error return: no object.
1070 * &zeroobj explicitly no object (as in w-).
1071 !!!! test if gold can be used in unusual ways (eaten etc.)
1072 !!!! may be able to remove "usegold"
1074 struct obj *
1075 getobj(let, word)
1076 register const char *let, *word;
1078 register struct obj *otmp;
1079 register char ilet;
1080 char buf[BUFSZ], qbuf[QBUFSZ];
1081 char lets[BUFSZ], altlets[BUFSZ], *ap;
1082 register int foo = 0;
1083 register char *bp = buf;
1084 xchar allowcnt = 0; /* 0, 1 or 2 */
1085 boolean usegold = FALSE; /* can't use gold because its illegal */
1086 boolean allowall = FALSE;
1087 boolean allownone = FALSE;
1088 boolean useboulder = FALSE;
1089 xchar foox = 0;
1090 long cnt;
1091 boolean cntgiven = FALSE;
1092 long dummymask;
1094 if (*let == ALLOW_COUNT)
1095 let++, allowcnt = 1;
1096 if (*let == COIN_CLASS)
1097 let++, usegold = TRUE;
1099 /* Equivalent of an "ugly check" for gold */
1100 if (usegold && !strcmp(word, "eat")
1101 && (!metallivorous(youmonst.data)
1102 || youmonst.data == &mons[PM_RUST_MONSTER]))
1103 usegold = FALSE;
1105 if (*let == ALL_CLASSES)
1106 let++, allowall = TRUE;
1107 if (*let == ALLOW_NONE)
1108 let++, allownone = TRUE;
1109 /* "ugly check" for reading fortune cookies, part 1.
1110 * The normal 'ugly check' keeps the object on the inventory list.
1111 * We don't want to do that for shirts/cookies, so the check for
1112 * them is handled a bit differently (and also requires that we set
1113 * allowall in the caller).
1115 if (allowall && !strcmp(word, "read"))
1116 allowall = FALSE;
1118 /* another ugly check: show boulders (not statues) */
1119 if (*let == WEAPON_CLASS && !strcmp(word, "throw")
1120 && throws_rocks(youmonst.data))
1121 useboulder = TRUE;
1123 if (allownone)
1124 *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
1125 ap = altlets;
1127 if (!flags.invlet_constant)
1128 reassign();
1129 else
1130 /* in case invent is in packorder, force it to be in invlet
1131 order before collecing candidate inventory letters;
1132 if player responds with '?' or '*' it will be changed
1133 back by display_pickinv(), but by then we'll have 'lets'
1134 and so won't have to re-sort in the for(;;) loop below */
1135 sortloot(&invent, SORTLOOT_INVLET, FALSE);
1137 for (otmp = invent; otmp; otmp = otmp->nobj) {
1138 if (&bp[foo] == &buf[sizeof buf - 1]
1139 || ap == &altlets[sizeof altlets - 1]) {
1140 /* we must have a huge number of NOINVSYM items somehow */
1141 impossible("getobj: inventory overflow");
1142 break;
1145 if (!*let || index(let, otmp->oclass)
1146 || (usegold && otmp->invlet == GOLD_SYM)
1147 || (useboulder && otmp->otyp == BOULDER)) {
1148 register int otyp = otmp->otyp;
1150 bp[foo++] = otmp->invlet;
1151 /* clang-format off */
1152 /* *INDENT-OFF* */
1153 /* ugly check: remove inappropriate things */
1154 if (
1155 (taking_off(word) /* exclude if not worn */
1156 && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1157 || (putting_on(word) /* exclude if already worn */
1158 && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1159 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1160 || (!strcmp(word, "wield")
1161 && (otmp->owornmask & W_WEP))
1162 #endif
1163 || (!strcmp(word, "ready") /* exclude when wielded... */
1164 && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
1165 && otmp->quan == 1L)) /* ...unless more than one */
1166 || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1167 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1169 foo--;
1170 foox++;
1172 /* Second ugly check; unlike the first it won't trigger an
1173 * "else" in "you don't have anything else to ___".
1175 else if (
1176 (putting_on(word)
1177 && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1178 || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1179 && otyp != TOWEL && otyp != LENSES)))
1180 || (!strcmp(word, "wield")
1181 && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1182 || (!strcmp(word, "eat") && !is_edible(otmp))
1183 || (!strcmp(word, "sacrifice")
1184 && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1185 && otyp != FAKE_AMULET_OF_YENDOR))
1186 || (!strcmp(word, "write with")
1187 && (otmp->oclass == TOOL_CLASS
1188 && otyp != MAGIC_MARKER && otyp != TOWEL))
1189 || (!strcmp(word, "tin")
1190 && (otyp != CORPSE || !tinnable(otmp)))
1191 || (!strcmp(word, "rub")
1192 && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1193 && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1194 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1195 || (!strcmp(word, "use or apply")
1196 /* Picks, axes, pole-weapons, bullwhips */
1197 && ((otmp->oclass == WEAPON_CLASS
1198 && !is_pick(otmp) && !is_axe(otmp)
1199 && !is_pole(otmp) && otyp != BULLWHIP)
1200 || (otmp->oclass == POTION_CLASS
1201 /* only applicable potion is oil, and it will only
1202 be offered as a choice when already discovered */
1203 && (otyp != POT_OIL || !otmp->dknown
1204 || !objects[POT_OIL].oc_name_known))
1205 || (otmp->oclass == FOOD_CLASS
1206 && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1207 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1208 || (!strcmp(word, "invoke")
1209 && !otmp->oartifact
1210 && !objects[otyp].oc_unique
1211 && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1212 && otyp != CRYSTAL_BALL /* synonym for apply */
1213 /* note: presenting the possibility of invoking non-artifact
1214 mirrors and/or lamps is simply a cruel deception... */
1215 && otyp != MIRROR
1216 && otyp != MAGIC_LAMP
1217 && (otyp != OIL_LAMP /* don't list known oil lamp */
1218 || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1219 || (!strcmp(word, "untrap with")
1220 && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1221 || (otmp->oclass == POTION_CLASS
1222 /* only applicable potion is oil, and it will only
1223 be offered as a choice when already discovered */
1224 && (otyp != POT_OIL || !otmp->dknown
1225 || !objects[POT_OIL].oc_name_known))))
1226 || (!strcmp(word, "tip") && !Is_container(otmp)
1227 /* include horn of plenty if sufficiently discovered */
1228 && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1229 || !objects[HORN_OF_PLENTY].oc_name_known))
1230 || (!strcmp(word, "charge") && !is_chargeable(otmp))
1231 || (!strcmp(word, "open") && otyp != TIN)
1232 || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1234 foo--;
1236 /* Third ugly check: acceptable but not listed as likely
1237 * candidates in the prompt or in the inventory subset if
1238 * player responds with '?'.
1240 else if (
1241 /* ugly check for unworn armor that can't be worn */
1242 (putting_on(word) && *let == ARMOR_CLASS
1243 && !canwearobj(otmp, &dummymask, FALSE))
1244 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1245 || ((putting_on(word) || taking_off(word))
1246 && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1247 /* or unsuitable items rubbed on known touchstone */
1248 || (!strncmp(word, "rub on the stone", 16)
1249 && *let == GEM_CLASS && otmp->dknown
1250 && objects[otyp].oc_name_known)
1251 /* suppress corpses on astral, amulets elsewhere */
1252 || (!strcmp(word, "sacrifice")
1253 /* (!astral && amulet) || (astral && !amulet) */
1254 && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1255 /* suppress container being stashed into */
1256 || (!strcmp(word, "stash") && !ck_bag(otmp))
1257 /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1258 or accessory (ring) covered by cursed worn armor (gloves) */
1259 || (taking_off(word)
1260 && inaccessible_equipment(otmp, (const char *) 0,
1261 (boolean) (otmp->oclass == RING_CLASS)))
1262 || (!strcmp(word, "write on")
1263 && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
1264 || !otmp->dknown || !objects[otyp].oc_name_known))
1266 /* acceptable but not listed as likely candidate */
1267 foo--;
1268 allowall = TRUE;
1269 *ap++ = otmp->invlet;
1271 /* *INDENT-ON* */
1272 /* clang-format on */
1273 } else {
1274 /* "ugly check" for reading fortune cookies, part 2 */
1275 if ((!strcmp(word, "read") && is_readable(otmp)))
1276 allowall = usegold = TRUE;
1280 bp[foo] = 0;
1281 if (foo == 0 && bp > buf && bp[-1] == ' ')
1282 *--bp = 0;
1283 Strcpy(lets, bp); /* necessary since we destroy buf */
1284 if (foo > 5) /* compactify string */
1285 compactify(bp);
1286 *ap = '\0';
1288 if (!foo && !allowall && !allownone) {
1289 You("don't have anything %sto %s.", foox ? "else " : "", word);
1290 return (struct obj *) 0;
1291 } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
1292 /* we wanted all scrolls and books in altlets[], but that came with
1293 'allowall' which we don't want since it prevents "silly thing"
1294 result if anything other than scroll or spellbook is chosen */
1295 allowall = FALSE;
1297 for (;;) {
1298 cnt = 0;
1299 cntgiven = FALSE;
1300 if (!buf[0]) {
1301 Sprintf(qbuf, "What do you want to %s? [*]", word);
1302 } else {
1303 Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
1305 if (in_doagain)
1306 ilet = readchar();
1307 else
1308 ilet = yn_function(qbuf, (char *) 0, '\0');
1309 if (digit(ilet)) {
1310 long tmpcnt = 0;
1312 if (!allowcnt) {
1313 pline("No count allowed with this command.");
1314 continue;
1316 ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt);
1317 if (tmpcnt) {
1318 cnt = tmpcnt;
1319 cntgiven = TRUE;
1322 if (index(quitchars, ilet)) {
1323 if (flags.verbose)
1324 pline1(Never_mind);
1325 return (struct obj *) 0;
1327 if (ilet == HANDS_SYM) { /* '-' */
1328 if (!allownone) {
1329 char *suf = (char *) 0;
1331 strcpy(buf, word);
1332 if ((bp = strstr(buf, " on the ")) != 0) {
1333 /* rub on the stone[s] */
1334 *bp = '\0';
1335 suf = (bp + 1);
1337 if ((bp = strstr(buf, " or ")) != 0) {
1338 *bp = '\0';
1339 bp = (rn2(2) ? buf : (bp + 4));
1340 } else
1341 bp = buf;
1342 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1343 suf ? suf : "");
1345 return (allownone ? &zeroobj : (struct obj *) 0);
1347 /* since gold is now kept in inventory, we need to do processing for
1348 select-from-invent before checking whether gold has been picked */
1349 if (ilet == '?' || ilet == '*') {
1350 char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1351 long ctmp = 0;
1353 qbuf[0] = '\0';
1354 if (!strcmp(word, "grease"))
1355 Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
1356 else if (!strcmp(word, "write with"))
1357 Sprintf(qbuf, "your %s", body_part(FINGERTIP));
1358 else if (!strcmp(word, "wield"))
1359 Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
1360 makeplural(body_part(HAND)),
1361 !uwep ? " (wielded)" : "");
1362 else if (!strcmp(word, "ready"))
1363 Sprintf(qbuf, "empty quiver%s",
1364 !uquiver ? " (nothing readied)" : "");
1366 if (ilet == '?' && !*lets && *altlets)
1367 allowed_choices = altlets;
1368 ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
1369 TRUE, allowcnt ? &ctmp : (long *) 0);
1370 if (!ilet)
1371 continue;
1372 if (ilet == HANDS_SYM)
1373 return &zeroobj;
1374 if (ilet == '\033') {
1375 if (flags.verbose)
1376 pline1(Never_mind);
1377 return (struct obj *) 0;
1379 if (allowcnt && ctmp >= 0) {
1380 cnt = ctmp;
1381 cntgiven = TRUE;
1383 /* they typed a letter (not a space) at the prompt */
1385 /* find the item which was picked */
1386 for (otmp = invent; otmp; otmp = otmp->nobj)
1387 if (otmp->invlet == ilet)
1388 break;
1389 /* some items have restrictions */
1390 if (ilet == def_oc_syms[COIN_CLASS].sym
1391 /* guard against the [hypothetical] chace of having more
1392 than one invent slot of gold and picking the non-'$' one */
1393 || (otmp && otmp->oclass == COIN_CLASS)) {
1394 if (!usegold) {
1395 You("cannot %s gold.", word);
1396 return (struct obj *) 0;
1398 /* Historic note: early Nethack had a bug which was
1399 * first reported for Larn, where trying to drop 2^32-n
1400 * gold pieces was allowed, and did interesting things
1401 * to your money supply. The LRS is the tax bureau
1402 * from Larn.
1404 if (cntgiven && cnt <= 0) {
1405 if (cnt < 0)
1406 pline_The(
1407 "LRS would be very interested to know you have that much.");
1408 return (struct obj *) 0;
1411 if (cntgiven && !strcmp(word, "throw")) {
1412 /* permit counts for throwing gold, but don't accept
1413 * counts for other things since the throw code will
1414 * split off a single item anyway */
1415 if (cnt == 0)
1416 return (struct obj *) 0;
1417 if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
1418 && !(otmp && otmp->oclass == COIN_CLASS))) {
1419 You("can only throw one item at a time.");
1420 continue;
1423 context.botl = 1; /* May have changed the amount of money */
1424 savech(ilet);
1425 /* [we used to set otmp (by finding ilet in invent) here, but
1426 that's been moved above so that otmp can be checked earlier] */
1427 /* verify the chosen object */
1428 if (!otmp) {
1429 You("don't have that object.");
1430 if (in_doagain)
1431 return (struct obj *) 0;
1432 continue;
1433 } else if (cnt < 0 || otmp->quan < cnt) {
1434 You("don't have that many! You have only %ld.", otmp->quan);
1435 if (in_doagain)
1436 return (struct obj *) 0;
1437 continue;
1439 break;
1441 if (!allowall && let && !index(let, otmp->oclass)
1442 && !(usegold && otmp->oclass == COIN_CLASS)) {
1443 silly_thing(word, otmp);
1444 return (struct obj *) 0;
1446 if (cntgiven) {
1447 if (cnt == 0)
1448 return (struct obj *) 0;
1449 if (cnt != otmp->quan) {
1450 /* don't split a stack of cursed loadstones */
1451 if (splittable(otmp))
1452 otmp = splitobj(otmp, cnt);
1453 else if (otmp->otyp == LOADSTONE && otmp->cursed)
1454 /* kludge for canletgo()'s can't-drop-this message */
1455 otmp->corpsenm = (int) cnt;
1458 return otmp;
1461 void
1462 silly_thing(word, otmp)
1463 const char *word;
1464 struct obj *otmp;
1466 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1467 nhUse(otmp);
1468 #else
1469 const char *s1, *s2, *s3;
1470 int ocls = otmp->oclass, otyp = otmp->otyp;
1472 s1 = s2 = s3 = 0;
1473 /* check for attempted use of accessory commands ('P','R') on armor
1474 and for corresponding armor commands ('W','T') on accessories */
1475 if (ocls == ARMOR_CLASS) {
1476 if (!strcmp(word, "put on"))
1477 s1 = "W", s2 = "wear", s3 = "";
1478 else if (!strcmp(word, "remove"))
1479 s1 = "T", s2 = "take", s3 = " off";
1480 } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1481 || ocls == AMULET_CLASS
1482 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1483 if (!strcmp(word, "wear"))
1484 s1 = "P", s2 = "put", s3 = " on";
1485 else if (!strcmp(word, "take off"))
1486 s1 = "R", s2 = "remove", s3 = "";
1488 if (s1)
1489 pline("Use the '%s' command to %s %s%s.", s1, s2,
1490 !(is_plural(otmp) || pair_of(otmp)) ? "that" : "those", s3);
1491 else
1492 #endif
1493 pline(silly_thing_to, word);
1496 STATIC_PTR int
1497 ckvalidcat(otmp)
1498 struct obj *otmp;
1500 /* use allow_category() from pickup.c */
1501 return (int) allow_category(otmp);
1504 STATIC_PTR int
1505 ckunpaid(otmp)
1506 struct obj *otmp;
1508 return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1511 boolean
1512 wearing_armor()
1514 return (boolean) (uarm || uarmc || uarmf || uarmg
1515 || uarmh || uarms || uarmu);
1518 boolean
1519 is_worn(otmp)
1520 struct obj *otmp;
1522 return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
1523 ? TRUE
1524 : FALSE;
1527 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1528 STATIC_VAR struct xprnctx {
1529 char let;
1530 boolean dot;
1531 } safeq_xprn_ctx;
1533 /* safe_qbuf() -> short_oname() callback */
1534 STATIC_PTR char *
1535 safeq_xprname(obj)
1536 struct obj *obj;
1538 return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1539 0L, 0L);
1542 /* alternate safe_qbuf() -> short_oname() callback */
1543 STATIC_PTR char *
1544 safeq_shortxprname(obj)
1545 struct obj *obj;
1547 return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1548 safeq_xprn_ctx.dot, 0L, 0L);
1551 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1552 RING_CLASS, AMULET_CLASS,
1553 TOOL_CLASS, 0 };
1555 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1556 Return the number of times fn was called successfully.
1557 If combo is TRUE, we just use this to get a category list. */
1559 ggetobj(word, fn, mx, combo, resultflags)
1560 const char *word;
1561 int FDECL((*fn), (OBJ_P)), mx;
1562 boolean combo; /* combination menu flag */
1563 unsigned *resultflags;
1565 int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1566 boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1567 boolean takeoff, ident, allflag, m_seen;
1568 int itemcount;
1569 int oletct, iletct, unpaid, oc_of_sym;
1570 char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
1571 char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1572 char buf[BUFSZ], qbuf[QBUFSZ];
1574 if (!invent) {
1575 You("have nothing to %s.", word);
1576 if (resultflags)
1577 *resultflags = ALL_FINISHED;
1578 return 0;
1580 if (resultflags)
1581 *resultflags = 0;
1582 takeoff = ident = allflag = m_seen = FALSE;
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*/