mplayer.c formatting
[aNetHack.git] / src / invent.c
blob1e89d406b0df3cdeb5fd89fc346b1d40a314bc78
1 /* NetHack 3.6 invent.c $NHDT-Date: 1457994703 2016/03/14 22:31:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.199 $ */
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(splittable, (struct obj *));
20 STATIC_DCL boolean FDECL(taking_off, (const char *));
21 STATIC_DCL boolean FDECL(putting_on, (const char *));
22 STATIC_PTR int FDECL(ckunpaid, (struct obj *));
23 STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
24 STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
25 STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
26 STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
27 BOOLEAN_P, long *));
28 STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
29 STATIC_DCL void FDECL(tally_BUCX, (struct obj *,
30 int *, int *, int *, int *, int *));
31 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
32 STATIC_DCL void NDECL(dounpaid);
33 STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
34 STATIC_DCL void FDECL(menu_identify, (int));
35 STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
36 STATIC_DCL char FDECL(obj_to_let, (struct obj *));
38 static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
40 /* wizards can wish for venom, which will become an invisible inventory
41 * item without this. putting it in inv_order would mean venom would
42 * suddenly become a choice for all the inventory-class commands, which
43 * would probably cause mass confusion. the test for inventory venom
44 * is only WIZARD and not wizard because the wizard can leave venom lying
45 * around on a bones level for normal players to find. [Note to the
46 * confused: 'WIZARD' used to be a compile-time conditional so this was
47 * guarded by #ifdef WIZARD/.../#endif.]
49 static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
51 struct sortloot_item {
52 struct obj *obj;
53 int indx;
55 unsigned sortlootmode = 0;
57 /* qsort comparison routine for sortloot() */
58 STATIC_OVL int CFDECLSPEC
59 sortloot_cmp(vptr1, vptr2)
60 const genericptr vptr1;
61 const genericptr vptr2;
63 struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
64 *sli2 = (struct sortloot_item *) vptr2;
65 struct obj *obj1 = sli1->obj,
66 *obj2 = sli2->obj;
67 char *cls1, *cls2;
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;
142 /* Sort object names in lexicographical order, ignoring quantity. */
143 if ((namcmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2))) != 0)
144 return namcmp;
146 /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and
147 unknown to 0. */
148 val1 = obj1->bknown
149 ? (obj1->blessed << 2)
150 + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
151 : 0;
152 val2 = obj2->bknown
153 ? (obj2->blessed << 2)
154 + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
155 : 0;
156 if (val1 != val2)
157 return val2 - val1; /* bigger is better */
159 /* Sort by greasing. This will put the objects in degreasing order. */
160 val1 = obj1->greased;
161 val2 = obj2->greased;
162 if (val1 != val2)
163 return val2 - val1; /* bigger is better */
165 /* Sort by erosion. The effective amount is what matters. */
166 val1 = greatest_erosion(obj1);
167 val2 = greatest_erosion(obj2);
168 if (val1 != val2)
169 return val1 - val2; /* bigger is WORSE */
171 /* Sort by erodeproofing. Map known-invulnerable to 1, and both
172 known-vulnerable and unknown-vulnerability to 0, because that's
173 how they're displayed. */
174 val1 = obj1->rknown && obj1->oerodeproof;
175 val2 = obj2->rknown && obj2->oerodeproof;
176 if (val1 != val2)
177 return val2 - val1; /* bigger is better */
179 /* Sort by enchantment. Map unknown to -1000, which is comfortably
180 below the range of obj->spe. oc_uses_known means that obj->known
181 matters, which usually indirectly means that obj->spe is relevant.
182 Lots of objects use obj->spe for some other purpose (see obj.h). */
183 if (objects[obj1->otyp].oc_uses_known
184 /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
185 && obj1->oclass != FOOD_CLASS) {
186 val1 = obj1->known ? obj1->spe : -1000;
187 val2 = obj2->known ? obj2->spe : -1000;
188 if (val1 != val2)
189 return val2 - val1; /* bigger is better */
192 tiebreak:
193 /* They're identical, as far as we're concerned. We want
194 to force a deterministic order, and do so by producing a
195 stable sort: maintain the original order of equal items. */
196 return (sli2->indx - sli1->indx);
199 void
200 sortloot(olist, mode, by_nexthere)
201 struct obj **olist;
202 unsigned mode; /* flags for sortloot_cmp() */
203 boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
205 struct sortloot_item *sliarray, osli, nsli;
206 struct obj *o, **nxt_p;
207 unsigned n, i;
208 boolean already_sorted = TRUE;
210 sortlootmode = mode; /* extra input for sortloot_cmp() */
211 for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0;
212 osli = nsli) {
213 nsli.obj = by_nexthere ? o->nexthere : o->nobj;
214 nsli.indx = (int) ++n;
215 if (nsli.obj && already_sorted
216 && sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0)
217 already_sorted = FALSE;
219 if (n > 1 && !already_sorted) {
220 sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray);
221 for (i = 0, o = *olist; o;
222 ++i, o = by_nexthere ? o->nexthere : o->nobj)
223 sliarray[i].obj = o, sliarray[i].indx = (int) i;
225 qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
226 for (i = 0; i < n; ++i) {
227 o = sliarray[i].obj;
228 nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj);
229 *nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0;
231 *olist = sliarray[0].obj;
232 free((genericptr_t) sliarray);
234 sortlootmode = 0;
237 void
238 assigninvlet(otmp)
239 register struct obj *otmp;
241 boolean inuse[52];
242 register int i;
243 register struct obj *obj;
245 /* there should be at most one of these in inventory... */
246 if (otmp->oclass == COIN_CLASS) {
247 otmp->invlet = GOLD_SYM;
248 return;
251 for (i = 0; i < 52; i++)
252 inuse[i] = FALSE;
253 for (obj = invent; obj; obj = obj->nobj)
254 if (obj != otmp) {
255 i = obj->invlet;
256 if ('a' <= i && i <= 'z')
257 inuse[i - 'a'] = TRUE;
258 else if ('A' <= i && i <= 'Z')
259 inuse[i - 'A' + 26] = TRUE;
260 if (i == otmp->invlet)
261 otmp->invlet = 0;
263 if ((i = otmp->invlet)
264 && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
265 return;
266 for (i = lastinvnr + 1; i != lastinvnr; i++) {
267 if (i == 52) {
268 i = -1;
269 continue;
271 if (!inuse[i])
272 break;
274 otmp->invlet =
275 (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26));
276 lastinvnr = i;
279 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
280 #define inv_rank(o) ((o)->invlet ^ 040)
282 /* sort the inventory; used by addinv() and doorganize() */
283 STATIC_OVL void
284 reorder_invent()
286 struct obj *otmp, *prev, *next;
287 boolean need_more_sorting;
289 do {
291 * We expect at most one item to be out of order, so this
292 * isn't nearly as inefficient as it may first appear.
294 need_more_sorting = FALSE;
295 for (otmp = invent, prev = 0; otmp;) {
296 next = otmp->nobj;
297 if (next && inv_rank(next) < inv_rank(otmp)) {
298 need_more_sorting = TRUE;
299 if (prev)
300 prev->nobj = next;
301 else
302 invent = next;
303 otmp->nobj = next->nobj;
304 next->nobj = otmp;
305 prev = next;
306 } else {
307 prev = otmp;
308 otmp = next;
311 } while (need_more_sorting);
314 #undef inv_rank
316 /* scan a list of objects to see whether another object will merge with
317 one of them; used in pickup.c when all 52 inventory slots are in use,
318 to figure out whether another object could still be picked up */
319 struct obj *
320 merge_choice(objlist, obj)
321 struct obj *objlist, *obj;
323 struct monst *shkp;
324 int save_nocharge;
326 if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
327 return (struct obj *) 0;
328 /* if this is an item on the shop floor, the attributes it will
329 have when carried are different from what they are now; prevent
330 that from eliciting an incorrect result from mergable() */
331 save_nocharge = obj->no_charge;
332 if (objlist == invent && obj->where == OBJ_FLOOR
333 && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
334 if (obj->no_charge)
335 obj->no_charge = 0;
336 /* A billable object won't have its `unpaid' bit set, so would
337 erroneously seem to be a candidate to merge with a similar
338 ordinary object. That's no good, because once it's really
339 picked up, it won't merge after all. It might merge with
340 another unpaid object, but we can't check that here (depends
341 too much upon shk's bill) and if it doesn't merge it would
342 end up in the '#' overflow inventory slot, so reject it now. */
343 else if (inhishop(shkp))
344 return (struct obj *) 0;
346 while (objlist) {
347 if (mergable(objlist, obj))
348 break;
349 objlist = objlist->nobj;
351 obj->no_charge = save_nocharge;
352 return objlist;
355 /* merge obj with otmp and delete obj if types agree */
357 merged(potmp, pobj)
358 struct obj **potmp, **pobj;
360 register struct obj *otmp = *potmp, *obj = *pobj;
362 if (mergable(otmp, obj)) {
363 /* Approximate age: we do it this way because if we were to
364 * do it "accurately" (merge only when ages are identical)
365 * we'd wind up never merging any corpses.
366 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
368 * Don't do the age manipulation if lit. We would need
369 * to stop the burn on both items, then merge the age,
370 * then restart the burn. Glob ages are averaged in the
371 * absorb routine, which uses weight rather than quantity
372 * to adjust for proportion (glob quantity is always 1).
374 if (!obj->lamplit && !obj->globby)
375 otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
376 / (otmp->quan + obj->quan);
378 otmp->quan += obj->quan;
379 /* temporary special case for gold objects!!!! */
380 if (otmp->oclass == COIN_CLASS)
381 otmp->owt = weight(otmp);
382 /* and puddings!!!1!!one! */
383 else if (!Is_pudding(otmp))
384 otmp->owt += obj->owt;
385 if (!has_oname(otmp) && has_oname(obj))
386 otmp = *potmp = oname(otmp, ONAME(obj));
387 obj_extract_self(obj);
389 /* really should merge the timeouts */
390 if (obj->lamplit)
391 obj_merge_light_sources(obj, otmp);
392 if (obj->timed)
393 obj_stop_timers(obj); /* follows lights */
395 /* fixup for `#adjust' merging wielded darts, daggers, &c */
396 if (obj->owornmask && carried(otmp)) {
397 long wmask = otmp->owornmask | obj->owornmask;
399 /* Both the items might be worn in competing slots;
400 merger preference (regardless of which is which):
401 primary weapon + alternate weapon -> primary weapon;
402 primary weapon + quiver -> primary weapon;
403 alternate weapon + quiver -> alternate weapon.
404 (Prior to 3.3.0, it was not possible for the two
405 stacks to be worn in different slots and `obj'
406 didn't need to be unworn when merging.) */
407 if (wmask & W_WEP)
408 wmask = W_WEP;
409 else if (wmask & W_SWAPWEP)
410 wmask = W_SWAPWEP;
411 else if (wmask & W_QUIVER)
412 wmask = W_QUIVER;
413 else {
414 impossible("merging strangely worn items (%lx)", wmask);
415 wmask = otmp->owornmask;
417 if ((otmp->owornmask & ~wmask) != 0L)
418 setnotworn(otmp);
419 setworn(otmp, wmask);
420 setnotworn(obj);
421 #if 0
422 /* (this should not be necessary, since items
423 already in a monster's inventory don't ever get
424 merged into other objects [only vice versa]) */
425 } else if (obj->owornmask && mcarried(otmp)) {
426 if (obj == MON_WEP(otmp->ocarry)) {
427 MON_WEP(otmp->ocarry) = otmp;
428 otmp->owornmask = W_WEP;
430 #endif /*0*/
433 /* handle puddings a bit differently; absorption will free the
434 other object automatically so we can just return out from here */
435 if (obj->globby) {
436 pudding_merge_message(otmp, obj);
437 obj_absorb(potmp, pobj);
438 return 1;
441 obfree(obj, otmp); /* free(obj), bill->otmp */
442 return 1;
444 return 0;
448 * Adjust hero intrinsics as if this object was being added to the hero's
449 * inventory. Called _before_ the object has been added to the hero's
450 * inventory.
452 * This is called when adding objects to the hero's inventory normally (via
453 * addinv) or when an object in the hero's inventory has been polymorphed
454 * in-place.
456 * It may be valid to merge this code with with addinv_core2().
458 void
459 addinv_core1(obj)
460 struct obj *obj;
462 if (obj->oclass == COIN_CLASS) {
463 context.botl = 1;
464 } else if (obj->otyp == AMULET_OF_YENDOR) {
465 if (u.uhave.amulet)
466 impossible("already have amulet?");
467 u.uhave.amulet = 1;
468 u.uachieve.amulet = 1;
469 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
470 if (u.uhave.menorah)
471 impossible("already have candelabrum?");
472 u.uhave.menorah = 1;
473 u.uachieve.menorah = 1;
474 } else if (obj->otyp == BELL_OF_OPENING) {
475 if (u.uhave.bell)
476 impossible("already have silver bell?");
477 u.uhave.bell = 1;
478 u.uachieve.bell = 1;
479 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
480 if (u.uhave.book)
481 impossible("already have the book?");
482 u.uhave.book = 1;
483 u.uachieve.book = 1;
484 } else if (obj->oartifact) {
485 if (is_quest_artifact(obj)) {
486 if (u.uhave.questart)
487 impossible("already have quest artifact?");
488 u.uhave.questart = 1;
489 artitouch(obj);
491 set_artifact_intrinsic(obj, 1, W_ART);
493 if (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
494 u.uachieve.mines_luckstone = 1;
495 obj->record_achieve_special = 0;
496 } else if ((obj->otyp == AMULET_OF_REFLECTION
497 || obj->otyp == BAG_OF_HOLDING)
498 && obj->record_achieve_special) {
499 u.uachieve.finish_sokoban = 1;
500 obj->record_achieve_special = 0;
505 * Adjust hero intrinsics as if this object was being added to the hero's
506 * inventory. Called _after_ the object has been added to the hero's
507 * inventory.
509 * This is called when adding objects to the hero's inventory normally (via
510 * addinv) or when an object in the hero's inventory has been polymorphed
511 * in-place.
513 void
514 addinv_core2(obj)
515 struct obj *obj;
517 if (confers_luck(obj)) {
518 /* new luckstone must be in inventory by this point
519 * for correct calculation */
520 set_moreluck();
525 * Add obj to the hero's inventory. Make sure the object is "free".
526 * Adjust hero attributes as necessary.
528 struct obj *
529 addinv(obj)
530 struct obj *obj;
532 struct obj *otmp, *prev;
533 int saved_otyp = (int) obj->otyp; /* for panic */
534 boolean obj_was_thrown;
536 if (obj->where != OBJ_FREE)
537 panic("addinv: obj not free");
538 /* normally addtobill() clears no_charge when items in a shop are
539 picked up, but won't do so if the shop has become untended */
540 obj->no_charge = 0; /* should not be set in hero's invent */
541 if (Has_contents(obj))
542 picked_container(obj); /* clear no_charge */
543 obj_was_thrown = obj->was_thrown;
544 obj->was_thrown = 0; /* not meaningful for invent */
546 addinv_core1(obj);
548 /* merge with quiver in preference to any other inventory slot
549 in case quiver and wielded weapon are both eligible; adding
550 extra to quivered stack is more useful than to wielded one */
551 if (uquiver && merged(&uquiver, &obj)) {
552 obj = uquiver;
553 if (!obj)
554 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
555 goto added;
557 /* merge if possible; find end of chain in the process */
558 for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
559 if (merged(&otmp, &obj)) {
560 obj = otmp;
561 if (!obj)
562 panic("addinv: null obj after merge otyp=%d", saved_otyp);
563 goto added;
565 /* didn't merge, so insert into chain */
566 assigninvlet(obj);
567 if (flags.invlet_constant || !prev) {
568 obj->nobj = invent; /* insert at beginning */
569 invent = obj;
570 if (flags.invlet_constant)
571 reorder_invent();
572 } else {
573 prev->nobj = obj; /* insert at end */
574 obj->nobj = 0;
576 obj->where = OBJ_INVENT;
578 /* fill empty quiver if obj was thrown */
579 if (flags.pickup_thrown && !uquiver && obj_was_thrown
580 && (throwing_weapon(obj) || is_ammo(obj)))
581 setuqwep(obj);
582 added:
583 addinv_core2(obj);
584 carry_obj_effects(obj); /* carrying affects the obj */
585 update_inventory();
586 return obj;
590 * Some objects are affected by being carried.
591 * Make those adjustments here. Called _after_ the object
592 * has been added to the hero's or monster's inventory,
593 * and after hero's intrinsics have been updated.
595 void
596 carry_obj_effects(obj)
597 struct obj *obj;
599 /* Cursed figurines can spontaneously transform
600 when carried. */
601 if (obj->otyp == FIGURINE) {
602 if (obj->cursed && obj->corpsenm != NON_PM
603 && !dead_species(obj->corpsenm, TRUE)) {
604 attach_fig_transform_timeout(obj);
609 /* Add an item to the inventory unless we're fumbling or it refuses to be
610 * held (via touch_artifact), and give a message.
611 * If there aren't any free inventory slots, we'll drop it instead.
612 * If both success and failure messages are NULL, then we're just doing the
613 * fumbling/slot-limit checking for a silent grab. In any case,
614 * touch_artifact will print its own messages if they are warranted.
616 struct obj *
617 hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
618 struct obj *obj;
619 const char *drop_fmt, *drop_arg, *hold_msg;
621 char buf[BUFSZ];
623 if (!Blind)
624 obj->dknown = 1; /* maximize mergibility */
625 if (obj->oartifact) {
626 /* place_object may change these */
627 boolean crysknife = (obj->otyp == CRYSKNIFE);
628 int oerode = obj->oerodeproof;
629 boolean wasUpolyd = Upolyd;
631 /* in case touching this object turns out to be fatal */
632 place_object(obj, u.ux, u.uy);
634 if (!touch_artifact(obj, &youmonst)) {
635 obj_extract_self(obj); /* remove it from the floor */
636 dropy(obj); /* now put it back again :-) */
637 return obj;
638 } else if (wasUpolyd && !Upolyd) {
639 /* loose your grip if you revert your form */
640 if (drop_fmt)
641 pline(drop_fmt, drop_arg);
642 obj_extract_self(obj);
643 dropy(obj);
644 return obj;
646 obj_extract_self(obj);
647 if (crysknife) {
648 obj->otyp = CRYSKNIFE;
649 obj->oerodeproof = oerode;
652 if (Fumbling) {
653 if (drop_fmt)
654 pline(drop_fmt, drop_arg);
655 dropy(obj);
656 } else {
657 long oquan = obj->quan;
658 int prev_encumbr = near_capacity(); /* before addinv() */
660 /* encumbrance only matters if it would now become worse
661 than max( current_value, stressed ) */
662 if (prev_encumbr < MOD_ENCUMBER)
663 prev_encumbr = MOD_ENCUMBER;
664 /* addinv() may redraw the entire inventory, overwriting
665 drop_arg when it comes from something like doname() */
666 if (drop_arg)
667 drop_arg = strcpy(buf, drop_arg);
669 obj = addinv(obj);
670 if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
671 && near_capacity() > prev_encumbr)) {
672 if (drop_fmt)
673 pline(drop_fmt, drop_arg);
674 /* undo any merge which took place */
675 if (obj->quan > oquan)
676 obj = splitobj(obj, oquan);
677 dropx(obj);
678 } else {
679 if (flags.autoquiver && !uquiver && !obj->owornmask
680 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
681 || ammo_and_launcher(obj, uswapwep)))
682 setuqwep(obj);
683 if (hold_msg || drop_fmt)
684 prinv(hold_msg, obj, oquan);
687 return obj;
690 /* useup() all of an item regardless of its quantity */
691 void
692 useupall(obj)
693 struct obj *obj;
695 setnotworn(obj);
696 freeinv(obj);
697 obfree(obj, (struct obj *) 0); /* deletes contents also */
700 void
701 useup(obj)
702 register struct obj *obj;
704 /* Note: This works correctly for containers because they (containers)
705 don't merge. */
706 if (obj->quan > 1L) {
707 obj->in_use = FALSE; /* no longer in use */
708 obj->quan--;
709 obj->owt = weight(obj);
710 update_inventory();
711 } else {
712 useupall(obj);
716 /* use one charge from an item and possibly incur shop debt for it */
717 void
718 consume_obj_charge(obj, maybe_unpaid)
719 struct obj *obj;
720 boolean maybe_unpaid; /* false if caller handles shop billing */
722 if (maybe_unpaid)
723 check_unpaid(obj);
724 obj->spe -= 1;
725 if (obj->known)
726 update_inventory();
730 * Adjust hero's attributes as if this object was being removed from the
731 * hero's inventory. This should only be called from freeinv() and
732 * where we are polymorphing an object already in the hero's inventory.
734 * Should think of a better name...
736 void
737 freeinv_core(obj)
738 struct obj *obj;
740 if (obj->oclass == COIN_CLASS) {
741 context.botl = 1;
742 return;
743 } else if (obj->otyp == AMULET_OF_YENDOR) {
744 if (!u.uhave.amulet)
745 impossible("don't have amulet?");
746 u.uhave.amulet = 0;
747 } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
748 if (!u.uhave.menorah)
749 impossible("don't have candelabrum?");
750 u.uhave.menorah = 0;
751 } else if (obj->otyp == BELL_OF_OPENING) {
752 if (!u.uhave.bell)
753 impossible("don't have silver bell?");
754 u.uhave.bell = 0;
755 } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
756 if (!u.uhave.book)
757 impossible("don't have the book?");
758 u.uhave.book = 0;
759 } else if (obj->oartifact) {
760 if (is_quest_artifact(obj)) {
761 if (!u.uhave.questart)
762 impossible("don't have quest artifact?");
763 u.uhave.questart = 0;
765 set_artifact_intrinsic(obj, 0, W_ART);
768 if (obj->otyp == LOADSTONE) {
769 curse(obj);
770 } else if (confers_luck(obj)) {
771 set_moreluck();
772 context.botl = 1;
773 } else if (obj->otyp == FIGURINE && obj->timed) {
774 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
778 /* remove an object from the hero's inventory */
779 void
780 freeinv(obj)
781 register struct obj *obj;
783 extract_nobj(obj, &invent);
784 freeinv_core(obj);
785 update_inventory();
788 void
789 delallobj(x, y)
790 int x, y;
792 struct obj *otmp, *otmp2;
794 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
795 if (otmp == uball)
796 unpunish();
797 /* after unpunish(), or might get deallocated chain */
798 otmp2 = otmp->nexthere;
799 if (otmp == uchain)
800 continue;
801 delobj(otmp);
805 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
806 void
807 delobj(obj)
808 register struct obj *obj;
810 boolean update_map;
812 if (obj->otyp == AMULET_OF_YENDOR
813 || obj->otyp == CANDELABRUM_OF_INVOCATION
814 || obj->otyp == BELL_OF_OPENING
815 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
816 /* player might be doing something stupid, but we
817 * can't guarantee that. assume special artifacts
818 * are indestructible via drawbridges, and exploding
819 * chests, and golem creation, and ...
821 return;
823 update_map = (obj->where == OBJ_FLOOR);
824 obj_extract_self(obj);
825 if (update_map)
826 newsym(obj->ox, obj->oy);
827 obfree(obj, (struct obj *) 0); /* frees contents also */
830 /* try to find a particular type of object at designated map location */
831 struct obj *
832 sobj_at(otyp, x, y)
833 int otyp;
834 int x, y;
836 register struct obj *otmp;
838 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
839 if (otmp->otyp == otyp)
840 break;
842 return otmp;
845 /* sobj_at(&c) traversal -- find next object of specified type */
846 struct obj *
847 nxtobj(obj, type, by_nexthere)
848 struct obj *obj;
849 int type;
850 boolean by_nexthere;
852 register struct obj *otmp;
854 otmp = obj; /* start with the object after this one */
855 do {
856 otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
857 if (!otmp)
858 break;
859 } while (otmp->otyp != type);
861 return otmp;
864 struct obj *
865 carrying(type)
866 register int type;
868 register struct obj *otmp;
870 for (otmp = invent; otmp; otmp = otmp->nobj)
871 if (otmp->otyp == type)
872 return otmp;
873 return (struct obj *) 0;
876 /* Fictional and not-so-fictional currencies.
877 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
879 static const char *const currencies[] = {
880 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
881 "Ankh-Morpork Dollar", /* Discworld */
882 "auric", /* The Domination of Draka */
883 "buckazoid", /* Space Quest */
884 "cirbozoid", /* Starslip */
885 "credit chit", /* Deus Ex */
886 "cubit", /* Battlestar Galactica */
887 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
888 "fretzer", /* Jules Verne */
889 "imperial credit", /* Star Wars */
890 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
891 "kongbuck", /* Snow Crash */
892 "nanite", /* System Shock 2 */
893 "quatloo", /* Star Trek, Sim City */
894 "simoleon", /* Sim City */
895 "solari", /* Spaceballs */
896 "spacebuck", /* Spaceballs */
897 "sporebuck", /* Spore */
898 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
899 "woolong", /* Cowboy Bebop */
900 "zorkmid", /* Zork, NetHack */
903 const char *
904 currency(amount)
905 long amount;
907 const char *res;
909 res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
910 if (amount != 1L)
911 res = makeplural(res);
912 return res;
915 boolean
916 have_lizard()
918 register struct obj *otmp;
920 for (otmp = invent; otmp; otmp = otmp->nobj)
921 if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
922 return TRUE;
923 return FALSE;
926 /* 3.6 tribute */
927 struct obj *
928 u_have_novel()
930 register struct obj *otmp;
932 for (otmp = invent; otmp; otmp = otmp->nobj)
933 if (otmp->otyp == SPE_NOVEL)
934 return otmp;
935 return (struct obj *) 0;
938 struct obj *
939 o_on(id, objchn)
940 unsigned int id;
941 register struct obj *objchn;
943 struct obj *temp;
945 while (objchn) {
946 if (objchn->o_id == id)
947 return objchn;
948 if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
949 return temp;
950 objchn = objchn->nobj;
952 return (struct obj *) 0;
955 boolean
956 obj_here(obj, x, y)
957 register struct obj *obj;
958 int x, y;
960 register struct obj *otmp;
962 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
963 if (obj == otmp)
964 return TRUE;
965 return FALSE;
968 struct obj *
969 g_at(x, y)
970 register int x, y;
972 register struct obj *obj = level.objects[x][y];
974 while (obj) {
975 if (obj->oclass == COIN_CLASS)
976 return obj;
977 obj = obj->nexthere;
979 return (struct obj *) 0;
982 /* compact a string of inventory letters by dashing runs of letters */
983 STATIC_OVL void
984 compactify(buf)
985 register char *buf;
987 register int i1 = 1, i2 = 1;
988 register char ilet, ilet1, ilet2;
990 ilet2 = buf[0];
991 ilet1 = buf[1];
992 buf[++i2] = buf[++i1];
993 ilet = buf[i1];
994 while (ilet) {
995 if (ilet == ilet1 + 1) {
996 if (ilet1 == ilet2 + 1)
997 buf[i2 - 1] = ilet1 = '-';
998 else if (ilet2 == '-') {
999 buf[i2 - 1] = ++ilet1;
1000 buf[i2] = buf[++i1];
1001 ilet = buf[i1];
1002 continue;
1004 } else if (ilet == NOINVSYM) {
1005 /* compact three or more consecutive '#'
1006 characters into "#-#" */
1007 if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
1008 buf[i2 - 1] = '-';
1009 else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
1010 && buf[i2 - 1] == NOINVSYM)
1011 --i2;
1013 ilet2 = ilet1;
1014 ilet1 = ilet;
1015 buf[++i2] = buf[++i1];
1016 ilet = buf[i1];
1020 /* some objects shouldn't be split when count given to getobj or askchain */
1021 STATIC_OVL boolean
1022 splittable(obj)
1023 struct obj *obj;
1025 return !((obj->otyp == LOADSTONE && obj->cursed)
1026 || (obj == uwep && welded(uwep)));
1029 /* match the prompt for either 'T' or 'R' command */
1030 STATIC_OVL boolean
1031 taking_off(action)
1032 const char *action;
1034 return !strcmp(action, "take off") || !strcmp(action, "remove");
1037 /* match the prompt for either 'W' or 'P' command */
1038 STATIC_OVL boolean
1039 putting_on(action)
1040 const char *action;
1042 return !strcmp(action, "wear") || !strcmp(action, "put on");
1046 * getobj returns:
1047 * struct obj *xxx: object to do something with.
1048 * (struct obj *) 0 error return: no object.
1049 * &zeroobj explicitly no object (as in w-).
1050 !!!! test if gold can be used in unusual ways (eaten etc.)
1051 !!!! may be able to remove "usegold"
1053 struct obj *
1054 getobj(let, word)
1055 register const char *let, *word;
1057 register struct obj *otmp;
1058 register char ilet;
1059 char buf[BUFSZ], qbuf[QBUFSZ];
1060 char lets[BUFSZ], altlets[BUFSZ], *ap;
1061 register int foo = 0;
1062 register char *bp = buf;
1063 xchar allowcnt = 0; /* 0, 1 or 2 */
1064 struct obj *firstobj = invent;
1065 boolean usegold = FALSE; /* can't use gold because its illegal */
1066 boolean allowall = FALSE;
1067 boolean allownone = FALSE;
1068 boolean useboulder = FALSE;
1069 xchar foox = 0;
1070 long cnt;
1071 boolean cntgiven = FALSE;
1072 long dummymask;
1074 if (*let == ALLOW_COUNT)
1075 let++, allowcnt = 1;
1076 if (*let == COIN_CLASS)
1077 let++, usegold = TRUE;
1079 /* Equivalent of an "ugly check" for gold */
1080 if (usegold && !strcmp(word, "eat")
1081 && (!metallivorous(youmonst.data)
1082 || youmonst.data == &mons[PM_RUST_MONSTER]))
1083 usegold = FALSE;
1085 if (*let == ALL_CLASSES)
1086 let++, allowall = TRUE;
1087 if (*let == ALLOW_NONE)
1088 let++, allownone = TRUE;
1089 /* "ugly check" for reading fortune cookies, part 1.
1090 * The normal 'ugly check' keeps the object on the inventory list.
1091 * We don't want to do that for shirts/cookies, so the check for
1092 * them is handled a bit differently (and also requires that we set
1093 * allowall in the caller).
1095 if (allowall && !strcmp(word, "read"))
1096 allowall = FALSE;
1098 /* another ugly check: show boulders (not statues) */
1099 if (*let == WEAPON_CLASS && !strcmp(word, "throw")
1100 && throws_rocks(youmonst.data))
1101 useboulder = TRUE;
1103 if (allownone)
1104 *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
1105 ap = altlets;
1107 if (!flags.invlet_constant)
1108 reassign();
1109 else
1110 /* in case invent is in packorder, force it to be in invlet
1111 order before collecing candidate inventory letters;
1112 if player responds with '?' or '*' it will be changed
1113 back by display_pickinv(), but by then we'll have 'lets'
1114 and so won't have to re-sort in the for(;;) loop below */
1115 sortloot(&invent, SORTLOOT_INVLET, FALSE);
1117 for (otmp = firstobj; otmp; otmp = otmp->nobj) {
1118 if (&bp[foo] == &buf[sizeof buf - 1]
1119 || ap == &altlets[sizeof altlets - 1]) {
1120 /* we must have a huge number of NOINVSYM items somehow */
1121 impossible("getobj: inventory overflow");
1122 break;
1125 if (!*let || index(let, otmp->oclass)
1126 || (usegold && otmp->invlet == GOLD_SYM)
1127 || (useboulder && otmp->otyp == BOULDER)) {
1128 register int otyp = otmp->otyp;
1130 bp[foo++] = otmp->invlet;
1131 /* clang-format off */
1132 /* *INDENT-OFF* */
1133 /* ugly check: remove inappropriate things */
1134 if (
1135 (taking_off(word) /* exclude if not worn */
1136 && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1137 || (putting_on(word) /* exclude if already worn */
1138 && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
1139 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1140 || (!strcmp(word, "wield")
1141 && (otmp->owornmask & W_WEP))
1142 #endif
1143 || (!strcmp(word, "ready") /* exclude if wielded */
1144 && (otmp == uwep || (otmp == uswapwep && u.twoweap)))
1145 || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
1146 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1148 foo--;
1149 foox++;
1151 /* Second ugly check; unlike the first it won't trigger an
1152 * "else" in "you don't have anything else to ___".
1154 else if (
1155 (putting_on(word)
1156 && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
1157 || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
1158 && otyp != TOWEL && otyp != LENSES)))
1159 || (!strcmp(word, "wield")
1160 && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
1161 || (!strcmp(word, "eat") && !is_edible(otmp))
1162 || (!strcmp(word, "sacrifice")
1163 && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
1164 && otyp != FAKE_AMULET_OF_YENDOR))
1165 || (!strcmp(word, "write with")
1166 && (otmp->oclass == TOOL_CLASS
1167 && otyp != MAGIC_MARKER && otyp != TOWEL))
1168 || (!strcmp(word, "tin")
1169 && (otyp != CORPSE || !tinnable(otmp)))
1170 || (!strcmp(word, "rub")
1171 && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
1172 && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
1173 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1174 || (!strcmp(word, "use or apply")
1175 /* Picks, axes, pole-weapons, bullwhips */
1176 && ((otmp->oclass == WEAPON_CLASS
1177 && !is_pick(otmp) && !is_axe(otmp)
1178 && !is_pole(otmp) && otyp != BULLWHIP)
1179 || (otmp->oclass == POTION_CLASS
1180 /* only applicable potion is oil, and it will only
1181 be offered as a choice when already discovered */
1182 && (otyp != POT_OIL || !otmp->dknown
1183 || !objects[POT_OIL].oc_name_known))
1184 || (otmp->oclass == FOOD_CLASS
1185 && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
1186 || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
1187 || (!strcmp(word, "invoke")
1188 && !otmp->oartifact
1189 && !objects[otyp].oc_unique
1190 && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
1191 && otyp != CRYSTAL_BALL /* synonym for apply */
1192 /* note: presenting the possibility of invoking non-artifact
1193 mirrors and/or lamps is simply a cruel deception... */
1194 && otyp != MIRROR
1195 && otyp != MAGIC_LAMP
1196 && (otyp != OIL_LAMP /* don't list known oil lamp */
1197 || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
1198 || (!strcmp(word, "untrap with")
1199 && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
1200 || (otmp->oclass == POTION_CLASS
1201 /* only applicable potion is oil, and it will only
1202 be offered as a choice when already discovered */
1203 && (otyp != POT_OIL || !otmp->dknown
1204 || !objects[POT_OIL].oc_name_known))))
1205 || (!strcmp(word, "tip") && !Is_container(otmp)
1206 /* include horn of plenty if sufficiently discovered */
1207 && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
1208 || !objects[HORN_OF_PLENTY].oc_name_known))
1209 || (!strcmp(word, "charge") && !is_chargeable(otmp))
1210 || (!strcmp(word, "open") && otyp != TIN)
1211 || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
1213 foo--;
1215 /* Third ugly check: acceptable but not listed as likely
1216 * candidates in the prompt or in the inventory subset if
1217 * player responds with '?'.
1219 else if (
1220 /* ugly check for unworn armor that can't be worn */
1221 (putting_on(word) && *let == ARMOR_CLASS
1222 && !canwearobj(otmp, &dummymask, FALSE))
1223 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1224 || ((putting_on(word) || taking_off(word))
1225 && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
1226 /* or unsuitable items rubbed on known touchstone */
1227 || (!strncmp(word, "rub on the stone", 16)
1228 && *let == GEM_CLASS && otmp->dknown
1229 && objects[otyp].oc_name_known)
1230 /* suppress corpses on astral, amulets elsewhere */
1231 || (!strcmp(word, "sacrifice")
1232 /* (!astral && amulet) || (astral && !amulet) */
1233 && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
1234 /* suppress container being stashed into */
1235 || (!strcmp(word, "stash") && !ck_bag(otmp))
1236 /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1237 or accessory (ring) covered by cursed worn armor (gloves) */
1238 || (taking_off(word)
1239 && inaccessible_equipment(otmp, (const char *) 0, FALSE))
1240 || (!strcmp(word, "write on")
1241 && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
1242 || !otmp->dknown || !objects[otyp].oc_name_known))
1244 /* acceptable but not listed as likely candidate */
1245 foo--;
1246 allowall = TRUE;
1247 *ap++ = otmp->invlet;
1249 /* *INDENT-ON* */
1250 /* clang-format on */
1251 } else {
1252 /* "ugly check" for reading fortune cookies, part 2 */
1253 if ((!strcmp(word, "read") && is_readable(otmp)))
1254 allowall = usegold = TRUE;
1258 bp[foo] = 0;
1259 if (foo == 0 && bp > buf && bp[-1] == ' ')
1260 *--bp = 0;
1261 Strcpy(lets, bp); /* necessary since we destroy buf */
1262 if (foo > 5) /* compactify string */
1263 compactify(bp);
1264 *ap = '\0';
1266 if (!foo && !allowall && !allownone) {
1267 You("don't have anything %sto %s.", foox ? "else " : "", word);
1268 return (struct obj *) 0;
1269 } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
1270 /* we wanted all scrolls and books in altlets[], but that came with
1271 'allowall' which we don't want since it prevents "silly thing"
1272 result if anything other than scroll or spellbook is chosen */
1273 allowall = FALSE;
1275 for (;;) {
1276 cnt = 0;
1277 cntgiven = FALSE;
1278 if (!buf[0]) {
1279 Sprintf(qbuf, "What do you want to %s? [*]", word);
1280 } else {
1281 Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
1283 if (in_doagain)
1284 ilet = readchar();
1285 else
1286 ilet = yn_function(qbuf, (char *) 0, '\0');
1287 if (digit(ilet)) {
1288 long tmpcnt = 0;
1290 if (!allowcnt) {
1291 pline("No count allowed with this command.");
1292 continue;
1294 ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt);
1295 if (tmpcnt) {
1296 cnt = tmpcnt;
1297 cntgiven = TRUE;
1300 if (index(quitchars, ilet)) {
1301 if (flags.verbose)
1302 pline1(Never_mind);
1303 return (struct obj *) 0;
1305 if (ilet == HANDS_SYM) { /* '-' */
1306 if (!allownone) {
1307 char *suf = (char *) 0;
1309 strcpy(buf, word);
1310 if ((bp = strstr(buf, " on the ")) != 0) {
1311 /* rub on the stone[s] */
1312 *bp = '\0';
1313 suf = (bp + 1);
1315 if ((bp = strstr(buf, " or ")) != 0) {
1316 *bp = '\0';
1317 bp = (rn2(2) ? buf : (bp + 4));
1318 } else
1319 bp = buf;
1320 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
1321 suf ? suf : "");
1323 return (allownone ? &zeroobj : (struct obj *) 0);
1325 /* since gold is now kept in inventory, we need to do processing for
1326 select-from-invent before checking whether gold has been picked */
1327 if (ilet == '?' || ilet == '*') {
1328 char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
1329 long ctmp = 0;
1331 qbuf[0] = '\0';
1332 if (!strcmp(word, "grease"))
1333 Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
1334 else if (!strcmp(word, "write with"))
1335 Sprintf(qbuf, "your %s", body_part(FINGERTIP));
1336 else if (!strcmp(word, "wield"))
1337 Sprintf(qbuf, "your %s %s", uarmg ? "gloved" : "bare",
1338 makeplural(body_part(HAND)));
1339 else if (!strcmp(word, "ready"))
1340 Strcpy(qbuf, "empty quiver");
1342 if (ilet == '?' && !*lets && *altlets)
1343 allowed_choices = altlets;
1344 ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
1345 TRUE, allowcnt ? &ctmp : (long *) 0);
1346 if (!ilet)
1347 continue;
1348 if (ilet == HANDS_SYM)
1349 return &zeroobj;
1350 if (ilet == '\033') {
1351 if (flags.verbose)
1352 pline1(Never_mind);
1353 return (struct obj *) 0;
1355 if (allowcnt && ctmp >= 0) {
1356 cnt = ctmp;
1357 cntgiven = TRUE;
1359 /* they typed a letter (not a space) at the prompt */
1361 /* find the item which was picked */
1362 for (otmp = invent; otmp; otmp = otmp->nobj)
1363 if (otmp->invlet == ilet)
1364 break;
1365 /* some items have restrictions */
1366 if (ilet == def_oc_syms[COIN_CLASS].sym
1367 /* guard against the [hypothetical] chace of having more
1368 than one invent slot of gold and picking the non-'$' one */
1369 || (otmp && otmp->oclass == COIN_CLASS)) {
1370 if (!usegold) {
1371 You("cannot %s gold.", word);
1372 return (struct obj *) 0;
1374 /* Historic note: early Nethack had a bug which was
1375 * first reported for Larn, where trying to drop 2^32-n
1376 * gold pieces was allowed, and did interesting things
1377 * to your money supply. The LRS is the tax bureau
1378 * from Larn.
1380 if (cntgiven && cnt <= 0) {
1381 if (cnt < 0)
1382 pline_The(
1383 "LRS would be very interested to know you have that much.");
1384 return (struct obj *) 0;
1387 if (cntgiven && !strcmp(word, "throw")) {
1388 /* permit counts for throwing gold, but don't accept
1389 * counts for other things since the throw code will
1390 * split off a single item anyway */
1391 if (cnt == 0)
1392 return (struct obj *) 0;
1393 if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
1394 && !(otmp && otmp->oclass == COIN_CLASS))) {
1395 You("can only throw one item at a time.");
1396 continue;
1399 context.botl = 1; /* May have changed the amount of money */
1400 savech(ilet);
1401 /* [we used to set otmp (by finding ilet in invent) here, but
1402 that's been moved above so that otmp can be checked earlier] */
1403 /* verify the chosen object */
1404 if (!otmp) {
1405 You("don't have that object.");
1406 if (in_doagain)
1407 return (struct obj *) 0;
1408 continue;
1409 } else if (cnt < 0 || otmp->quan < cnt) {
1410 You("don't have that many! You have only %ld.", otmp->quan);
1411 if (in_doagain)
1412 return (struct obj *) 0;
1413 continue;
1415 break;
1417 if (!allowall && let && !index(let, otmp->oclass)
1418 && !(usegold && otmp->oclass == COIN_CLASS)) {
1419 silly_thing(word, otmp);
1420 return (struct obj *) 0;
1422 if (cntgiven) {
1423 if (cnt == 0)
1424 return (struct obj *) 0;
1425 if (cnt != otmp->quan) {
1426 /* don't split a stack of cursed loadstones */
1427 if (splittable(otmp))
1428 otmp = splitobj(otmp, cnt);
1429 else if (otmp->otyp == LOADSTONE && otmp->cursed)
1430 /* kludge for canletgo()'s can't-drop-this message */
1431 otmp->corpsenm = (int) cnt;
1434 return otmp;
1437 void
1438 silly_thing(word, otmp)
1439 const char *word;
1440 struct obj *otmp;
1442 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1443 nhUse(otmp);
1444 #else
1445 const char *s1, *s2, *s3;
1446 int ocls = otmp->oclass, otyp = otmp->otyp;
1448 s1 = s2 = s3 = 0;
1449 /* check for attempted use of accessory commands ('P','R') on armor
1450 and for corresponding armor commands ('W','T') on accessories */
1451 if (ocls == ARMOR_CLASS) {
1452 if (!strcmp(word, "put on"))
1453 s1 = "W", s2 = "wear", s3 = "";
1454 else if (!strcmp(word, "remove"))
1455 s1 = "T", s2 = "take", s3 = " off";
1456 } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
1457 || ocls == AMULET_CLASS
1458 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1459 if (!strcmp(word, "wear"))
1460 s1 = "P", s2 = "put", s3 = " on";
1461 else if (!strcmp(word, "take off"))
1462 s1 = "R", s2 = "remove", s3 = "";
1464 if (s1)
1465 pline("Use the '%s' command to %s %s%s.", s1, s2,
1466 !is_plural(otmp) ? "that" : "those", s3);
1467 else
1468 #endif
1469 pline(silly_thing_to, word);
1472 STATIC_PTR int
1473 ckvalidcat(otmp)
1474 struct obj *otmp;
1476 /* use allow_category() from pickup.c */
1477 return (int) allow_category(otmp);
1480 STATIC_PTR int
1481 ckunpaid(otmp)
1482 struct obj *otmp;
1484 return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
1487 boolean
1488 wearing_armor()
1490 return (boolean) (uarm || uarmc || uarmf || uarmg
1491 || uarmh || uarms || uarmu);
1494 boolean
1495 is_worn(otmp)
1496 struct obj *otmp;
1498 return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
1499 ? TRUE
1500 : FALSE;
1503 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1504 STATIC_VAR struct xprnctx {
1505 char let;
1506 boolean dot;
1507 } safeq_xprn_ctx;
1509 /* safe_qbuf() -> short_oname() callback */
1510 STATIC_PTR char *
1511 safeq_xprname(obj)
1512 struct obj *obj;
1514 return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
1515 0L, 0L);
1518 /* alternate safe_qbuf() -> short_oname() callback */
1519 STATIC_PTR char *
1520 safeq_shortxprname(obj)
1521 struct obj *obj;
1523 return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
1524 safeq_xprn_ctx.dot, 0L, 0L);
1527 static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
1528 RING_CLASS, AMULET_CLASS,
1529 TOOL_CLASS, 0 };
1531 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1532 Return the number of times fn was called successfully.
1533 If combo is TRUE, we just use this to get a category list. */
1535 ggetobj(word, fn, mx, combo, resultflags)
1536 const char *word;
1537 int FDECL((*fn), (OBJ_P)), mx;
1538 boolean combo; /* combination menu flag */
1539 unsigned *resultflags;
1541 int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
1542 boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
1543 boolean takeoff, ident, allflag, m_seen;
1544 int itemcount;
1545 int oletct, iletct, unpaid, oc_of_sym;
1546 char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
1547 char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
1548 char buf[BUFSZ], qbuf[QBUFSZ];
1550 if (resultflags)
1551 *resultflags = 0;
1552 takeoff = ident = allflag = m_seen = FALSE;
1553 if (!invent) {
1554 You("have nothing to %s.", word);
1555 return 0;
1557 add_valid_menu_class(0); /* reset */
1558 if (taking_off(word)) {
1559 takeoff = TRUE;
1560 ofilter = is_worn;
1561 } else if (!strcmp(word, "identify")) {
1562 ident = TRUE;
1563 ofilter = not_fully_identified;
1566 iletct = collect_obj_classes(ilets, invent, FALSE, ofilter, &itemcount);
1567 unpaid = count_unpaid(invent);
1569 if (ident && !iletct) {
1570 return -1; /* no further identifications */
1571 } else if (!takeoff && (unpaid || invent)) {
1572 ilets[iletct++] = ' ';
1573 if (unpaid)
1574 ilets[iletct++] = 'u';
1575 if (count_buc(invent, BUC_BLESSED))
1576 ilets[iletct++] = 'B';
1577 if (count_buc(invent, BUC_UNCURSED))
1578 ilets[iletct++] = 'U';
1579 if (count_buc(invent, BUC_CURSED))
1580 ilets[iletct++] = 'C';
1581 if (count_buc(invent, BUC_UNKNOWN))
1582 ilets[iletct++] = 'X';
1583 if (invent)
1584 ilets[iletct++] = 'a';
1585 } else if (takeoff && invent) {
1586 ilets[iletct++] = ' ';
1588 ilets[iletct++] = 'i';
1589 if (!combo)
1590 ilets[iletct++] = 'm'; /* allow menu presentation on request */
1591 ilets[iletct] = '\0';
1593 for (;;) {
1594 Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word,
1595 ilets);
1596 getlin(qbuf, buf);
1597 if (buf[0] == '\033')
1598 return 0;
1599 if (index(buf, 'i')) {
1600 if (display_inventory((char *) 0, TRUE) == '\033')
1601 return 0;
1602 } else
1603 break;
1606 extra_removeables[0] = '\0';
1607 if (takeoff) {
1608 /* arbitrary types of items can be placed in the weapon slots
1609 [any duplicate entries in extra_removeables[] won't matter] */
1610 if (uwep)
1611 (void) strkitten(extra_removeables, uwep->oclass);
1612 if (uswapwep)
1613 (void) strkitten(extra_removeables, uswapwep->oclass);
1614 if (uquiver)
1615 (void) strkitten(extra_removeables, uquiver->oclass);
1618 ip = buf;
1619 olets[oletct = 0] = '\0';
1620 while ((sym = *ip++) != '\0') {
1621 if (sym == ' ')
1622 continue;
1623 oc_of_sym = def_char_to_objclass(sym);
1624 if (takeoff && oc_of_sym != MAXOCLASSES) {
1625 if (index(extra_removeables, oc_of_sym)) {
1626 ; /* skip rest of takeoff checks */
1627 } else if (!index(removeables, oc_of_sym)) {
1628 pline("Not applicable.");
1629 return 0;
1630 } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1631 noarmor(FALSE);
1632 return 0;
1633 } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
1634 && !uquiver) {
1635 You("are not wielding anything.");
1636 return 0;
1637 } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1638 You("are not wearing rings.");
1639 return 0;
1640 } else if (oc_of_sym == AMULET_CLASS && !uamul) {
1641 You("are not wearing an amulet.");
1642 return 0;
1643 } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1644 You("are not wearing a blindfold.");
1645 return 0;
1649 if (oc_of_sym == COIN_CLASS && !combo) {
1650 context.botl = 1;
1651 } else if (sym == 'a') {
1652 allflag = TRUE;
1653 } else if (sym == 'A') {
1654 /* same as the default */;
1655 } else if (sym == 'u') {
1656 add_valid_menu_class('u');
1657 ckfn = ckunpaid;
1658 } else if (sym == 'B') {
1659 add_valid_menu_class('B');
1660 ckfn = ckvalidcat;
1661 } else if (sym == 'U') {
1662 add_valid_menu_class('U');
1663 ckfn = ckvalidcat;
1664 } else if (sym == 'C') {
1665 add_valid_menu_class('C');
1666 ckfn = ckvalidcat;
1667 } else if (sym == 'X') {
1668 add_valid_menu_class('X');
1669 ckfn = ckvalidcat;
1670 } else if (sym == 'm') {
1671 m_seen = TRUE;
1672 } else if (oc_of_sym == MAXOCLASSES) {
1673 You("don't have any %c's.", sym);
1674 } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
1675 if (!index(olets, oc_of_sym)) {
1676 add_valid_menu_class(oc_of_sym);
1677 olets[oletct++] = oc_of_sym;
1678 olets[oletct] = 0;
1683 if (m_seen) {
1684 return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1685 } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
1686 return 0;
1687 #if 0
1688 /* !!!! test gold dropping */
1689 } else if (allowgold == 2 && !oletct) {
1690 return 1; /* you dropped gold (or at least tried to) */
1691 #endif
1692 } else {
1693 int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1695 * askchain() has already finished the job in this case
1696 * so set a special flag to convey that back to the caller
1697 * so that it won't continue processing.
1698 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1700 if (combo && allflag && resultflags)
1701 *resultflags |= ALL_FINISHED;
1702 return cnt;
1707 * Walk through the chain starting at objchn and ask for all objects
1708 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1709 * whether the action in question (i.e., fn) has to be performed.
1710 * If allflag then no questions are asked. Mx gives the max number
1711 * of objects to be treated. Return the number of objects treated.
1714 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1715 struct obj **objchn;
1716 int allflag, mx;
1717 const char *olets, *word; /* olets is an Obj Class char array */
1718 int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
1720 struct obj *otmp, *otmpo;
1721 register char sym, ilet;
1722 register int cnt = 0, dud = 0, tmp;
1723 boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
1724 char qbuf[QBUFSZ], qpfx[QBUFSZ];
1726 takeoff = taking_off(word);
1727 ident = !strcmp(word, "identify");
1728 take_out = !strcmp(word, "take out");
1729 put_in = !strcmp(word, "put in");
1730 nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
1731 || takeoff || take_out || put_in);
1732 ininv = (*objchn == invent);
1734 /* someday maybe we'll sort by 'olets' too (temporarily replace
1735 flags.packorder and pass SORTLOOT_PACK), but not yet... */
1736 sortloot(objchn, SORTLOOT_INVLET, FALSE);
1738 first = TRUE;
1740 * Interrogate in the object class order specified.
1741 * For example, if a person specifies =/ then first all rings
1742 * will be asked about followed by all wands. -dgk
1744 nextclass:
1745 ilet = 'a' - 1;
1746 if (*objchn && (*objchn)->oclass == COIN_CLASS)
1747 ilet--; /* extra iteration */
1749 * Multiple Drop can change the invent chain while it operates
1750 * (dropping a burning potion of oil while levitating creates
1751 * an explosion which can destroy inventory items), so simple
1752 * list traversal
1753 * for (otmp = *objchn; otmp; otmp = otmp2) {
1754 * otmp2 = otmp->nobj;
1755 * ...
1757 * is inadequate here. Use each object's bypass bit to keep
1758 * track of which list elements have already been processed.
1760 bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
1761 while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
1762 if (ilet == 'z')
1763 ilet = 'A';
1764 else
1765 ilet++;
1766 if (olets && *olets && otmp->oclass != *olets)
1767 continue;
1768 if (takeoff && !is_worn(otmp))
1769 continue;
1770 if (ident && !not_fully_identified(otmp))
1771 continue;
1772 if (ckfn && !(*ckfn)(otmp))
1773 continue;
1774 if (!allflag) {
1775 safeq_xprn_ctx.let = ilet;
1776 safeq_xprn_ctx.dot = !nodot;
1777 *qpfx = '\0';
1778 if (first) {
1779 /* traditional_loot() skips prompting when only one
1780 class of objects is involved, so prefix the first
1781 object being queried here with an explanation why */
1782 if (take_out || put_in)
1783 Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
1784 first = FALSE;
1786 (void) safe_qbuf(qbuf, qpfx, "?", otmp,
1787 ininv ? safeq_xprname : doname,
1788 ininv ? safeq_shortxprname : ansimpleoname,
1789 "item");
1790 sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
1791 : nyNaq(qbuf);
1792 } else
1793 sym = 'y';
1795 otmpo = otmp;
1796 if (sym == '#') {
1797 /* Number was entered; split the object unless it corresponds
1798 to 'none' or 'all'. 2 special cases: cursed loadstones and
1799 welded weapons (eg, multiple daggers) will remain as merged
1800 unit; done to avoid splitting an object that won't be
1801 droppable (even if we're picking up rather than dropping). */
1802 if (!yn_number) {
1803 sym = 'n';
1804 } else {
1805 sym = 'y';
1806 if (yn_number < otmp->quan && splittable(otmp))
1807 otmp = splitobj(otmp, yn_number);
1810 switch (sym) {
1811 case 'a':
1812 allflag = 1;
1813 case 'y':
1814 tmp = (*fn)(otmp);
1815 if (tmp < 0) {
1816 if (container_gone(fn)) {
1817 /* otmp caused magic bag to explode;
1818 both are now gone */
1819 otmp = 0; /* and return */
1820 } else if (otmp && otmp != otmpo) {
1821 /* split occurred, merge again */
1822 (void) merged(&otmpo, &otmp);
1824 goto ret;
1826 cnt += tmp;
1827 if (--mx == 0)
1828 goto ret;
1829 case 'n':
1830 if (nodot)
1831 dud++;
1832 default:
1833 break;
1834 case 'q':
1835 /* special case for seffects() */
1836 if (ident)
1837 cnt = -1;
1838 goto ret;
1841 if (olets && *olets && *++olets)
1842 goto nextclass;
1843 if (!takeoff && (dud || cnt))
1844 pline("That was all.");
1845 else if (!dud && !cnt)
1846 pline("No applicable objects.");
1847 ret:
1848 bypass_objlist(*objchn, FALSE);
1849 return cnt;
1853 * Object identification routines:
1856 /* make an object actually be identified; no display updating */
1857 void
1858 fully_identify_obj(otmp)
1859 struct obj *otmp;
1861 makeknown(otmp->otyp);
1862 if (otmp->oartifact)
1863 discover_artifact((xchar) otmp->oartifact);
1864 otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1865 if (Is_container(otmp) || otmp->otyp == STATUE)
1866 otmp->cknown = otmp->lknown = 1;
1867 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1868 learn_egg_type(otmp->corpsenm);
1871 /* ggetobj callback routine; identify an object and give immediate feedback */
1873 identify(otmp)
1874 struct obj *otmp;
1876 fully_identify_obj(otmp);
1877 prinv((char *) 0, otmp, 0L);
1878 return 1;
1881 /* menu of unidentified objects; select and identify up to id_limit of them */
1882 STATIC_OVL void
1883 menu_identify(id_limit)
1884 int id_limit;
1886 menu_item *pick_list;
1887 int n, i, first = 1, tryct = 5;
1888 char buf[BUFSZ];
1889 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1891 while (id_limit) {
1892 Sprintf(buf, "What would you like to identify %s?",
1893 first ? "first" : "next");
1894 n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
1895 | USE_INVLET | INVORDER_SORT),
1896 &pick_list, PICK_ANY, not_fully_identified);
1898 if (n > 0) {
1899 if (n > id_limit)
1900 n = id_limit;
1901 for (i = 0; i < n; i++, id_limit--)
1902 (void) identify(pick_list[i].item.a_obj);
1903 free((genericptr_t) pick_list);
1904 mark_synch(); /* Before we loop to pop open another menu */
1905 first = 0;
1906 } else if (n == -2) { /* player used ESC to quit menu */
1907 break;
1908 } else if (n == -1) { /* no eligible items found */
1909 pline("That was all.");
1910 break;
1911 } else if (!--tryct) { /* stop re-prompting */
1912 pline1(thats_enough_tries);
1913 break;
1914 } else { /* try again */
1915 pline("Choose an item; use ESC to decline.");
1920 /* dialog with user to identify a given number of items; 0 means all */
1921 void
1922 identify_pack(id_limit, learning_id)
1923 int id_limit;
1924 boolean learning_id; /* true if we just read unknown identify scroll */
1926 struct obj *obj, *the_obj;
1927 int n, unid_cnt;
1929 unid_cnt = 0;
1930 the_obj = 0; /* if unid_cnt ends up 1, this will be it */
1931 for (obj = invent; obj; obj = obj->nobj)
1932 if (not_fully_identified(obj))
1933 ++unid_cnt, the_obj = obj;
1935 if (!unid_cnt) {
1936 You("have already identified all %sof your possessions.",
1937 learning_id ? "the rest " : "");
1938 } else if (!id_limit || id_limit >= unid_cnt) {
1939 /* identify everything */
1940 if (unid_cnt == 1) {
1941 (void) identify(the_obj);
1942 } else {
1943 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1945 for (obj = invent; obj; obj = obj->nobj)
1946 if (not_fully_identified(obj))
1947 (void) identify(obj);
1949 } else {
1950 /* identify up to `id_limit' items */
1951 n = 0;
1952 if (flags.menu_style == MENU_TRADITIONAL)
1953 do {
1954 n = ggetobj("identify", identify, id_limit, FALSE,
1955 (unsigned *) 0);
1956 if (n < 0)
1957 break; /* quit or no eligible items */
1958 } while ((id_limit -= n) > 0);
1959 if (n == 0 || n < -1)
1960 menu_identify(id_limit);
1962 update_inventory();
1965 /* called when regaining sight; mark inventory objects which were picked
1966 up while blind as now having been seen */
1967 void
1968 learn_unseen_invent()
1970 struct obj *otmp;
1972 if (Blind)
1973 return; /* sanity check */
1975 for (otmp = invent; otmp; otmp = otmp->nobj) {
1976 if (otmp->dknown)
1977 continue; /* already seen */
1978 /* set dknown, perhaps bknown (for priest[ess]) */
1979 (void) xname(otmp);
1981 * If object->eknown gets implemented (see learnwand(zap.c)),
1982 * handle deferred discovery here.
1985 update_inventory();
1988 /* should of course only be called for things in invent */
1989 STATIC_OVL char
1990 obj_to_let(obj)
1991 struct obj *obj;
1993 if (!flags.invlet_constant) {
1994 obj->invlet = NOINVSYM;
1995 reassign();
1997 return obj->invlet;
2001 * Print the indicated quantity of the given object. If quan == 0L then use
2002 * the current quantity.
2004 void
2005 prinv(prefix, obj, quan)
2006 const char *prefix;
2007 struct obj *obj;
2008 long quan;
2010 if (!prefix)
2011 prefix = "";
2012 pline("%s%s%s", prefix, *prefix ? " " : "",
2013 xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
2016 char *
2017 xprname(obj, txt, let, dot, cost, quan)
2018 struct obj *obj;
2019 const char *txt; /* text to print instead of obj */
2020 char let; /* inventory letter */
2021 boolean dot; /* append period; (dot && cost => Iu) */
2022 long cost; /* cost (for inventory of unpaid or expended items) */
2023 long quan; /* if non-0, print this quantity, not obj->quan */
2025 #ifdef LINT /* handle static char li[BUFSZ]; */
2026 char li[BUFSZ];
2027 #else
2028 static char li[BUFSZ];
2029 #endif
2030 boolean use_invlet = (flags.invlet_constant
2031 && let != CONTAINED_SYM && let != HANDS_SYM);
2032 long savequan = 0;
2034 if (quan && obj) {
2035 savequan = obj->quan;
2036 obj->quan = quan;
2039 * If let is:
2040 * - Then obj == null and 'txt' refers to hands or fingers.
2041 * * Then obj == null and we are printing a total amount.
2042 * > Then the object is contained and doesn't have an inventory letter.
2044 if (cost != 0 || let == '*') {
2045 /* if dot is true, we're doing Iu, otherwise Ix */
2046 Sprintf(li,
2047 iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
2048 : "%c - %-45s %6ld %s",
2049 (dot && use_invlet ? obj->invlet : let),
2050 (txt ? txt : doname(obj)), cost, currency(cost));
2051 } else {
2052 /* ordinary inventory display or pickup message */
2053 Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
2054 (txt ? txt : doname(obj)), (dot ? "." : ""));
2056 if (savequan)
2057 obj->quan = savequan;
2059 return li;
2062 /* the 'i' command */
2064 ddoinv()
2066 (void) display_inventory((char *) 0, FALSE);
2067 return 0;
2071 * find_unpaid()
2073 * Scan the given list of objects. If last_found is NULL, return the first
2074 * unpaid object found. If last_found is not NULL, then skip over unpaid
2075 * objects until last_found is reached, then set last_found to NULL so the
2076 * next unpaid object is returned. This routine recursively follows
2077 * containers.
2079 STATIC_OVL struct obj *
2080 find_unpaid(list, last_found)
2081 struct obj *list, **last_found;
2083 struct obj *obj;
2085 while (list) {
2086 if (list->unpaid) {
2087 if (*last_found) {
2088 /* still looking for previous unpaid object */
2089 if (list == *last_found)
2090 *last_found = (struct obj *) 0;
2091 } else
2092 return ((*last_found = list));
2094 if (Has_contents(list)) {
2095 if ((obj = find_unpaid(list->cobj, last_found)) != 0)
2096 return obj;
2098 list = list->nobj;
2100 return (struct obj *) 0;
2103 /* for perm_invent when operating on a partial inventory display, so that
2104 the persistent one doesn't get shrunk during filtering for item selection
2105 then regrown to full inventory, possibly being resized in the process */
2106 static winid cached_pickinv_win = WIN_ERR;
2108 void
2109 free_pickinv_cache()
2111 if (cached_pickinv_win != WIN_ERR) {
2112 destroy_nhwindow(cached_pickinv_win);
2113 cached_pickinv_win = WIN_ERR;
2118 * Internal function used by display_inventory and getobj that can display
2119 * inventory and return a count as well as a letter. If out_cnt is not null,
2120 * any count returned from the menu selection is placed here.
2122 STATIC_OVL char
2123 display_pickinv(lets, xtra_choice, want_reply, out_cnt)
2124 register const char *lets;
2125 const char *xtra_choice; /* "fingers", pick hands rather than an object */
2126 boolean want_reply;
2127 long *out_cnt;
2129 struct obj *otmp;
2130 char ilet, ret;
2131 char *invlet = flags.inv_order;
2132 int n, classcount;
2133 winid win; /* windows being used */
2134 anything any;
2135 menu_item *selected;
2137 if (flags.perm_invent && ((lets && *lets) || xtra_choice)) {
2138 /* partial inventory in perm_invent setting; don't operate on
2139 full inventory window, use an alternate one instead; create
2140 the first time needed and keep it for re-use as needed later */
2141 if (cached_pickinv_win == WIN_ERR)
2142 cached_pickinv_win = create_nhwindow(NHW_MENU);
2143 win = cached_pickinv_win;
2144 } else
2145 win = WIN_INVEN;
2148 * Exit early if no inventory -- but keep going if we are doing
2149 * a permanent inventory update. We need to keep going so the
2150 * permanent inventory window updates itself to remove the last
2151 * item(s) dropped. One down side: the addition of the exception
2152 * for permanent inventory window updates _can_ pop the window
2153 * up when it's not displayed -- even if it's empty -- because we
2154 * don't know at this level if its up or not. This may not be
2155 * an issue if empty checks are done before hand and the call
2156 * to here is short circuited away.
2158 * 2: our count here is only to distinguish between 0 and 1 and
2159 * more than 1; for the last one, we don't need a precise number.
2160 * For perm_invent update we force 'more than 1'.
2162 n = (flags.perm_invent && !lets && !want_reply) ? 2
2163 : lets ? (int) strlen(lets)
2164 : !invent ? 0 : !invent->nobj ? 1 : 2;
2165 /* for xtra_choice, there's another 'item' not included in initial 'n';
2166 for !lets (full invent) and for override_ID (wizard mode identify),
2167 skip message_menu handling of single item even if item count was 1 */
2168 if (xtra_choice || (n == 1 && (!lets || iflags.override_ID)))
2169 ++n;
2171 if (n == 0) {
2172 pline("Not carrying anything.");
2173 return 0;
2176 /* oxymoron? temporarily assign permanent inventory letters */
2177 if (!flags.invlet_constant)
2178 reassign();
2180 if (n == 1) {
2181 /* when only one item of interest, use pline instead of menus;
2182 we actually use a fake message-line menu in order to allow
2183 the user to perform selection at the --More-- prompt for tty */
2184 ret = '\0';
2185 if (xtra_choice) {
2186 /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2187 "nothing" (ready Quiver), or "fingers" (apply grease) */
2188 ret = message_menu(HANDS_SYM, PICK_ONE,
2189 xprname((struct obj *) 0, xtra_choice,
2190 HANDS_SYM, TRUE, 0L, 0L)); /* '-' */
2191 } else {
2192 for (otmp = invent; otmp; otmp = otmp->nobj)
2193 if (!lets || otmp->invlet == lets[0])
2194 break;
2195 if (otmp)
2196 ret = message_menu(otmp->invlet,
2197 want_reply ? PICK_ONE : PICK_NONE,
2198 xprname(otmp, (char *) 0, lets[0],
2199 TRUE, 0L, 0L));
2201 if (out_cnt)
2202 *out_cnt = -1L; /* select all */
2203 return ret;
2206 sortloot(&invent,
2207 (((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET)
2208 | (flags.sortpack ? SORTLOOT_PACK : 0)),
2209 FALSE);
2211 start_menu(win);
2212 any = zeroany;
2213 if (wizard && iflags.override_ID) {
2214 char prompt[QBUFSZ];
2216 any.a_char = -1;
2217 /* wiz_identify stuffed the wiz_identify command character (^I)
2218 into iflags.override_ID for our use as an accelerator */
2219 Sprintf(prompt, "Debug Identify (%s to permanently identify)",
2220 visctrl(iflags.override_ID));
2221 add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
2222 prompt, MENU_UNSELECTED);
2223 } else if (xtra_choice) {
2224 /* wizard override ID and xtra_choice are mutually exclusive */
2225 if (flags.sortpack)
2226 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2227 "Miscellaneous", MENU_UNSELECTED);
2228 any.a_char = HANDS_SYM; /* '-' */
2229 add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
2230 xtra_choice, MENU_UNSELECTED);
2232 nextclass:
2233 classcount = 0;
2234 for (otmp = invent; otmp; otmp = otmp->nobj) {
2235 if (!flags.sortpack || otmp->oclass == *invlet) {
2236 any = zeroany; /* all bits zero */
2237 ilet = otmp->invlet;
2238 if (flags.sortpack && !classcount) {
2239 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
2240 let_to_name(*invlet, FALSE,
2241 (want_reply && iflags.menu_head_objsym)),
2242 MENU_UNSELECTED);
2243 classcount++;
2245 any.a_char = ilet;
2246 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2247 doname(otmp), MENU_UNSELECTED);
2250 if (flags.sortpack) {
2251 if (*++invlet)
2252 goto nextclass;
2253 if (--invlet != venom_inv) {
2254 invlet = venom_inv;
2255 goto nextclass;
2258 end_menu(win, (char *) 0);
2260 n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
2261 if (n > 0) {
2262 ret = selected[0].item.a_char;
2263 if (out_cnt)
2264 *out_cnt = selected[0].count;
2265 free((genericptr_t) selected);
2266 } else
2267 ret = !n ? '\0' : '\033'; /* cancelled */
2269 return ret;
2273 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2274 * list all objects with object classes that match the order in lets.
2276 * Returns the letter identifier of a selected item, or 0 if nothing
2277 * was selected.
2279 char
2280 display_inventory(lets, want_reply)
2281 const char *lets;
2282 boolean want_reply;
2284 return display_pickinv(lets, (char *) 0, want_reply, (long *) 0);
2288 * Show what is current using inventory letters.
2291 STATIC_OVL char
2292 display_used_invlets(avoidlet)
2293 char avoidlet;
2295 struct obj *otmp;
2296 char ilet, ret = 0;
2297 char *invlet = flags.inv_order;
2298 int n, classcount, invdone = 0;
2299 winid win;
2300 anything any;
2301 menu_item *selected;
2303 if (invent) {
2304 win = create_nhwindow(NHW_MENU);
2305 start_menu(win);
2306 while (!invdone) {
2307 any = zeroany; /* set all bits to zero */
2308 classcount = 0;
2309 for (otmp = invent; otmp; otmp = otmp->nobj) {
2310 ilet = otmp->invlet;
2311 if (ilet == avoidlet)
2312 continue;
2313 if (!flags.sortpack || otmp->oclass == *invlet) {
2314 if (flags.sortpack && !classcount) {
2315 any = zeroany; /* zero */
2316 add_menu(win, NO_GLYPH, &any, 0, 0,
2317 iflags.menu_headings,
2318 let_to_name(*invlet, FALSE, FALSE),
2319 MENU_UNSELECTED);
2320 classcount++;
2322 any.a_char = ilet;
2323 add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
2324 doname(otmp), MENU_UNSELECTED);
2327 if (flags.sortpack && *++invlet)
2328 continue;
2329 invdone = 1;
2331 end_menu(win, "Inventory letters used:");
2333 n = select_menu(win, PICK_ONE, &selected);
2334 if (n > 0) {
2335 ret = selected[0].item.a_char;
2336 free((genericptr_t) selected);
2337 } else
2338 ret = !n ? '\0' : '\033'; /* cancelled */
2339 destroy_nhwindow(win);
2341 return ret;
2345 * Returns the number of unpaid items within the given list. This includes
2346 * contained objects.
2349 count_unpaid(list)
2350 struct obj *list;
2352 int count = 0;
2354 while (list) {
2355 if (list->unpaid)
2356 count++;
2357 if (Has_contents(list))
2358 count += count_unpaid(list->cobj);
2359 list = list->nobj;
2361 return count;
2365 * Returns the number of items with b/u/c/unknown within the given list.
2366 * This does NOT include contained objects.
2368 * Assumes that the hero sees or touches or otherwise senses the objects
2369 * at some point: bknown is forced for priest[ess], like in xname().
2372 count_buc(list, type)
2373 struct obj *list;
2374 int type;
2376 int count = 0;
2378 for (; list; list = list->nobj) {
2379 /* coins are "none of the above" as far as BUCX filtering goes */
2380 if (list->oclass == COIN_CLASS)
2381 continue;
2382 /* priests always know bless/curse state */
2383 if (Role_if(PM_PRIEST))
2384 list->bknown = 1;
2386 /* check whether this object matches the requested type */
2387 if (!list->bknown
2388 ? (type == BUC_UNKNOWN)
2389 : list->blessed ? (type == BUC_BLESSED)
2390 : list->cursed ? (type == BUC_CURSED)
2391 : (type == BUC_UNCURSED))
2392 ++count;
2394 return count;
2397 /* similar to count_buc(), but tallies all states at once
2398 rather than looking for a specific type */
2399 STATIC_OVL void
2400 tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
2401 struct obj *list;
2402 int *bcp, *ucp, *ccp, *xcp, *ocp;
2404 *bcp = *ucp = *ccp = *xcp = *ocp = 0;
2405 for (; list; list = list->nobj) {
2406 if (list->oclass == COIN_CLASS) {
2407 ++(*ocp); /* "other" */
2408 continue;
2410 /* priests always know bless/curse state */
2411 if (Role_if(PM_PRIEST))
2412 list->bknown = 1;
2414 if (!list->bknown)
2415 ++(*xcp);
2416 else if (list->blessed)
2417 ++(*bcp);
2418 else if (list->cursed)
2419 ++(*ccp);
2420 else /* neither blessed nor cursed => uncursed */
2421 ++(*ucp);
2425 long
2426 count_contents(container, nested, quantity, everything)
2427 struct obj *container;
2428 boolean nested, /* include contents of any nested containers */
2429 quantity, /* count all vs count separate stacks */
2430 everything; /* all objects vs only unpaid objects */
2432 struct obj *otmp;
2433 long count = 0L;
2435 for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
2436 if (nested && Has_contents(otmp))
2437 count += count_contents(otmp, nested, quantity, everything);
2438 if (everything || otmp->unpaid)
2439 count += quantity ? otmp->quan : 1L;
2441 return count;
2444 STATIC_OVL void
2445 dounpaid()
2447 winid win;
2448 struct obj *otmp, *marker;
2449 register char ilet;
2450 char *invlet = flags.inv_order;
2451 int classcount, count, num_so_far;
2452 long cost, totcost;
2454 count = count_unpaid(invent);
2456 if (count == 1) {
2457 marker = (struct obj *) 0;
2458 otmp = find_unpaid(invent, &marker);
2459 cost = unpaid_cost(otmp, FALSE);
2460 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2461 pline1(xprname(otmp, distant_name(otmp, doname),
2462 carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
2463 cost, 0L));
2464 iflags.suppress_price--;
2465 return;
2468 win = create_nhwindow(NHW_MENU);
2469 cost = totcost = 0;
2470 num_so_far = 0; /* count of # printed so far */
2471 if (!flags.invlet_constant)
2472 reassign();
2474 do {
2475 classcount = 0;
2476 for (otmp = invent; otmp; otmp = otmp->nobj) {
2477 ilet = otmp->invlet;
2478 if (otmp->unpaid) {
2479 if (!flags.sortpack || otmp->oclass == *invlet) {
2480 if (flags.sortpack && !classcount) {
2481 putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
2482 classcount++;
2485 totcost += cost = unpaid_cost(otmp, FALSE);
2486 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
2487 putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
2488 ilet, TRUE, cost, 0L));
2489 iflags.suppress_price--;
2490 num_so_far++;
2494 } while (flags.sortpack && (*++invlet));
2496 if (count > num_so_far) {
2497 /* something unpaid is contained */
2498 if (flags.sortpack)
2499 putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
2501 * Search through the container objects in the inventory for
2502 * unpaid items. The top level inventory items have already
2503 * been listed.
2505 for (otmp = invent; otmp; otmp = otmp->nobj) {
2506 if (Has_contents(otmp)) {
2507 long contcost = 0L;
2509 marker = (struct obj *) 0; /* haven't found any */
2510 while (find_unpaid(otmp->cobj, &marker)) {
2511 totcost += cost = unpaid_cost(marker, FALSE);
2512 contcost += cost;
2513 if (otmp->cknown) {
2514 iflags.suppress_price++; /* suppress "(unpaid)" sfx */
2515 putstr(win, 0,
2516 xprname(marker, distant_name(marker, doname),
2517 CONTAINED_SYM, TRUE, cost, 0L));
2518 iflags.suppress_price--;
2521 if (!otmp->cknown) {
2522 char contbuf[BUFSZ];
2524 /* Shopkeeper knows what to charge for contents */
2525 Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
2526 putstr(win, 0,
2527 xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
2528 TRUE, contcost, 0L));
2534 putstr(win, 0, "");
2535 putstr(win, 0,
2536 xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
2537 display_nhwindow(win, FALSE);
2538 destroy_nhwindow(win);
2541 /* query objlist callback: return TRUE if obj type matches "this_type" */
2542 static int this_type;
2544 STATIC_OVL boolean
2545 this_type_only(obj)
2546 struct obj *obj;
2548 boolean res = (obj->oclass == this_type);
2550 if (obj->oclass != COIN_CLASS) {
2551 switch (this_type) {
2552 case 'B':
2553 res = (obj->bknown && obj->blessed);
2554 break;
2555 case 'U':
2556 res = (obj->bknown && !(obj->blessed || obj->cursed));
2557 break;
2558 case 'C':
2559 res = (obj->bknown && obj->cursed);
2560 break;
2561 case 'X':
2562 res = !obj->bknown;
2563 break;
2564 default:
2565 break; /* use 'res' as-is */
2568 return res;
2571 /* the 'I' command */
2573 dotypeinv()
2575 char c = '\0';
2576 int n, i = 0;
2577 char *extra_types, types[BUFSZ];
2578 int class_count, oclass, unpaid_count, itemcount;
2579 int bcnt, ccnt, ucnt, xcnt, ocnt;
2580 boolean billx = *u.ushops && doinvbill(0);
2581 menu_item *pick_list;
2582 boolean traditional = TRUE;
2583 const char *prompt = "What type of object do you want an inventory of?";
2585 if (!invent && !billx) {
2586 You("aren't carrying anything.");
2587 return 0;
2589 unpaid_count = count_unpaid(invent);
2590 tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
2592 if (flags.menu_style != MENU_TRADITIONAL) {
2593 if (flags.menu_style == MENU_FULL
2594 || flags.menu_style == MENU_PARTIAL) {
2595 traditional = FALSE;
2596 i = UNPAID_TYPES;
2597 if (billx)
2598 i |= BILLED_TYPES;
2599 if (bcnt)
2600 i |= BUC_BLESSED;
2601 if (ucnt)
2602 i |= BUC_UNCURSED;
2603 if (ccnt)
2604 i |= BUC_CURSED;
2605 if (xcnt)
2606 i |= BUC_UNKNOWN;
2607 n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2608 if (!n)
2609 return 0;
2610 this_type = c = pick_list[0].item.a_int;
2611 free((genericptr_t) pick_list);
2614 if (traditional) {
2615 /* collect a list of classes of objects carried, for use as a prompt
2617 types[0] = 0;
2618 class_count =
2619 collect_obj_classes(types, invent, FALSE,
2620 (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
2621 if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
2622 types[class_count++] = ' ';
2623 if (unpaid_count)
2624 types[class_count++] = 'u';
2625 if (billx)
2626 types[class_count++] = 'x';
2627 if (bcnt)
2628 types[class_count++] = 'B';
2629 if (ucnt)
2630 types[class_count++] = 'U';
2631 if (ccnt)
2632 types[class_count++] = 'C';
2633 if (xcnt)
2634 types[class_count++] = 'X';
2635 types[class_count] = '\0';
2636 /* add everything not already included; user won't see these */
2637 extra_types = eos(types);
2638 *extra_types++ = '\033';
2639 if (!unpaid_count)
2640 *extra_types++ = 'u';
2641 if (!billx)
2642 *extra_types++ = 'x';
2643 if (!bcnt)
2644 *extra_types++ = 'B';
2645 if (!ucnt)
2646 *extra_types++ = 'U';
2647 if (!ccnt)
2648 *extra_types++ = 'C';
2649 if (!xcnt)
2650 *extra_types++ = 'X';
2651 *extra_types = '\0'; /* for index() */
2652 for (i = 0; i < MAXOCLASSES; i++)
2653 if (!index(types, def_oc_syms[i].sym)) {
2654 *extra_types++ = def_oc_syms[i].sym;
2655 *extra_types = '\0';
2658 if (class_count > 1) {
2659 c = yn_function(prompt, types, '\0');
2660 savech(c);
2661 if (c == '\0') {
2662 clear_nhwindow(WIN_MESSAGE);
2663 return 0;
2665 } else {
2666 /* only one thing to itemize */
2667 if (unpaid_count)
2668 c = 'u';
2669 else if (billx)
2670 c = 'x';
2671 else
2672 c = types[0];
2675 if (c == 'x' || (c == 'X' && billx && !xcnt)) {
2676 if (billx)
2677 (void) doinvbill(1);
2678 else
2679 pline("No used-up objects%s.",
2680 unpaid_count ? " on your shopping bill" : "");
2681 return 0;
2683 if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
2684 if (unpaid_count)
2685 dounpaid();
2686 else
2687 You("are not carrying any unpaid objects.");
2688 return 0;
2690 if (traditional) {
2691 if (index("BUCX", c))
2692 oclass = c; /* not a class but understood by this_type_only() */
2693 else
2694 oclass = def_char_to_objclass(c); /* change to object class */
2696 if (oclass == COIN_CLASS)
2697 return doprgold();
2698 if (index(types, c) > index(types, '\033')) {
2699 /* '> ESC' => hidden choice, something known not to be carried */
2700 const char *which = 0;
2702 switch (c) {
2703 case 'B':
2704 which = "known to be blessed";
2705 break;
2706 case 'U':
2707 which = "known to be uncursed";
2708 break;
2709 case 'C':
2710 which = "known to be cursed";
2711 break;
2712 case 'X':
2713 You(
2714 "have no objects whose blessed/uncursed/cursed status is unknown.");
2715 break; /* better phrasing is desirable */
2716 default:
2717 which = "such";
2718 break;
2720 if (which)
2721 You("have no %s objects.", which);
2722 return 0;
2724 this_type = oclass;
2726 if (query_objlist((char *) 0, &invent,
2727 ((flags.invlet_constant ? USE_INVLET : 0)
2728 | INVORDER_SORT),
2729 &pick_list, PICK_NONE, this_type_only) > 0)
2730 free((genericptr_t) pick_list);
2731 return 0;
2734 /* return a string describing the dungeon feature at <x,y> if there
2735 is one worth mentioning at that location; otherwise null */
2736 const char *
2737 dfeature_at(x, y, buf)
2738 int x, y;
2739 char *buf;
2741 struct rm *lev = &levl[x][y];
2742 int ltyp = lev->typ, cmap = -1;
2743 const char *dfeature = 0;
2744 static char altbuf[BUFSZ];
2746 if (IS_DOOR(ltyp)) {
2747 switch (lev->doormask) {
2748 case D_NODOOR:
2749 cmap = S_ndoor;
2750 break; /* "doorway" */
2751 case D_ISOPEN:
2752 cmap = S_vodoor;
2753 break; /* "open door" */
2754 case D_BROKEN:
2755 dfeature = "broken door";
2756 break;
2757 default:
2758 cmap = S_vcdoor;
2759 break; /* "closed door" */
2761 /* override door description for open drawbridge */
2762 if (is_drawbridge_wall(x, y) >= 0)
2763 dfeature = "open drawbridge portcullis", cmap = -1;
2764 } else if (IS_FOUNTAIN(ltyp))
2765 cmap = S_fountain; /* "fountain" */
2766 else if (IS_THRONE(ltyp))
2767 cmap = S_throne; /* "opulent throne" */
2768 else if (is_lava(x, y))
2769 cmap = S_lava; /* "molten lava" */
2770 else if (is_ice(x, y))
2771 cmap = S_ice; /* "ice" */
2772 else if (is_pool(x, y))
2773 dfeature = "pool of water";
2774 else if (IS_SINK(ltyp))
2775 cmap = S_sink; /* "sink" */
2776 else if (IS_ALTAR(ltyp)) {
2777 Sprintf(altbuf, "%saltar to %s (%s)",
2778 ((lev->altarmask & AM_SHRINE)
2779 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
2780 ? "high "
2781 : "",
2782 a_gname(),
2783 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2784 dfeature = altbuf;
2785 } else if ((x == xupstair && y == yupstair)
2786 || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
2787 cmap = S_upstair; /* "staircase up" */
2788 else if ((x == xdnstair && y == ydnstair)
2789 || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2790 cmap = S_dnstair; /* "staircase down" */
2791 else if (x == xupladder && y == yupladder)
2792 cmap = S_upladder; /* "ladder up" */
2793 else if (x == xdnladder && y == ydnladder)
2794 cmap = S_dnladder; /* "ladder down" */
2795 else if (ltyp == DRAWBRIDGE_DOWN)
2796 cmap = S_vodbridge; /* "lowered drawbridge" */
2797 else if (ltyp == DBWALL)
2798 cmap = S_vcdbridge; /* "raised drawbridge" */
2799 else if (IS_GRAVE(ltyp))
2800 cmap = S_grave; /* "grave" */
2801 else if (ltyp == TREE)
2802 cmap = S_tree; /* "tree" */
2803 else if (ltyp == IRONBARS)
2804 dfeature = "set of iron bars";
2806 if (cmap >= 0)
2807 dfeature = defsyms[cmap].explanation;
2808 if (dfeature)
2809 Strcpy(buf, dfeature);
2810 return dfeature;
2813 /* look at what is here; if there are many objects (pile_limit or more),
2814 don't show them unless obj_cnt is 0 */
2816 look_here(obj_cnt, picked_some)
2817 int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
2818 boolean picked_some;
2820 struct obj *otmp;
2821 struct trap *trap;
2822 const char *verb = Blind ? "feel" : "see";
2823 const char *dfeature = (char *) 0;
2824 char fbuf[BUFSZ], fbuf2[BUFSZ];
2825 winid tmpwin;
2826 boolean skip_objects, felt_cockatrice = FALSE;
2828 /* default pile_limit is 5; a value of 0 means "never skip"
2829 (and 1 effectively forces "always skip") */
2830 skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
2831 if (u.uswallow && u.ustuck) {
2832 struct monst *mtmp = u.ustuck;
2834 Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
2835 mbodypart(mtmp, STOMACH));
2836 /* Skip "Contents of " by using fbuf index 12 */
2837 You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
2838 verb, &fbuf[12]);
2839 otmp = mtmp->minvent;
2840 if (otmp) {
2841 for (; otmp; otmp = otmp->nobj) {
2842 /* If swallower is an animal, it should have become stone
2843 * but... */
2844 if (otmp->otyp == CORPSE)
2845 feel_cockatrice(otmp, FALSE);
2847 if (Blind)
2848 Strcpy(fbuf, "You feel");
2849 Strcat(fbuf, ":");
2850 (void) display_minventory(mtmp, MINV_ALL, fbuf);
2851 } else {
2852 You("%s no objects here.", verb);
2854 return !!Blind;
2856 if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
2857 There("is %s here.",
2858 an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2860 otmp = level.objects[u.ux][u.uy];
2861 dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2862 if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2863 dfeature = 0;
2865 if (Blind) {
2866 boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2868 if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2869 /* don't say "altar" twice, dfeature has more info */
2870 You("try to feel what is here.");
2871 } else {
2872 const char *where = (Blind && !can_reach_floor(TRUE))
2873 ? "lying beneath you"
2874 : "lying here on the ",
2875 *onwhat = (Blind && !can_reach_floor(TRUE))
2876 ? ""
2877 : surface(u.ux, u.uy);
2879 You("try to feel what is %s%s.", drift ? "floating here" : where,
2880 drift ? "" : onwhat);
2882 if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
2883 dfeature = 0; /* ice already identified */
2884 if (!can_reach_floor(TRUE)) {
2885 pline("But you can't reach it!");
2886 return 0;
2890 if (dfeature)
2891 Sprintf(fbuf, "There is %s here.", an(dfeature));
2893 if (!otmp || is_lava(u.ux, u.uy)
2894 || (is_pool(u.ux, u.uy) && !Underwater)) {
2895 if (dfeature)
2896 pline1(fbuf);
2897 read_engr_at(u.ux, u.uy); /* Eric Backus */
2898 if (!skip_objects && (Blind || !dfeature))
2899 You("%s no objects here.", verb);
2900 return !!Blind;
2902 /* we know there is something here */
2904 if (skip_objects) {
2905 if (dfeature)
2906 pline1(fbuf);
2907 read_engr_at(u.ux, u.uy); /* Eric Backus */
2908 if (obj_cnt == 1 && otmp->quan == 1L)
2909 There("is %s object here.", picked_some ? "another" : "an");
2910 else
2911 There("are %s%s objects here.",
2912 (obj_cnt < 5)
2913 ? "a few"
2914 : (obj_cnt < 10)
2915 ? "several"
2916 : "many",
2917 picked_some ? " more" : "");
2918 for (; otmp; otmp = otmp->nexthere)
2919 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2920 pline("%s %s%s.",
2921 (obj_cnt > 1)
2922 ? "Including"
2923 : (otmp->quan > 1L)
2924 ? "They're"
2925 : "It's",
2926 corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
2927 poly_when_stoned(youmonst.data)
2928 ? ""
2929 : ", unfortunately");
2930 feel_cockatrice(otmp, FALSE);
2931 break;
2933 } else if (!otmp->nexthere) {
2934 /* only one object */
2935 if (dfeature)
2936 pline1(fbuf);
2937 read_engr_at(u.ux, u.uy); /* Eric Backus */
2938 You("%s here %s.", verb, doname_with_price(otmp));
2939 iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
2940 if (otmp->otyp == CORPSE)
2941 feel_cockatrice(otmp, FALSE);
2942 } else {
2943 char buf[BUFSZ];
2945 display_nhwindow(WIN_MESSAGE, FALSE);
2946 tmpwin = create_nhwindow(NHW_MENU);
2947 if (dfeature) {
2948 putstr(tmpwin, 0, fbuf);
2949 putstr(tmpwin, 0, "");
2951 Sprintf(buf, "%s that %s here:",
2952 picked_some ? "Other things" : "Things",
2953 Blind ? "you feel" : "are");
2954 putstr(tmpwin, 0, buf);
2955 for (; otmp; otmp = otmp->nexthere) {
2956 if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2957 felt_cockatrice = TRUE;
2958 Sprintf(buf, "%s...", doname(otmp));
2959 putstr(tmpwin, 0, buf);
2960 break;
2962 putstr(tmpwin, 0, doname_with_price(otmp));
2964 display_nhwindow(tmpwin, TRUE);
2965 destroy_nhwindow(tmpwin);
2966 if (felt_cockatrice)
2967 feel_cockatrice(otmp, FALSE);
2968 read_engr_at(u.ux, u.uy); /* Eric Backus */
2970 return !!Blind;
2973 /* the ':' command - explicitly look at what is here, including all objects */
2975 dolook()
2977 int res;
2979 /* don't let
2980 MSGTYPE={norep,noshow} "You see here"
2981 interfere with feedback from the look-here command */
2982 hide_unhide_msgtypes(TRUE, MSGTYP_MASK_REP_SHOW);
2983 res = look_here(0, FALSE);
2984 /* restore normal msgtype handling */
2985 hide_unhide_msgtypes(FALSE, MSGTYP_MASK_REP_SHOW);
2986 return res;
2989 boolean
2990 will_feel_cockatrice(otmp, force_touch)
2991 struct obj *otmp;
2992 boolean force_touch;
2994 if ((Blind || force_touch) && !uarmg && !Stone_resistance
2995 && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
2996 return TRUE;
2997 return FALSE;
3000 void
3001 feel_cockatrice(otmp, force_touch)
3002 struct obj *otmp;
3003 boolean force_touch;
3005 char kbuf[BUFSZ];
3007 if (will_feel_cockatrice(otmp, force_touch)) {
3008 /* "the <cockatrice> corpse" */
3009 Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
3011 if (poly_when_stoned(youmonst.data))
3012 You("touched %s with your bare %s.", kbuf,
3013 makeplural(body_part(HAND)));
3014 else
3015 pline("Touching %s is a fatal mistake...", kbuf);
3016 /* normalize body shape here; hand, not body_part(HAND) */
3017 Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
3018 /* will call polymon() for the poly_when_stoned() case */
3019 instapetrify(kbuf);
3023 void
3024 stackobj(obj)
3025 struct obj *obj;
3027 struct obj *otmp;
3029 for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
3030 if (otmp != obj && merged(&obj, &otmp))
3031 break;
3032 return;
3035 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3036 boolean
3037 mergable(otmp, obj)
3038 register struct obj *otmp, *obj;
3040 int objnamelth = 0, otmpnamelth = 0;
3042 if (obj == otmp)
3043 return FALSE; /* already the same object */
3044 if (obj->otyp != otmp->otyp)
3045 return FALSE; /* different types */
3046 if (obj->nomerge) /* explicitly marked to prevent merge */
3047 return FALSE;
3049 /* coins of the same kind will always merge */
3050 if (obj->oclass == COIN_CLASS)
3051 return TRUE;
3053 if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
3054 || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
3055 || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
3056 || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
3057 || obj->bypass != otmp->bypass)
3058 return FALSE;
3060 if (obj->globby)
3061 return TRUE;
3062 /* Checks beyond this point either aren't applicable to globs
3063 * or don't inhibit their merger.
3066 if (obj->oclass == FOOD_CLASS
3067 && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
3068 return FALSE;
3070 if (obj->dknown != otmp->dknown
3071 || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
3072 || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
3073 || obj->greased != otmp->greased)
3074 return FALSE;
3076 if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
3077 && (obj->oerodeproof != otmp->oerodeproof
3078 || obj->rknown != otmp->rknown))
3079 return FALSE;
3081 if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
3082 if (obj->corpsenm != otmp->corpsenm)
3083 return FALSE;
3086 /* hatching eggs don't merge; ditto for revivable corpses */
3087 if ((obj->otyp == EGG && (obj->timed || otmp->timed))
3088 || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
3089 && is_reviver(&mons[otmp->corpsenm])))
3090 return FALSE;
3092 /* allow candle merging only if their ages are close */
3093 /* see begin_burn() for a reference for the magic "25" */
3094 if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
3095 return FALSE;
3097 /* burning potions of oil never merge */
3098 if (obj->otyp == POT_OIL && obj->lamplit)
3099 return FALSE;
3101 /* don't merge surcharged item with base-cost item */
3102 if (obj->unpaid && !same_price(obj, otmp))
3103 return FALSE;
3105 /* if they have names, make sure they're the same */
3106 objnamelth = strlen(safe_oname(obj));
3107 otmpnamelth = strlen(safe_oname(otmp));
3108 if ((objnamelth != otmpnamelth
3109 && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
3110 || (objnamelth && otmpnamelth
3111 && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
3112 return FALSE;
3114 /* for the moment, any additional information is incompatible */
3115 if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
3116 || has_omid(otmp) || has_olong(otmp))
3117 return FALSE;
3119 if (obj->oartifact != otmp->oartifact)
3120 return FALSE;
3122 if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
3123 return (boolean) objects[obj->otyp].oc_merge;
3124 } else
3125 return FALSE;
3128 /* the '$' command */
3130 doprgold()
3132 /* the messages used to refer to "carrying gold", but that didn't
3133 take containers into account */
3134 long umoney = money_cnt(invent);
3135 if (!umoney)
3136 Your("wallet is empty.");
3137 else
3138 Your("wallet contains %ld %s.", umoney, currency(umoney));
3139 shopper_financial_report();
3140 return 0;
3143 /* the ')' command */
3145 doprwep()
3147 if (!uwep) {
3148 You("are empty %s.", body_part(HANDED));
3149 } else {
3150 prinv((char *) 0, uwep, 0L);
3151 if (u.twoweap)
3152 prinv((char *) 0, uswapwep, 0L);
3154 return 0;
3157 /* caller is responsible for checking !wearing_armor() */
3158 STATIC_OVL void
3159 noarmor(report_uskin)
3160 boolean report_uskin;
3162 if (!uskin || !report_uskin) {
3163 You("are not wearing any armor.");
3164 } else {
3165 char *p, *uskinname, buf[BUFSZ];
3167 uskinname = strcpy(buf, simpleonames(uskin));
3168 /* shorten "set of <color> dragon scales" to "<color> scales"
3169 and "<color> dragon scale mail" to "<color> scale mail" */
3170 if (!strncmpi(uskinname, "set of ", 7))
3171 uskinname += 7;
3172 if ((p = strstri(uskinname, " dragon ")) != 0)
3173 while ((p[1] = p[8]) != '\0')
3174 ++p;
3176 You("are not wearing armor but have %s embedded in your skin.",
3177 uskinname);
3181 /* the '[' command */
3183 doprarm()
3185 char lets[8];
3186 register int ct = 0;
3188 * Note: players sometimes get here by pressing a function key which
3189 * transmits ''ESC [ <something>'' rather than by pressing '[';
3190 * there's nothing we can--or should-do about that here.
3193 if (!wearing_armor()) {
3194 noarmor(TRUE);
3195 } else {
3196 if (uarmu)
3197 lets[ct++] = obj_to_let(uarmu);
3198 if (uarm)
3199 lets[ct++] = obj_to_let(uarm);
3200 if (uarmc)
3201 lets[ct++] = obj_to_let(uarmc);
3202 if (uarmh)
3203 lets[ct++] = obj_to_let(uarmh);
3204 if (uarms)
3205 lets[ct++] = obj_to_let(uarms);
3206 if (uarmg)
3207 lets[ct++] = obj_to_let(uarmg);
3208 if (uarmf)
3209 lets[ct++] = obj_to_let(uarmf);
3210 lets[ct] = 0;
3211 (void) display_inventory(lets, FALSE);
3213 return 0;
3216 /* the '=' command */
3218 doprring()
3220 if (!uleft && !uright)
3221 You("are not wearing any rings.");
3222 else {
3223 char lets[3];
3224 register int ct = 0;
3226 if (uleft)
3227 lets[ct++] = obj_to_let(uleft);
3228 if (uright)
3229 lets[ct++] = obj_to_let(uright);
3230 lets[ct] = 0;
3231 (void) display_inventory(lets, FALSE);
3233 return 0;
3236 /* the '"' command */
3238 dopramulet()
3240 if (!uamul)
3241 You("are not wearing an amulet.");
3242 else
3243 prinv((char *) 0, uamul, 0L);
3244 return 0;
3247 STATIC_OVL boolean
3248 tool_in_use(obj)
3249 struct obj *obj;
3251 if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
3252 return TRUE;
3253 if (obj->oclass != TOOL_CLASS)
3254 return FALSE;
3255 return (boolean) (obj == uwep || obj->lamplit
3256 || (obj->otyp == LEASH && obj->leashmon));
3259 /* the '(' command */
3261 doprtool()
3263 struct obj *otmp;
3264 int ct = 0;
3265 char lets[52 + 1];
3267 for (otmp = invent; otmp; otmp = otmp->nobj)
3268 if (tool_in_use(otmp))
3269 lets[ct++] = obj_to_let(otmp);
3270 lets[ct] = '\0';
3271 if (!ct)
3272 You("are not using any tools.");
3273 else
3274 (void) display_inventory(lets, FALSE);
3275 return 0;
3278 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3279 show inventory of all currently wielded, worn, or used objects */
3281 doprinuse()
3283 struct obj *otmp;
3284 int ct = 0;
3285 char lets[52 + 1];
3287 for (otmp = invent; otmp; otmp = otmp->nobj)
3288 if (is_worn(otmp) || tool_in_use(otmp))
3289 lets[ct++] = obj_to_let(otmp);
3290 lets[ct] = '\0';
3291 if (!ct)
3292 You("are not wearing or wielding anything.");
3293 else
3294 (void) display_inventory(lets, FALSE);
3295 return 0;
3299 * uses up an object that's on the floor, charging for it as necessary
3301 void
3302 useupf(obj, numused)
3303 register struct obj *obj;
3304 long numused;
3306 register struct obj *otmp;
3307 boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
3309 /* burn_floor_objects() keeps an object pointer that it tries to
3310 * useupf() multiple times, so obj must survive if plural */
3311 if (obj->quan > numused)
3312 otmp = splitobj(obj, numused);
3313 else
3314 otmp = obj;
3315 if (costly_spot(otmp->ox, otmp->oy)) {
3316 if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
3317 addtobill(otmp, FALSE, FALSE, FALSE);
3318 else
3319 (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
3321 delobj(otmp);
3322 if (at_u && u.uundetected && hides_under(youmonst.data))
3323 (void) hideunder(&youmonst);
3327 * Conversion from a class to a string for printing.
3328 * This must match the object class order.
3330 STATIC_VAR NEARDATA const char *names[] = {
3331 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3332 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3333 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3336 static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
3338 static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
3340 static NEARDATA char *invbuf = (char *) 0;
3341 static NEARDATA unsigned invbufsiz = 0;
3343 char *
3344 let_to_name(let, unpaid, showsym)
3345 char let;
3346 boolean unpaid, showsym;
3348 const char *ocsymfmt = " ('%c')";
3349 const int invbuf_sympadding = 8; /* arbitrary */
3350 const char *class_name;
3351 const char *pos;
3352 int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
3353 unsigned len;
3355 if (oclass)
3356 class_name = names[oclass];
3357 else if ((pos = index(oth_symbols, let)) != 0)
3358 class_name = oth_names[pos - oth_symbols];
3359 else
3360 class_name = names[0];
3362 len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
3363 + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
3364 if (len > invbufsiz) {
3365 if (invbuf)
3366 free((genericptr_t) invbuf);
3367 invbufsiz = len + 10; /* add slop to reduce incremental realloc */
3368 invbuf = (char *) alloc(invbufsiz);
3370 if (unpaid)
3371 Strcat(strcpy(invbuf, "Unpaid "), class_name);
3372 else
3373 Strcpy(invbuf, class_name);
3374 if ((oclass != 0) && showsym) {
3375 char *bp = eos(invbuf);
3376 int mlen = invbuf_sympadding - strlen(class_name);
3377 while (--mlen > 0) {
3378 *bp = ' ';
3379 bp++;
3381 *bp = '\0';
3382 Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
3384 return invbuf;
3387 /* release the static buffer used by let_to_name() */
3388 void
3389 free_invbuf()
3391 if (invbuf)
3392 free((genericptr_t) invbuf), invbuf = (char *) 0;
3393 invbufsiz = 0;
3396 /* give consecutive letters to every item in inventory (for !fixinv mode);
3397 gold is always forced to '$' slot at head of list */
3398 void
3399 reassign()
3401 int i;
3402 struct obj *obj, *prevobj, *goldobj;
3404 /* first, remove [first instance of] gold from invent, if present */
3405 prevobj = goldobj = 0;
3406 for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
3407 if (obj->oclass == COIN_CLASS) {
3408 goldobj = obj;
3409 if (prevobj)
3410 prevobj->nobj = goldobj->nobj;
3411 else
3412 invent = goldobj->nobj;
3413 break;
3415 /* second, re-letter the rest of the list */
3416 for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
3417 obj->invlet =
3418 (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
3419 /* third, assign gold the "letter" '$' and re-insert it at head */
3420 if (goldobj) {
3421 goldobj->invlet = GOLD_SYM;
3422 goldobj->nobj = invent;
3423 invent = goldobj;
3425 if (i >= 52)
3426 i = 52 - 1;
3427 lastinvnr = i;
3430 /* #adjust command
3432 * User specifies a 'from' slot for inventory stack to move,
3433 * then a 'to' slot for its destination. Open slots and those
3434 * filled by compatible stacks are listed as likely candidates
3435 * but user can pick any inventory letter (including 'from').
3436 * All compatible items found are gathered into the 'from'
3437 * stack as it is moved. If the 'to' slot isn't empty and
3438 * doesn't merge, then its stack is swapped to the 'from' slot.
3440 * If the user specifies a count when choosing the 'from' slot,
3441 * and that count is less than the full size of the stack,
3442 * then the stack will be split. The 'count' portion is moved
3443 * to the destination, and the only candidate for merging with
3444 * it is the stack already at the 'to' slot, if any. When the
3445 * destination is non-empty but won't merge, whatever is there
3446 * will be moved to an open slot; if there isn't any open slot
3447 * available, the adjustment attempt fails.
3449 * Splitting has one special case: if 'to' slot is non-empty
3450 * and is compatible with 'from' in all respects except for
3451 * user-assigned names, the 'count' portion being moved is
3452 * effectively renamed so that it will merge with 'to' stack.
3455 doorganize() /* inventory organizer by Del Lamb */
3457 struct obj *obj, *otmp, *splitting, *bumped;
3458 int ix, cur, trycnt;
3459 char let;
3460 char alphabet[52 + 1], buf[52 + 1];
3461 char qbuf[QBUFSZ];
3462 char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3463 const char *adj_type;
3465 if (!invent) {
3466 You("aren't carrying anything to adjust.");
3467 return 0;
3470 if (!flags.invlet_constant)
3471 reassign();
3472 /* get object the user wants to organize (the 'from' slot) */
3473 allowall[0] = ALLOW_COUNT;
3474 allowall[1] = ALL_CLASSES;
3475 allowall[2] = '\0';
3476 if (!(obj = getobj(allowall, "adjust")))
3477 return 0;
3479 /* figure out whether user gave a split count to getobj() */
3480 splitting = bumped = 0;
3481 for (otmp = invent; otmp; otmp = otmp->nobj)
3482 if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
3483 if (otmp->invlet == obj->invlet)
3484 splitting = otmp;
3485 break;
3488 /* initialize the list with all lower and upper case letters */
3489 for (ix = 0, let = 'a'; let <= 'z';)
3490 alphabet[ix++] = let++;
3491 for (let = 'A'; let <= 'Z';)
3492 alphabet[ix++] = let++;
3493 alphabet[ix] = '\0';
3494 /* for floating inv letters, truncate list after the first open slot */
3495 if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
3496 alphabet[ix + (splitting ? 0 : 1)] = '\0';
3498 /* blank out all the letters currently in use in the inventory */
3499 /* except those that will be merged with the selected object */
3500 for (otmp = invent; otmp; otmp = otmp->nobj)
3501 if (otmp != obj && !mergable(otmp, obj)) {
3502 let = otmp->invlet;
3503 if (let >= 'a' && let <= 'z')
3504 alphabet[let - 'a'] = ' ';
3505 else if (let >= 'A' && let <= 'Z')
3506 alphabet[let - 'A' + 26] = ' ';
3509 /* compact the list by removing all the blanks */
3510 for (ix = cur = 0; alphabet[ix]; ix++)
3511 if (alphabet[ix] != ' ')
3512 buf[cur++] = alphabet[ix];
3513 if (!cur && obj->invlet == NOINVSYM)
3514 buf[cur++] = NOINVSYM;
3515 buf[cur] = '\0';
3516 /* and by dashing runs of letters */
3517 if (cur > 5)
3518 compactify(buf);
3520 /* get 'to' slot to use as destination */
3521 Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
3522 invent ? " (? see used letters)" : "");
3523 for (trycnt = 1; ; ++trycnt) {
3524 let = yn_function(qbuf, (char *) 0, '\0');
3525 if (let == '?' || let == '*') {
3526 let = display_used_invlets(splitting ? obj->invlet : 0);
3527 if (!let)
3528 continue;
3529 if (let == '\033')
3530 goto noadjust;
3532 if (index(quitchars, let)
3533 /* adjusting to same slot is meaningful since all
3534 compatible stacks get collected along the way,
3535 but splitting to same slot is not */
3536 || (splitting && let == obj->invlet)) {
3537 noadjust:
3538 if (splitting)
3539 (void) merged(&splitting, &obj);
3540 pline1(Never_mind);
3541 return 0;
3543 if ((letter(let) && let != '@') || index(buf, let))
3544 break; /* got one */
3545 if (trycnt == 5)
3546 goto noadjust;
3547 pline("Select an inventory slot letter."); /* else try again */
3550 /* change the inventory and print the resulting item */
3551 adj_type = !splitting ? "Moving:" : "Splitting:";
3554 * don't use freeinv/addinv to avoid double-touching artifacts,
3555 * dousing lamps, losing luck, cursing loadstone, etc.
3557 extract_nobj(obj, &invent);
3559 for (otmp = invent; otmp;) {
3560 if (!splitting) {
3561 if (merged(&otmp, &obj)) {
3562 adj_type = "Merging:";
3563 obj = otmp;
3564 otmp = otmp->nobj;
3565 extract_nobj(obj, &invent);
3566 continue; /* otmp has already been updated */
3567 } else if (otmp->invlet == let) {
3568 adj_type = "Swapping:";
3569 otmp->invlet = obj->invlet;
3571 } else {
3572 /* splitting: don't merge extra compatible stacks;
3573 if destination is compatible, do merge with it,
3574 otherwise bump whatever is there to an open slot */
3575 if (otmp->invlet == let) {
3576 int olth = 0;
3578 if (has_oname(obj))
3579 olth = strlen(ONAME(obj));
3580 /* ugly hack: if these objects aren't going to merge
3581 solely because they have conflicting user-assigned
3582 names, strip off the name of the one being moved */
3583 if (olth && !obj->oartifact && !mergable(otmp, obj)) {
3584 char *holdname = ONAME(obj);
3586 ONAME(obj) = (char *) 0;
3587 /* restore name iff merging is still not possible */
3588 if (!mergable(otmp, obj)) {
3589 ONAME(obj) = holdname;
3590 holdname = (char *) 0;
3591 } else
3592 free((genericptr_t) holdname);
3595 if (merged(&otmp, &obj)) {
3596 obj = otmp;
3597 extract_nobj(obj, &invent);
3598 } else if (inv_cnt(FALSE) >= 52) {
3599 (void) merged(&splitting, &obj); /* undo split */
3600 /* "knapsack cannot accommodate any more items" */
3601 Your("pack is too full.");
3602 return 0;
3603 } else {
3604 bumped = otmp;
3605 extract_nobj(bumped, &invent);
3607 break;
3608 } /* found 'to' slot */
3609 } /* splitting */
3610 otmp = otmp->nobj;
3613 /* inline addinv; insert loose object at beginning of inventory */
3614 obj->invlet = let;
3615 obj->nobj = invent;
3616 obj->where = OBJ_INVENT;
3617 invent = obj;
3618 reorder_invent();
3619 if (bumped) {
3620 /* splitting the 'from' stack is causing an incompatible
3621 stack in the 'to' slot to be moved into an open one;
3622 we need to do another inline insertion to inventory */
3623 assigninvlet(bumped);
3624 bumped->nobj = invent;
3625 bumped->where = OBJ_INVENT;
3626 invent = bumped;
3627 reorder_invent();
3630 /* messages deferred until inventory has been fully reestablished */
3631 prinv(adj_type, obj, 0L);
3632 if (bumped)
3633 prinv("Moving:", bumped, 0L);
3634 if (splitting)
3635 clear_splitobjs(); /* reset splitobj context */
3636 update_inventory();
3637 return 0;
3640 /* common to display_minventory and display_cinventory */
3641 STATIC_OVL void
3642 invdisp_nothing(hdr, txt)
3643 const char *hdr, *txt;
3645 winid win;
3646 anything any;
3647 menu_item *selected;
3649 any = zeroany;
3650 win = create_nhwindow(NHW_MENU);
3651 start_menu(win);
3652 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
3653 MENU_UNSELECTED);
3654 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
3655 add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
3656 end_menu(win, (char *) 0);
3657 if (select_menu(win, PICK_NONE, &selected) > 0)
3658 free((genericptr_t) selected);
3659 destroy_nhwindow(win);
3660 return;
3663 /* query_objlist callback: return things that are worn or wielded */
3664 STATIC_OVL boolean
3665 worn_wield_only(obj)
3666 struct obj *obj;
3668 #if 1
3669 /* check for things that *are* worn or wielded (only used for monsters,
3670 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3671 return (boolean) (obj->owornmask != 0L);
3672 #else
3673 /* this used to check for things that *might* be worn or wielded,
3674 but that's not particularly interesting */
3675 if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
3676 return TRUE;
3677 return (boolean) (obj->oclass == WEAPON_CLASS
3678 || obj->oclass == ARMOR_CLASS
3679 || obj->oclass == AMULET_CLASS
3680 || obj->oclass == RING_CLASS);
3681 #endif
3685 * Display a monster's inventory.
3686 * Returns a pointer to the object from the monster's inventory selected
3687 * or NULL if nothing was selected.
3689 * By default, only worn and wielded items are displayed. The caller
3690 * can pick one. Modifier flags are:
3692 * MINV_NOLET - nothing selectable
3693 * MINV_ALL - display all inventory
3695 struct obj *
3696 display_minventory(mon, dflags, title)
3697 register struct monst *mon;
3698 int dflags;
3699 char *title;
3701 struct obj *ret;
3702 char tmp[QBUFSZ];
3703 int n;
3704 menu_item *selected = 0;
3705 int do_all = (dflags & MINV_ALL) != 0,
3706 incl_hero = (do_all && u.uswallow && mon == u.ustuck),
3707 have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero);
3709 Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
3710 do_all ? "possessions" : "armament");
3712 if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
3713 /* Fool the 'weapon in hand' routine into
3714 * displaying 'weapon in claw', etc. properly.
3716 youmonst.data = mon->data;
3718 n = query_objlist(title ? title : tmp, &(mon->minvent),
3719 (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
3720 &selected,
3721 (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
3722 do_all ? allow_all : worn_wield_only);
3724 set_uasmon();
3725 } else {
3726 invdisp_nothing(title ? title : tmp, "(none)");
3727 n = 0;
3730 if (n > 0) {
3731 ret = selected[0].item.a_obj;
3732 free((genericptr_t) selected);
3733 } else
3734 ret = (struct obj *) 0;
3735 return ret;
3739 * Display the contents of a container in inventory style.
3740 * Currently, this is only used for statues, via wand of probing.
3742 struct obj *
3743 display_cinventory(obj)
3744 register struct obj *obj;
3746 struct obj *ret;
3747 char qbuf[QBUFSZ];
3748 int n;
3749 menu_item *selected = 0;
3751 (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
3752 "that");
3754 if (obj->cobj) {
3755 n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
3756 &selected, PICK_NONE, allow_all);
3757 } else {
3758 invdisp_nothing(qbuf, "(empty)");
3759 n = 0;
3761 if (n > 0) {
3762 ret = selected[0].item.a_obj;
3763 free((genericptr_t) selected);
3764 } else
3765 ret = (struct obj *) 0;
3766 obj->cknown = 1;
3767 return ret;
3770 /* query objlist callback: return TRUE if obj is at given location */
3771 static coord only;
3773 STATIC_OVL boolean
3774 only_here(obj)
3775 struct obj *obj;
3777 return (obj->ox == only.x && obj->oy == only.y);
3781 * Display a list of buried items in inventory style. Return a non-zero
3782 * value if there were items at that spot.
3784 * Currently, this is only used with a wand of probing zapped downwards.
3787 display_binventory(x, y, as_if_seen)
3788 int x, y;
3789 boolean as_if_seen;
3791 struct obj *obj;
3792 menu_item *selected = 0;
3793 int n;
3795 /* count # of objects here */
3796 for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
3797 if (obj->ox == x && obj->oy == y) {
3798 if (as_if_seen)
3799 obj->dknown = 1;
3800 n++;
3803 if (n) {
3804 only.x = x;
3805 only.y = y;
3806 if (query_objlist("Things that are buried here:",
3807 &level.buriedobjlist, INVORDER_SORT,
3808 &selected, PICK_NONE, only_here) > 0)
3809 free((genericptr_t) selected);
3810 only.x = only.y = 0;
3812 return n;
3815 /*invent.c*/