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. */
8 #define CONTAINED_SYM '>' /* designator for inside a container */
11 STATIC_DCL
int FDECL(CFDECLSPEC sortloot_cmp
, (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 *,
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
{
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
,
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
);
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];
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] */
95 val1
= armcat
[objects
[obj1
->otyp
].oc_armcat
];
96 val2
= armcat
[objects
[obj2
->otyp
].oc_armcat
];
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
;
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
;
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;
121 /* order by assigned inventory letter */
122 if ((sortlootmode
& SORTLOOT_INVLET
) != 0) {
124 val1
= ('a' <= c
&& c
<= 'z') ? (c
- 'a' + 2)
125 : ('A' <= c
&& c
<= 'Z') ? (c
- 'A' + 2 + 26)
127 : (c
== '#') ? 1 + 52 + 1
128 : 1 + 52 + 1 + 1; /* none of the above */
130 val2
= ('a' <= c
&& c
<= 'z') ? (c
- 'a' + 2)
131 : ('A' <= c
&& c
<= 'Z') ? (c
- 'A' + 2 + 26)
133 : (c
== '#') ? 1 + 52 + 1
134 : 1 + 52 + 1 + 1; /* none of the above */
139 if ((sortlootmode
& SORTLOOT_LOOT
) == 0)
142 /* Sort object names in lexicographical order, ignoring quantity. */
143 if ((namcmp
= strcmpi(cxname_singular(obj1
), cxname_singular(obj2
))) != 0)
146 /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and
149 ? (obj1
->blessed
<< 2)
150 + ((!obj1
->blessed
&& !obj1
->cursed
) << 1) + obj1
->cursed
153 ? (obj2
->blessed
<< 2)
154 + ((!obj2
->blessed
&& !obj2
->cursed
) << 1) + obj2
->cursed
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
;
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
);
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
;
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;
189 return val2
- val1
; /* bigger is better */
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
);
200 sortloot(olist
, mode
, by_nexthere
)
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
;
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;
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
) {
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
);
239 register struct obj
*otmp
;
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
;
251 for (i
= 0; i
< 52; i
++)
253 for (obj
= invent
; obj
; obj
= obj
->nobj
)
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
)
263 if ((i
= otmp
->invlet
)
264 && (('a' <= i
&& i
<= 'z') || ('A' <= i
&& i
<= 'Z')))
266 for (i
= lastinvnr
+ 1; i
!= lastinvnr
; i
++) {
275 (inuse
[i
] ? NOINVSYM
: (i
< 26) ? ('a' + i
) : ('A' + i
- 26));
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() */
286 struct obj
*otmp
, *prev
, *next
;
287 boolean need_more_sorting
;
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
;) {
297 if (next
&& inv_rank(next
) < inv_rank(otmp
)) {
298 need_more_sorting
= TRUE
;
303 otmp
->nobj
= next
->nobj
;
311 } while (need_more_sorting
);
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 */
320 merge_choice(objlist
, obj
)
321 struct obj
*objlist
, *obj
;
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) {
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;
347 if (mergable(objlist
, obj
))
349 objlist
= objlist
->nobj
;
351 obj
->no_charge
= save_nocharge
;
355 /* merge obj with otmp and delete obj if types agree */
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 */
391 obj_merge_light_sources(obj
, otmp
);
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.) */
409 else if (wmask
& W_SWAPWEP
)
411 else if (wmask
& W_QUIVER
)
414 impossible("merging strangely worn items (%lx)", wmask
);
415 wmask
= otmp
->owornmask
;
417 if ((otmp
->owornmask
& ~wmask
) != 0L)
419 setworn(otmp
, wmask
);
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
;
433 /* handle puddings a bit differently; absorption will free the
434 other object automatically so we can just return out from here */
436 pudding_merge_message(otmp
, obj
);
437 obj_absorb(potmp
, pobj
);
441 obfree(obj
, otmp
); /* free(obj), bill->otmp */
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
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
456 * It may be valid to merge this code with with addinv_core2().
462 if (obj
->oclass
== COIN_CLASS
) {
464 } else if (obj
->otyp
== AMULET_OF_YENDOR
) {
466 impossible("already have amulet?");
468 u
.uachieve
.amulet
= 1;
469 } else if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
471 impossible("already have candelabrum?");
473 u
.uachieve
.menorah
= 1;
474 } else if (obj
->otyp
== BELL_OF_OPENING
) {
476 impossible("already have silver bell?");
479 } else if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
481 impossible("already have the book?");
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;
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
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
517 if (confers_luck(obj
)) {
518 /* new luckstone must be in inventory by this point
519 * for correct calculation */
525 * Add obj to the hero's inventory. Make sure the object is "free".
526 * Adjust hero attributes as necessary.
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 */
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
)) {
554 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp
);
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
)) {
562 panic("addinv: null obj after merge otyp=%d", saved_otyp
);
565 /* didn't merge, so insert into chain */
567 if (flags
.invlet_constant
|| !prev
) {
568 obj
->nobj
= invent
; /* insert at beginning */
570 if (flags
.invlet_constant
)
573 prev
->nobj
= obj
; /* insert at end */
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
)))
584 carry_obj_effects(obj
); /* carrying affects the 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.
596 carry_obj_effects(obj
)
599 /* Cursed figurines can spontaneously transform
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.
617 hold_another_object(obj
, drop_fmt
, drop_arg
, hold_msg
)
619 const char *drop_fmt
, *drop_arg
, *hold_msg
;
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 :-) */
638 } else if (wasUpolyd
&& !Upolyd
) {
639 /* loose your grip if you revert your form */
641 pline(drop_fmt
, drop_arg
);
642 obj_extract_self(obj
);
646 obj_extract_self(obj
);
648 obj
->otyp
= CRYSKNIFE
;
649 obj
->oerodeproof
= oerode
;
654 pline(drop_fmt
, drop_arg
);
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() */
667 drop_arg
= strcpy(buf
, drop_arg
);
670 if (inv_cnt(FALSE
) > 52 || ((obj
->otyp
!= LOADSTONE
|| !obj
->cursed
)
671 && near_capacity() > prev_encumbr
)) {
673 pline(drop_fmt
, drop_arg
);
674 /* undo any merge which took place */
675 if (obj
->quan
> oquan
)
676 obj
= splitobj(obj
, oquan
);
679 if (flags
.autoquiver
&& !uquiver
&& !obj
->owornmask
680 && (is_missile(obj
) || ammo_and_launcher(obj
, uwep
)
681 || ammo_and_launcher(obj
, uswapwep
)))
683 if (hold_msg
|| drop_fmt
)
684 prinv(hold_msg
, obj
, oquan
);
690 /* useup() all of an item regardless of its quantity */
697 obfree(obj
, (struct obj
*) 0); /* deletes contents also */
702 register struct obj
*obj
;
704 /* Note: This works correctly for containers because they (containers)
706 if (obj
->quan
> 1L) {
707 obj
->in_use
= FALSE
; /* no longer in use */
709 obj
->owt
= weight(obj
);
716 /* use one charge from an item and possibly incur shop debt for it */
718 consume_obj_charge(obj
, maybe_unpaid
)
720 boolean maybe_unpaid
; /* false if caller handles shop billing */
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...
740 if (obj
->oclass
== COIN_CLASS
) {
743 } else if (obj
->otyp
== AMULET_OF_YENDOR
) {
745 impossible("don't have amulet?");
747 } else if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
748 if (!u
.uhave
.menorah
)
749 impossible("don't have candelabrum?");
751 } else if (obj
->otyp
== BELL_OF_OPENING
) {
753 impossible("don't have silver bell?");
755 } else if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
757 impossible("don't have the book?");
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
) {
770 } else if (confers_luck(obj
)) {
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 */
781 register struct obj
*obj
;
783 extract_nobj(obj
, &invent
);
792 struct obj
*otmp
, *otmp2
;
794 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp2
) {
797 /* after unpunish(), or might get deallocated chain */
798 otmp2
= otmp
->nexthere
;
805 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
808 register struct obj
*obj
;
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 ...
823 update_map
= (obj
->where
== OBJ_FLOOR
);
824 obj_extract_self(obj
);
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 */
836 register struct obj
*otmp
;
838 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
)
839 if (otmp
->otyp
== otyp
)
845 /* sobj_at(&c) traversal -- find next object of specified type */
847 nxtobj(obj
, type
, by_nexthere
)
852 register struct obj
*otmp
;
854 otmp
= obj
; /* start with the object after this one */
856 otmp
= !by_nexthere
? otmp
->nobj
: otmp
->nexthere
;
859 } while (otmp
->otyp
!= type
);
868 register struct obj
*otmp
;
870 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
871 if (otmp
->otyp
== type
)
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 */
909 res
= Hallucination
? currencies
[rn2(SIZE(currencies
))] : "zorkmid";
911 res
= makeplural(res
);
918 register struct obj
*otmp
;
920 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
921 if (otmp
->otyp
== CORPSE
&& otmp
->corpsenm
== PM_LIZARD
)
930 register struct obj
*otmp
;
932 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
933 if (otmp
->otyp
== SPE_NOVEL
)
935 return (struct obj
*) 0;
941 register struct obj
*objchn
;
946 if (objchn
->o_id
== id
)
948 if (Has_contents(objchn
) && (temp
= o_on(id
, objchn
->cobj
)))
950 objchn
= objchn
->nobj
;
952 return (struct obj
*) 0;
957 register struct obj
*obj
;
960 register struct obj
*otmp
;
962 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
)
972 register struct obj
*obj
= level
.objects
[x
][y
];
975 if (obj
->oclass
== COIN_CLASS
)
979 return (struct obj
*) 0;
982 /* compact a string of inventory letters by dashing runs of letters */
987 register int i1
= 1, i2
= 1;
988 register char ilet
, ilet1
, ilet2
;
992 buf
[++i2
] = buf
[++i1
];
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
];
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
)
1009 else if (i2
>= 3 && buf
[i2
- 3] == NOINVSYM
&& buf
[i2
- 2] == '-'
1010 && buf
[i2
- 1] == NOINVSYM
)
1015 buf
[++i2
] = buf
[++i1
];
1020 /* some objects shouldn't be split when count given to getobj or askchain */
1025 return !((obj
->otyp
== LOADSTONE
&& obj
->cursed
)
1026 || (obj
== uwep
&& welded(uwep
)));
1029 /* match the prompt for either 'T' or 'R' command */
1034 return !strcmp(action
, "take off") || !strcmp(action
, "remove");
1037 /* match the prompt for either 'W' or 'P' command */
1042 return !strcmp(action
, "wear") || !strcmp(action
, "put on");
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"
1055 register const char *let
, *word
;
1057 register struct obj
*otmp
;
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
;
1071 boolean cntgiven
= FALSE
;
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
]))
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"))
1098 /* another ugly check: show boulders (not statues) */
1099 if (*let
== WEAPON_CLASS
&& !strcmp(word
, "throw")
1100 && throws_rocks(youmonst
.data
))
1104 *bp
++ = HANDS_SYM
, *bp
++ = ' '; /* '-' */
1107 if (!flags
.invlet_constant
)
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");
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 */
1133 /* ugly check: remove inappropriate things */
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
))
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
))
1151 /* Second ugly check; unlike the first it won't trigger an
1152 * "else" in "you don't have anything else to ___".
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")
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... */
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
))
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 '?'.
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 */
1247 *ap
++ = otmp
->invlet
;
1250 /* clang-format on */
1252 /* "ugly check" for reading fortune cookies, part 2 */
1253 if ((!strcmp(word
, "read") && is_readable(otmp
)))
1254 allowall
= usegold
= TRUE
;
1259 if (foo
== 0 && bp
> buf
&& bp
[-1] == ' ')
1261 Strcpy(lets
, bp
); /* necessary since we destroy buf */
1262 if (foo
> 5) /* compactify string */
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 */
1279 Sprintf(qbuf
, "What do you want to %s? [*]", word
);
1281 Sprintf(qbuf
, "What do you want to %s? [%s or ?*]", word
, buf
);
1286 ilet
= yn_function(qbuf
, (char *) 0, '\0');
1291 pline("No count allowed with this command.");
1294 ilet
= get_count(NULL
, ilet
, LARGEST_INT
, &tmpcnt
);
1300 if (index(quitchars
, ilet
)) {
1303 return (struct obj
*) 0;
1305 if (ilet
== HANDS_SYM
) { /* '-' */
1307 char *suf
= (char *) 0;
1310 if ((bp
= strstr(buf
, " on the ")) != 0) {
1311 /* rub on the stone[s] */
1315 if ((bp
= strstr(buf
, " or ")) != 0) {
1317 bp
= (rn2(2) ? buf
: (bp
+ 4));
1320 You("mime %s something%s%s.", ing_suffix(bp
), 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;
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);
1348 if (ilet
== HANDS_SYM
)
1350 if (ilet
== '\033') {
1353 return (struct obj
*) 0;
1355 if (allowcnt
&& ctmp
>= 0) {
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
)
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
)) {
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
1380 if (cntgiven
&& cnt
<= 0) {
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 */
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.");
1399 context
.botl
= 1; /* May have changed the amount of money */
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 */
1405 You("don't have that object.");
1407 return (struct obj
*) 0;
1409 } else if (cnt
< 0 || otmp
->quan
< cnt
) {
1410 You("don't have that many! You have only %ld.", otmp
->quan
);
1412 return (struct obj
*) 0;
1417 if (!allowall
&& let
&& !index(let
, otmp
->oclass
)
1418 && !(usegold
&& otmp
->oclass
== COIN_CLASS
)) {
1419 silly_thing(word
, otmp
);
1420 return (struct obj
*) 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
;
1438 silly_thing(word
, otmp
)
1442 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1445 const char *s1
, *s2
, *s3
;
1446 int ocls
= otmp
->oclass
, otyp
= otmp
->otyp
;
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
= "";
1465 pline("Use the '%s' command to %s %s%s.", s1
, s2
,
1466 !is_plural(otmp
) ? "that" : "those", s3
);
1469 pline(silly_thing_to
, word
);
1476 /* use allow_category() from pickup.c */
1477 return (int) allow_category(otmp
);
1484 return (otmp
->unpaid
|| (Has_contents(otmp
) && count_unpaid(otmp
->cobj
)));
1490 return (boolean
) (uarm
|| uarmc
|| uarmf
|| uarmg
1491 || uarmh
|| uarms
|| uarmu
);
1498 return (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_SADDLE
| W_WEAPON
))
1503 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1504 STATIC_VAR
struct xprnctx
{
1509 /* safe_qbuf() -> short_oname() callback */
1514 return xprname(obj
, (char *) 0, safeq_xprn_ctx
.let
, safeq_xprn_ctx
.dot
,
1518 /* alternate safe_qbuf() -> short_oname() callback */
1520 safeq_shortxprname(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
,
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
)
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
;
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
];
1552 takeoff
= ident
= allflag
= m_seen
= FALSE
;
1554 You("have nothing to %s.", word
);
1557 add_valid_menu_class(0); /* reset */
1558 if (taking_off(word
)) {
1561 } else if (!strcmp(word
, "identify")) {
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
++] = ' ';
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';
1584 ilets
[iletct
++] = 'a';
1585 } else if (takeoff
&& invent
) {
1586 ilets
[iletct
++] = ' ';
1588 ilets
[iletct
++] = 'i';
1590 ilets
[iletct
++] = 'm'; /* allow menu presentation on request */
1591 ilets
[iletct
] = '\0';
1594 Sprintf(qbuf
, "What kinds of thing do you want to %s? [%s]", word
,
1597 if (buf
[0] == '\033')
1599 if (index(buf
, 'i')) {
1600 if (display_inventory((char *) 0, TRUE
) == '\033')
1606 extra_removeables
[0] = '\0';
1608 /* arbitrary types of items can be placed in the weapon slots
1609 [any duplicate entries in extra_removeables[] won't matter] */
1611 (void) strkitten(extra_removeables
, uwep
->oclass
);
1613 (void) strkitten(extra_removeables
, uswapwep
->oclass
);
1615 (void) strkitten(extra_removeables
, uquiver
->oclass
);
1619 olets
[oletct
= 0] = '\0';
1620 while ((sym
= *ip
++) != '\0') {
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.");
1630 } else if (oc_of_sym
== ARMOR_CLASS
&& !wearing_armor()) {
1633 } else if (oc_of_sym
== WEAPON_CLASS
&& !uwep
&& !uswapwep
1635 You("are not wielding anything.");
1637 } else if (oc_of_sym
== RING_CLASS
&& !uright
&& !uleft
) {
1638 You("are not wearing rings.");
1640 } else if (oc_of_sym
== AMULET_CLASS
&& !uamul
) {
1641 You("are not wearing an amulet.");
1643 } else if (oc_of_sym
== TOOL_CLASS
&& !ublindf
) {
1644 You("are not wearing a blindfold.");
1649 if (oc_of_sym
== COIN_CLASS
&& !combo
) {
1651 } else if (sym
== 'a') {
1653 } else if (sym
== 'A') {
1654 /* same as the default */;
1655 } else if (sym
== 'u') {
1656 add_valid_menu_class('u');
1658 } else if (sym
== 'B') {
1659 add_valid_menu_class('B');
1661 } else if (sym
== 'U') {
1662 add_valid_menu_class('U');
1664 } else if (sym
== 'C') {
1665 add_valid_menu_class('C');
1667 } else if (sym
== 'X') {
1668 add_valid_menu_class('X');
1670 } else if (sym
== 'm') {
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
;
1684 return (allflag
|| (!oletct
&& ckfn
!= ckunpaid
)) ? -2 : -3;
1685 } else if (flags
.menu_style
!= MENU_TRADITIONAL
&& combo
&& !allflag
) {
1688 /* !!!! test gold dropping */
1689 } else if (allowgold
== 2 && !oletct
) {
1690 return 1; /* you dropped gold (or at least tried to) */
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
;
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
;
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
);
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
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
1753 * for (otmp = *objchn; otmp; otmp = otmp2) {
1754 * otmp2 = otmp->nobj;
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) {
1766 if (olets
&& *olets
&& otmp
->oclass
!= *olets
)
1768 if (takeoff
&& !is_worn(otmp
))
1770 if (ident
&& !not_fully_identified(otmp
))
1772 if (ckfn
&& !(*ckfn
)(otmp
))
1775 safeq_xprn_ctx
.let
= ilet
;
1776 safeq_xprn_ctx
.dot
= !nodot
;
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
);
1786 (void) safe_qbuf(qbuf
, qpfx
, "?", otmp
,
1787 ininv
? safeq_xprname
: doname
,
1788 ininv
? safeq_shortxprname
: ansimpleoname
,
1790 sym
= (takeoff
|| ident
|| otmp
->quan
< 2L) ? nyaq(qbuf
)
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). */
1806 if (yn_number
< otmp
->quan
&& splittable(otmp
))
1807 otmp
= splitobj(otmp
, yn_number
);
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
);
1835 /* special case for seffects() */
1841 if (olets
&& *olets
&& *++olets
)
1843 if (!takeoff
&& (dud
|| cnt
))
1844 pline("That was all.");
1845 else if (!dud
&& !cnt
)
1846 pline("No applicable objects.");
1848 bypass_objlist(*objchn
, FALSE
);
1853 * Object identification routines:
1856 /* make an object actually be identified; no display updating */
1858 fully_identify_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 */
1876 fully_identify_obj(otmp
);
1877 prinv((char *) 0, otmp
, 0L);
1881 /* menu of unidentified objects; select and identify up to id_limit of them */
1883 menu_identify(id_limit
)
1886 menu_item
*pick_list
;
1887 int n
, i
, first
= 1, tryct
= 5;
1889 /* assumptions: id_limit > 0 and at least one unID'd item is present */
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
);
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 */
1906 } else if (n
== -2) { /* player used ESC to quit menu */
1908 } else if (n
== -1) { /* no eligible items found */
1909 pline("That was all.");
1911 } else if (!--tryct
) { /* stop re-prompting */
1912 pline1(thats_enough_tries
);
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 */
1922 identify_pack(id_limit
, learning_id
)
1924 boolean learning_id
; /* true if we just read unknown identify scroll */
1926 struct obj
*obj
, *the_obj
;
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
;
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
);
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
);
1950 /* identify up to `id_limit' items */
1952 if (flags
.menu_style
== MENU_TRADITIONAL
)
1954 n
= ggetobj("identify", identify
, id_limit
, FALSE
,
1957 break; /* quit or no eligible items */
1958 } while ((id_limit
-= n
) > 0);
1959 if (n
== 0 || n
< -1)
1960 menu_identify(id_limit
);
1965 /* called when regaining sight; mark inventory objects which were picked
1966 up while blind as now having been seen */
1968 learn_unseen_invent()
1973 return; /* sanity check */
1975 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
1977 continue; /* already seen */
1978 /* set dknown, perhaps bknown (for priest[ess]) */
1981 * If object->eknown gets implemented (see learnwand(zap.c)),
1982 * handle deferred discovery here.
1988 /* should of course only be called for things in invent */
1993 if (!flags
.invlet_constant
) {
1994 obj
->invlet
= NOINVSYM
;
2001 * Print the indicated quantity of the given object. If quan == 0L then use
2002 * the current quantity.
2005 prinv(prefix
, obj
, quan
)
2012 pline("%s%s%s", prefix
, *prefix
? " " : "",
2013 xprname(obj
, (char *) 0, obj_to_let(obj
), TRUE
, 0L, quan
));
2017 xprname(obj
, txt
, let
, dot
, cost
, quan
)
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]; */
2028 static char li
[BUFSZ
];
2030 boolean use_invlet
= (flags
.invlet_constant
2031 && let
!= CONTAINED_SYM
&& let
!= HANDS_SYM
);
2035 savequan
= obj
->quan
;
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 */
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
));
2052 /* ordinary inventory display or pickup message */
2053 Sprintf(li
, "%c - %s%s", (use_invlet
? obj
->invlet
: let
),
2054 (txt
? txt
: doname(obj
)), (dot
? "." : ""));
2057 obj
->quan
= savequan
;
2062 /* the 'i' command */
2066 (void) display_inventory((char *) 0, FALSE
);
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
2079 STATIC_OVL
struct obj
*
2080 find_unpaid(list
, last_found
)
2081 struct obj
*list
, **last_found
;
2088 /* still looking for previous unpaid object */
2089 if (list
== *last_found
)
2090 *last_found
= (struct obj
*) 0;
2092 return ((*last_found
= list
));
2094 if (Has_contents(list
)) {
2095 if ((obj
= find_unpaid(list
->cobj
, last_found
)) != 0)
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
;
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.
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 */
2131 char *invlet
= flags
.inv_order
;
2133 winid win
; /* windows being used */
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
;
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
)))
2172 pline("Not carrying anything.");
2176 /* oxymoron? temporarily assign permanent inventory letters */
2177 if (!flags
.invlet_constant
)
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 */
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)); /* '-' */
2192 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2193 if (!lets
|| otmp
->invlet
== lets
[0])
2196 ret
= message_menu(otmp
->invlet
,
2197 want_reply
? PICK_ONE
: PICK_NONE
,
2198 xprname(otmp
, (char *) 0, lets
[0],
2202 *out_cnt
= -1L; /* select all */
2207 (((flags
.sortloot
== 'f') ? SORTLOOT_LOOT
: SORTLOOT_INVLET
)
2208 | (flags
.sortpack
? SORTLOOT_PACK
: 0)),
2213 if (wizard
&& iflags
.override_ID
) {
2214 char prompt
[QBUFSZ
];
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 */
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
);
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
)),
2246 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2247 doname(otmp
), MENU_UNSELECTED
);
2250 if (flags
.sortpack
) {
2253 if (--invlet
!= venom_inv
) {
2258 end_menu(win
, (char *) 0);
2260 n
= select_menu(win
, want_reply
? PICK_ONE
: PICK_NONE
, &selected
);
2262 ret
= selected
[0].item
.a_char
;
2264 *out_cnt
= selected
[0].count
;
2265 free((genericptr_t
) selected
);
2267 ret
= !n
? '\0' : '\033'; /* cancelled */
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
2280 display_inventory(lets
, want_reply
)
2284 return display_pickinv(lets
, (char *) 0, want_reply
, (long *) 0);
2288 * Show what is current using inventory letters.
2292 display_used_invlets(avoidlet
)
2297 char *invlet
= flags
.inv_order
;
2298 int n
, classcount
, invdone
= 0;
2301 menu_item
*selected
;
2304 win
= create_nhwindow(NHW_MENU
);
2307 any
= zeroany
; /* set all bits to zero */
2309 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2310 ilet
= otmp
->invlet
;
2311 if (ilet
== avoidlet
)
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
),
2323 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2324 doname(otmp
), MENU_UNSELECTED
);
2327 if (flags
.sortpack
&& *++invlet
)
2331 end_menu(win
, "Inventory letters used:");
2333 n
= select_menu(win
, PICK_ONE
, &selected
);
2335 ret
= selected
[0].item
.a_char
;
2336 free((genericptr_t
) selected
);
2338 ret
= !n
? '\0' : '\033'; /* cancelled */
2339 destroy_nhwindow(win
);
2345 * Returns the number of unpaid items within the given list. This includes
2346 * contained objects.
2357 if (Has_contents(list
))
2358 count
+= count_unpaid(list
->cobj
);
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
)
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
)
2382 /* priests always know bless/curse state */
2383 if (Role_if(PM_PRIEST
))
2386 /* check whether this object matches the requested type */
2388 ? (type
== BUC_UNKNOWN
)
2389 : list
->blessed
? (type
== BUC_BLESSED
)
2390 : list
->cursed
? (type
== BUC_CURSED
)
2391 : (type
== BUC_UNCURSED
))
2397 /* similar to count_buc(), but tallies all states at once
2398 rather than looking for a specific type */
2400 tally_BUCX(list
, bcp
, ucp
, ccp
, xcp
, ocp
)
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" */
2410 /* priests always know bless/curse state */
2411 if (Role_if(PM_PRIEST
))
2416 else if (list
->blessed
)
2418 else if (list
->cursed
)
2420 else /* neither blessed nor cursed => uncursed */
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 */
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;
2448 struct obj
*otmp
, *marker
;
2450 char *invlet
= flags
.inv_order
;
2451 int classcount
, count
, num_so_far
;
2454 count
= count_unpaid(invent
);
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
,
2464 iflags
.suppress_price
--;
2468 win
= create_nhwindow(NHW_MENU
);
2470 num_so_far
= 0; /* count of # printed so far */
2471 if (!flags
.invlet_constant
)
2476 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2477 ilet
= otmp
->invlet
;
2479 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2480 if (flags
.sortpack
&& !classcount
) {
2481 putstr(win
, 0, let_to_name(*invlet
, TRUE
, FALSE
));
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
--;
2494 } while (flags
.sortpack
&& (*++invlet
));
2496 if (count
> num_so_far
) {
2497 /* something unpaid is contained */
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
2505 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2506 if (Has_contents(otmp
)) {
2509 marker
= (struct obj
*) 0; /* haven't found any */
2510 while (find_unpaid(otmp
->cobj
, &marker
)) {
2511 totcost
+= cost
= unpaid_cost(marker
, FALSE
);
2514 iflags
.suppress_price
++; /* suppress "(unpaid)" sfx */
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
)));
2527 xprname((struct obj
*) 0, contbuf
, CONTAINED_SYM
,
2528 TRUE
, contcost
, 0L));
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
;
2548 boolean res
= (obj
->oclass
== this_type
);
2550 if (obj
->oclass
!= COIN_CLASS
) {
2551 switch (this_type
) {
2553 res
= (obj
->bknown
&& obj
->blessed
);
2556 res
= (obj
->bknown
&& !(obj
->blessed
|| obj
->cursed
));
2559 res
= (obj
->bknown
&& obj
->cursed
);
2565 break; /* use 'res' as-is */
2571 /* the 'I' command */
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.");
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
;
2607 n
= query_category(prompt
, invent
, i
, &pick_list
, PICK_ONE
);
2610 this_type
= c
= pick_list
[0].item
.a_int
;
2611 free((genericptr_t
) pick_list
);
2615 /* collect a list of classes of objects carried, for use as a prompt
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
++] = ' ';
2624 types
[class_count
++] = 'u';
2626 types
[class_count
++] = 'x';
2628 types
[class_count
++] = 'B';
2630 types
[class_count
++] = 'U';
2632 types
[class_count
++] = 'C';
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';
2640 *extra_types
++ = 'u';
2642 *extra_types
++ = 'x';
2644 *extra_types
++ = 'B';
2646 *extra_types
++ = 'U';
2648 *extra_types
++ = 'C';
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');
2662 clear_nhwindow(WIN_MESSAGE
);
2666 /* only one thing to itemize */
2675 if (c
== 'x' || (c
== 'X' && billx
&& !xcnt
)) {
2677 (void) doinvbill(1);
2679 pline("No used-up objects%s.",
2680 unpaid_count
? " on your shopping bill" : "");
2683 if (c
== 'u' || (c
== 'U' && unpaid_count
&& !ucnt
)) {
2687 You("are not carrying any unpaid objects.");
2691 if (index("BUCX", c
))
2692 oclass
= c
; /* not a class but understood by this_type_only() */
2694 oclass
= def_char_to_objclass(c
); /* change to object class */
2696 if (oclass
== COIN_CLASS
)
2698 if (index(types
, c
) > index(types
, '\033')) {
2699 /* '> ESC' => hidden choice, something known not to be carried */
2700 const char *which
= 0;
2704 which
= "known to be blessed";
2707 which
= "known to be uncursed";
2710 which
= "known to be cursed";
2714 "have no objects whose blessed/uncursed/cursed status is unknown.");
2715 break; /* better phrasing is desirable */
2721 You("have no %s objects.", which
);
2726 if (query_objlist((char *) 0, &invent
,
2727 ((flags
.invlet_constant
? USE_INVLET
: 0)
2729 &pick_list
, PICK_NONE
, this_type_only
) > 0)
2730 free((genericptr_t
) pick_list
);
2734 /* return a string describing the dungeon feature at <x,y> if there
2735 is one worth mentioning at that location; otherwise null */
2737 dfeature_at(x
, y
, 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
) {
2750 break; /* "doorway" */
2753 break; /* "open door" */
2755 dfeature
= "broken door";
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
)))
2783 align_str(Amask2align(lev
->altarmask
& ~AM_SHRINE
)));
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";
2807 dfeature
= defsyms
[cmap
].explanation
;
2809 Strcpy(buf
, 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
;
2822 const char *verb
= Blind
? "feel" : "see";
2823 const char *dfeature
= (char *) 0;
2824 char fbuf
[BUFSZ
], fbuf2
[BUFSZ
];
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",
2839 otmp
= mtmp
->minvent
;
2841 for (; otmp
; otmp
= otmp
->nobj
) {
2842 /* If swallower is an animal, it should have become stone
2844 if (otmp
->otyp
== CORPSE
)
2845 feel_cockatrice(otmp
, FALSE
);
2848 Strcpy(fbuf
, "You feel");
2850 (void) display_minventory(mtmp
, MINV_ALL
, fbuf
);
2852 You("%s no objects here.", verb
);
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
)
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.");
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
))
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!");
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
)) {
2897 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2898 if (!skip_objects
&& (Blind
|| !dfeature
))
2899 You("%s no objects here.", verb
);
2902 /* we know there is something here */
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");
2911 There("are %s%s objects here.",
2917 picked_some
? " more" : "");
2918 for (; otmp
; otmp
= otmp
->nexthere
)
2919 if (otmp
->otyp
== CORPSE
&& will_feel_cockatrice(otmp
, FALSE
)) {
2926 corpse_xname(otmp
, (const char *) 0, CXN_ARTICLE
),
2927 poly_when_stoned(youmonst
.data
)
2929 : ", unfortunately");
2930 feel_cockatrice(otmp
, FALSE
);
2933 } else if (!otmp
->nexthere
) {
2934 /* only one object */
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
);
2945 display_nhwindow(WIN_MESSAGE
, FALSE
);
2946 tmpwin
= create_nhwindow(NHW_MENU
);
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
);
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 */
2973 /* the ':' command - explicitly look at what is here, including all objects */
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
);
2990 will_feel_cockatrice(otmp
, force_touch
)
2992 boolean force_touch
;
2994 if ((Blind
|| force_touch
) && !uarmg
&& !Stone_resistance
2995 && (otmp
->otyp
== CORPSE
&& touch_petrifies(&mons
[otmp
->corpsenm
])))
3001 feel_cockatrice(otmp
, force_touch
)
3003 boolean force_touch
;
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
)));
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 */
3029 for (otmp
= level
.objects
[obj
->ox
][obj
->oy
]; otmp
; otmp
= otmp
->nexthere
)
3030 if (otmp
!= obj
&& merged(&obj
, &otmp
))
3035 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3038 register struct obj
*otmp
, *obj
;
3040 int objnamelth
= 0, otmpnamelth
= 0;
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 */
3049 /* coins of the same kind will always merge */
3050 if (obj
->oclass
== COIN_CLASS
)
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
)
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
))
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
)
3076 if ((obj
->oclass
== WEAPON_CLASS
|| obj
->oclass
== ARMOR_CLASS
)
3077 && (obj
->oerodeproof
!= otmp
->oerodeproof
3078 || obj
->rknown
!= otmp
->rknown
))
3081 if (obj
->otyp
== CORPSE
|| obj
->otyp
== EGG
|| obj
->otyp
== TIN
) {
3082 if (obj
->corpsenm
!= otmp
->corpsenm
)
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
])))
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)
3097 /* burning potions of oil never merge */
3098 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
)
3101 /* don't merge surcharged item with base-cost item */
3102 if (obj
->unpaid
&& !same_price(obj
, otmp
))
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
)))
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
))
3119 if (obj
->oartifact
!= otmp
->oartifact
)
3122 if (obj
->known
== otmp
->known
|| !objects
[otmp
->otyp
].oc_uses_known
) {
3123 return (boolean
) objects
[obj
->otyp
].oc_merge
;
3128 /* the '$' command */
3132 /* the messages used to refer to "carrying gold", but that didn't
3133 take containers into account */
3134 long umoney
= money_cnt(invent
);
3136 Your("wallet is empty.");
3138 Your("wallet contains %ld %s.", umoney
, currency(umoney
));
3139 shopper_financial_report();
3143 /* the ')' command */
3148 You("are empty %s.", body_part(HANDED
));
3150 prinv((char *) 0, uwep
, 0L);
3152 prinv((char *) 0, uswapwep
, 0L);
3157 /* caller is responsible for checking !wearing_armor() */
3159 noarmor(report_uskin
)
3160 boolean report_uskin
;
3162 if (!uskin
|| !report_uskin
) {
3163 You("are not wearing any armor.");
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))
3172 if ((p
= strstri(uskinname
, " dragon ")) != 0)
3173 while ((p
[1] = p
[8]) != '\0')
3176 You("are not wearing armor but have %s embedded in your skin.",
3181 /* the '[' command */
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()) {
3197 lets
[ct
++] = obj_to_let(uarmu
);
3199 lets
[ct
++] = obj_to_let(uarm
);
3201 lets
[ct
++] = obj_to_let(uarmc
);
3203 lets
[ct
++] = obj_to_let(uarmh
);
3205 lets
[ct
++] = obj_to_let(uarms
);
3207 lets
[ct
++] = obj_to_let(uarmg
);
3209 lets
[ct
++] = obj_to_let(uarmf
);
3211 (void) display_inventory(lets
, FALSE
);
3216 /* the '=' command */
3220 if (!uleft
&& !uright
)
3221 You("are not wearing any rings.");
3224 register int ct
= 0;
3227 lets
[ct
++] = obj_to_let(uleft
);
3229 lets
[ct
++] = obj_to_let(uright
);
3231 (void) display_inventory(lets
, FALSE
);
3236 /* the '"' command */
3241 You("are not wearing an amulet.");
3243 prinv((char *) 0, uamul
, 0L);
3251 if ((obj
->owornmask
& (W_TOOL
| W_SADDLE
)) != 0L)
3253 if (obj
->oclass
!= TOOL_CLASS
)
3255 return (boolean
) (obj
== uwep
|| obj
->lamplit
3256 || (obj
->otyp
== LEASH
&& obj
->leashmon
));
3259 /* the '(' command */
3267 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3268 if (tool_in_use(otmp
))
3269 lets
[ct
++] = obj_to_let(otmp
);
3272 You("are not using any tools.");
3274 (void) display_inventory(lets
, FALSE
);
3278 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3279 show inventory of all currently wielded, worn, or used objects */
3287 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3288 if (is_worn(otmp
) || tool_in_use(otmp
))
3289 lets
[ct
++] = obj_to_let(otmp
);
3292 You("are not wearing or wielding anything.");
3294 (void) display_inventory(lets
, FALSE
);
3299 * uses up an object that's on the floor, charging for it as necessary
3302 useupf(obj
, numused
)
3303 register struct obj
*obj
;
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
);
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
);
3319 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
, FALSE
);
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;
3344 let_to_name(let
, unpaid
, showsym
)
3346 boolean unpaid
, showsym
;
3348 const char *ocsymfmt
= " ('%c')";
3349 const int invbuf_sympadding
= 8; /* arbitrary */
3350 const char *class_name
;
3352 int oclass
= (let
>= 1 && let
< MAXOCLASSES
) ? let
: 0;
3356 class_name
= names
[oclass
];
3357 else if ((pos
= index(oth_symbols
, let
)) != 0)
3358 class_name
= oth_names
[pos
- oth_symbols
];
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
) {
3366 free((genericptr_t
) invbuf
);
3367 invbufsiz
= len
+ 10; /* add slop to reduce incremental realloc */
3368 invbuf
= (char *) alloc(invbufsiz
);
3371 Strcat(strcpy(invbuf
, "Unpaid "), class_name
);
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) {
3382 Sprintf(eos(invbuf
), ocsymfmt
, def_oc_syms
[oclass
].sym
);
3387 /* release the static buffer used by let_to_name() */
3392 free((genericptr_t
) invbuf
), invbuf
= (char *) 0;
3396 /* give consecutive letters to every item in inventory (for !fixinv mode);
3397 gold is always forced to '$' slot at head of list */
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
) {
3410 prevobj
->nobj
= goldobj
->nobj
;
3412 invent
= goldobj
->nobj
;
3415 /* second, re-letter the rest of the list */
3416 for (obj
= invent
, i
= 0; obj
; obj
= obj
->nobj
, i
++)
3418 (i
< 26) ? ('a' + i
) : (i
< 52) ? ('A' + i
- 26) : NOINVSYM
;
3419 /* third, assign gold the "letter" '$' and re-insert it at head */
3421 goldobj
->invlet
= GOLD_SYM
;
3422 goldobj
->nobj
= invent
;
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
;
3460 char alphabet
[52 + 1], buf
[52 + 1];
3462 char allowall
[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3463 const char *adj_type
;
3466 You("aren't carrying anything to adjust.");
3470 if (!flags
.invlet_constant
)
3472 /* get object the user wants to organize (the 'from' slot) */
3473 allowall
[0] = ALLOW_COUNT
;
3474 allowall
[1] = ALL_CLASSES
;
3476 if (!(obj
= getobj(allowall
, "adjust")))
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
)
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
)) {
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
;
3516 /* and by dashing runs of letters */
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);
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
)) {
3539 (void) merged(&splitting
, &obj
);
3543 if ((letter(let
) && let
!= '@') || index(buf
, let
))
3544 break; /* got one */
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
;) {
3561 if (merged(&otmp
, &obj
)) {
3562 adj_type
= "Merging:";
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
;
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
) {
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;
3592 free((genericptr_t
) holdname
);
3595 if (merged(&otmp
, &obj
)) {
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.");
3605 extract_nobj(bumped
, &invent
);
3608 } /* found 'to' slot */
3613 /* inline addinv; insert loose object at beginning of inventory */
3616 obj
->where
= OBJ_INVENT
;
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
;
3630 /* messages deferred until inventory has been fully reestablished */
3631 prinv(adj_type
, obj
, 0L);
3633 prinv("Moving:", bumped
, 0L);
3635 clear_splitobjs(); /* reset splitobj context */
3640 /* common to display_minventory and display_cinventory */
3642 invdisp_nothing(hdr
, txt
)
3643 const char *hdr
, *txt
;
3647 menu_item
*selected
;
3650 win
= create_nhwindow(NHW_MENU
);
3652 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, hdr
,
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
);
3663 /* query_objlist callback: return things that are worn or wielded */
3665 worn_wield_only(obj
)
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);
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
)
3677 return (boolean
) (obj
->oclass
== WEAPON_CLASS
3678 || obj
->oclass
== ARMOR_CLASS
3679 || obj
->oclass
== AMULET_CLASS
3680 || obj
->oclass
== RING_CLASS
);
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
3696 display_minventory(mon
, dflags
, title
)
3697 register struct monst
*mon
;
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)),
3721 (dflags
& MINV_NOLET
) ? PICK_NONE
: PICK_ONE
,
3722 do_all
? allow_all
: worn_wield_only
);
3726 invdisp_nothing(title
? title
: tmp
, "(none)");
3731 ret
= selected
[0].item
.a_obj
;
3732 free((genericptr_t
) selected
);
3734 ret
= (struct obj
*) 0;
3739 * Display the contents of a container in inventory style.
3740 * Currently, this is only used for statues, via wand of probing.
3743 display_cinventory(obj
)
3744 register struct obj
*obj
;
3749 menu_item
*selected
= 0;
3751 (void) safe_qbuf(qbuf
, "Contents of ", ":", obj
, doname
, ansimpleoname
,
3755 n
= query_objlist(qbuf
, &(obj
->cobj
), INVORDER_SORT
,
3756 &selected
, PICK_NONE
, allow_all
);
3758 invdisp_nothing(qbuf
, "(empty)");
3762 ret
= selected
[0].item
.a_obj
;
3763 free((genericptr_t
) selected
);
3765 ret
= (struct obj
*) 0;
3770 /* query objlist callback: return TRUE if obj is at given location */
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
)
3792 menu_item
*selected
= 0;
3795 /* count # of objects here */
3796 for (n
= 0, obj
= level
.buriedobjlist
; obj
; obj
= obj
->nobj
)
3797 if (obj
->ox
== x
&& obj
->oy
== 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;