Add missing symbols to Blank symset and Guidebook
[aNetHack.git] / src / invent.c
blobfa478b516a2ce18b5d96c89d498f737de64b3c4b
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 (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
517 u.uachieve.mines_luckstone = 1;
518 obj->record_achieve_special = 0;
519 } else if ((obj->otyp == AMULET_OF_REFLECTION
520 || obj->otyp == BAG_OF_HOLDING)
521 && obj->record_achieve_special) {
522 u.uachieve.finish_sokoban = 1;
523 obj->record_achieve_special = 0;
528 * Adjust hero intrinsics as if this object was being added to the hero's
529 * inventory. Called _after_ the object has been added to the hero's
530 * inventory.
532 * This is called when adding objects to the hero's inventory normally (via
533 * addinv) or when an object in the hero's inventory has been polymorphed
534 * in-place.
536 void
537 addinv_core2(obj)
538 struct obj *obj;
540 if (confers_luck(obj)) {
541 /* new luckstone must be in inventory by this point
542 * for correct calculation */
543 set_moreluck();
548 * Add obj to the hero's inventory. Make sure the object is "free".
549 * Adjust hero attributes as necessary.
551 struct obj *
552 addinv(obj)
553 struct obj *obj;
555 struct obj *otmp, *prev;
556 int saved_otyp = (int) obj->otyp; /* for panic */
557 boolean obj_was_thrown;
559 if (obj->where != OBJ_FREE)
560 panic("addinv: obj not free");
561 /* normally addtobill() clears no_charge when items in a shop are
562 picked up, but won't do so if the shop has become untended */
563 obj->no_charge = 0; /* should not be set in hero's invent */
564 if (Has_contents(obj))
565 picked_container(obj); /* clear no_charge */
566 obj_was_thrown = obj->was_thrown;
567 obj->was_thrown = 0; /* not meaningful for invent */
569 addinv_core1(obj);
571 /* merge with quiver in preference to any other inventory slot
572 in case quiver and wielded weapon are both eligible; adding
573 extra to quivered stack is more useful than to wielded one */
574 if (uquiver && merged(&uquiver, &obj)) {
575 obj = uquiver;
576 if (!obj)
577 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
578 goto added;
580 /* merge if possible; find end of chain in the process */
581 for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
582 if (merged(&otmp, &obj)) {
583 obj = otmp;
584 if (!obj)
585 panic("addinv: null obj after merge otyp=%d", saved_otyp);
586 goto added;
588 /* didn't merge, so insert into chain */
589 assigninvlet(obj);
590 if (flags.invlet_constant || !prev) {
591 obj->nobj = invent; /* insert at beginning */
592 invent = obj;
593 if (flags.invlet_constant)
594 reorder_invent();
595 } else {
596 prev->nobj = obj; /* insert at end */
597 obj->nobj = 0;
599 obj->where = OBJ_INVENT;
601 /* fill empty quiver if obj was thrown */
602 if (flags.pickup_thrown && !uquiver && obj_was_thrown
603 && (throwing_weapon(obj) || is_ammo(obj)))
604 setuqwep(obj);
605 added:
606 addinv_core2(obj);
607 carry_obj_effects(obj); /* carrying affects the obj */
608 update_inventory();
609 return obj;
613 * Some objects are affected by being carried.
614 * Make those adjustments here. Called _after_ the object
615 * has been added to the hero's or monster's inventory,
616 * and after hero's intrinsics have been updated.
618 void
619 carry_obj_effects(obj)
620 struct obj *obj;
622 /* Cursed figurines can spontaneously transform
623 when carried. */
624 if (obj->otyp == FIGURINE) {
625 if (obj->cursed && obj->corpsenm != NON_PM
626 && !dead_species(obj->corpsenm, TRUE)) {
627 attach_fig_transform_timeout(obj);
632 /* Add an item to the inventory unless we're fumbling or it refuses to be
633 * held (via touch_artifact), and give a message.
634 * If there aren't any free inventory slots, we'll drop it instead.
635 * If both success and failure messages are NULL, then we're just doing the
636 * fumbling/slot-limit checking for a silent grab. In any case,
637 * touch_artifact will print its own messages if they are warranted.
639 struct obj *
640 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
641 struct obj *obj;
642 const char *drop_fmt, *drop_arg, *hold_msg;
644 char buf[BUFSZ];
646 if (!Blind)
647 obj->dknown = 1; /* maximize mergibility */
648 if (obj->oartifact) {
649 /* place_object may change these */
650 boolean crysknife = (obj->otyp == CRYSKNIFE);
651 int oerode = obj->oerodeproof;
652 boolean wasUpolyd = Upolyd;
654 /* in case touching this object turns out to be fatal */
655 place_object(obj, u.ux, u.uy);
657 if (!touch_artifact(obj, &youmonst)) {
658 obj_extract_self(obj); /* remove it from the floor */
659 dropy(obj); /* now put it back again :-) */
660 return obj;
661 } else if (wasUpolyd && !Upolyd) {
662 /* loose your grip if you revert your form */
663 if (drop_fmt)
664 pline(drop_fmt, drop_arg);
665 obj_extract_self(obj);
666 dropy(obj);
667 return obj;
669 obj_extract_self(obj);
670 if (crysknife) {
671 obj->otyp = CRYSKNIFE;
672 obj->oerodeproof = oerode;
675 if (Fumbling) {
676 if (drop_fmt)
677 pline(drop_fmt, drop_arg);
678 dropy(obj);
679 } else {
680 long oquan = obj->quan;
681 int prev_encumbr = near_capacity(); /* before addinv() */
683 /* encumbrance only matters if it would now become worse
684 than max( current_value, stressed ) */
685 if (prev_encumbr < MOD_ENCUMBER)
686 prev_encumbr = MOD_ENCUMBER;
687 /* addinv() may redraw the entire inventory, overwriting
688 drop_arg when it comes from something like doname() */
689 if (drop_arg)
690 drop_arg = strcpy(buf, drop_arg);
692 obj = addinv(obj);
693 if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
694 && near_capacity() > prev_encumbr)) {
695 if (drop_fmt)
696 pline(drop_fmt, drop_arg);
697 /* undo any merge which took place */
698 if (obj->quan > oquan)
699 obj = splitobj(obj, oquan);
700 dropx(obj);
701 } else {
702 if (flags.autoquiver && !uquiver && !obj->owornmask
703 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
704 || ammo_and_launcher(obj, uswapwep)))
705 setuqwep(obj);
706 if (hold_msg || drop_fmt)
707 prinv(hold_msg, obj, oquan);
710 return obj;
713 /* useup() all of an item regardless of its quantity */
714 void
715 useupall(obj)
716 struct obj *obj;
718 setnotworn(obj);
719 freeinv(obj);
720 obfree(obj, (struct obj *) 0); /* deletes contents also */
723 void
724 useup(obj)
725 register struct obj *obj;
727 /* Note: This works correctly for containers because they (containers)
728 don't merge. */
729 if (obj->quan > 1L) {
730 obj->in_use = FALSE; /* no longer in use */
731 obj->quan--;
732 obj->owt = weight(obj);
733 update_inventory();
734 } else {
735 useupall(obj);
739 /* use one charge from an item and possibly incur shop debt for it */
740 void
741 consume_obj_charge(obj, maybe_unpaid)
742 struct obj *obj;
743 boolean maybe_unpaid; /* false if caller handles shop billing */
745 if (maybe_unpaid)
746 check_unpaid(obj);
747 obj->spe -= 1;
748 if (obj->known)
749 update_inventory();
753 * Adjust hero's attributes as if this object was being removed from the
754 * hero's inventory. This should only be called from freeinv() and
755 * where we are polymorphing an object already in the hero's inventory.
757 * Should think of a better name...
759 void
760 freeinv_core(obj)
761 struct obj *obj;
763 if (obj->oclass == COIN_CLASS) {
764 context.botl = 1;
765 return;
766 } else if (obj->otyp == AMULET_OF_YENDOR) {
767 if (!u.uhave.amulet)
768 impossible("don't have amulet?");
769 u.uhave.amulet = 0;
770 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
771 if (!u.uhave.menorah)
772 impossible("don't have candelabrum?");
773 u.uhave.menorah = 0;
774 } else if (obj->otyp == BELL_OF_OPENING) {
775 if (!u.uhave.bell)
776 impossible("don't have silver bell?");
777 u.uhave.bell = 0;
778 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
779 if (!u.uhave.book)
780 impossible("don't have the book?");
781 u.uhave.book = 0;
782 } else if (obj->oartifact) {
783 if (is_quest_artifact(obj)) {
784 if (!u.uhave.questart)
785 impossible("don't have quest artifact?");
786 u.uhave.questart = 0;
788 set_artifact_intrinsic(obj, 0, W_ART);
791 if (obj->otyp == LOADSTONE) {
792 curse(obj);
793 } else if (confers_luck(obj)) {
794 set_moreluck();
795 context.botl = 1;
796 } else if (obj->otyp == FIGURINE && obj->timed) {
797 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
801 /* remove an object from the hero's inventory */
802 void
803 freeinv(obj)
804 register struct obj *obj;
806 extract_nobj(obj, &invent);
807 freeinv_core(obj);
808 update_inventory();
811 void
812 delallobj(x, y)
813 int x, y;
815 struct obj *otmp, *otmp2;
817 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
818 if (otmp == uball)
819 unpunish();
820 /* after unpunish(), or might get deallocated chain */
821 otmp2 = otmp->nexthere;
822 if (otmp == uchain)
823 continue;
824 delobj(otmp);
828 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
829 void
830 delobj(obj)
831 register struct obj *obj;
833 boolean update_map;
835 if (obj->otyp == AMULET_OF_YENDOR
836 || obj->otyp == CANDELABRUM_OF_INVOCATION
837 || obj->otyp == BELL_OF_OPENING
838 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
839 /* player might be doing something stupid, but we
840 * can't guarantee that. assume special artifacts
841 * are indestructible via drawbridges, and exploding
842 * chests, and golem creation, and ...
844 return;
846 update_map = (obj->where == OBJ_FLOOR);
847 obj_extract_self(obj);
848 if (update_map)
849 newsym(obj->ox, obj->oy);
850 obfree(obj, (struct obj *) 0); /* frees contents also */
853 /* try to find a particular type of object at designated map location */
854 struct obj *
855 sobj_at(otyp, x, y)
856 int otyp;
857 int x, y;
859 register struct obj *otmp;
861 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
862 if (otmp->otyp == otyp)
863 break;
865 return otmp;
868 /* sobj_at(&c) traversal -- find next object of specified type */
869 struct obj *
870 nxtobj(obj, type, by_nexthere)
871 struct obj *obj;
872 int type;
873 boolean by_nexthere;
875 register struct obj *otmp;
877 otmp = obj; /* start with the object after this one */
878 do {
879 otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
880 if (!otmp)
881 break;
882 } while (otmp->otyp != type);
884 return otmp;
887 struct obj *
888 carrying(type)
889 register int type;
891 register struct obj *otmp;
893 for (otmp = invent; otmp; otmp = otmp->nobj)
894 if (otmp->otyp == type)
895 return otmp;
896 return (struct obj *) 0;
899 /* Fictional and not-so-fictional currencies.
900 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
902 static const char *const currencies[] = {
903 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
904 "Ankh-Morpork Dollar", /* Discworld */
905 "auric", /* The Domination of Draka */
906 "buckazoid", /* Space Quest */
907 "cirbozoid", /* Starslip */
908 "credit chit", /* Deus Ex */
909 "cubit", /* Battlestar Galactica */
910 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
911 "fretzer", /* Jules Verne */
912 "imperial credit", /* Star Wars */
913 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
914 "kongbuck", /* Snow Crash */
915 "nanite", /* System Shock 2 */
916 "quatloo", /* Star Trek, Sim City */
917 "simoleon", /* Sim City */
918 "solari", /* Spaceballs */
919 "spacebuck", /* Spaceballs */
920 "sporebuck", /* Spore */
921 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
922 "woolong", /* Cowboy Bebop */
923 "zorkmid", /* Zork, NetHack */
926 const char *
927 currency(amount)
928 long amount;
930 const char *res;
932 res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
933 if (amount != 1L)
934 res = makeplural(res);
935 return res;
938 boolean
939 have_lizard()
941 register struct obj *otmp;
943 for (otmp = invent; otmp; otmp = otmp->nobj)
944 if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
945 return TRUE;
946 return FALSE;
949 /* 3.6 tribute */
950 struct obj *
951 u_have_novel()
953 register struct obj *otmp;
955 for (otmp = invent; otmp; otmp = otmp->nobj)
956 if (otmp->otyp == SPE_NOVEL)
957 return otmp;
958 return (struct obj *) 0;
961 struct obj *
962 o_on(id, objchn)
963 unsigned int id;
964 register struct obj *objchn;
966 struct obj *temp;
968 while (objchn) {
969 if (objchn->o_id == id)
970 return objchn;
971 if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
972 return temp;
973 objchn = objchn->nobj;
975 return (struct obj *) 0;
978 boolean
979 obj_here(obj, x, y)
980 register struct obj *obj;
981 int x, y;
983 register struct obj *otmp;
985 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
986 if (obj == otmp)
987 return TRUE;
988 return FALSE;
991 struct obj *
992 g_at(x, y)
993 register int x, y;
995 register struct obj *obj = level.objects[x][y];
997 while (obj) {
998 if (obj->oclass == COIN_CLASS)
999 return obj;
1000 obj = obj->nexthere;
1002 return (struct obj *) 0;
1005 /* compact a string of inventory letters by dashing runs of letters */
1006 STATIC_OVL void
1007 compactify(buf)
1008 register char *buf;
1010 register int i1 = 1, i2 = 1;
1011 register char ilet, ilet1, ilet2;
1013 ilet2 = buf[0];
1014 ilet1 = buf[1];
1015 buf[++i2] = buf[++i1];
1016 ilet = buf[i1];
1017 while (ilet) {
1018 if (ilet == ilet1 + 1) {
1019 if (ilet1 == ilet2 + 1)
1020 buf[i2 - 1] = ilet1 = '-';
1021 else if (ilet2 == '-') {
1022 buf[i2 - 1] = ++ilet1;
1023 buf[i2] = buf[++i1];
1024 ilet = buf[i1];
1025 continue;
1027 } else if (ilet == NOINVSYM) {
1028 /* compact three or more consecutive '#'
1029 characters into "#-#" */
1030 if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
1031 buf[i2 - 1] = '-';
1032 else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
1033 && buf[i2 - 1] == NOINVSYM)
1034 --i2;
1036 ilet2 = ilet1;
1037 ilet1 = ilet;
1038 buf[++i2] = buf[++i1];
1039 ilet = buf[i1];
1043 /* some objects shouldn't be split when count given to getobj or askchain */
1044 boolean
1045 splittable(obj)
1046 struct obj *obj;
1048 return !((obj->otyp == LOADSTONE && obj->cursed)
1049 || (obj == uwep && welded(uwep)));
1052 /* match the prompt for either 'T' or 'R' command */
1053 STATIC_OVL boolean
1054 taking_off(action)
1055 const char *action;
1057 return !strcmp(action, "take off") || !strcmp(action, "remove");
1060 /* match the prompt for either 'W' or 'P' command */
1061 STATIC_OVL boolean
1062 putting_on(action)
1063 const char *action;
1065 return !strcmp(action, "wear") || !strcmp(action, "put on");
1069 * getobj returns:
1070 * struct obj *xxx: object to do something with.
1071 * (struct obj *) 0 error return: no object.
1072 * &zeroobj explicitly no object (as in w-).
1073 !!!! test if gold can be used in unusual ways (eaten etc.)
1074 !!!! may be able to remove "usegold"
1076 struct obj *
1077 getobj(let, word)
1078 register const char *let, *word;
1080 register struct obj *otmp;
1081 register char ilet;
1082 char buf[BUFSZ], qbuf[QBUFSZ];
1083 char lets[BUFSZ], altlets[BUFSZ], *ap;
1084 register int foo = 0;
1085 register char *bp = buf;
1086 xchar allowcnt = 0; /* 0, 1 or 2 */
1087 boolean usegold = FALSE; /* can't use gold because its illegal */
1088 boolean allowall = FALSE;
1089 boolean allownone = FALSE;
1090 boolean useboulder = FALSE;
1091 xchar foox = 0;
1092 long cnt;
1093 boolean cntgiven = FALSE;
1094 long dummymask;
1096 if (*let == ALLOW_COUNT)
1097 let++, allowcnt = 1;
1098 if (*let == COIN_CLASS)
1099 let++, usegold = TRUE;
1101 /* Equivalent of an "ugly check" for gold */
1102 if (usegold && !strcmp(word, "eat")
1103 && (!metallivorous(youmonst.data)
1104 || youmonst.data == &mons[PM_RUST_MONSTER]))
1105 usegold = FALSE;
1107 if (*let == ALL_CLASSES)
1108 let++, allowall = TRUE;
1109 if (*let == ALLOW_NONE)
1110 let++, allownone = TRUE;
1111 /* "ugly check" for reading fortune cookies, part 1.
1112 * The normal 'ugly check' keeps the object on the inventory list.
1113 * We don't want to do that for shirts/cookies, so the check for
1114 * them is handled a bit differently (and also requires that we set
1115 * allowall in the caller).
1117 if (allowall && !strcmp(word, "read"))
1118 allowall = FALSE;
1120 /* another ugly check: show boulders (not statues) */
1121 if (*let == WEAPON_CLASS && !strcmp(word, "throw")
1122 && throws_rocks(youmonst.data))
1123 useboulder = TRUE;
1125 if (allownone)
1126 *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
1127 ap = altlets;
1129 if (!flags.invlet_constant)
1130 reassign();
1131 else
1132 /* in case invent is in packorder, force it to be in invlet
1133 order before collecing candidate inventory letters;
1134 if player responds with '?' or '*' it will be changed
1135 back by display_pickinv(), but by then we'll have 'lets'
1136 and so won't have to re-sort in the for(;;) loop below */
1137 sortloot(&invent, SORTLOOT_INVLET, FALSE);
1139 for (otmp = invent; otmp; otmp = otmp->nobj) {
1140 if (&bp[foo] == &buf[sizeof buf - 1]
1141 || ap == &altlets[sizeof altlets - 1]) {
1142 /* we must have a huge number of NOINVSYM items somehow */
1143 impossible("getobj: inventory overflow");
1144 break;
1147 if (!*let || index(let, otmp->oclass)
1148 || (usegold && otmp->invlet == GOLD_SYM)
1149 || (useboulder && otmp->otyp == BOULDER)) {
1150 register int otyp = otmp->otyp;
1152 bp[foo++] = otmp->invlet;
1153 /* clang-format off */
1154 /* *INDENT-OFF* */
1155 /* ugly check: remove inappropriate things */
1156 if (
1157 (taking_off(word) /* exclude if not worn */
1158 && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1159 || (putting_on(word) /* exclude if already worn */
1160 && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1161 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1162 || (!strcmp(word, "wield")
1163 && (otmp->owornmask & W_WEP))
1164 #endif
1165 || (!strcmp(word, "ready") /* exclude when wielded... */
1166 && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
1167 && otmp->quan == 1L)) /* ...unless more than one */
1168 || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1169 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1171 foo--;
1172 foox++;
1174 /* Second ugly check; unlike the first it won't trigger an
1175 * "else" in "you don't have anything else to ___".
1177 else if (
1178 (putting_on(word)
1179 && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1180 || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1181 && otyp != TOWEL && otyp != LENSES)))
1182 || (!strcmp(word, "wield")
1183 && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1184 || (!strcmp(word, "eat") && !is_edible(otmp))
1185 || (!strcmp(word, "sacrifice")
1186 && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1187 && otyp != FAKE_AMULET_OF_YENDOR))
1188 || (!strcmp(word, "write with")
1189 && (otmp->oclass == TOOL_CLASS
1190 && otyp != MAGIC_MARKER && otyp != TOWEL))
1191 || (!strcmp(word, "tin")
1192 && (otyp != CORPSE || !tinnable(otmp)))
1193 || (!strcmp(word, "rub")
1194 && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1195 && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1196 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1197 || (!strcmp(word, "use or apply")
1198 /* Picks, axes, pole-weapons, bullwhips */
1199 && ((otmp->oclass == WEAPON_CLASS
1200 && !is_pick(otmp) && !is_axe(otmp)
1201 && !is_pole(otmp) && otyp != BULLWHIP)
1202 || (otmp->oclass == POTION_CLASS
1203 /* only applicable potion is oil, and it will only
1204 be offered as a choice when already discovered */
1205 && (otyp != POT_OIL || !otmp->dknown
1206 || !objects[POT_OIL].oc_name_known))
1207 || (otmp->oclass == FOOD_CLASS
1208 && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1209 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1210 || (!strcmp(word, "invoke")
1211 && !otmp->oartifact
1212 && !objects[otyp].oc_unique
1213 && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1214 && otyp != CRYSTAL_BALL /* synonym for apply */
1215 /* note: presenting the possibility of invoking non-artifact
1216 mirrors and/or lamps is simply a cruel deception... */
1217 && otyp != MIRROR
1218 && otyp != MAGIC_LAMP
1219 && (otyp != OIL_LAMP /* don't list known oil lamp */
1220 || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1221 || (!strcmp(word, "untrap with")
1222 && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1223 || (otmp->oclass == POTION_CLASS
1224 /* only applicable potion is oil, and it will only
1225 be offered as a choice when already discovered */
1226 && (otyp != POT_OIL || !otmp->dknown
1227 || !objects[POT_OIL].oc_name_known))))
1228 || (!strcmp(word, "tip") && !Is_container(otmp)
1229 /* include horn of plenty if sufficiently discovered */
1230 && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1231 || !objects[HORN_OF_PLENTY].oc_name_known))
1232 || (!strcmp(word, "charge") && !is_chargeable(otmp))
1233 || (!strcmp(word, "open") && otyp != TIN)
1234 || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1236 foo--;
1238 /* Third ugly check: acceptable but not listed as likely
1239 * candidates in the prompt or in the inventory subset if
1240 * player responds with '?'.
1242 else if (
1243 /* ugly check for unworn armor that can't be worn */
1244 (putting_on(word) && *let == ARMOR_CLASS
1245 && !canwearobj(otmp, &dummymask, FALSE))
1246 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1247 || ((putting_on(word) || taking_off(word))
1248 && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1249 /* or unsuitable items rubbed on known touchstone */
1250 || (!strncmp(word, "rub on the stone", 16)
1251 && *let == GEM_CLASS && otmp->dknown
1252 && objects[otyp].oc_name_known)
1253 /* suppress corpses on astral, amulets elsewhere */
1254 || (!strcmp(word, "sacrifice")
1255 /* (!astral && amulet) || (astral && !amulet) */
1256 && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1257 /* suppress container being stashed into */
1258 || (!strcmp(word, "stash") && !ck_bag(otmp))
1259 /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1260 or accessory (ring) covered by cursed worn armor (gloves) */
1261 || (taking_off(word)
1262 && inaccessible_equipment(otmp, (const char *) 0,
1263 (boolean) (otmp->oclass == RING_CLASS)))
1264 || (!strcmp(word, "write on")
1265 && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
1266 || !otmp->dknown || !objects[otyp].oc_name_known))
1268 /* acceptable but not listed as likely candidate */
1269 foo--;
1270 allowall = TRUE;
1271 *ap++ = otmp->invlet;
1273 /* *INDENT-ON* */
1274 /* clang-format on */
1275 } else {
1276 /* "ugly check" for reading fortune cookies, part 2 */
1277 if ((!strcmp(word, "read") && is_readable(otmp)))
1278 allowall = usegold = TRUE;
1282 bp[foo] = 0;
1283 if (foo == 0 && bp > buf && bp[-1] == ' ')
1284 *--bp = 0;
1285 Strcpy(lets, bp); /* necessary since we destroy buf */
1286 if (foo > 5) /* compactify string */
1287 compactify(bp);
1288 *ap = '\0';
1290 if (!foo && !allowall && !allownone) {
1291 You("don't have anything %sto %s.", foox ? "else " : "", word);
1292 return (struct obj *) 0;
1293 } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
1294 /* we wanted all scrolls and books in altlets[], but that came with
1295 'allowall' which we don't want since it prevents "silly thing"
1296 result if anything other than scroll or spellbook is chosen */
1297 allowall = FALSE;
1299 for (;;) {
1300 cnt = 0;
1301 cntgiven = FALSE;
1302 if (!buf[0]) {
1303 Sprintf(qbuf, "What do you want to %s? [*]", word);
1304 } else {
1305 Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
1307 if (in_doagain)
1308 ilet = readchar();
1309 else
1310 ilet = yn_function(qbuf, (char *) 0, '\0');
1311 if (digit(ilet)) {
1312 long tmpcnt = 0;
1314 if (!allowcnt) {
1315 pline("No count allowed with this command.");
1316 continue;
1318 ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt);
1319 if (tmpcnt) {
1320 cnt = tmpcnt;
1321 cntgiven = TRUE;
1324 if (index(quitchars, ilet)) {
1325 if (flags.verbose)
1326 pline1(Never_mind);
1327 return (struct obj *) 0;
1329 if (ilet == HANDS_SYM) { /* '-' */
1330 if (!allownone) {
1331 char *suf = (char *) 0;
1333 strcpy(buf, word);
1334 if ((bp = strstr(buf, " on the ")) != 0) {
1335 /* rub on the stone[s] */
1336 *bp = '\0';
1337 suf = (bp + 1);
1339 if ((bp = strstr(buf, " or ")) != 0) {
1340 *bp = '\0';
1341 bp = (rn2(2) ? buf : (bp + 4));
1342 } else
1343 bp = buf;
1344 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1345 suf ? suf : "");
1347 return (allownone ? &zeroobj : (struct obj *) 0);
1349 /* since gold is now kept in inventory, we need to do processing for
1350 select-from-invent before checking whether gold has been picked */
1351 if (ilet == '?' || ilet == '*') {
1352 char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1353 long ctmp = 0;
1355 qbuf[0] = '\0';
1356 if (!strcmp(word, "grease"))
1357 Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
1358 else if (!strcmp(word, "write with"))
1359 Sprintf(qbuf, "your %s", body_part(FINGERTIP));
1360 else if (!strcmp(word, "wield"))
1361 Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
1362 makeplural(body_part(HAND)),
1363 !uwep ? " (wielded)" : "");
1364 else if (!strcmp(word, "ready"))
1365 Sprintf(qbuf, "empty quiver%s",
1366 !uquiver ? " (nothing readied)" : "");
1368 if (ilet == '?' && !*lets && *altlets)
1369 allowed_choices = altlets;
1370 ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
1371 TRUE, allowcnt ? &ctmp : (long *) 0);
1372 if (!ilet)
1373 continue;
1374 if (ilet == HANDS_SYM)
1375 return &zeroobj;
1376 if (ilet == '\033') {
1377 if (flags.verbose)
1378 pline1(Never_mind);
1379 return (struct obj *) 0;
1381 if (allowcnt && ctmp >= 0) {
1382 cnt = ctmp;
1383 cntgiven = TRUE;
1385 /* they typed a letter (not a space) at the prompt */
1387 /* find the item which was picked */
1388 for (otmp = invent; otmp; otmp = otmp->nobj)
1389 if (otmp->invlet == ilet)
1390 break;
1391 /* some items have restrictions */
1392 if (ilet == def_oc_syms[COIN_CLASS].sym
1393 /* guard against the [hypothetical] chace of having more
1394 than one invent slot of gold and picking the non-'$' one */
1395 || (otmp && otmp->oclass == COIN_CLASS)) {
1396 if (!usegold) {
1397 You("cannot %s gold.", word);
1398 return (struct obj *) 0;
1400 /* Historic note: early Nethack had a bug which was
1401 * first reported for Larn, where trying to drop 2^32-n
1402 * gold pieces was allowed, and did interesting things
1403 * to your money supply. The LRS is the tax bureau
1404 * from Larn.
1406 if (cntgiven && cnt <= 0) {
1407 if (cnt < 0)
1408 pline_The(
1409 "LRS would be very interested to know you have that much.");
1410 return (struct obj *) 0;
1413 if (cntgiven && !strcmp(word, "throw")) {
1414 /* permit counts for throwing gold, but don't accept
1415 * counts for other things since the throw code will
1416 * split off a single item anyway */
1417 if (cnt == 0)
1418 return (struct obj *) 0;
1419 if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
1420 && !(otmp && otmp->oclass == COIN_CLASS))) {
1421 You("can only throw one item at a time.");
1422 continue;
1425 context.botl = 1; /* May have changed the amount of money */
1426 savech(ilet);
1427 /* [we used to set otmp (by finding ilet in invent) here, but
1428 that's been moved above so that otmp can be checked earlier] */
1429 /* verify the chosen object */
1430 if (!otmp) {
1431 You("don't have that object.");
1432 if (in_doagain)
1433 return (struct obj *) 0;
1434 continue;
1435 } else if (cnt < 0 || otmp->quan < cnt) {
1436 You("don't have that many! You have only %ld.", otmp->quan);
1437 if (in_doagain)
1438 return (struct obj *) 0;
1439 continue;
1441 break;
1443 if (!allowall && let && !index(let, otmp->oclass)
1444 && !(usegold && otmp->oclass == COIN_CLASS)) {
1445 silly_thing(word, otmp);
1446 return (struct obj *) 0;
1448 if (cntgiven) {
1449 if (cnt == 0)
1450 return (struct obj *) 0;
1451 if (cnt != otmp->quan) {
1452 /* don't split a stack of cursed loadstones */
1453 if (splittable(otmp))
1454 otmp = splitobj(otmp, cnt);
1455 else if (otmp->otyp == LOADSTONE && otmp->cursed)
1456 /* kludge for canletgo()'s can't-drop-this message */
1457 otmp->corpsenm = (int) cnt;
1460 return otmp;
1463 void
1464 silly_thing(word, otmp)
1465 const char *word;
1466 struct obj *otmp;
1468 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1469 nhUse(otmp);
1470 #else
1471 const char *s1, *s2, *s3;
1472 int ocls = otmp->oclass, otyp = otmp->otyp;
1474 s1 = s2 = s3 = 0;
1475 /* check for attempted use of accessory commands ('P','R') on armor
1476 and for corresponding armor commands ('W','T') on accessories */
1477 if (ocls == ARMOR_CLASS) {
1478 if (!strcmp(word, "put on"))
1479 s1 = "W", s2 = "wear", s3 = "";
1480 else if (!strcmp(word, "remove"))
1481 s1 = "T", s2 = "take", s3 = " off";
1482 } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1483 || ocls == AMULET_CLASS
1484 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1485 if (!strcmp(word, "wear"))
1486 s1 = "P", s2 = "put", s3 = " on";
1487 else if (!strcmp(word, "take off"))
1488 s1 = "R", s2 = "remove", s3 = "";
1490 if (s1)
1491 pline("Use the '%s' command to %s %s%s.", s1, s2,
1492 !(is_plural(otmp) || pair_of(otmp)) ? "that" : "those", s3);
1493 else
1494 #endif
1495 pline(silly_thing_to, word);
1498 STATIC_PTR int
1499 ckvalidcat(otmp)
1500 struct obj *otmp;
1502 /* use allow_category() from pickup.c */
1503 return (int) allow_category(otmp);
1506 STATIC_PTR int
1507 ckunpaid(otmp)
1508 struct obj *otmp;
1510 return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1513 boolean
1514 wearing_armor()
1516 return (boolean) (uarm || uarmc || uarmf || uarmg
1517 || uarmh || uarms || uarmu);
1520 boolean
1521 is_worn(otmp)
1522 struct obj *otmp;
1524 return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
1525 ? TRUE
1526 : FALSE;
1529 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1530 STATIC_VAR struct xprnctx {
1531 char let;
1532 boolean dot;
1533 } safeq_xprn_ctx;
1535 /* safe_qbuf() -> short_oname() callback */
1536 STATIC_PTR char *
1537 safeq_xprname(obj)
1538 struct obj *obj;
1540 return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1541 0L, 0L);
1544 /* alternate safe_qbuf() -> short_oname() callback */
1545 STATIC_PTR char *
1546 safeq_shortxprname(obj)
1547 struct obj *obj;
1549 return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1550 safeq_xprn_ctx.dot, 0L, 0L);
1553 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1554 RING_CLASS, AMULET_CLASS,
1555 TOOL_CLASS, 0 };
1557 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1558 Return the number of times fn was called successfully.
1559 If combo is TRUE, we just use this to get a category list. */
1561 ggetobj(word, fn, mx, combo, resultflags)
1562 const char *word;
1563 int FDECL((*fn), (OBJ_P)), mx;
1564 boolean combo; /* combination menu flag */
1565 unsigned *resultflags;
1567 int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1568 boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1569 boolean takeoff, ident, allflag, m_seen;
1570 int itemcount;
1571 int oletct, iletct, unpaid, oc_of_sym;
1572 char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
1573 char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1574 char buf[BUFSZ], qbuf[QBUFSZ];
1576 if (!invent) {
1577 You("have nothing to %s.", word);
1578 if (resultflags)
1579 *resultflags = ALL_FINISHED;
1580 return 0;
1582 if (resultflags)
1583 *resultflags = 0;
1584 takeoff = ident = allflag = m_seen = FALSE;
1585 add_valid_menu_class(0); /* reset */
1586 if (taking_off(word)) {
1587 takeoff = TRUE;
1588 ofilter = is_worn;
1589 } else if (!strcmp(word, "identify")) {
1590 ident = TRUE;
1591 ofilter = not_fully_identified;
1594 iletct = collect_obj_classes(ilets, invent, FALSE, ofilter, &itemcount);
1595 unpaid = count_unpaid(invent);
1597 if (ident && !iletct) {
1598 return -1; /* no further identifications */
1599 } else if (!takeoff && (unpaid || invent)) {
1600 ilets[iletct++] = ' ';
1601 if (unpaid)
1602 ilets[iletct++] = 'u';
1603 if (count_buc(invent, BUC_BLESSED))
1604 ilets[iletct++] = 'B';
1605 if (count_buc(invent, BUC_UNCURSED))
1606 ilets[iletct++] = 'U';
1607 if (count_buc(invent, BUC_CURSED))
1608 ilets[iletct++] = 'C';
1609 if (count_buc(invent, BUC_UNKNOWN))
1610 ilets[iletct++] = 'X';
1611 if (invent)
1612 ilets[iletct++] = 'a';
1613 } else if (takeoff && invent) {
1614 ilets[iletct++] = ' ';
1616 ilets[iletct++] = 'i';
1617 if (!combo)
1618 ilets[iletct++] = 'm'; /* allow menu presentation on request */
1619 ilets[iletct] = '\0';
1621 for (;;) {
1622 Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
1623 word, ilets);
1624 getlin(qbuf, buf);
1625 if (buf[0] == '\033')
1626 return 0;
1627 if (index(buf, 'i')) {
1628 char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
1629 struct obj *otmp;
1631 /* applicable inventory letters; if empty, show entire invent */
1632 ailets[0] = '\0';
1633 if (ofilter)
1634 for (otmp = invent; otmp; otmp = otmp->nobj)
1635 /* index() check: limit overflow items to one '#' */
1636 if ((*ofilter)(otmp) && !index(ailets, otmp->invlet))
1637 (void) strkitten(ailets, otmp->invlet);
1638 if (display_inventory(ailets, TRUE) == '\033')
1639 return 0;
1640 } else
1641 break;
1644 extra_removeables[0] = '\0';
1645 if (takeoff) {
1646 /* arbitrary types of items can be placed in the weapon slots
1647 [any duplicate entries in extra_removeables[] won't matter] */
1648 if (uwep)
1649 (void) strkitten(extra_removeables, uwep->oclass);
1650 if (uswapwep)
1651 (void) strkitten(extra_removeables, uswapwep->oclass);
1652 if (uquiver)
1653 (void) strkitten(extra_removeables, uquiver->oclass);
1656 ip = buf;
1657 olets[oletct = 0] = '\0';
1658 while ((sym = *ip++) != '\0') {
1659 if (sym == ' ')
1660 continue;
1661 oc_of_sym = def_char_to_objclass(sym);
1662 if (takeoff && oc_of_sym != MAXOCLASSES) {
1663 if (index(extra_removeables, oc_of_sym)) {
1664 ; /* skip rest of takeoff checks */
1665 } else if (!index(removeables, oc_of_sym)) {
1666 pline("Not applicable.");
1667 return 0;
1668 } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1669 noarmor(FALSE);
1670 return 0;
1671 } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
1672 && !uquiver) {
1673 You("are not wielding anything.");
1674 return 0;
1675 } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1676 You("are not wearing rings.");
1677 return 0;
1678 } else if (oc_of_sym == AMULET_CLASS && !uamul) {
1679 You("are not wearing an amulet.");
1680 return 0;
1681 } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1682 You("are not wearing a blindfold.");
1683 return 0;
1687 if (oc_of_sym == COIN_CLASS && !combo) {
1688 context.botl = 1;
1689 } else if (sym == 'a') {
1690 allflag = TRUE;
1691 } else if (sym == 'A') {
1692 /* same as the default */;
1693 } else if (sym == 'u') {
1694 add_valid_menu_class('u');
1695 ckfn = ckunpaid;
1696 } else if (sym == 'B') {
1697 add_valid_menu_class('B');
1698 ckfn = ckvalidcat;
1699 } else if (sym == 'U') {
1700 add_valid_menu_class('U');
1701 ckfn = ckvalidcat;
1702 } else if (sym == 'C') {
1703 add_valid_menu_class('C');
1704 ckfn = ckvalidcat;
1705 } else if (sym == 'X') {
1706 add_valid_menu_class('X');
1707 ckfn = ckvalidcat;
1708 } else if (sym == 'm') {
1709 m_seen = TRUE;
1710 } else if (oc_of_sym == MAXOCLASSES) {
1711 You("don't have any %c's.", sym);
1712 } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
1713 if (!index(olets, oc_of_sym)) {
1714 add_valid_menu_class(oc_of_sym);
1715 olets[oletct++] = oc_of_sym;
1716 olets[oletct] = 0;
1721 if (m_seen) {
1722 return (allflag
1723 || (!oletct && ckfn != ckunpaid && ckfn != ckvalidcat))
1724 ? -2 : -3;
1725 } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
1726 return 0;
1727 #if 0
1728 /* !!!! test gold dropping */
1729 } else if (allowgold == 2 && !oletct) {
1730 return 1; /* you dropped gold (or at least tried to) */
1731 #endif
1732 } else {
1733 int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1735 * askchain() has already finished the job in this case
1736 * so set a special flag to convey that back to the caller
1737 * so that it won't continue processing.
1738 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1740 if (combo && allflag && resultflags)
1741 *resultflags |= ALL_FINISHED;
1742 return cnt;
1747 * Walk through the chain starting at objchn and ask for all objects
1748 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1749 * whether the action in question (i.e., fn) has to be performed.
1750 * If allflag then no questions are asked. Mx gives the max number
1751 * of objects to be treated. Return the number of objects treated.
1754 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1755 struct obj **objchn;
1756 int allflag, mx;
1757 const char *olets, *word; /* olets is an Obj Class char array */
1758 int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
1760 struct obj *otmp, *otmpo;
1761 register char sym, ilet;
1762 register int cnt = 0, dud = 0, tmp;
1763 boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
1764 char qbuf[QBUFSZ], qpfx[QBUFSZ];
1766 takeoff = taking_off(word);
1767 ident = !strcmp(word, "identify");
1768 take_out = !strcmp(word, "take out");
1769 put_in = !strcmp(word, "put in");
1770 nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
1771 || takeoff || take_out || put_in);
1772 ininv = (*objchn == invent);
1774 /* someday maybe we'll sort by 'olets' too (temporarily replace
1775 flags.packorder and pass SORTLOOT_PACK), but not yet... */
1776 sortloot(objchn, SORTLOOT_INVLET, FALSE);
1778 first = TRUE;
1780 * Interrogate in the object class order specified.
1781 * For example, if a person specifies =/ then first all rings
1782 * will be asked about followed by all wands. -dgk
1784 nextclass:
1785 ilet = 'a' - 1;
1786 if (*objchn && (*objchn)->oclass == COIN_CLASS)
1787 ilet--; /* extra iteration */
1789 * Multiple Drop can change the invent chain while it operates
1790 * (dropping a burning potion of oil while levitating creates
1791 * an explosion which can destroy inventory items), so simple
1792 * list traversal
1793 * for (otmp = *objchn; otmp; otmp = otmp2) {
1794 * otmp2 = otmp->nobj;
1795 * ...
1797 * is inadequate here. Use each object's bypass bit to keep
1798 * track of which list elements have already been processed.
1800 bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
1801 while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
1802 if (ilet == 'z')
1803 ilet = 'A';
1804 else
1805 ilet++;
1806 if (olets && *olets && otmp->oclass != *olets)
1807 continue;
1808 if (takeoff && !is_worn(otmp))
1809 continue;
1810 if (ident && !not_fully_identified(otmp))
1811 continue;
1812 if (ckfn && !(*ckfn)(otmp))
1813 continue;
1814 if (!allflag) {
1815 safeq_xprn_ctx.let = ilet;
1816 safeq_xprn_ctx.dot = !nodot;
1817 *qpfx = '\0';
1818 if (first) {
1819 /* traditional_loot() skips prompting when only one
1820 class of objects is involved, so prefix the first
1821 object being queried here with an explanation why */
1822 if (take_out || put_in)
1823 Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
1824 first = FALSE;
1826 (void) safe_qbuf(qbuf, qpfx, "?", otmp,
1827 ininv ? safeq_xprname : doname,
1828 ininv ? safeq_shortxprname : ansimpleoname,
1829 "item");
1830 sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
1831 : nyNaq(qbuf);
1832 } else
1833 sym = 'y';
1835 otmpo = otmp;
1836 if (sym == '#') {
1837 /* Number was entered; split the object unless it corresponds
1838 to 'none' or 'all'. 2 special cases: cursed loadstones and
1839 welded weapons (eg, multiple daggers) will remain as merged
1840 unit; done to avoid splitting an object that won't be
1841 droppable (even if we're picking up rather than dropping). */
1842 if (!yn_number) {
1843 sym = 'n';
1844 } else {
1845 sym = 'y';
1846 if (yn_number < otmp->quan && splittable(otmp))
1847 otmp = splitobj(otmp, yn_number);
1850 switch (sym) {
1851 case 'a':
1852 allflag = 1;
1853 case 'y':
1854 tmp = (*fn)(otmp);
1855 if (tmp < 0) {
1856 if (container_gone(fn)) {
1857 /* otmp caused magic bag to explode;
1858 both are now gone */
1859 otmp = 0; /* and return */
1860 } else if (otmp && otmp != otmpo) {
1861 /* split occurred, merge again */
1862 (void) merged(&otmpo, &otmp);
1864 goto ret;
1866 cnt += tmp;
1867 if (--mx == 0)
1868 goto ret;
1869 case 'n':
1870 if (nodot)
1871 dud++;
1872 default:
1873 break;
1874 case 'q':
1875 /* special case for seffects() */
1876 if (ident)
1877 cnt = -1;
1878 goto ret;
1881 if (olets && *olets && *++olets)
1882 goto nextclass;
1883 if (!takeoff && (dud || cnt))
1884 pline("That was all.");
1885 else if (!dud && !cnt)
1886 pline("No applicable objects.");
1887 ret:
1888 bypass_objlist(*objchn, FALSE);
1889 return cnt;
1893 * Object identification routines:
1896 /* make an object actually be identified; no display updating */
1897 void
1898 fully_identify_obj(otmp)
1899 struct obj *otmp;
1901 makeknown(otmp->otyp);
1902 if (otmp->oartifact)
1903 discover_artifact((xchar) otmp->oartifact);
1904 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1905 if (Is_container(otmp) || otmp->otyp == STATUE)
1906 otmp->cknown = otmp->lknown = 1;
1907 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1908 learn_egg_type(otmp->corpsenm);
1911 /* ggetobj callback routine; identify an object and give immediate feedback */
1913 identify(otmp)
1914 struct obj *otmp;
1916 fully_identify_obj(otmp);
1917 prinv((char *) 0, otmp, 0L);
1918 return 1;
1921 /* menu of unidentified objects; select and identify up to id_limit of them */
1922 STATIC_OVL void
1923 menu_identify(id_limit)
1924 int id_limit;
1926 menu_item *pick_list;
1927 int n, i, first = 1, tryct = 5;
1928 char buf[BUFSZ];
1929 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1931 while (id_limit) {
1932 Sprintf(buf, "What would you like to identify %s?",
1933 first ? "first" : "next");
1934 n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
1935 | USE_INVLET | INVORDER_SORT),
1936 &pick_list, PICK_ANY, not_fully_identified);
1938 if (n > 0) {
1939 if (n > id_limit)
1940 n = id_limit;
1941 for (i = 0; i < n; i++, id_limit--)
1942 (void) identify(pick_list[i].item.a_obj);
1943 free((genericptr_t) pick_list);
1944 mark_synch(); /* Before we loop to pop open another menu */
1945 first = 0;
1946 } else if (n == -2) { /* player used ESC to quit menu */
1947 break;
1948 } else if (n == -1) { /* no eligible items found */
1949 pline("That was all.");
1950 break;
1951 } else if (!--tryct) { /* stop re-prompting */
1952 pline1(thats_enough_tries);
1953 break;
1954 } else { /* try again */
1955 pline("Choose an item; use ESC to decline.");
1960 /* dialog with user to identify a given number of items; 0 means all */
1961 void
1962 identify_pack(id_limit, learning_id)
1963 int id_limit;
1964 boolean learning_id; /* true if we just read unknown identify scroll */
1966 struct obj *obj, *the_obj;
1967 int n, unid_cnt;
1969 unid_cnt = 0;
1970 the_obj = 0; /* if unid_cnt ends up 1, this will be it */
1971 for (obj = invent; obj; obj = obj->nobj)
1972 if (not_fully_identified(obj))
1973 ++unid_cnt, the_obj = obj;
1975 if (!unid_cnt) {
1976 You("have already identified all %sof your possessions.",
1977 learning_id ? "the rest " : "");
1978 } else if (!id_limit || id_limit >= unid_cnt) {
1979 /* identify everything */
1980 if (unid_cnt == 1) {
1981 (void) identify(the_obj);
1982 } else {
1983 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1985 for (obj = invent; obj; obj = obj->nobj)
1986 if (not_fully_identified(obj))
1987 (void) identify(obj);
1989 } else {
1990 /* identify up to `id_limit' items */
1991 n = 0;
1992 if (flags.menu_style == MENU_TRADITIONAL)
1993 do {
1994 n = ggetobj("identify", identify, id_limit, FALSE,
1995 (unsigned *) 0);
1996 if (n < 0)
1997 break; /* quit or no eligible items */
1998 } while ((id_limit -= n) > 0);
1999 if (n == 0 || n < -1)
2000 menu_identify(id_limit);
2002 update_inventory();
2005 /* called when regaining sight; mark inventory objects which were picked
2006 up while blind as now having been seen */
2007 void
2008 learn_unseen_invent()
2010 struct obj *otmp;
2012 if (Blind)
2013 return; /* sanity check */
2015 for (otmp = invent; otmp; otmp = otmp->nobj) {
2016 if (otmp->dknown)
2017 continue; /* already seen */
2018 /* set dknown, perhaps bknown (for priest[ess]) */
2019 (void) xname(otmp);
2021 * If object->eknown gets implemented (see learnwand(zap.c)),
2022 * handle deferred discovery here.
2025 update_inventory();
2028 /* should of course only be called for things in invent */
2029 STATIC_OVL char
2030 obj_to_let(obj)
2031 struct obj *obj;
2033 if (!flags.invlet_constant) {
2034 obj->invlet = NOINVSYM;
2035 reassign();
2037 return obj->invlet;
2041 * Print the indicated quantity of the given object. If quan == 0L then use
2042 * the current quantity.
2044 void
2045 prinv(prefix, obj, quan)
2046 const char *prefix;
2047 struct obj *obj;
2048 long quan;
2050 if (!prefix)
2051 prefix = "";
2052 pline("%s%s%s", prefix, *prefix ? " " : "",
2053 xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
2056 char *
2057 xprname(obj, txt, let, dot, cost, quan)
2058 struct obj *obj;
2059 const char *txt; /* text to print instead of obj */
2060 char let; /* inventory letter */
2061 boolean dot; /* append period; (dot && cost => Iu) */
2062 long cost; /* cost (for inventory of unpaid or expended items) */
2063 long quan; /* if non-0, print this quantity, not obj->quan */
2065 #ifdef LINT /* handle static char li[BUFSZ]; */
2066 char li[BUFSZ];
2067 #else
2068 static char li[BUFSZ];
2069 #endif
2070 boolean use_invlet = (flags.invlet_constant
2071 && let != CONTAINED_SYM && let != HANDS_SYM);
2072 long savequan = 0;
2074 if (quan && obj) {
2075 savequan = obj->quan;
2076 obj->quan = quan;
2079 * If let is:
2080 * - Then obj == null and 'txt' refers to hands or fingers.
2081 * * Then obj == null and we are printing a total amount.
2082 * > Then the object is contained and doesn't have an inventory letter.
2084 if (cost != 0 || let == '*') {
2085 /* if dot is true, we're doing Iu, otherwise Ix */
2086 Sprintf(li,
2087 iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
2088 : "%c - %-45s %6ld %s",
2089 (dot && use_invlet ? obj->invlet : let),
2090 (txt ? txt : doname(obj)), cost, currency(cost));
2091 } else {
2092 /* ordinary inventory display or pickup message */
2093 Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
2094 (txt ? txt : doname(obj)), (dot ? "." : ""));
2096 if (savequan)
2097 obj->quan = savequan;
2099 return li;
2102 /* the 'i' command */
2104 ddoinv()
2106 (void) display_inventory((char *) 0, FALSE);
2107 return 0;
2111 * find_unpaid()
2113 * Scan the given list of objects. If last_found is NULL, return the first
2114 * unpaid object found. If last_found is not NULL, then skip over unpaid
2115 * objects until last_found is reached, then set last_found to NULL so the
2116 * next unpaid object is returned. This routine recursively follows
2117 * containers.
2119 STATIC_OVL struct obj *
2120 find_unpaid(list, last_found)
2121 struct obj *list, **last_found;
2123 struct obj *obj;
2125 while (list) {
2126 if (list->unpaid) {
2127 if (*last_found) {
2128 /* still looking for previous unpaid object */
2129 if (list == *last_found)
2130 *last_found = (struct obj *) 0;
2131 } else
2132 return ((*last_found = list));
2134 if (Has_contents(list)) {
2135 if ((obj = find_unpaid(list->cobj, last_found)) != 0)
2136 return obj;
2138 list = list->nobj;
2140 return (struct obj *) 0;
2143 /* for perm_invent when operating on a partial inventory display, so that
2144 the persistent one doesn't get shrunk during filtering for item selection
2145 then regrown to full inventory, possibly being resized in the process */
2146 static winid cached_pickinv_win = WIN_ERR;
2148 void
2149 free_pickinv_cache()
2151 if (cached_pickinv_win != WIN_ERR) {
2152 destroy_nhwindow(cached_pickinv_win);
2153 cached_pickinv_win = WIN_ERR;
2158 * Internal function used by display_inventory and getobj that can display
2159 * inventory and return a count as well as a letter. If out_cnt is not null,
2160 * any count returned from the menu selection is placed here.
2162 STATIC_OVL char
2163 display_pickinv(lets, xtra_choice, want_reply, out_cnt)
2164 register const char *lets;
2165 const char *xtra_choice; /* "fingers", pick hands rather than an object */
2166 boolean want_reply;
2167 long *out_cnt;
2169 struct obj *otmp;
2170 char ilet, ret;
2171 char *invlet = flags.inv_order;
2172 int n, classcount;
2173 winid win; /* windows being used */
2174 anything any;
2175 menu_item *selected;
2177 if (lets && !*lets)
2178 lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
2180 if (flags.perm_invent && (lets || xtra_choice)) {
2181 /* partial inventory in perm_invent setting; don't operate on
2182 full inventory window, use an alternate one instead; create
2183 the first time needed and keep it for re-use as needed later */
2184 if (cached_pickinv_win == WIN_ERR)
2185 cached_pickinv_win = create_nhwindow(NHW_MENU);
2186 win = cached_pickinv_win;
2187 } else
2188 win = WIN_INVEN;
2191 * Exit early if no inventory -- but keep going if we are doing
2192 * a permanent inventory update. We need to keep going so the
2193 * permanent inventory window updates itself to remove the last
2194 * item(s) dropped. One down side: the addition of the exception
2195 * for permanent inventory window updates _can_ pop the window
2196 * up when it's not displayed -- even if it's empty -- because we
2197 * don't know at this level if its up or not. This may not be
2198 * an issue if empty checks are done before hand and the call
2199 * to here is short circuited away.
2201 * 2: our count here is only to distinguish between 0 and 1 and
2202 * more than 1; for the last one, we don't need a precise number.
2203 * For perm_invent update we force 'more than 1'.
2205 n = (flags.perm_invent && !lets && !want_reply) ? 2
2206 : lets ? (int) strlen(lets)
2207 : !invent ? 0 : !invent->nobj ? 1 : 2;
2208 /* for xtra_choice, there's another 'item' not included in initial 'n';
2209 for !lets (full invent) and for override_ID (wizard mode identify),
2210 skip message_menu handling of single item even if item count was 1 */
2211 if (xtra_choice || (n == 1 && (!lets || iflags.override_ID)))
2212 ++n;
2214 if (n == 0) {
2215 pline("Not carrying anything.");
2216 return 0;
2219 /* oxymoron? temporarily assign permanent inventory letters */
2220 if (!flags.invlet_constant)
2221 reassign();
2223 if (n == 1) {
2224 /* when only one item of interest, use pline instead of menus;
2225 we actually use a fake message-line menu in order to allow
2226 the user to perform selection at the --More-- prompt for tty */
2227 ret = '\0';
2228 if (xtra_choice) {
2229 /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2230 "nothing" (ready Quiver), or "fingers" (apply grease) */
2231 ret = message_menu(HANDS_SYM, PICK_ONE,
2232 xprname((struct obj *) 0, xtra_choice,
2233 HANDS_SYM, TRUE, 0L, 0L)); /* '-' */
2234 } else {
2235 for (otmp = invent; otmp; otmp = otmp->nobj)
2236 if (!lets || otmp->invlet == lets[0])
2237 break;
2238 if (otmp)
2239 ret = message_menu(otmp->invlet,
2240 want_reply ? PICK_ONE : PICK_NONE,
2241 xprname(otmp, (char *) 0, lets[0],
2242 TRUE, 0L, 0L));
2244 if (out_cnt)
2245 *out_cnt = -1L; /* select all */
2246 return ret;
2249 sortloot(&invent,
2250 (((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET)
2251 | (flags.sortpack ? SORTLOOT_PACK : 0)),
2252 FALSE);
2254 start_menu(win);
2255 any = zeroany;
2256 if (wizard && iflags.override_ID) {
2257 char prompt[QBUFSZ];
2259 any.a_char = -1;
2260 /* wiz_identify stuffed the wiz_identify command character (^I)
2261 into iflags.override_ID for our use as an accelerator */
2262 Sprintf(prompt, "Debug Identify (%s to permanently identify)",
2263 visctrl(iflags.override_ID));
2264 add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
2265 prompt, MENU_UNSELECTED);
2266 } else if (xtra_choice) {
2267 /* wizard override ID and xtra_choice are mutually exclusive */
2268 if (flags.sortpack)
2269 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2270 "Miscellaneous", MENU_UNSELECTED);
2271 any.a_char = HANDS_SYM; /* '-' */
2272 add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
2273 xtra_choice, MENU_UNSELECTED);
2275 nextclass:
2276 classcount = 0;
2277 for (otmp = invent; otmp; otmp = otmp->nobj) {
2278 if (lets && !index(lets, otmp->invlet))
2279 continue;
2280 if (!flags.sortpack || otmp->oclass == *invlet) {
2281 any = zeroany; /* all bits zero */
2282 ilet = otmp->invlet;
2283 if (flags.sortpack && !classcount) {
2284 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2285 let_to_name(*invlet, FALSE,
2286 (want_reply && iflags.menu_head_objsym)),
2287 MENU_UNSELECTED);
2288 classcount++;
2290 any.a_char = ilet;
2291 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2292 doname(otmp), MENU_UNSELECTED);
2295 if (flags.sortpack) {
2296 if (*++invlet)
2297 goto nextclass;
2298 if (--invlet != venom_inv) {
2299 invlet = venom_inv;
2300 goto nextclass;
2303 end_menu(win, (char *) 0);
2305 n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
2306 if (n > 0) {
2307 ret = selected[0].item.a_char;
2308 if (out_cnt)
2309 *out_cnt = selected[0].count;
2310 free((genericptr_t) selected);
2311 } else
2312 ret = !n ? '\0' : '\033'; /* cancelled */
2314 return ret;
2318 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2319 * list all objects with object classes that match the order in lets.
2321 * Returns the letter identifier of a selected item, or 0 if nothing
2322 * was selected.
2324 char
2325 display_inventory(lets, want_reply)
2326 const char *lets;
2327 boolean want_reply;
2329 return display_pickinv(lets, (char *) 0, want_reply, (long *) 0);
2333 * Show what is current using inventory letters.
2336 STATIC_OVL char
2337 display_used_invlets(avoidlet)
2338 char avoidlet;
2340 struct obj *otmp;
2341 char ilet, ret = 0;
2342 char *invlet = flags.inv_order;
2343 int n, classcount, invdone = 0;
2344 winid win;
2345 anything any;
2346 menu_item *selected;
2348 if (invent) {
2349 win = create_nhwindow(NHW_MENU);
2350 start_menu(win);
2351 while (!invdone) {
2352 any = zeroany; /* set all bits to zero */
2353 classcount = 0;
2354 for (otmp = invent; otmp; otmp = otmp->nobj) {
2355 ilet = otmp->invlet;
2356 if (ilet == avoidlet)
2357 continue;
2358 if (!flags.sortpack || otmp->oclass == *invlet) {
2359 if (flags.sortpack && !classcount) {
2360 any = zeroany; /* zero */
2361 add_menu(win, NO_GLYPH, &any, 0, 0,
2362 iflags.menu_headings,
2363 let_to_name(*invlet, FALSE, FALSE),
2364 MENU_UNSELECTED);
2365 classcount++;
2367 any.a_char = ilet;
2368 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2369 doname(otmp), MENU_UNSELECTED);
2372 if (flags.sortpack && *++invlet)
2373 continue;
2374 invdone = 1;
2376 end_menu(win, "Inventory letters used:");
2378 n = select_menu(win, PICK_ONE, &selected);
2379 if (n > 0) {
2380 ret = selected[0].item.a_char;
2381 free((genericptr_t) selected);
2382 } else
2383 ret = !n ? '\0' : '\033'; /* cancelled */
2384 destroy_nhwindow(win);
2386 return ret;
2390 * Returns the number of unpaid items within the given list. This includes
2391 * contained objects.
2394 count_unpaid(list)
2395 struct obj *list;
2397 int count = 0;
2399 while (list) {
2400 if (list->unpaid)
2401 count++;
2402 if (Has_contents(list))
2403 count += count_unpaid(list->cobj);
2404 list = list->nobj;
2406 return count;
2410 * Returns the number of items with b/u/c/unknown within the given list.
2411 * This does NOT include contained objects.
2413 * Assumes that the hero sees or touches or otherwise senses the objects
2414 * at some point: bknown is forced for priest[ess], like in xname().
2417 count_buc(list, type)
2418 struct obj *list;
2419 int type;
2421 int count = 0;
2423 for (; list; list = list->nobj) {
2424 /* coins are "none of the above" as far as BUCX filtering goes */
2425 if (list->oclass == COIN_CLASS)
2426 continue;
2427 /* priests always know bless/curse state */
2428 if (Role_if(PM_PRIEST))
2429 list->bknown = 1;
2431 /* check whether this object matches the requested type */
2432 if (!list->bknown
2433 ? (type == BUC_UNKNOWN)
2434 : list->blessed ? (type == BUC_BLESSED)
2435 : list->cursed ? (type == BUC_CURSED)
2436 : (type == BUC_UNCURSED))
2437 ++count;
2439 return count;
2442 /* similar to count_buc(), but tallies all states at once
2443 rather than looking for a specific type */
2444 STATIC_OVL void
2445 tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
2446 struct obj *list;
2447 int *bcp, *ucp, *ccp, *xcp, *ocp;
2449 *bcp = *ucp = *ccp = *xcp = *ocp = 0;
2450 for (; list; list = list->nobj) {
2451 if (list->oclass == COIN_CLASS) {
2452 ++(*ocp); /* "other" */
2453 continue;
2455 /* priests always know bless/curse state */
2456 if (Role_if(PM_PRIEST))
2457 list->bknown = 1;
2459 if (!list->bknown)
2460 ++(*xcp);
2461 else if (list->blessed)
2462 ++(*bcp);
2463 else if (list->cursed)
2464 ++(*ccp);
2465 else /* neither blessed nor cursed => uncursed */
2466 ++(*ucp);
2470 long
2471 count_contents(container, nested, quantity, everything)
2472 struct obj *container;
2473 boolean nested, /* include contents of any nested containers */
2474 quantity, /* count all vs count separate stacks */
2475 everything; /* all objects vs only unpaid objects */
2477 struct obj *otmp;
2478 long count = 0L;
2480 for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
2481 if (nested && Has_contents(otmp))
2482 count += count_contents(otmp, nested, quantity, everything);
2483 if (everything || otmp->unpaid)
2484 count += quantity ? otmp->quan : 1L;
2486 return count;
2489 STATIC_OVL void
2490 dounpaid()
2492 winid win;
2493 struct obj *otmp, *marker;
2494 register char ilet;
2495 char *invlet = flags.inv_order;
2496 int classcount, count, num_so_far;
2497 long cost, totcost;
2499 count = count_unpaid(invent);
2501 if (count == 1) {
2502 marker = (struct obj *) 0;
2503 otmp = find_unpaid(invent, &marker);
2504 cost = unpaid_cost(otmp, FALSE);
2505 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2506 pline1(xprname(otmp, distant_name(otmp, doname),
2507 carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
2508 cost, 0L));
2509 iflags.suppress_price--;
2510 return;
2513 win = create_nhwindow(NHW_MENU);
2514 cost = totcost = 0;
2515 num_so_far = 0; /* count of # printed so far */
2516 if (!flags.invlet_constant)
2517 reassign();
2519 do {
2520 classcount = 0;
2521 for (otmp = invent; otmp; otmp = otmp->nobj) {
2522 ilet = otmp->invlet;
2523 if (otmp->unpaid) {
2524 if (!flags.sortpack || otmp->oclass == *invlet) {
2525 if (flags.sortpack && !classcount) {
2526 putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
2527 classcount++;
2530 totcost += cost = unpaid_cost(otmp, FALSE);
2531 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2532 putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
2533 ilet, TRUE, cost, 0L));
2534 iflags.suppress_price--;
2535 num_so_far++;
2539 } while (flags.sortpack && (*++invlet));
2541 if (count > num_so_far) {
2542 /* something unpaid is contained */
2543 if (flags.sortpack)
2544 putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
2546 * Search through the container objects in the inventory for
2547 * unpaid items. The top level inventory items have already
2548 * been listed.
2550 for (otmp = invent; otmp; otmp = otmp->nobj) {
2551 if (Has_contents(otmp)) {
2552 long contcost = 0L;
2554 marker = (struct obj *) 0; /* haven't found any */
2555 while (find_unpaid(otmp->cobj, &marker)) {
2556 totcost += cost = unpaid_cost(marker, FALSE);
2557 contcost += cost;
2558 if (otmp->cknown) {
2559 iflags.suppress_price++; /* suppress "(unpaid)" sfx */
2560 putstr(win, 0,
2561 xprname(marker, distant_name(marker, doname),
2562 CONTAINED_SYM, TRUE, cost, 0L));
2563 iflags.suppress_price--;
2566 if (!otmp->cknown) {
2567 char contbuf[BUFSZ];
2569 /* Shopkeeper knows what to charge for contents */
2570 Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
2571 putstr(win, 0,
2572 xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
2573 TRUE, contcost, 0L));
2579 putstr(win, 0, "");
2580 putstr(win, 0,
2581 xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
2582 display_nhwindow(win, FALSE);
2583 destroy_nhwindow(win);
2586 /* query objlist callback: return TRUE if obj type matches "this_type" */
2587 static int this_type;
2589 STATIC_OVL boolean
2590 this_type_only(obj)
2591 struct obj *obj;
2593 boolean res = (obj->oclass == this_type);
2595 if (obj->oclass != COIN_CLASS) {
2596 switch (this_type) {
2597 case 'B':
2598 res = (obj->bknown && obj->blessed);
2599 break;
2600 case 'U':
2601 res = (obj->bknown && !(obj->blessed || obj->cursed));
2602 break;
2603 case 'C':
2604 res = (obj->bknown && obj->cursed);
2605 break;
2606 case 'X':
2607 res = !obj->bknown;
2608 break;
2609 default:
2610 break; /* use 'res' as-is */
2613 return res;
2616 /* the 'I' command */
2618 dotypeinv()
2620 char c = '\0';
2621 int n, i = 0;
2622 char *extra_types, types[BUFSZ];
2623 int class_count, oclass, unpaid_count, itemcount;
2624 int bcnt, ccnt, ucnt, xcnt, ocnt;
2625 boolean billx = *u.ushops && doinvbill(0);
2626 menu_item *pick_list;
2627 boolean traditional = TRUE;
2628 const char *prompt = "What type of object do you want an inventory of?";
2630 if (!invent && !billx) {
2631 You("aren't carrying anything.");
2632 return 0;
2634 unpaid_count = count_unpaid(invent);
2635 tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
2637 if (flags.menu_style != MENU_TRADITIONAL) {
2638 if (flags.menu_style == MENU_FULL
2639 || flags.menu_style == MENU_PARTIAL) {
2640 traditional = FALSE;
2641 i = UNPAID_TYPES;
2642 if (billx)
2643 i |= BILLED_TYPES;
2644 if (bcnt)
2645 i |= BUC_BLESSED;
2646 if (ucnt)
2647 i |= BUC_UNCURSED;
2648 if (ccnt)
2649 i |= BUC_CURSED;
2650 if (xcnt)
2651 i |= BUC_UNKNOWN;
2652 n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2653 if (!n)
2654 return 0;
2655 this_type = c = pick_list[0].item.a_int;
2656 free((genericptr_t) pick_list);
2659 if (traditional) {
2660 /* collect a list of classes of objects carried, for use as a prompt
2662 types[0] = 0;
2663 class_count =
2664 collect_obj_classes(types, invent, FALSE,
2665 (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
2666 if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
2667 types[class_count++] = ' ';
2668 if (unpaid_count)
2669 types[class_count++] = 'u';
2670 if (billx)
2671 types[class_count++] = 'x';
2672 if (bcnt)
2673 types[class_count++] = 'B';
2674 if (ucnt)
2675 types[class_count++] = 'U';
2676 if (ccnt)
2677 types[class_count++] = 'C';
2678 if (xcnt)
2679 types[class_count++] = 'X';
2680 types[class_count] = '\0';
2681 /* add everything not already included; user won't see these */
2682 extra_types = eos(types);
2683 *extra_types++ = '\033';
2684 if (!unpaid_count)
2685 *extra_types++ = 'u';
2686 if (!billx)
2687 *extra_types++ = 'x';
2688 if (!bcnt)
2689 *extra_types++ = 'B';
2690 if (!ucnt)
2691 *extra_types++ = 'U';
2692 if (!ccnt)
2693 *extra_types++ = 'C';
2694 if (!xcnt)
2695 *extra_types++ = 'X';
2696 *extra_types = '\0'; /* for index() */
2697 for (i = 0; i < MAXOCLASSES; i++)
2698 if (!index(types, def_oc_syms[i].sym)) {
2699 *extra_types++ = def_oc_syms[i].sym;
2700 *extra_types = '\0';
2703 if (class_count > 1) {
2704 c = yn_function(prompt, types, '\0');
2705 savech(c);
2706 if (c == '\0') {
2707 clear_nhwindow(WIN_MESSAGE);
2708 return 0;
2710 } else {
2711 /* only one thing to itemize */
2712 if (unpaid_count)
2713 c = 'u';
2714 else if (billx)
2715 c = 'x';
2716 else
2717 c = types[0];
2720 if (c == 'x' || (c == 'X' && billx && !xcnt)) {
2721 if (billx)
2722 (void) doinvbill(1);
2723 else
2724 pline("No used-up objects%s.",
2725 unpaid_count ? " on your shopping bill" : "");
2726 return 0;
2728 if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
2729 if (unpaid_count)
2730 dounpaid();
2731 else
2732 You("are not carrying any unpaid objects.");
2733 return 0;
2735 if (traditional) {
2736 if (index("BUCX", c))
2737 oclass = c; /* not a class but understood by this_type_only() */
2738 else
2739 oclass = def_char_to_objclass(c); /* change to object class */
2741 if (oclass == COIN_CLASS)
2742 return doprgold();
2743 if (index(types, c) > index(types, '\033')) {
2744 /* '> ESC' => hidden choice, something known not to be carried */
2745 const char *which = 0;
2747 switch (c) {
2748 case 'B':
2749 which = "known to be blessed";
2750 break;
2751 case 'U':
2752 which = "known to be uncursed";
2753 break;
2754 case 'C':
2755 which = "known to be cursed";
2756 break;
2757 case 'X':
2758 You(
2759 "have no objects whose blessed/uncursed/cursed status is unknown.");
2760 break; /* better phrasing is desirable */
2761 default:
2762 which = "such";
2763 break;
2765 if (which)
2766 You("have no %s objects.", which);
2767 return 0;
2769 this_type = oclass;
2771 if (query_objlist((char *) 0, &invent,
2772 ((flags.invlet_constant ? USE_INVLET : 0)
2773 | INVORDER_SORT),
2774 &pick_list, PICK_NONE, this_type_only) > 0)
2775 free((genericptr_t) pick_list);
2776 return 0;
2779 /* return a string describing the dungeon feature at <x,y> if there
2780 is one worth mentioning at that location; otherwise null */
2781 const char *
2782 dfeature_at(x, y, buf)
2783 int x, y;
2784 char *buf;
2786 struct rm *lev = &levl[x][y];
2787 int ltyp = lev->typ, cmap = -1;
2788 const char *dfeature = 0;
2789 static char altbuf[BUFSZ];
2791 if (IS_DOOR(ltyp)) {
2792 switch (lev->doormask) {
2793 case D_NODOOR:
2794 cmap = S_ndoor;
2795 break; /* "doorway" */
2796 case D_ISOPEN:
2797 cmap = S_vodoor;
2798 break; /* "open door" */
2799 case D_BROKEN:
2800 dfeature = "broken door";
2801 break;
2802 default:
2803 cmap = S_vcdoor;
2804 break; /* "closed door" */
2806 /* override door description for open drawbridge */
2807 if (is_drawbridge_wall(x, y) >= 0)
2808 dfeature = "open drawbridge portcullis", cmap = -1;
2809 } else if (IS_FOUNTAIN(ltyp))
2810 cmap = S_fountain; /* "fountain" */
2811 else if (IS_THRONE(ltyp))
2812 cmap = S_throne; /* "opulent throne" */
2813 else if (is_lava(x, y))
2814 cmap = S_lava; /* "molten lava" */
2815 else if (is_ice(x, y))
2816 cmap = S_ice; /* "ice" */
2817 else if (is_pool(x, y))
2818 dfeature = "pool of water";
2819 else if (IS_SINK(ltyp))
2820 cmap = S_sink; /* "sink" */
2821 else if (IS_ALTAR(ltyp)) {
2822 Sprintf(altbuf, "%saltar to %s (%s)",
2823 ((lev->altarmask & AM_SHRINE)
2824 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
2825 ? "high "
2826 : "",
2827 a_gname(),
2828 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2829 dfeature = altbuf;
2830 } else if ((x == xupstair && y == yupstair)
2831 || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2832 cmap = S_upstair; /* "staircase up" */
2833 else if ((x == xdnstair && y == ydnstair)
2834 || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2835 cmap = S_dnstair; /* "staircase down" */
2836 else if (x == xupladder && y == yupladder)
2837 cmap = S_upladder; /* "ladder up" */
2838 else if (x == xdnladder && y == ydnladder)
2839 cmap = S_dnladder; /* "ladder down" */
2840 else if (ltyp == DRAWBRIDGE_DOWN)
2841 cmap = S_vodbridge; /* "lowered drawbridge" */
2842 else if (ltyp == DBWALL)
2843 cmap = S_vcdbridge; /* "raised drawbridge" */
2844 else if (IS_GRAVE(ltyp))
2845 cmap = S_grave; /* "grave" */
2846 else if (ltyp == TREE)
2847 cmap = S_tree; /* "tree" */
2848 else if (ltyp == IRONBARS)
2849 dfeature = "set of iron bars";
2851 if (cmap >= 0)
2852 dfeature = defsyms[cmap].explanation;
2853 if (dfeature)
2854 Strcpy(buf, dfeature);
2855 return dfeature;
2858 /* look at what is here; if there are many objects (pile_limit or more),
2859 don't show them unless obj_cnt is 0 */
2861 look_here(obj_cnt, picked_some)
2862 int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
2863 boolean picked_some;
2865 struct obj *otmp;
2866 struct trap *trap;
2867 const char *verb = Blind ? "feel" : "see";
2868 const char *dfeature = (char *) 0;
2869 char fbuf[BUFSZ], fbuf2[BUFSZ];
2870 winid tmpwin;
2871 boolean skip_objects, felt_cockatrice = FALSE;
2873 /* default pile_limit is 5; a value of 0 means "never skip"
2874 (and 1 effectively forces "always skip") */
2875 skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
2876 if (u.uswallow && u.ustuck) {
2877 struct monst *mtmp = u.ustuck;
2879 Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
2880 mbodypart(mtmp, STOMACH));
2881 /* Skip "Contents of " by using fbuf index 12 */
2882 You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
2883 verb, &fbuf[12]);
2884 otmp = mtmp->minvent;
2885 if (otmp) {
2886 for (; otmp; otmp = otmp->nobj) {
2887 /* If swallower is an animal, it should have become stone
2888 * but... */
2889 if (otmp->otyp == CORPSE)
2890 feel_cockatrice(otmp, FALSE);
2892 if (Blind)
2893 Strcpy(fbuf, "You feel");
2894 Strcat(fbuf, ":");
2895 (void) display_minventory(mtmp, MINV_ALL | PICK_NONE, fbuf);
2896 } else {
2897 You("%s no objects here.", verb);
2899 return !!Blind;
2901 if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
2902 There("is %s here.",
2903 an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2905 otmp = level.objects[u.ux][u.uy];
2906 dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2907 if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2908 dfeature = 0;
2910 if (Blind) {
2911 boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2913 if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2914 /* don't say "altar" twice, dfeature has more info */
2915 You("try to feel what is here.");
2916 } else {
2917 const char *where = (Blind && !can_reach_floor(TRUE))
2918 ? "lying beneath you"
2919 : "lying here on the ",
2920 *onwhat = (Blind && !can_reach_floor(TRUE))
2921 ? ""
2922 : surface(u.ux, u.uy);
2924 You("try to feel what is %s%s.", drift ? "floating here" : where,
2925 drift ? "" : onwhat);
2927 if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
2928 dfeature = 0; /* ice already identified */
2929 if (!can_reach_floor(TRUE)) {
2930 pline("But you can't reach it!");
2931 return 0;
2935 if (dfeature)
2936 Sprintf(fbuf, "There is %s here.", an(dfeature));
2938 if (!otmp || is_lava(u.ux, u.uy)
2939 || (is_pool(u.ux, u.uy) && !Underwater)) {
2940 if (dfeature)
2941 pline1(fbuf);
2942 read_engr_at(u.ux, u.uy); /* Eric Backus */
2943 if (!skip_objects && (Blind || !dfeature))
2944 You("%s no objects here.", verb);
2945 return !!Blind;
2947 /* we know there is something here */
2949 if (skip_objects) {
2950 if (dfeature)
2951 pline1(fbuf);
2952 read_engr_at(u.ux, u.uy); /* Eric Backus */
2953 if (obj_cnt == 1 && otmp->quan == 1L)
2954 There("is %s object here.", picked_some ? "another" : "an");
2955 else
2956 There("are %s%s objects here.",
2957 (obj_cnt < 5)
2958 ? "a few"
2959 : (obj_cnt < 10)
2960 ? "several"
2961 : "many",
2962 picked_some ? " more" : "");
2963 for (; otmp; otmp = otmp->nexthere)
2964 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2965 pline("%s %s%s.",
2966 (obj_cnt > 1)
2967 ? "Including"
2968 : (otmp->quan > 1L)
2969 ? "They're"
2970 : "It's",
2971 corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
2972 poly_when_stoned(youmonst.data)
2973 ? ""
2974 : ", unfortunately");
2975 feel_cockatrice(otmp, FALSE);
2976 break;
2978 } else if (!otmp->nexthere) {
2979 /* only one object */
2980 if (dfeature)
2981 pline1(fbuf);
2982 read_engr_at(u.ux, u.uy); /* Eric Backus */
2983 You("%s here %s.", verb, doname_with_price(otmp));
2984 iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
2985 if (otmp->otyp == CORPSE)
2986 feel_cockatrice(otmp, FALSE);
2987 } else {
2988 char buf[BUFSZ];
2990 display_nhwindow(WIN_MESSAGE, FALSE);
2991 tmpwin = create_nhwindow(NHW_MENU);
2992 if (dfeature) {
2993 putstr(tmpwin, 0, fbuf);
2994 putstr(tmpwin, 0, "");
2996 Sprintf(buf, "%s that %s here:",
2997 picked_some ? "Other things" : "Things",
2998 Blind ? "you feel" : "are");
2999 putstr(tmpwin, 0, buf);
3000 for (; otmp; otmp = otmp->nexthere) {
3001 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
3002 felt_cockatrice = TRUE;
3003 Sprintf(buf, "%s...", doname(otmp));
3004 putstr(tmpwin, 0, buf);
3005 break;
3007 putstr(tmpwin, 0, doname_with_price(otmp));
3009 display_nhwindow(tmpwin, TRUE);
3010 destroy_nhwindow(tmpwin);
3011 if (felt_cockatrice)
3012 feel_cockatrice(otmp, FALSE);
3013 read_engr_at(u.ux, u.uy); /* Eric Backus */
3015 return !!Blind;
3018 /* the ':' command - explicitly look at what is here, including all objects */
3020 dolook()
3022 int res;
3024 /* don't let
3025 MSGTYPE={norep,noshow} "You see here"
3026 interfere with feedback from the look-here command */
3027 hide_unhide_msgtypes(TRUE, MSGTYP_MASK_REP_SHOW);
3028 res = look_here(0, FALSE);
3029 /* restore normal msgtype handling */
3030 hide_unhide_msgtypes(FALSE, MSGTYP_MASK_REP_SHOW);
3031 return res;
3034 boolean
3035 will_feel_cockatrice(otmp, force_touch)
3036 struct obj *otmp;
3037 boolean force_touch;
3039 if ((Blind || force_touch) && !uarmg && !Stone_resistance
3040 && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
3041 return TRUE;
3042 return FALSE;
3045 void
3046 feel_cockatrice(otmp, force_touch)
3047 struct obj *otmp;
3048 boolean force_touch;
3050 char kbuf[BUFSZ];
3052 if (will_feel_cockatrice(otmp, force_touch)) {
3053 /* "the <cockatrice> corpse" */
3054 Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
3056 if (poly_when_stoned(youmonst.data))
3057 You("touched %s with your bare %s.", kbuf,
3058 makeplural(body_part(HAND)));
3059 else
3060 pline("Touching %s is a fatal mistake...", kbuf);
3061 /* normalize body shape here; hand, not body_part(HAND) */
3062 Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
3063 /* will call polymon() for the poly_when_stoned() case */
3064 instapetrify(kbuf);
3068 void
3069 stackobj(obj)
3070 struct obj *obj;
3072 struct obj *otmp;
3074 for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
3075 if (otmp != obj && merged(&obj, &otmp))
3076 break;
3077 return;
3080 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3081 boolean
3082 mergable(otmp, obj)
3083 register struct obj *otmp, *obj;
3085 int objnamelth = 0, otmpnamelth = 0;
3087 if (obj == otmp)
3088 return FALSE; /* already the same object */
3089 if (obj->otyp != otmp->otyp)
3090 return FALSE; /* different types */
3091 if (obj->nomerge) /* explicitly marked to prevent merge */
3092 return FALSE;
3094 /* coins of the same kind will always merge */
3095 if (obj->oclass == COIN_CLASS)
3096 return TRUE;
3098 if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
3099 || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
3100 || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
3101 || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
3102 || obj->bypass != otmp->bypass)
3103 return FALSE;
3105 if (obj->globby)
3106 return TRUE;
3107 /* Checks beyond this point either aren't applicable to globs
3108 * or don't inhibit their merger.
3111 if (obj->oclass == FOOD_CLASS
3112 && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
3113 return FALSE;
3115 if (obj->dknown != otmp->dknown
3116 || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
3117 || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
3118 || obj->greased != otmp->greased)
3119 return FALSE;
3121 if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
3122 && (obj->oerodeproof != otmp->oerodeproof
3123 || obj->rknown != otmp->rknown))
3124 return FALSE;
3126 if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
3127 if (obj->corpsenm != otmp->corpsenm)
3128 return FALSE;
3131 /* hatching eggs don't merge; ditto for revivable corpses */
3132 if ((obj->otyp == EGG && (obj->timed || otmp->timed))
3133 || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
3134 && is_reviver(&mons[otmp->corpsenm])))
3135 return FALSE;
3137 /* allow candle merging only if their ages are close */
3138 /* see begin_burn() for a reference for the magic "25" */
3139 if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
3140 return FALSE;
3142 /* burning potions of oil never merge */
3143 if (obj->otyp == POT_OIL && obj->lamplit)
3144 return FALSE;
3146 /* don't merge surcharged item with base-cost item */
3147 if (obj->unpaid && !same_price(obj, otmp))
3148 return FALSE;
3150 /* if they have names, make sure they're the same */
3151 objnamelth = strlen(safe_oname(obj));
3152 otmpnamelth = strlen(safe_oname(otmp));
3153 if ((objnamelth != otmpnamelth
3154 && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
3155 || (objnamelth && otmpnamelth
3156 && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
3157 return FALSE;
3159 /* for the moment, any additional information is incompatible */
3160 if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
3161 || has_omid(otmp) || has_olong(otmp))
3162 return FALSE;
3164 if (obj->oartifact != otmp->oartifact)
3165 return FALSE;
3167 if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
3168 return (boolean) objects[obj->otyp].oc_merge;
3169 } else
3170 return FALSE;
3173 /* the '$' command */
3175 doprgold()
3177 /* the messages used to refer to "carrying gold", but that didn't
3178 take containers into account */
3179 long umoney = money_cnt(invent);
3180 if (!umoney)
3181 Your("wallet is empty.");
3182 else
3183 Your("wallet contains %ld %s.", umoney, currency(umoney));
3184 shopper_financial_report();
3185 return 0;
3188 /* the ')' command */
3190 doprwep()
3192 if (!uwep) {
3193 You("are empty %s.", body_part(HANDED));
3194 } else {
3195 prinv((char *) 0, uwep, 0L);
3196 if (u.twoweap)
3197 prinv((char *) 0, uswapwep, 0L);
3199 return 0;
3202 /* caller is responsible for checking !wearing_armor() */
3203 STATIC_OVL void
3204 noarmor(report_uskin)
3205 boolean report_uskin;
3207 if (!uskin || !report_uskin) {
3208 You("are not wearing any armor.");
3209 } else {
3210 char *p, *uskinname, buf[BUFSZ];
3212 uskinname = strcpy(buf, simpleonames(uskin));
3213 /* shorten "set of <color> dragon scales" to "<color> scales"
3214 and "<color> dragon scale mail" to "<color> scale mail" */
3215 if (!strncmpi(uskinname, "set of ", 7))
3216 uskinname += 7;
3217 if ((p = strstri(uskinname, " dragon ")) != 0)
3218 while ((p[1] = p[8]) != '\0')
3219 ++p;
3221 You("are not wearing armor but have %s embedded in your skin.",
3222 uskinname);
3226 /* the '[' command */
3228 doprarm()
3230 char lets[8];
3231 register int ct = 0;
3233 * Note: players sometimes get here by pressing a function key which
3234 * transmits ''ESC [ <something>'' rather than by pressing '[';
3235 * there's nothing we can--or should-do about that here.
3238 if (!wearing_armor()) {
3239 noarmor(TRUE);
3240 } else {
3241 if (uarmu)
3242 lets[ct++] = obj_to_let(uarmu);
3243 if (uarm)
3244 lets[ct++] = obj_to_let(uarm);
3245 if (uarmc)
3246 lets[ct++] = obj_to_let(uarmc);
3247 if (uarmh)
3248 lets[ct++] = obj_to_let(uarmh);
3249 if (uarms)
3250 lets[ct++] = obj_to_let(uarms);
3251 if (uarmg)
3252 lets[ct++] = obj_to_let(uarmg);
3253 if (uarmf)
3254 lets[ct++] = obj_to_let(uarmf);
3255 lets[ct] = 0;
3256 (void) display_inventory(lets, FALSE);
3258 return 0;
3261 /* the '=' command */
3263 doprring()
3265 if (!uleft && !uright)
3266 You("are not wearing any rings.");
3267 else {
3268 char lets[3];
3269 register int ct = 0;
3271 if (uleft)
3272 lets[ct++] = obj_to_let(uleft);
3273 if (uright)
3274 lets[ct++] = obj_to_let(uright);
3275 lets[ct] = 0;
3276 (void) display_inventory(lets, FALSE);
3278 return 0;
3281 /* the '"' command */
3283 dopramulet()
3285 if (!uamul)
3286 You("are not wearing an amulet.");
3287 else
3288 prinv((char *) 0, uamul, 0L);
3289 return 0;
3292 STATIC_OVL boolean
3293 tool_in_use(obj)
3294 struct obj *obj;
3296 if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
3297 return TRUE;
3298 if (obj->oclass != TOOL_CLASS)
3299 return FALSE;
3300 return (boolean) (obj == uwep || obj->lamplit
3301 || (obj->otyp == LEASH && obj->leashmon));
3304 /* the '(' command */
3306 doprtool()
3308 struct obj *otmp;
3309 int ct = 0;
3310 char lets[52 + 1];
3312 for (otmp = invent; otmp; otmp = otmp->nobj)
3313 if (tool_in_use(otmp))
3314 lets[ct++] = obj_to_let(otmp);
3315 lets[ct] = '\0';
3316 if (!ct)
3317 You("are not using any tools.");
3318 else
3319 (void) display_inventory(lets, FALSE);
3320 return 0;
3323 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3324 show inventory of all currently wielded, worn, or used objects */
3326 doprinuse()
3328 struct obj *otmp;
3329 int ct = 0;
3330 char lets[52 + 1];
3332 for (otmp = invent; otmp; otmp = otmp->nobj)
3333 if (is_worn(otmp) || tool_in_use(otmp))
3334 lets[ct++] = obj_to_let(otmp);
3335 lets[ct] = '\0';
3336 if (!ct)
3337 You("are not wearing or wielding anything.");
3338 else
3339 (void) display_inventory(lets, FALSE);
3340 return 0;
3344 * uses up an object that's on the floor, charging for it as necessary
3346 void
3347 useupf(obj, numused)
3348 register struct obj *obj;
3349 long numused;
3351 register struct obj *otmp;
3352 boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
3354 /* burn_floor_objects() keeps an object pointer that it tries to
3355 * useupf() multiple times, so obj must survive if plural */
3356 if (obj->quan > numused)
3357 otmp = splitobj(obj, numused);
3358 else
3359 otmp = obj;
3360 if (costly_spot(otmp->ox, otmp->oy)) {
3361 if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
3362 addtobill(otmp, FALSE, FALSE, FALSE);
3363 else
3364 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
3366 delobj(otmp);
3367 if (at_u && u.uundetected && hides_under(youmonst.data))
3368 (void) hideunder(&youmonst);
3372 * Conversion from a class to a string for printing.
3373 * This must match the object class order.
3375 STATIC_VAR NEARDATA const char *names[] = {
3376 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3377 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3378 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3381 static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
3383 static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
3385 static NEARDATA char *invbuf = (char *) 0;
3386 static NEARDATA unsigned invbufsiz = 0;
3388 char *
3389 let_to_name(let, unpaid, showsym)
3390 char let;
3391 boolean unpaid, showsym;
3393 const char *ocsymfmt = " ('%c')";
3394 const int invbuf_sympadding = 8; /* arbitrary */
3395 const char *class_name;
3396 const char *pos;
3397 int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
3398 unsigned len;
3400 if (oclass)
3401 class_name = names[oclass];
3402 else if ((pos = index(oth_symbols, let)) != 0)
3403 class_name = oth_names[pos - oth_symbols];
3404 else
3405 class_name = names[0];
3407 len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
3408 + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
3409 if (len > invbufsiz) {
3410 if (invbuf)
3411 free((genericptr_t) invbuf);
3412 invbufsiz = len + 10; /* add slop to reduce incremental realloc */
3413 invbuf = (char *) alloc(invbufsiz);
3415 if (unpaid)
3416 Strcat(strcpy(invbuf, "Unpaid "), class_name);
3417 else
3418 Strcpy(invbuf, class_name);
3419 if ((oclass != 0) && showsym) {
3420 char *bp = eos(invbuf);
3421 int mlen = invbuf_sympadding - strlen(class_name);
3422 while (--mlen > 0) {
3423 *bp = ' ';
3424 bp++;
3426 *bp = '\0';
3427 Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
3429 return invbuf;
3432 /* release the static buffer used by let_to_name() */
3433 void
3434 free_invbuf()
3436 if (invbuf)
3437 free((genericptr_t) invbuf), invbuf = (char *) 0;
3438 invbufsiz = 0;
3441 /* give consecutive letters to every item in inventory (for !fixinv mode);
3442 gold is always forced to '$' slot at head of list */
3443 void
3444 reassign()
3446 int i;
3447 struct obj *obj, *prevobj, *goldobj;
3449 /* first, remove [first instance of] gold from invent, if present */
3450 prevobj = goldobj = 0;
3451 for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
3452 if (obj->oclass == COIN_CLASS) {
3453 goldobj = obj;
3454 if (prevobj)
3455 prevobj->nobj = goldobj->nobj;
3456 else
3457 invent = goldobj->nobj;
3458 break;
3460 /* second, re-letter the rest of the list */
3461 for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
3462 obj->invlet =
3463 (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
3464 /* third, assign gold the "letter" '$' and re-insert it at head */
3465 if (goldobj) {
3466 goldobj->invlet = GOLD_SYM;
3467 goldobj->nobj = invent;
3468 invent = goldobj;
3470 if (i >= 52)
3471 i = 52 - 1;
3472 lastinvnr = i;
3475 /* #adjust command
3477 * User specifies a 'from' slot for inventory stack to move,
3478 * then a 'to' slot for its destination. Open slots and those
3479 * filled by compatible stacks are listed as likely candidates
3480 * but user can pick any inventory letter (including 'from').
3481 * All compatible items found are gathered into the 'from'
3482 * stack as it is moved. If the 'to' slot isn't empty and
3483 * doesn't merge, then its stack is swapped to the 'from' slot.
3485 * If the user specifies a count when choosing the 'from' slot,
3486 * and that count is less than the full size of the stack,
3487 * then the stack will be split. The 'count' portion is moved
3488 * to the destination, and the only candidate for merging with
3489 * it is the stack already at the 'to' slot, if any. When the
3490 * destination is non-empty but won't merge, whatever is there
3491 * will be moved to an open slot; if there isn't any open slot
3492 * available, the adjustment attempt fails.
3494 * Splitting has one special case: if 'to' slot is non-empty
3495 * and is compatible with 'from' in all respects except for
3496 * user-assigned names, the 'count' portion being moved is
3497 * effectively renamed so that it will merge with 'to' stack.
3500 doorganize() /* inventory organizer by Del Lamb */
3502 struct obj *obj, *otmp, *splitting, *bumped;
3503 int ix, cur, trycnt;
3504 char let;
3505 char alphabet[52 + 1], buf[52 + 1];
3506 char qbuf[QBUFSZ];
3507 char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3508 const char *adj_type;
3510 if (!invent) {
3511 You("aren't carrying anything to adjust.");
3512 return 0;
3515 if (!flags.invlet_constant)
3516 reassign();
3517 /* get object the user wants to organize (the 'from' slot) */
3518 allowall[0] = ALLOW_COUNT;
3519 allowall[1] = ALL_CLASSES;
3520 allowall[2] = '\0';
3521 if (!(obj = getobj(allowall, "adjust")))
3522 return 0;
3524 /* figure out whether user gave a split count to getobj() */
3525 splitting = bumped = 0;
3526 for (otmp = invent; otmp; otmp = otmp->nobj)
3527 if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
3528 if (otmp->invlet == obj->invlet)
3529 splitting = otmp;
3530 break;
3533 /* initialize the list with all lower and upper case letters */
3534 for (ix = 0, let = 'a'; let <= 'z';)
3535 alphabet[ix++] = let++;
3536 for (let = 'A'; let <= 'Z';)
3537 alphabet[ix++] = let++;
3538 alphabet[ix] = '\0';
3539 /* for floating inv letters, truncate list after the first open slot */
3540 if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
3541 alphabet[ix + (splitting ? 0 : 1)] = '\0';
3543 /* blank out all the letters currently in use in the inventory */
3544 /* except those that will be merged with the selected object */
3545 for (otmp = invent; otmp; otmp = otmp->nobj)
3546 if (otmp != obj && !mergable(otmp, obj)) {
3547 let = otmp->invlet;
3548 if (let >= 'a' && let <= 'z')
3549 alphabet[let - 'a'] = ' ';
3550 else if (let >= 'A' && let <= 'Z')
3551 alphabet[let - 'A' + 26] = ' ';
3554 /* compact the list by removing all the blanks */
3555 for (ix = cur = 0; alphabet[ix]; ix++)
3556 if (alphabet[ix] != ' ')
3557 buf[cur++] = alphabet[ix];
3558 if (!cur && obj->invlet == NOINVSYM)
3559 buf[cur++] = NOINVSYM;
3560 buf[cur] = '\0';
3561 /* and by dashing runs of letters */
3562 if (cur > 5)
3563 compactify(buf);
3565 /* get 'to' slot to use as destination */
3566 Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
3567 invent ? " (? see used letters)" : "");
3568 for (trycnt = 1; ; ++trycnt) {
3569 let = yn_function(qbuf, (char *) 0, '\0');
3570 if (let == '?' || let == '*') {
3571 let = display_used_invlets(splitting ? obj->invlet : 0);
3572 if (!let)
3573 continue;
3574 if (let == '\033')
3575 goto noadjust;
3577 if (index(quitchars, let)
3578 /* adjusting to same slot is meaningful since all
3579 compatible stacks get collected along the way,
3580 but splitting to same slot is not */
3581 || (splitting && let == obj->invlet)) {
3582 noadjust:
3583 if (splitting)
3584 (void) merged(&splitting, &obj);
3585 pline1(Never_mind);
3586 return 0;
3588 if ((letter(let) && let != '@') || index(buf, let))
3589 break; /* got one */
3590 if (trycnt == 5)
3591 goto noadjust;
3592 pline("Select an inventory slot letter."); /* else try again */
3595 /* change the inventory and print the resulting item */
3596 adj_type = !splitting ? "Moving:" : "Splitting:";
3599 * don't use freeinv/addinv to avoid double-touching artifacts,
3600 * dousing lamps, losing luck, cursing loadstone, etc.
3602 extract_nobj(obj, &invent);
3604 for (otmp = invent; otmp;) {
3605 if (!splitting) {
3606 if (merged(&otmp, &obj)) {
3607 adj_type = "Merging:";
3608 obj = otmp;
3609 otmp = otmp->nobj;
3610 extract_nobj(obj, &invent);
3611 continue; /* otmp has already been updated */
3612 } else if (otmp->invlet == let) {
3613 adj_type = "Swapping:";
3614 otmp->invlet = obj->invlet;
3616 } else {
3617 /* splitting: don't merge extra compatible stacks;
3618 if destination is compatible, do merge with it,
3619 otherwise bump whatever is there to an open slot */
3620 if (otmp->invlet == let) {
3621 int olth = 0;
3623 if (has_oname(obj))
3624 olth = strlen(ONAME(obj));
3625 /* ugly hack: if these objects aren't going to merge
3626 solely because they have conflicting user-assigned
3627 names, strip off the name of the one being moved */
3628 if (olth && !obj->oartifact && !mergable(otmp, obj)) {
3629 char *holdname = ONAME(obj);
3631 ONAME(obj) = (char *) 0;
3632 /* restore name iff merging is still not possible */
3633 if (!mergable(otmp, obj)) {
3634 ONAME(obj) = holdname;
3635 holdname = (char *) 0;
3636 } else
3637 free((genericptr_t) holdname);
3640 if (merged(&otmp, &obj)) {
3641 obj = otmp;
3642 extract_nobj(obj, &invent);
3643 } else if (inv_cnt(FALSE) >= 52) {
3644 (void) merged(&splitting, &obj); /* undo split */
3645 /* "knapsack cannot accommodate any more items" */
3646 Your("pack is too full.");
3647 return 0;
3648 } else {
3649 bumped = otmp;
3650 extract_nobj(bumped, &invent);
3652 break;
3653 } /* found 'to' slot */
3654 } /* splitting */
3655 otmp = otmp->nobj;
3658 /* inline addinv; insert loose object at beginning of inventory */
3659 obj->invlet = let;
3660 obj->nobj = invent;
3661 obj->where = OBJ_INVENT;
3662 invent = obj;
3663 reorder_invent();
3664 if (bumped) {
3665 /* splitting the 'from' stack is causing an incompatible
3666 stack in the 'to' slot to be moved into an open one;
3667 we need to do another inline insertion to inventory */
3668 assigninvlet(bumped);
3669 bumped->nobj = invent;
3670 bumped->where = OBJ_INVENT;
3671 invent = bumped;
3672 reorder_invent();
3675 /* messages deferred until inventory has been fully reestablished */
3676 prinv(adj_type, obj, 0L);
3677 if (bumped)
3678 prinv("Moving:", bumped, 0L);
3679 if (splitting)
3680 clear_splitobjs(); /* reset splitobj context */
3681 update_inventory();
3682 return 0;
3685 /* common to display_minventory and display_cinventory */
3686 STATIC_OVL void
3687 invdisp_nothing(hdr, txt)
3688 const char *hdr, *txt;
3690 winid win;
3691 anything any;
3692 menu_item *selected;
3694 any = zeroany;
3695 win = create_nhwindow(NHW_MENU);
3696 start_menu(win);
3697 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
3698 MENU_UNSELECTED);
3699 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3700 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
3701 end_menu(win, (char *) 0);
3702 if (select_menu(win, PICK_NONE, &selected) > 0)
3703 free((genericptr_t) selected);
3704 destroy_nhwindow(win);
3705 return;
3708 /* query_objlist callback: return things that are worn or wielded */
3709 STATIC_OVL boolean
3710 worn_wield_only(obj)
3711 struct obj *obj;
3713 #if 1
3714 /* check for things that *are* worn or wielded (only used for monsters,
3715 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3716 return (boolean) (obj->owornmask != 0L);
3717 #else
3718 /* this used to check for things that *might* be worn or wielded,
3719 but that's not particularly interesting */
3720 if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
3721 return TRUE;
3722 return (boolean) (obj->oclass == WEAPON_CLASS
3723 || obj->oclass == ARMOR_CLASS
3724 || obj->oclass == AMULET_CLASS
3725 || obj->oclass == RING_CLASS);
3726 #endif
3730 * Display a monster's inventory.
3731 * Returns a pointer to the object from the monster's inventory selected
3732 * or NULL if nothing was selected.
3734 * By default, only worn and wielded items are displayed. The caller
3735 * can pick one. Modifier flags are:
3737 * PICK_NONE, PICK_ONE - standard menu control
3738 * PICK_ANY - allowed, but we only return a single object
3739 * MINV_NOLET - nothing selectable
3740 * MINV_ALL - display all inventory
3742 struct obj *
3743 display_minventory(mon, dflags, title)
3744 register struct monst *mon;
3745 int dflags;
3746 char *title;
3748 struct obj *ret;
3749 char tmp[QBUFSZ];
3750 int n;
3751 menu_item *selected = 0;
3752 int do_all = (dflags & MINV_ALL) != 0,
3753 incl_hero = (do_all && u.uswallow && mon == u.ustuck),
3754 have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
3755 pickings = (dflags & MINV_PICKMASK);
3757 Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
3758 do_all ? "possessions" : "armament");
3760 if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
3761 /* Fool the 'weapon in hand' routine into
3762 * displaying 'weapon in claw', etc. properly.
3764 youmonst.data = mon->data;
3766 n = query_objlist(title ? title : tmp, &(mon->minvent),
3767 (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
3768 &selected, pickings,
3769 do_all ? allow_all : worn_wield_only);
3770 set_uasmon();
3771 } else {
3772 invdisp_nothing(title ? title : tmp, "(none)");
3773 n = 0;
3776 if (n > 0) {
3777 ret = selected[0].item.a_obj;
3778 free((genericptr_t) selected);
3779 } else
3780 ret = (struct obj *) 0;
3781 return ret;
3785 * Display the contents of a container in inventory style.
3786 * Currently, this is only used for statues, via wand of probing.
3788 struct obj *
3789 display_cinventory(obj)
3790 register struct obj *obj;
3792 struct obj *ret;
3793 char qbuf[QBUFSZ];
3794 int n;
3795 menu_item *selected = 0;
3797 (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
3798 "that");
3800 if (obj->cobj) {
3801 n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
3802 &selected, PICK_NONE, allow_all);
3803 } else {
3804 invdisp_nothing(qbuf, "(empty)");
3805 n = 0;
3807 if (n > 0) {
3808 ret = selected[0].item.a_obj;
3809 free((genericptr_t) selected);
3810 } else
3811 ret = (struct obj *) 0;
3812 obj->cknown = 1;
3813 return ret;
3816 /* query objlist callback: return TRUE if obj is at given location */
3817 static coord only;
3819 STATIC_OVL boolean
3820 only_here(obj)
3821 struct obj *obj;
3823 return (obj->ox == only.x && obj->oy == only.y);
3827 * Display a list of buried items in inventory style. Return a non-zero
3828 * value if there were items at that spot.
3830 * Currently, this is only used with a wand of probing zapped downwards.
3833 display_binventory(x, y, as_if_seen)
3834 int x, y;
3835 boolean as_if_seen;
3837 struct obj *obj;
3838 menu_item *selected = 0;
3839 int n;
3841 /* count # of objects here */
3842 for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
3843 if (obj->ox == x && obj->oy == y) {
3844 if (as_if_seen)
3845 obj->dknown = 1;
3846 n++;
3849 if (n) {
3850 only.x = x;
3851 only.y = y;
3852 if (query_objlist("Things that are buried here:",
3853 &level.buriedobjlist, INVORDER_SORT,
3854 &selected, PICK_NONE, only_here) > 0)
3855 free((genericptr_t) selected);
3856 only.x = only.y = 0;
3858 return n;
3861 /*invent.c*/