1 /* NetHack 3.6 invent.c $NHDT-Date: 1472809075 2016/09/02 09:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.210 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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(taking_off
, (const char *));
20 STATIC_DCL boolean
FDECL(putting_on
, (const char *));
21 STATIC_PTR
int FDECL(ckunpaid
, (struct obj
*));
22 STATIC_PTR
int FDECL(ckvalidcat
, (struct obj
*));
23 STATIC_PTR
char *FDECL(safeq_xprname
, (struct obj
*));
24 STATIC_PTR
char *FDECL(safeq_shortxprname
, (struct obj
*));
25 STATIC_DCL
char FDECL(display_pickinv
, (const char *, const char *,
27 STATIC_DCL
char FDECL(display_used_invlets
, (CHAR_P
));
28 STATIC_DCL
void FDECL(tally_BUCX
, (struct obj
*,
29 int *, int *, int *, int *, int *));
30 STATIC_DCL boolean
FDECL(this_type_only
, (struct obj
*));
31 STATIC_DCL
void NDECL(dounpaid
);
32 STATIC_DCL
struct obj
*FDECL(find_unpaid
, (struct obj
*, struct obj
**));
33 STATIC_DCL
void FDECL(menu_identify
, (int));
34 STATIC_DCL boolean
FDECL(tool_in_use
, (struct obj
*));
35 STATIC_DCL
char FDECL(obj_to_let
, (struct obj
*));
37 static int lastinvnr
= 51; /* 0 ... 51 (never saved&restored) */
39 /* wizards can wish for venom, which will become an invisible inventory
40 * item without this. putting it in inv_order would mean venom would
41 * suddenly become a choice for all the inventory-class commands, which
42 * would probably cause mass confusion. the test for inventory venom
43 * is only WIZARD and not wizard because the wizard can leave venom lying
44 * around on a bones level for normal players to find. [Note to the
45 * confused: 'WIZARD' used to be a compile-time conditional so this was
46 * guarded by #ifdef WIZARD/.../#endif.]
48 static char venom_inv
[] = { VENOM_CLASS
, 0 }; /* (constant) */
50 struct sortloot_item
{
54 unsigned sortlootmode
= 0;
56 /* qsort comparison routine for sortloot() */
57 STATIC_OVL
int CFDECLSPEC
58 sortloot_cmp(vptr1
, vptr2
)
59 const genericptr vptr1
;
60 const genericptr vptr2
;
62 struct sortloot_item
*sli1
= (struct sortloot_item
*) vptr1
,
63 *sli2
= (struct sortloot_item
*) vptr2
;
64 struct obj
*obj1
= sli1
->obj
,
67 char *cls1
, *cls2
, nam1
[BUFSZ
], nam2
[BUFSZ
];
68 int val1
, val2
, c
, namcmp
;
70 /* order by object class like inventory display */
71 if ((sortlootmode
& SORTLOOT_PACK
) != 0) {
72 cls1
= index(flags
.inv_order
, obj1
->oclass
);
73 cls2
= index(flags
.inv_order
, obj2
->oclass
);
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)
143 * Sort object names in lexicographical order, ignoring quantity.
145 /* Force diluted potions to come out after undiluted of same type;
146 obj->odiluted overloads obj->oeroded. */
147 sav1
.odiluted
= obj1
->odiluted
;
148 sav2
.odiluted
= obj2
->odiluted
;
149 if (obj1
->oclass
== POTION_CLASS
)
151 if (obj1
->oclass
== POTION_CLASS
)
153 /* Force holy and unholy water to sort adjacent to water rather
154 than among 'h's and 'u's. BUCX order will keep them distinct. */
155 Strcpy(nam1
, cxname_singular(obj1
));
156 if (obj1
->otyp
== POT_WATER
&& obj1
->bknown
157 && (obj1
->blessed
|| obj1
->cursed
))
158 (void) strsubst(nam1
, obj1
->blessed
? "holy " : "unholy ", "");
159 Strcpy(nam2
, cxname_singular(obj2
));
160 if (obj2
->otyp
== POT_WATER
&& obj2
->bknown
161 && (obj2
->blessed
|| obj2
->cursed
))
162 (void) strsubst(nam2
, obj2
->blessed
? "holy " : "unholy ", "");
163 obj1
->odiluted
= sav1
.odiluted
;
164 obj2
->odiluted
= sav2
.odiluted
;
166 if ((namcmp
= strcmpi(nam1
, nam2
)) != 0)
169 /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and
172 ? (obj1
->blessed
<< 2)
173 + ((!obj1
->blessed
&& !obj1
->cursed
) << 1) + obj1
->cursed
176 ? (obj2
->blessed
<< 2)
177 + ((!obj2
->blessed
&& !obj2
->cursed
) << 1) + obj2
->cursed
180 return val2
- val1
; /* bigger is better */
182 /* Sort by greasing. This will put the objects in degreasing order. */
183 val1
= obj1
->greased
;
184 val2
= obj2
->greased
;
186 return val2
- val1
; /* bigger is better */
188 /* Sort by erosion. The effective amount is what matters. */
189 val1
= greatest_erosion(obj1
);
190 val2
= greatest_erosion(obj2
);
192 return val1
- val2
; /* bigger is WORSE */
194 /* Sort by erodeproofing. Map known-invulnerable to 1, and both
195 known-vulnerable and unknown-vulnerability to 0, because that's
196 how they're displayed. */
197 val1
= obj1
->rknown
&& obj1
->oerodeproof
;
198 val2
= obj2
->rknown
&& obj2
->oerodeproof
;
200 return val2
- val1
; /* bigger is better */
202 /* Sort by enchantment. Map unknown to -1000, which is comfortably
203 below the range of obj->spe. oc_uses_known means that obj->known
204 matters, which usually indirectly means that obj->spe is relevant.
205 Lots of objects use obj->spe for some other purpose (see obj.h). */
206 if (objects
[obj1
->otyp
].oc_uses_known
207 /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
208 && obj1
->oclass
!= FOOD_CLASS
) {
209 val1
= obj1
->known
? obj1
->spe
: -1000;
210 val2
= obj2
->known
? obj2
->spe
: -1000;
212 return val2
- val1
; /* bigger is better */
216 /* They're identical, as far as we're concerned. We want
217 to force a deterministic order, and do so by producing a
218 stable sort: maintain the original order of equal items. */
219 return (sli2
->indx
- sli1
->indx
);
223 sortloot(olist
, mode
, by_nexthere
)
225 unsigned mode
; /* flags for sortloot_cmp() */
226 boolean by_nexthere
; /* T: traverse via obj->nexthere, F: via obj->nobj */
228 struct sortloot_item
*sliarray
, osli
, nsli
;
229 struct obj
*o
, **nxt_p
;
231 boolean already_sorted
= TRUE
;
233 sortlootmode
= mode
; /* extra input for sortloot_cmp() */
234 for (n
= osli
.indx
= 0, osli
.obj
= *olist
; (o
= osli
.obj
) != 0;
236 nsli
.obj
= by_nexthere
? o
->nexthere
: o
->nobj
;
237 nsli
.indx
= (int) ++n
;
238 if (nsli
.obj
&& already_sorted
239 && sortloot_cmp((genericptr_t
) &osli
, (genericptr_t
) &nsli
) > 0)
240 already_sorted
= FALSE
;
242 if (n
> 1 && !already_sorted
) {
243 sliarray
= (struct sortloot_item
*) alloc(n
* sizeof *sliarray
);
244 for (i
= 0, o
= *olist
; o
;
245 ++i
, o
= by_nexthere
? o
->nexthere
: o
->nobj
)
246 sliarray
[i
].obj
= o
, sliarray
[i
].indx
= (int) i
;
248 qsort((genericptr_t
) sliarray
, n
, sizeof *sliarray
, sortloot_cmp
);
249 for (i
= 0; i
< n
; ++i
) {
251 nxt_p
= by_nexthere
? &(o
->nexthere
) : &(o
->nobj
);
252 *nxt_p
= (i
< n
- 1) ? sliarray
[i
+ 1].obj
: (struct obj
*) 0;
254 *olist
= sliarray
[0].obj
;
255 free((genericptr_t
) sliarray
);
262 register struct obj
*otmp
;
266 register struct obj
*obj
;
268 /* there should be at most one of these in inventory... */
269 if (otmp
->oclass
== COIN_CLASS
) {
270 otmp
->invlet
= GOLD_SYM
;
274 for (i
= 0; i
< 52; i
++)
276 for (obj
= invent
; obj
; obj
= obj
->nobj
)
279 if ('a' <= i
&& i
<= 'z')
280 inuse
[i
- 'a'] = TRUE
;
281 else if ('A' <= i
&& i
<= 'Z')
282 inuse
[i
- 'A' + 26] = TRUE
;
283 if (i
== otmp
->invlet
)
286 if ((i
= otmp
->invlet
)
287 && (('a' <= i
&& i
<= 'z') || ('A' <= i
&& i
<= 'Z')))
289 for (i
= lastinvnr
+ 1; i
!= lastinvnr
; i
++) {
298 (inuse
[i
] ? NOINVSYM
: (i
< 26) ? ('a' + i
) : ('A' + i
- 26));
302 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
303 #define inv_rank(o) ((o)->invlet ^ 040)
305 /* sort the inventory; used by addinv() and doorganize() */
309 struct obj
*otmp
, *prev
, *next
;
310 boolean need_more_sorting
;
314 * We expect at most one item to be out of order, so this
315 * isn't nearly as inefficient as it may first appear.
317 need_more_sorting
= FALSE
;
318 for (otmp
= invent
, prev
= 0; otmp
;) {
320 if (next
&& inv_rank(next
) < inv_rank(otmp
)) {
321 need_more_sorting
= TRUE
;
326 otmp
->nobj
= next
->nobj
;
334 } while (need_more_sorting
);
339 /* scan a list of objects to see whether another object will merge with
340 one of them; used in pickup.c when all 52 inventory slots are in use,
341 to figure out whether another object could still be picked up */
343 merge_choice(objlist
, obj
)
344 struct obj
*objlist
, *obj
;
349 if (obj
->otyp
== SCR_SCARE_MONSTER
) /* punt on these */
350 return (struct obj
*) 0;
351 /* if this is an item on the shop floor, the attributes it will
352 have when carried are different from what they are now; prevent
353 that from eliciting an incorrect result from mergable() */
354 save_nocharge
= obj
->no_charge
;
355 if (objlist
== invent
&& obj
->where
== OBJ_FLOOR
356 && (shkp
= shop_keeper(inside_shop(obj
->ox
, obj
->oy
))) != 0) {
359 /* A billable object won't have its `unpaid' bit set, so would
360 erroneously seem to be a candidate to merge with a similar
361 ordinary object. That's no good, because once it's really
362 picked up, it won't merge after all. It might merge with
363 another unpaid object, but we can't check that here (depends
364 too much upon shk's bill) and if it doesn't merge it would
365 end up in the '#' overflow inventory slot, so reject it now. */
366 else if (inhishop(shkp
))
367 return (struct obj
*) 0;
370 if (mergable(objlist
, obj
))
372 objlist
= objlist
->nobj
;
374 obj
->no_charge
= save_nocharge
;
378 /* merge obj with otmp and delete obj if types agree */
381 struct obj
**potmp
, **pobj
;
383 register struct obj
*otmp
= *potmp
, *obj
= *pobj
;
385 if (mergable(otmp
, obj
)) {
386 /* Approximate age: we do it this way because if we were to
387 * do it "accurately" (merge only when ages are identical)
388 * we'd wind up never merging any corpses.
389 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
391 * Don't do the age manipulation if lit. We would need
392 * to stop the burn on both items, then merge the age,
393 * then restart the burn. Glob ages are averaged in the
394 * absorb routine, which uses weight rather than quantity
395 * to adjust for proportion (glob quantity is always 1).
397 if (!obj
->lamplit
&& !obj
->globby
)
398 otmp
->age
= ((otmp
->age
* otmp
->quan
) + (obj
->age
* obj
->quan
))
399 / (otmp
->quan
+ obj
->quan
);
401 otmp
->quan
+= obj
->quan
;
402 /* temporary special case for gold objects!!!! */
403 if (otmp
->oclass
== COIN_CLASS
)
404 otmp
->owt
= weight(otmp
);
405 /* and puddings!!!1!!one! */
406 else if (!Is_pudding(otmp
))
407 otmp
->owt
+= obj
->owt
;
408 if (!has_oname(otmp
) && has_oname(obj
))
409 otmp
= *potmp
= oname(otmp
, ONAME(obj
));
410 obj_extract_self(obj
);
412 /* really should merge the timeouts */
414 obj_merge_light_sources(obj
, otmp
);
416 obj_stop_timers(obj
); /* follows lights */
418 /* fixup for `#adjust' merging wielded darts, daggers, &c */
419 if (obj
->owornmask
&& carried(otmp
)) {
420 long wmask
= otmp
->owornmask
| obj
->owornmask
;
422 /* Both the items might be worn in competing slots;
423 merger preference (regardless of which is which):
424 primary weapon + alternate weapon -> primary weapon;
425 primary weapon + quiver -> primary weapon;
426 alternate weapon + quiver -> alternate weapon.
427 (Prior to 3.3.0, it was not possible for the two
428 stacks to be worn in different slots and `obj'
429 didn't need to be unworn when merging.) */
432 else if (wmask
& W_SWAPWEP
)
434 else if (wmask
& W_QUIVER
)
437 impossible("merging strangely worn items (%lx)", wmask
);
438 wmask
= otmp
->owornmask
;
440 if ((otmp
->owornmask
& ~wmask
) != 0L)
442 setworn(otmp
, wmask
);
445 /* (this should not be necessary, since items
446 already in a monster's inventory don't ever get
447 merged into other objects [only vice versa]) */
448 } else if (obj
->owornmask
&& mcarried(otmp
)) {
449 if (obj
== MON_WEP(otmp
->ocarry
)) {
450 MON_WEP(otmp
->ocarry
) = otmp
;
451 otmp
->owornmask
= W_WEP
;
456 /* handle puddings a bit differently; absorption will free the
457 other object automatically so we can just return out from here */
459 pudding_merge_message(otmp
, obj
);
460 obj_absorb(potmp
, pobj
);
464 obfree(obj
, otmp
); /* free(obj), bill->otmp */
471 * Adjust hero intrinsics as if this object was being added to the hero's
472 * inventory. Called _before_ the object has been added to the hero's
475 * This is called when adding objects to the hero's inventory normally (via
476 * addinv) or when an object in the hero's inventory has been polymorphed
479 * It may be valid to merge this code with with addinv_core2().
485 if (obj
->oclass
== COIN_CLASS
) {
487 } else if (obj
->otyp
== AMULET_OF_YENDOR
) {
489 impossible("already have amulet?");
491 u
.uachieve
.amulet
= 1;
492 } else if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
494 impossible("already have candelabrum?");
496 u
.uachieve
.menorah
= 1;
497 } else if (obj
->otyp
== BELL_OF_OPENING
) {
499 impossible("already have silver bell?");
502 } else if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
504 impossible("already have the book?");
507 } else if (obj
->oartifact
) {
508 if (is_quest_artifact(obj
)) {
509 if (u
.uhave
.questart
)
510 impossible("already have quest artifact?");
511 u
.uhave
.questart
= 1;
514 set_artifact_intrinsic(obj
, 1, W_ART
);
516 if (obj
->otyp
== LUCKSTONE
&& obj
->record_achieve_special
) {
517 u
.uachieve
.mines_luckstone
= 1;
518 obj
->record_achieve_special
= 0;
519 } else if ((obj
->otyp
== AMULET_OF_REFLECTION
520 || obj
->otyp
== BAG_OF_HOLDING
)
521 && obj
->record_achieve_special
) {
522 u
.uachieve
.finish_sokoban
= 1;
523 obj
->record_achieve_special
= 0;
528 * Adjust hero intrinsics as if this object was being added to the hero's
529 * inventory. Called _after_ the object has been added to the hero's
532 * This is called when adding objects to the hero's inventory normally (via
533 * addinv) or when an object in the hero's inventory has been polymorphed
540 if (confers_luck(obj
)) {
541 /* new luckstone must be in inventory by this point
542 * for correct calculation */
548 * Add obj to the hero's inventory. Make sure the object is "free".
549 * Adjust hero attributes as necessary.
555 struct obj
*otmp
, *prev
;
556 int saved_otyp
= (int) obj
->otyp
; /* for panic */
557 boolean obj_was_thrown
;
559 if (obj
->where
!= OBJ_FREE
)
560 panic("addinv: obj not free");
561 /* normally addtobill() clears no_charge when items in a shop are
562 picked up, but won't do so if the shop has become untended */
563 obj
->no_charge
= 0; /* should not be set in hero's invent */
564 if (Has_contents(obj
))
565 picked_container(obj
); /* clear no_charge */
566 obj_was_thrown
= obj
->was_thrown
;
567 obj
->was_thrown
= 0; /* not meaningful for invent */
571 /* merge with quiver in preference to any other inventory slot
572 in case quiver and wielded weapon are both eligible; adding
573 extra to quivered stack is more useful than to wielded one */
574 if (uquiver
&& merged(&uquiver
, &obj
)) {
577 panic("addinv: null obj after quiver merge otyp=%d", saved_otyp
);
580 /* merge if possible; find end of chain in the process */
581 for (prev
= 0, otmp
= invent
; otmp
; prev
= otmp
, otmp
= otmp
->nobj
)
582 if (merged(&otmp
, &obj
)) {
585 panic("addinv: null obj after merge otyp=%d", saved_otyp
);
588 /* didn't merge, so insert into chain */
590 if (flags
.invlet_constant
|| !prev
) {
591 obj
->nobj
= invent
; /* insert at beginning */
593 if (flags
.invlet_constant
)
596 prev
->nobj
= obj
; /* insert at end */
599 obj
->where
= OBJ_INVENT
;
601 /* fill empty quiver if obj was thrown */
602 if (flags
.pickup_thrown
&& !uquiver
&& obj_was_thrown
603 && (throwing_weapon(obj
) || is_ammo(obj
)))
607 carry_obj_effects(obj
); /* carrying affects the obj */
613 * Some objects are affected by being carried.
614 * Make those adjustments here. Called _after_ the object
615 * has been added to the hero's or monster's inventory,
616 * and after hero's intrinsics have been updated.
619 carry_obj_effects(obj
)
622 /* Cursed figurines can spontaneously transform
624 if (obj
->otyp
== FIGURINE
) {
625 if (obj
->cursed
&& obj
->corpsenm
!= NON_PM
626 && !dead_species(obj
->corpsenm
, TRUE
)) {
627 attach_fig_transform_timeout(obj
);
632 /* Add an item to the inventory unless we're fumbling or it refuses to be
633 * held (via touch_artifact), and give a message.
634 * If there aren't any free inventory slots, we'll drop it instead.
635 * If both success and failure messages are NULL, then we're just doing the
636 * fumbling/slot-limit checking for a silent grab. In any case,
637 * touch_artifact will print its own messages if they are warranted.
640 hold_another_object(obj
, drop_fmt
, drop_arg
, hold_msg
)
642 const char *drop_fmt
, *drop_arg
, *hold_msg
;
647 obj
->dknown
= 1; /* maximize mergibility */
648 if (obj
->oartifact
) {
649 /* place_object may change these */
650 boolean crysknife
= (obj
->otyp
== CRYSKNIFE
);
651 int oerode
= obj
->oerodeproof
;
652 boolean wasUpolyd
= Upolyd
;
654 /* in case touching this object turns out to be fatal */
655 place_object(obj
, u
.ux
, u
.uy
);
657 if (!touch_artifact(obj
, &youmonst
)) {
658 obj_extract_self(obj
); /* remove it from the floor */
659 dropy(obj
); /* now put it back again :-) */
661 } else if (wasUpolyd
&& !Upolyd
) {
662 /* loose your grip if you revert your form */
664 pline(drop_fmt
, drop_arg
);
665 obj_extract_self(obj
);
669 obj_extract_self(obj
);
671 obj
->otyp
= CRYSKNIFE
;
672 obj
->oerodeproof
= oerode
;
677 pline(drop_fmt
, drop_arg
);
680 long oquan
= obj
->quan
;
681 int prev_encumbr
= near_capacity(); /* before addinv() */
683 /* encumbrance only matters if it would now become worse
684 than max( current_value, stressed ) */
685 if (prev_encumbr
< MOD_ENCUMBER
)
686 prev_encumbr
= MOD_ENCUMBER
;
687 /* addinv() may redraw the entire inventory, overwriting
688 drop_arg when it comes from something like doname() */
690 drop_arg
= strcpy(buf
, drop_arg
);
693 if (inv_cnt(FALSE
) > 52 || ((obj
->otyp
!= LOADSTONE
|| !obj
->cursed
)
694 && near_capacity() > prev_encumbr
)) {
696 pline(drop_fmt
, drop_arg
);
697 /* undo any merge which took place */
698 if (obj
->quan
> oquan
)
699 obj
= splitobj(obj
, oquan
);
702 if (flags
.autoquiver
&& !uquiver
&& !obj
->owornmask
703 && (is_missile(obj
) || ammo_and_launcher(obj
, uwep
)
704 || ammo_and_launcher(obj
, uswapwep
)))
706 if (hold_msg
|| drop_fmt
)
707 prinv(hold_msg
, obj
, oquan
);
713 /* useup() all of an item regardless of its quantity */
720 obfree(obj
, (struct obj
*) 0); /* deletes contents also */
725 register struct obj
*obj
;
727 /* Note: This works correctly for containers because they (containers)
729 if (obj
->quan
> 1L) {
730 obj
->in_use
= FALSE
; /* no longer in use */
732 obj
->owt
= weight(obj
);
739 /* use one charge from an item and possibly incur shop debt for it */
741 consume_obj_charge(obj
, maybe_unpaid
)
743 boolean maybe_unpaid
; /* false if caller handles shop billing */
753 * Adjust hero's attributes as if this object was being removed from the
754 * hero's inventory. This should only be called from freeinv() and
755 * where we are polymorphing an object already in the hero's inventory.
757 * Should think of a better name...
763 if (obj
->oclass
== COIN_CLASS
) {
766 } else if (obj
->otyp
== AMULET_OF_YENDOR
) {
768 impossible("don't have amulet?");
770 } else if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
) {
771 if (!u
.uhave
.menorah
)
772 impossible("don't have candelabrum?");
774 } else if (obj
->otyp
== BELL_OF_OPENING
) {
776 impossible("don't have silver bell?");
778 } else if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
780 impossible("don't have the book?");
782 } else if (obj
->oartifact
) {
783 if (is_quest_artifact(obj
)) {
784 if (!u
.uhave
.questart
)
785 impossible("don't have quest artifact?");
786 u
.uhave
.questart
= 0;
788 set_artifact_intrinsic(obj
, 0, W_ART
);
791 if (obj
->otyp
== LOADSTONE
) {
793 } else if (confers_luck(obj
)) {
796 } else if (obj
->otyp
== FIGURINE
&& obj
->timed
) {
797 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(obj
));
801 /* remove an object from the hero's inventory */
804 register struct obj
*obj
;
806 extract_nobj(obj
, &invent
);
815 struct obj
*otmp
, *otmp2
;
817 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp2
) {
820 /* after unpunish(), or might get deallocated chain */
821 otmp2
= otmp
->nexthere
;
828 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
831 register struct obj
*obj
;
835 if (obj
->otyp
== AMULET_OF_YENDOR
836 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
837 || obj
->otyp
== BELL_OF_OPENING
838 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
839 /* player might be doing something stupid, but we
840 * can't guarantee that. assume special artifacts
841 * are indestructible via drawbridges, and exploding
842 * chests, and golem creation, and ...
846 update_map
= (obj
->where
== OBJ_FLOOR
);
847 obj_extract_self(obj
);
849 newsym(obj
->ox
, obj
->oy
);
850 obfree(obj
, (struct obj
*) 0); /* frees contents also */
853 /* try to find a particular type of object at designated map location */
859 register struct obj
*otmp
;
861 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
)
862 if (otmp
->otyp
== otyp
)
868 /* sobj_at(&c) traversal -- find next object of specified type */
870 nxtobj(obj
, type
, by_nexthere
)
875 register struct obj
*otmp
;
877 otmp
= obj
; /* start with the object after this one */
879 otmp
= !by_nexthere
? otmp
->nobj
: otmp
->nexthere
;
882 } while (otmp
->otyp
!= type
);
891 register struct obj
*otmp
;
893 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
894 if (otmp
->otyp
== type
)
896 return (struct obj
*) 0;
899 /* Fictional and not-so-fictional currencies.
900 * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
902 static const char *const currencies
[] = {
903 "Altarian Dollar", /* The Hitchhiker's Guide to the Galaxy */
904 "Ankh-Morpork Dollar", /* Discworld */
905 "auric", /* The Domination of Draka */
906 "buckazoid", /* Space Quest */
907 "cirbozoid", /* Starslip */
908 "credit chit", /* Deus Ex */
909 "cubit", /* Battlestar Galactica */
910 "Flanian Pobble Bead", /* The Hitchhiker's Guide to the Galaxy */
911 "fretzer", /* Jules Verne */
912 "imperial credit", /* Star Wars */
913 "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
914 "kongbuck", /* Snow Crash */
915 "nanite", /* System Shock 2 */
916 "quatloo", /* Star Trek, Sim City */
917 "simoleon", /* Sim City */
918 "solari", /* Spaceballs */
919 "spacebuck", /* Spaceballs */
920 "sporebuck", /* Spore */
921 "Triganic Pu", /* The Hitchhiker's Guide to the Galaxy */
922 "woolong", /* Cowboy Bebop */
923 "zorkmid", /* Zork, NetHack */
932 res
= Hallucination
? currencies
[rn2(SIZE(currencies
))] : "zorkmid";
934 res
= makeplural(res
);
941 register struct obj
*otmp
;
943 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
944 if (otmp
->otyp
== CORPSE
&& otmp
->corpsenm
== PM_LIZARD
)
953 register struct obj
*otmp
;
955 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
956 if (otmp
->otyp
== SPE_NOVEL
)
958 return (struct obj
*) 0;
964 register struct obj
*objchn
;
969 if (objchn
->o_id
== id
)
971 if (Has_contents(objchn
) && (temp
= o_on(id
, objchn
->cobj
)))
973 objchn
= objchn
->nobj
;
975 return (struct obj
*) 0;
980 register struct obj
*obj
;
983 register struct obj
*otmp
;
985 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
)
995 register struct obj
*obj
= level
.objects
[x
][y
];
998 if (obj
->oclass
== COIN_CLASS
)
1000 obj
= obj
->nexthere
;
1002 return (struct obj
*) 0;
1005 /* compact a string of inventory letters by dashing runs of letters */
1010 register int i1
= 1, i2
= 1;
1011 register char ilet
, ilet1
, ilet2
;
1015 buf
[++i2
] = buf
[++i1
];
1018 if (ilet
== ilet1
+ 1) {
1019 if (ilet1
== ilet2
+ 1)
1020 buf
[i2
- 1] = ilet1
= '-';
1021 else if (ilet2
== '-') {
1022 buf
[i2
- 1] = ++ilet1
;
1023 buf
[i2
] = buf
[++i1
];
1027 } else if (ilet
== NOINVSYM
) {
1028 /* compact three or more consecutive '#'
1029 characters into "#-#" */
1030 if (i2
>= 2 && buf
[i2
- 2] == NOINVSYM
&& buf
[i2
- 1] == NOINVSYM
)
1032 else if (i2
>= 3 && buf
[i2
- 3] == NOINVSYM
&& buf
[i2
- 2] == '-'
1033 && buf
[i2
- 1] == NOINVSYM
)
1038 buf
[++i2
] = buf
[++i1
];
1043 /* some objects shouldn't be split when count given to getobj or askchain */
1048 return !((obj
->otyp
== LOADSTONE
&& obj
->cursed
)
1049 || (obj
== uwep
&& welded(uwep
)));
1052 /* match the prompt for either 'T' or 'R' command */
1057 return !strcmp(action
, "take off") || !strcmp(action
, "remove");
1060 /* match the prompt for either 'W' or 'P' command */
1065 return !strcmp(action
, "wear") || !strcmp(action
, "put on");
1070 * struct obj *xxx: object to do something with.
1071 * (struct obj *) 0 error return: no object.
1072 * &zeroobj explicitly no object (as in w-).
1073 !!!! test if gold can be used in unusual ways (eaten etc.)
1074 !!!! may be able to remove "usegold"
1078 register const char *let
, *word
;
1080 register struct obj
*otmp
;
1082 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
1083 char lets
[BUFSZ
], altlets
[BUFSZ
], *ap
;
1084 register int foo
= 0;
1085 register char *bp
= buf
;
1086 xchar allowcnt
= 0; /* 0, 1 or 2 */
1087 boolean usegold
= FALSE
; /* can't use gold because its illegal */
1088 boolean allowall
= FALSE
;
1089 boolean allownone
= FALSE
;
1090 boolean useboulder
= FALSE
;
1093 boolean cntgiven
= FALSE
;
1096 if (*let
== ALLOW_COUNT
)
1097 let
++, allowcnt
= 1;
1098 if (*let
== COIN_CLASS
)
1099 let
++, usegold
= TRUE
;
1101 /* Equivalent of an "ugly check" for gold */
1102 if (usegold
&& !strcmp(word
, "eat")
1103 && (!metallivorous(youmonst
.data
)
1104 || youmonst
.data
== &mons
[PM_RUST_MONSTER
]))
1107 if (*let
== ALL_CLASSES
)
1108 let
++, allowall
= TRUE
;
1109 if (*let
== ALLOW_NONE
)
1110 let
++, allownone
= TRUE
;
1111 /* "ugly check" for reading fortune cookies, part 1.
1112 * The normal 'ugly check' keeps the object on the inventory list.
1113 * We don't want to do that for shirts/cookies, so the check for
1114 * them is handled a bit differently (and also requires that we set
1115 * allowall in the caller).
1117 if (allowall
&& !strcmp(word
, "read"))
1120 /* another ugly check: show boulders (not statues) */
1121 if (*let
== WEAPON_CLASS
&& !strcmp(word
, "throw")
1122 && throws_rocks(youmonst
.data
))
1126 *bp
++ = HANDS_SYM
, *bp
++ = ' '; /* '-' */
1129 if (!flags
.invlet_constant
)
1132 /* in case invent is in packorder, force it to be in invlet
1133 order before collecing candidate inventory letters;
1134 if player responds with '?' or '*' it will be changed
1135 back by display_pickinv(), but by then we'll have 'lets'
1136 and so won't have to re-sort in the for(;;) loop below */
1137 sortloot(&invent
, SORTLOOT_INVLET
, FALSE
);
1139 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
1140 if (&bp
[foo
] == &buf
[sizeof buf
- 1]
1141 || ap
== &altlets
[sizeof altlets
- 1]) {
1142 /* we must have a huge number of NOINVSYM items somehow */
1143 impossible("getobj: inventory overflow");
1147 if (!*let
|| index(let
, otmp
->oclass
)
1148 || (usegold
&& otmp
->invlet
== GOLD_SYM
)
1149 || (useboulder
&& otmp
->otyp
== BOULDER
)) {
1150 register int otyp
= otmp
->otyp
;
1152 bp
[foo
++] = otmp
->invlet
;
1153 /* clang-format off */
1155 /* ugly check: remove inappropriate things */
1157 (taking_off(word
) /* exclude if not worn */
1158 && !(otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
)))
1159 || (putting_on(word
) /* exclude if already worn */
1160 && (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
)))
1161 #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
1162 || (!strcmp(word
, "wield")
1163 && (otmp
->owornmask
& W_WEP
))
1165 || (!strcmp(word
, "ready") /* exclude when wielded... */
1166 && ((otmp
== uwep
|| (otmp
== uswapwep
&& u
.twoweap
))
1167 && otmp
->quan
== 1L)) /* ...unless more than one */
1168 || ((!strcmp(word
, "dip") || !strcmp(word
, "grease"))
1169 && inaccessible_equipment(otmp
, (const char *) 0, FALSE
))
1174 /* Second ugly check; unlike the first it won't trigger an
1175 * "else" in "you don't have anything else to ___".
1179 && ((otmp
->oclass
== FOOD_CLASS
&& otmp
->otyp
!= MEAT_RING
)
1180 || (otmp
->oclass
== TOOL_CLASS
&& otyp
!= BLINDFOLD
1181 && otyp
!= TOWEL
&& otyp
!= LENSES
)))
1182 || (!strcmp(word
, "wield")
1183 && (otmp
->oclass
== TOOL_CLASS
&& !is_weptool(otmp
)))
1184 || (!strcmp(word
, "eat") && !is_edible(otmp
))
1185 || (!strcmp(word
, "sacrifice")
1186 && (otyp
!= CORPSE
&& otyp
!= AMULET_OF_YENDOR
1187 && otyp
!= FAKE_AMULET_OF_YENDOR
))
1188 || (!strcmp(word
, "write with")
1189 && (otmp
->oclass
== TOOL_CLASS
1190 && otyp
!= MAGIC_MARKER
&& otyp
!= TOWEL
))
1191 || (!strcmp(word
, "tin")
1192 && (otyp
!= CORPSE
|| !tinnable(otmp
)))
1193 || (!strcmp(word
, "rub")
1194 && ((otmp
->oclass
== TOOL_CLASS
&& otyp
!= OIL_LAMP
1195 && otyp
!= MAGIC_LAMP
&& otyp
!= BRASS_LANTERN
)
1196 || (otmp
->oclass
== GEM_CLASS
&& !is_graystone(otmp
))))
1197 || (!strcmp(word
, "use or apply")
1198 /* Picks, axes, pole-weapons, bullwhips */
1199 && ((otmp
->oclass
== WEAPON_CLASS
1200 && !is_pick(otmp
) && !is_axe(otmp
)
1201 && !is_pole(otmp
) && otyp
!= BULLWHIP
)
1202 || (otmp
->oclass
== POTION_CLASS
1203 /* only applicable potion is oil, and it will only
1204 be offered as a choice when already discovered */
1205 && (otyp
!= POT_OIL
|| !otmp
->dknown
1206 || !objects
[POT_OIL
].oc_name_known
))
1207 || (otmp
->oclass
== FOOD_CLASS
1208 && otyp
!= CREAM_PIE
&& otyp
!= EUCALYPTUS_LEAF
)
1209 || (otmp
->oclass
== GEM_CLASS
&& !is_graystone(otmp
))))
1210 || (!strcmp(word
, "invoke")
1212 && !objects
[otyp
].oc_unique
1213 && (otyp
!= FAKE_AMULET_OF_YENDOR
|| otmp
->known
)
1214 && otyp
!= CRYSTAL_BALL
/* synonym for apply */
1215 /* note: presenting the possibility of invoking non-artifact
1216 mirrors and/or lamps is simply a cruel deception... */
1218 && otyp
!= MAGIC_LAMP
1219 && (otyp
!= OIL_LAMP
/* don't list known oil lamp */
1220 || (otmp
->dknown
&& objects
[OIL_LAMP
].oc_name_known
)))
1221 || (!strcmp(word
, "untrap with")
1222 && ((otmp
->oclass
== TOOL_CLASS
&& otyp
!= CAN_OF_GREASE
)
1223 || (otmp
->oclass
== POTION_CLASS
1224 /* only applicable potion is oil, and it will only
1225 be offered as a choice when already discovered */
1226 && (otyp
!= POT_OIL
|| !otmp
->dknown
1227 || !objects
[POT_OIL
].oc_name_known
))))
1228 || (!strcmp(word
, "tip") && !Is_container(otmp
)
1229 /* include horn of plenty if sufficiently discovered */
1230 && (otmp
->otyp
!= HORN_OF_PLENTY
|| !otmp
->dknown
1231 || !objects
[HORN_OF_PLENTY
].oc_name_known
))
1232 || (!strcmp(word
, "charge") && !is_chargeable(otmp
))
1233 || (!strcmp(word
, "open") && otyp
!= TIN
)
1234 || (!strcmp(word
, "call") && !objtyp_is_callable(otyp
))
1238 /* Third ugly check: acceptable but not listed as likely
1239 * candidates in the prompt or in the inventory subset if
1240 * player responds with '?'.
1243 /* ugly check for unworn armor that can't be worn */
1244 (putting_on(word
) && *let
== ARMOR_CLASS
1245 && !canwearobj(otmp
, &dummymask
, FALSE
))
1246 /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
1247 || ((putting_on(word
) || taking_off(word
))
1248 && ((*let
== ARMOR_CLASS
) ^ (otmp
->oclass
== ARMOR_CLASS
)))
1249 /* or unsuitable items rubbed on known touchstone */
1250 || (!strncmp(word
, "rub on the stone", 16)
1251 && *let
== GEM_CLASS
&& otmp
->dknown
1252 && objects
[otyp
].oc_name_known
)
1253 /* suppress corpses on astral, amulets elsewhere */
1254 || (!strcmp(word
, "sacrifice")
1255 /* (!astral && amulet) || (astral && !amulet) */
1256 && (!Is_astralevel(&u
.uz
) ^ (otmp
->oclass
!= AMULET_CLASS
)))
1257 /* suppress container being stashed into */
1258 || (!strcmp(word
, "stash") && !ck_bag(otmp
))
1259 /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
1260 or accessory (ring) covered by cursed worn armor (gloves) */
1261 || (taking_off(word
)
1262 && inaccessible_equipment(otmp
, (const char *) 0,
1263 (boolean
) (otmp
->oclass
== RING_CLASS
)))
1264 || (!strcmp(word
, "write on")
1265 && (!(otyp
== SCR_BLANK_PAPER
|| otyp
== SPE_BLANK_PAPER
)
1266 || !otmp
->dknown
|| !objects
[otyp
].oc_name_known
))
1268 /* acceptable but not listed as likely candidate */
1271 *ap
++ = otmp
->invlet
;
1274 /* clang-format on */
1276 /* "ugly check" for reading fortune cookies, part 2 */
1277 if ((!strcmp(word
, "read") && is_readable(otmp
)))
1278 allowall
= usegold
= TRUE
;
1283 if (foo
== 0 && bp
> buf
&& bp
[-1] == ' ')
1285 Strcpy(lets
, bp
); /* necessary since we destroy buf */
1286 if (foo
> 5) /* compactify string */
1290 if (!foo
&& !allowall
&& !allownone
) {
1291 You("don't have anything %sto %s.", foox
? "else " : "", word
);
1292 return (struct obj
*) 0;
1293 } else if (!strcmp(word
, "write on")) { /* ugly check for magic marker */
1294 /* we wanted all scrolls and books in altlets[], but that came with
1295 'allowall' which we don't want since it prevents "silly thing"
1296 result if anything other than scroll or spellbook is chosen */
1303 Sprintf(qbuf
, "What do you want to %s? [*]", word
);
1305 Sprintf(qbuf
, "What do you want to %s? [%s or ?*]", word
, buf
);
1310 ilet
= yn_function(qbuf
, (char *) 0, '\0');
1315 pline("No count allowed with this command.");
1318 ilet
= get_count(NULL
, ilet
, LARGEST_INT
, &tmpcnt
);
1324 if (index(quitchars
, ilet
)) {
1327 return (struct obj
*) 0;
1329 if (ilet
== HANDS_SYM
) { /* '-' */
1331 char *suf
= (char *) 0;
1334 if ((bp
= strstr(buf
, " on the ")) != 0) {
1335 /* rub on the stone[s] */
1339 if ((bp
= strstr(buf
, " or ")) != 0) {
1341 bp
= (rn2(2) ? buf
: (bp
+ 4));
1344 You("mime %s something%s%s.", ing_suffix(bp
), suf
? " " : "",
1347 return (allownone
? &zeroobj
: (struct obj
*) 0);
1349 /* since gold is now kept in inventory, we need to do processing for
1350 select-from-invent before checking whether gold has been picked */
1351 if (ilet
== '?' || ilet
== '*') {
1352 char *allowed_choices
= (ilet
== '?') ? lets
: (char *) 0;
1356 if (!strcmp(word
, "grease"))
1357 Sprintf(qbuf
, "your %s", makeplural(body_part(FINGER
)));
1358 else if (!strcmp(word
, "write with"))
1359 Sprintf(qbuf
, "your %s", body_part(FINGERTIP
));
1360 else if (!strcmp(word
, "wield"))
1361 Sprintf(qbuf
, "your %s %s%s", uarmg
? "gloved" : "bare",
1362 makeplural(body_part(HAND
)),
1363 !uwep
? " (wielded)" : "");
1364 else if (!strcmp(word
, "ready"))
1365 Sprintf(qbuf
, "empty quiver%s",
1366 !uquiver
? " (nothing readied)" : "");
1368 if (ilet
== '?' && !*lets
&& *altlets
)
1369 allowed_choices
= altlets
;
1370 ilet
= display_pickinv(allowed_choices
, *qbuf
? qbuf
: (char *) 0,
1371 TRUE
, allowcnt
? &ctmp
: (long *) 0);
1374 if (ilet
== HANDS_SYM
)
1376 if (ilet
== '\033') {
1379 return (struct obj
*) 0;
1381 if (allowcnt
&& ctmp
>= 0) {
1385 /* they typed a letter (not a space) at the prompt */
1387 /* find the item which was picked */
1388 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
1389 if (otmp
->invlet
== ilet
)
1391 /* some items have restrictions */
1392 if (ilet
== def_oc_syms
[COIN_CLASS
].sym
1393 /* guard against the [hypothetical] chace of having more
1394 than one invent slot of gold and picking the non-'$' one */
1395 || (otmp
&& otmp
->oclass
== COIN_CLASS
)) {
1397 You("cannot %s gold.", word
);
1398 return (struct obj
*) 0;
1400 /* Historic note: early Nethack had a bug which was
1401 * first reported for Larn, where trying to drop 2^32-n
1402 * gold pieces was allowed, and did interesting things
1403 * to your money supply. The LRS is the tax bureau
1406 if (cntgiven
&& cnt
<= 0) {
1409 "LRS would be very interested to know you have that much.");
1410 return (struct obj
*) 0;
1413 if (cntgiven
&& !strcmp(word
, "throw")) {
1414 /* permit counts for throwing gold, but don't accept
1415 * counts for other things since the throw code will
1416 * split off a single item anyway */
1418 return (struct obj
*) 0;
1419 if (cnt
> 1 && (ilet
!= def_oc_syms
[COIN_CLASS
].sym
1420 && !(otmp
&& otmp
->oclass
== COIN_CLASS
))) {
1421 You("can only throw one item at a time.");
1425 context
.botl
= 1; /* May have changed the amount of money */
1427 /* [we used to set otmp (by finding ilet in invent) here, but
1428 that's been moved above so that otmp can be checked earlier] */
1429 /* verify the chosen object */
1431 You("don't have that object.");
1433 return (struct obj
*) 0;
1435 } else if (cnt
< 0 || otmp
->quan
< cnt
) {
1436 You("don't have that many! You have only %ld.", otmp
->quan
);
1438 return (struct obj
*) 0;
1443 if (!allowall
&& let
&& !index(let
, otmp
->oclass
)
1444 && !(usegold
&& otmp
->oclass
== COIN_CLASS
)) {
1445 silly_thing(word
, otmp
);
1446 return (struct obj
*) 0;
1450 return (struct obj
*) 0;
1451 if (cnt
!= otmp
->quan
) {
1452 /* don't split a stack of cursed loadstones */
1453 if (splittable(otmp
))
1454 otmp
= splitobj(otmp
, cnt
);
1455 else if (otmp
->otyp
== LOADSTONE
&& otmp
->cursed
)
1456 /* kludge for canletgo()'s can't-drop-this message */
1457 otmp
->corpsenm
= (int) cnt
;
1464 silly_thing(word
, otmp
)
1468 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
1471 const char *s1
, *s2
, *s3
;
1472 int ocls
= otmp
->oclass
, otyp
= otmp
->otyp
;
1475 /* check for attempted use of accessory commands ('P','R') on armor
1476 and for corresponding armor commands ('W','T') on accessories */
1477 if (ocls
== ARMOR_CLASS
) {
1478 if (!strcmp(word
, "put on"))
1479 s1
= "W", s2
= "wear", s3
= "";
1480 else if (!strcmp(word
, "remove"))
1481 s1
= "T", s2
= "take", s3
= " off";
1482 } else if ((ocls
== RING_CLASS
|| otyp
== MEAT_RING
)
1483 || ocls
== AMULET_CLASS
1484 || (otyp
== BLINDFOLD
|| otyp
== TOWEL
|| otyp
== LENSES
)) {
1485 if (!strcmp(word
, "wear"))
1486 s1
= "P", s2
= "put", s3
= " on";
1487 else if (!strcmp(word
, "take off"))
1488 s1
= "R", s2
= "remove", s3
= "";
1491 pline("Use the '%s' command to %s %s%s.", s1
, s2
,
1492 !(is_plural(otmp
) || pair_of(otmp
)) ? "that" : "those", s3
);
1495 pline(silly_thing_to
, word
);
1502 /* use allow_category() from pickup.c */
1503 return (int) allow_category(otmp
);
1510 return (otmp
->unpaid
|| (Has_contents(otmp
) && count_unpaid(otmp
->cobj
)));
1516 return (boolean
) (uarm
|| uarmc
|| uarmf
|| uarmg
1517 || uarmh
|| uarms
|| uarmu
);
1524 return (otmp
->owornmask
& (W_ARMOR
| W_ACCESSORY
| W_SADDLE
| W_WEAPON
))
1529 /* extra xprname() input that askchain() can't pass through safe_qbuf() */
1530 STATIC_VAR
struct xprnctx
{
1535 /* safe_qbuf() -> short_oname() callback */
1540 return xprname(obj
, (char *) 0, safeq_xprn_ctx
.let
, safeq_xprn_ctx
.dot
,
1544 /* alternate safe_qbuf() -> short_oname() callback */
1546 safeq_shortxprname(obj
)
1549 return xprname(obj
, ansimpleoname(obj
), safeq_xprn_ctx
.let
,
1550 safeq_xprn_ctx
.dot
, 0L, 0L);
1553 static NEARDATA
const char removeables
[] = { ARMOR_CLASS
, WEAPON_CLASS
,
1554 RING_CLASS
, AMULET_CLASS
,
1557 /* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
1558 Return the number of times fn was called successfully.
1559 If combo is TRUE, we just use this to get a category list. */
1561 ggetobj(word
, fn
, mx
, combo
, resultflags
)
1563 int FDECL((*fn
), (OBJ_P
)), mx
;
1564 boolean combo
; /* combination menu flag */
1565 unsigned *resultflags
;
1567 int FDECL((*ckfn
), (OBJ_P
)) = (int FDECL((*), (OBJ_P
))) 0;
1568 boolean
FDECL((*ofilter
), (OBJ_P
)) = (boolean
FDECL((*), (OBJ_P
))) 0;
1569 boolean takeoff
, ident
, allflag
, m_seen
;
1571 int oletct
, iletct
, unpaid
, oc_of_sym
;
1572 char sym
, *ip
, olets
[MAXOCLASSES
+ 5], ilets
[MAXOCLASSES
+ 5];
1573 char extra_removeables
[3 + 1]; /* uwep,uswapwep,uquiver */
1574 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
1577 You("have nothing to %s.", word
);
1579 *resultflags
= ALL_FINISHED
;
1584 takeoff
= ident
= allflag
= m_seen
= FALSE
;
1585 add_valid_menu_class(0); /* reset */
1586 if (taking_off(word
)) {
1589 } else if (!strcmp(word
, "identify")) {
1591 ofilter
= not_fully_identified
;
1594 iletct
= collect_obj_classes(ilets
, invent
, FALSE
, ofilter
, &itemcount
);
1595 unpaid
= count_unpaid(invent
);
1597 if (ident
&& !iletct
) {
1598 return -1; /* no further identifications */
1599 } else if (!takeoff
&& (unpaid
|| invent
)) {
1600 ilets
[iletct
++] = ' ';
1602 ilets
[iletct
++] = 'u';
1603 if (count_buc(invent
, BUC_BLESSED
))
1604 ilets
[iletct
++] = 'B';
1605 if (count_buc(invent
, BUC_UNCURSED
))
1606 ilets
[iletct
++] = 'U';
1607 if (count_buc(invent
, BUC_CURSED
))
1608 ilets
[iletct
++] = 'C';
1609 if (count_buc(invent
, BUC_UNKNOWN
))
1610 ilets
[iletct
++] = 'X';
1612 ilets
[iletct
++] = 'a';
1613 } else if (takeoff
&& invent
) {
1614 ilets
[iletct
++] = ' ';
1616 ilets
[iletct
++] = 'i';
1618 ilets
[iletct
++] = 'm'; /* allow menu presentation on request */
1619 ilets
[iletct
] = '\0';
1622 Sprintf(qbuf
, "What kinds of thing do you want to %s? [%s]",
1625 if (buf
[0] == '\033')
1627 if (index(buf
, 'i')) {
1628 char ailets
[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
1631 /* applicable inventory letters; if empty, show entire invent */
1634 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
1635 /* index() check: limit overflow items to one '#' */
1636 if ((*ofilter
)(otmp
) && !index(ailets
, otmp
->invlet
))
1637 (void) strkitten(ailets
, otmp
->invlet
);
1638 if (display_inventory(ailets
, TRUE
) == '\033')
1644 extra_removeables
[0] = '\0';
1646 /* arbitrary types of items can be placed in the weapon slots
1647 [any duplicate entries in extra_removeables[] won't matter] */
1649 (void) strkitten(extra_removeables
, uwep
->oclass
);
1651 (void) strkitten(extra_removeables
, uswapwep
->oclass
);
1653 (void) strkitten(extra_removeables
, uquiver
->oclass
);
1657 olets
[oletct
= 0] = '\0';
1658 while ((sym
= *ip
++) != '\0') {
1661 oc_of_sym
= def_char_to_objclass(sym
);
1662 if (takeoff
&& oc_of_sym
!= MAXOCLASSES
) {
1663 if (index(extra_removeables
, oc_of_sym
)) {
1664 ; /* skip rest of takeoff checks */
1665 } else if (!index(removeables
, oc_of_sym
)) {
1666 pline("Not applicable.");
1668 } else if (oc_of_sym
== ARMOR_CLASS
&& !wearing_armor()) {
1671 } else if (oc_of_sym
== WEAPON_CLASS
&& !uwep
&& !uswapwep
1673 You("are not wielding anything.");
1675 } else if (oc_of_sym
== RING_CLASS
&& !uright
&& !uleft
) {
1676 You("are not wearing rings.");
1678 } else if (oc_of_sym
== AMULET_CLASS
&& !uamul
) {
1679 You("are not wearing an amulet.");
1681 } else if (oc_of_sym
== TOOL_CLASS
&& !ublindf
) {
1682 You("are not wearing a blindfold.");
1687 if (oc_of_sym
== COIN_CLASS
&& !combo
) {
1689 } else if (sym
== 'a') {
1691 } else if (sym
== 'A') {
1692 /* same as the default */;
1693 } else if (sym
== 'u') {
1694 add_valid_menu_class('u');
1696 } else if (sym
== 'B') {
1697 add_valid_menu_class('B');
1699 } else if (sym
== 'U') {
1700 add_valid_menu_class('U');
1702 } else if (sym
== 'C') {
1703 add_valid_menu_class('C');
1705 } else if (sym
== 'X') {
1706 add_valid_menu_class('X');
1708 } else if (sym
== 'm') {
1710 } else if (oc_of_sym
== MAXOCLASSES
) {
1711 You("don't have any %c's.", sym
);
1712 } else if (oc_of_sym
!= VENOM_CLASS
) { /* suppress venom */
1713 if (!index(olets
, oc_of_sym
)) {
1714 add_valid_menu_class(oc_of_sym
);
1715 olets
[oletct
++] = oc_of_sym
;
1723 || (!oletct
&& ckfn
!= ckunpaid
&& ckfn
!= ckvalidcat
))
1725 } else if (flags
.menu_style
!= MENU_TRADITIONAL
&& combo
&& !allflag
) {
1728 /* !!!! test gold dropping */
1729 } else if (allowgold
== 2 && !oletct
) {
1730 return 1; /* you dropped gold (or at least tried to) */
1733 int cnt
= askchain(&invent
, olets
, allflag
, fn
, ckfn
, mx
, word
);
1735 * askchain() has already finished the job in this case
1736 * so set a special flag to convey that back to the caller
1737 * so that it won't continue processing.
1738 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1740 if (combo
&& allflag
&& resultflags
)
1741 *resultflags
|= ALL_FINISHED
;
1747 * Walk through the chain starting at objchn and ask for all objects
1748 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1749 * whether the action in question (i.e., fn) has to be performed.
1750 * If allflag then no questions are asked. Mx gives the max number
1751 * of objects to be treated. Return the number of objects treated.
1754 askchain(objchn
, olets
, allflag
, fn
, ckfn
, mx
, word
)
1755 struct obj
**objchn
;
1757 const char *olets
, *word
; /* olets is an Obj Class char array */
1758 int FDECL((*fn
), (OBJ_P
)), FDECL((*ckfn
), (OBJ_P
));
1760 struct obj
*otmp
, *otmpo
;
1761 register char sym
, ilet
;
1762 register int cnt
= 0, dud
= 0, tmp
;
1763 boolean takeoff
, nodot
, ident
, take_out
, put_in
, first
, ininv
;
1764 char qbuf
[QBUFSZ
], qpfx
[QBUFSZ
];
1766 takeoff
= taking_off(word
);
1767 ident
= !strcmp(word
, "identify");
1768 take_out
= !strcmp(word
, "take out");
1769 put_in
= !strcmp(word
, "put in");
1770 nodot
= (!strcmp(word
, "nodot") || !strcmp(word
, "drop") || ident
1771 || takeoff
|| take_out
|| put_in
);
1772 ininv
= (*objchn
== invent
);
1774 /* someday maybe we'll sort by 'olets' too (temporarily replace
1775 flags.packorder and pass SORTLOOT_PACK), but not yet... */
1776 sortloot(objchn
, SORTLOOT_INVLET
, FALSE
);
1780 * Interrogate in the object class order specified.
1781 * For example, if a person specifies =/ then first all rings
1782 * will be asked about followed by all wands. -dgk
1786 if (*objchn
&& (*objchn
)->oclass
== COIN_CLASS
)
1787 ilet
--; /* extra iteration */
1789 * Multiple Drop can change the invent chain while it operates
1790 * (dropping a burning potion of oil while levitating creates
1791 * an explosion which can destroy inventory items), so simple
1793 * for (otmp = *objchn; otmp; otmp = otmp2) {
1794 * otmp2 = otmp->nobj;
1797 * is inadequate here. Use each object's bypass bit to keep
1798 * track of which list elements have already been processed.
1800 bypass_objlist(*objchn
, FALSE
); /* clear chain's bypass bits */
1801 while ((otmp
= nxt_unbypassed_obj(*objchn
)) != 0) {
1806 if (olets
&& *olets
&& otmp
->oclass
!= *olets
)
1808 if (takeoff
&& !is_worn(otmp
))
1810 if (ident
&& !not_fully_identified(otmp
))
1812 if (ckfn
&& !(*ckfn
)(otmp
))
1815 safeq_xprn_ctx
.let
= ilet
;
1816 safeq_xprn_ctx
.dot
= !nodot
;
1819 /* traditional_loot() skips prompting when only one
1820 class of objects is involved, so prefix the first
1821 object being queried here with an explanation why */
1822 if (take_out
|| put_in
)
1823 Sprintf(qpfx
, "%s: ", word
), *qpfx
= highc(*qpfx
);
1826 (void) safe_qbuf(qbuf
, qpfx
, "?", otmp
,
1827 ininv
? safeq_xprname
: doname
,
1828 ininv
? safeq_shortxprname
: ansimpleoname
,
1830 sym
= (takeoff
|| ident
|| otmp
->quan
< 2L) ? nyaq(qbuf
)
1837 /* Number was entered; split the object unless it corresponds
1838 to 'none' or 'all'. 2 special cases: cursed loadstones and
1839 welded weapons (eg, multiple daggers) will remain as merged
1840 unit; done to avoid splitting an object that won't be
1841 droppable (even if we're picking up rather than dropping). */
1846 if (yn_number
< otmp
->quan
&& splittable(otmp
))
1847 otmp
= splitobj(otmp
, yn_number
);
1856 if (container_gone(fn
)) {
1857 /* otmp caused magic bag to explode;
1858 both are now gone */
1859 otmp
= 0; /* and return */
1860 } else if (otmp
&& otmp
!= otmpo
) {
1861 /* split occurred, merge again */
1862 (void) merged(&otmpo
, &otmp
);
1875 /* special case for seffects() */
1881 if (olets
&& *olets
&& *++olets
)
1883 if (!takeoff
&& (dud
|| cnt
))
1884 pline("That was all.");
1885 else if (!dud
&& !cnt
)
1886 pline("No applicable objects.");
1888 bypass_objlist(*objchn
, FALSE
);
1893 * Object identification routines:
1896 /* make an object actually be identified; no display updating */
1898 fully_identify_obj(otmp
)
1901 makeknown(otmp
->otyp
);
1902 if (otmp
->oartifact
)
1903 discover_artifact((xchar
) otmp
->oartifact
);
1904 otmp
->known
= otmp
->dknown
= otmp
->bknown
= otmp
->rknown
= 1;
1905 if (Is_container(otmp
) || otmp
->otyp
== STATUE
)
1906 otmp
->cknown
= otmp
->lknown
= 1;
1907 if (otmp
->otyp
== EGG
&& otmp
->corpsenm
!= NON_PM
)
1908 learn_egg_type(otmp
->corpsenm
);
1911 /* ggetobj callback routine; identify an object and give immediate feedback */
1916 fully_identify_obj(otmp
);
1917 prinv((char *) 0, otmp
, 0L);
1921 /* menu of unidentified objects; select and identify up to id_limit of them */
1923 menu_identify(id_limit
)
1926 menu_item
*pick_list
;
1927 int n
, i
, first
= 1, tryct
= 5;
1929 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1932 Sprintf(buf
, "What would you like to identify %s?",
1933 first
? "first" : "next");
1934 n
= query_objlist(buf
, &invent
, (SIGNAL_NOMENU
| SIGNAL_ESCAPE
1935 | USE_INVLET
| INVORDER_SORT
),
1936 &pick_list
, PICK_ANY
, not_fully_identified
);
1941 for (i
= 0; i
< n
; i
++, id_limit
--)
1942 (void) identify(pick_list
[i
].item
.a_obj
);
1943 free((genericptr_t
) pick_list
);
1944 mark_synch(); /* Before we loop to pop open another menu */
1946 } else if (n
== -2) { /* player used ESC to quit menu */
1948 } else if (n
== -1) { /* no eligible items found */
1949 pline("That was all.");
1951 } else if (!--tryct
) { /* stop re-prompting */
1952 pline1(thats_enough_tries
);
1954 } else { /* try again */
1955 pline("Choose an item; use ESC to decline.");
1960 /* dialog with user to identify a given number of items; 0 means all */
1962 identify_pack(id_limit
, learning_id
)
1964 boolean learning_id
; /* true if we just read unknown identify scroll */
1966 struct obj
*obj
, *the_obj
;
1970 the_obj
= 0; /* if unid_cnt ends up 1, this will be it */
1971 for (obj
= invent
; obj
; obj
= obj
->nobj
)
1972 if (not_fully_identified(obj
))
1973 ++unid_cnt
, the_obj
= obj
;
1976 You("have already identified all %sof your possessions.",
1977 learning_id
? "the rest " : "");
1978 } else if (!id_limit
|| id_limit
>= unid_cnt
) {
1979 /* identify everything */
1980 if (unid_cnt
== 1) {
1981 (void) identify(the_obj
);
1983 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1985 for (obj
= invent
; obj
; obj
= obj
->nobj
)
1986 if (not_fully_identified(obj
))
1987 (void) identify(obj
);
1990 /* identify up to `id_limit' items */
1992 if (flags
.menu_style
== MENU_TRADITIONAL
)
1994 n
= ggetobj("identify", identify
, id_limit
, FALSE
,
1997 break; /* quit or no eligible items */
1998 } while ((id_limit
-= n
) > 0);
1999 if (n
== 0 || n
< -1)
2000 menu_identify(id_limit
);
2005 /* called when regaining sight; mark inventory objects which were picked
2006 up while blind as now having been seen */
2008 learn_unseen_invent()
2013 return; /* sanity check */
2015 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2017 continue; /* already seen */
2018 /* set dknown, perhaps bknown (for priest[ess]) */
2021 * If object->eknown gets implemented (see learnwand(zap.c)),
2022 * handle deferred discovery here.
2028 /* should of course only be called for things in invent */
2033 if (!flags
.invlet_constant
) {
2034 obj
->invlet
= NOINVSYM
;
2041 * Print the indicated quantity of the given object. If quan == 0L then use
2042 * the current quantity.
2045 prinv(prefix
, obj
, quan
)
2052 pline("%s%s%s", prefix
, *prefix
? " " : "",
2053 xprname(obj
, (char *) 0, obj_to_let(obj
), TRUE
, 0L, quan
));
2057 xprname(obj
, txt
, let
, dot
, cost
, quan
)
2059 const char *txt
; /* text to print instead of obj */
2060 char let
; /* inventory letter */
2061 boolean dot
; /* append period; (dot && cost => Iu) */
2062 long cost
; /* cost (for inventory of unpaid or expended items) */
2063 long quan
; /* if non-0, print this quantity, not obj->quan */
2065 #ifdef LINT /* handle static char li[BUFSZ]; */
2068 static char li
[BUFSZ
];
2070 boolean use_invlet
= (flags
.invlet_constant
2071 && let
!= CONTAINED_SYM
&& let
!= HANDS_SYM
);
2075 savequan
= obj
->quan
;
2080 * - Then obj == null and 'txt' refers to hands or fingers.
2081 * * Then obj == null and we are printing a total amount.
2082 * > Then the object is contained and doesn't have an inventory letter.
2084 if (cost
!= 0 || let
== '*') {
2085 /* if dot is true, we're doing Iu, otherwise Ix */
2087 iflags
.menu_tab_sep
? "%c - %s\t%6ld %s"
2088 : "%c - %-45s %6ld %s",
2089 (dot
&& use_invlet
? obj
->invlet
: let
),
2090 (txt
? txt
: doname(obj
)), cost
, currency(cost
));
2092 /* ordinary inventory display or pickup message */
2093 Sprintf(li
, "%c - %s%s", (use_invlet
? obj
->invlet
: let
),
2094 (txt
? txt
: doname(obj
)), (dot
? "." : ""));
2097 obj
->quan
= savequan
;
2102 /* the 'i' command */
2106 (void) display_inventory((char *) 0, FALSE
);
2113 * Scan the given list of objects. If last_found is NULL, return the first
2114 * unpaid object found. If last_found is not NULL, then skip over unpaid
2115 * objects until last_found is reached, then set last_found to NULL so the
2116 * next unpaid object is returned. This routine recursively follows
2119 STATIC_OVL
struct obj
*
2120 find_unpaid(list
, last_found
)
2121 struct obj
*list
, **last_found
;
2128 /* still looking for previous unpaid object */
2129 if (list
== *last_found
)
2130 *last_found
= (struct obj
*) 0;
2132 return ((*last_found
= list
));
2134 if (Has_contents(list
)) {
2135 if ((obj
= find_unpaid(list
->cobj
, last_found
)) != 0)
2140 return (struct obj
*) 0;
2143 /* for perm_invent when operating on a partial inventory display, so that
2144 the persistent one doesn't get shrunk during filtering for item selection
2145 then regrown to full inventory, possibly being resized in the process */
2146 static winid cached_pickinv_win
= WIN_ERR
;
2149 free_pickinv_cache()
2151 if (cached_pickinv_win
!= WIN_ERR
) {
2152 destroy_nhwindow(cached_pickinv_win
);
2153 cached_pickinv_win
= WIN_ERR
;
2158 * Internal function used by display_inventory and getobj that can display
2159 * inventory and return a count as well as a letter. If out_cnt is not null,
2160 * any count returned from the menu selection is placed here.
2163 display_pickinv(lets
, xtra_choice
, want_reply
, out_cnt
)
2164 register const char *lets
;
2165 const char *xtra_choice
; /* "fingers", pick hands rather than an object */
2171 char *invlet
= flags
.inv_order
;
2173 winid win
; /* windows being used */
2175 menu_item
*selected
;
2178 lets
= 0; /* simplify tests: (lets) instead of (lets && *lets) */
2180 if (flags
.perm_invent
&& (lets
|| xtra_choice
)) {
2181 /* partial inventory in perm_invent setting; don't operate on
2182 full inventory window, use an alternate one instead; create
2183 the first time needed and keep it for re-use as needed later */
2184 if (cached_pickinv_win
== WIN_ERR
)
2185 cached_pickinv_win
= create_nhwindow(NHW_MENU
);
2186 win
= cached_pickinv_win
;
2191 * Exit early if no inventory -- but keep going if we are doing
2192 * a permanent inventory update. We need to keep going so the
2193 * permanent inventory window updates itself to remove the last
2194 * item(s) dropped. One down side: the addition of the exception
2195 * for permanent inventory window updates _can_ pop the window
2196 * up when it's not displayed -- even if it's empty -- because we
2197 * don't know at this level if its up or not. This may not be
2198 * an issue if empty checks are done before hand and the call
2199 * to here is short circuited away.
2201 * 2: our count here is only to distinguish between 0 and 1 and
2202 * more than 1; for the last one, we don't need a precise number.
2203 * For perm_invent update we force 'more than 1'.
2205 n
= (flags
.perm_invent
&& !lets
&& !want_reply
) ? 2
2206 : lets
? (int) strlen(lets
)
2207 : !invent
? 0 : !invent
->nobj
? 1 : 2;
2208 /* for xtra_choice, there's another 'item' not included in initial 'n';
2209 for !lets (full invent) and for override_ID (wizard mode identify),
2210 skip message_menu handling of single item even if item count was 1 */
2211 if (xtra_choice
|| (n
== 1 && (!lets
|| iflags
.override_ID
)))
2215 pline("Not carrying anything.");
2219 /* oxymoron? temporarily assign permanent inventory letters */
2220 if (!flags
.invlet_constant
)
2224 /* when only one item of interest, use pline instead of menus;
2225 we actually use a fake message-line menu in order to allow
2226 the user to perform selection at the --More-- prompt for tty */
2229 /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2230 "nothing" (ready Quiver), or "fingers" (apply grease) */
2231 ret
= message_menu(HANDS_SYM
, PICK_ONE
,
2232 xprname((struct obj
*) 0, xtra_choice
,
2233 HANDS_SYM
, TRUE
, 0L, 0L)); /* '-' */
2235 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2236 if (!lets
|| otmp
->invlet
== lets
[0])
2239 ret
= message_menu(otmp
->invlet
,
2240 want_reply
? PICK_ONE
: PICK_NONE
,
2241 xprname(otmp
, (char *) 0, lets
[0],
2245 *out_cnt
= -1L; /* select all */
2250 (((flags
.sortloot
== 'f') ? SORTLOOT_LOOT
: SORTLOOT_INVLET
)
2251 | (flags
.sortpack
? SORTLOOT_PACK
: 0)),
2256 if (wizard
&& iflags
.override_ID
) {
2257 char prompt
[QBUFSZ
];
2260 /* wiz_identify stuffed the wiz_identify command character (^I)
2261 into iflags.override_ID for our use as an accelerator */
2262 Sprintf(prompt
, "Debug Identify (%s to permanently identify)",
2263 visctrl(iflags
.override_ID
));
2264 add_menu(win
, NO_GLYPH
, &any
, '_', iflags
.override_ID
, ATR_NONE
,
2265 prompt
, MENU_UNSELECTED
);
2266 } else if (xtra_choice
) {
2267 /* wizard override ID and xtra_choice are mutually exclusive */
2269 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2270 "Miscellaneous", MENU_UNSELECTED
);
2271 any
.a_char
= HANDS_SYM
; /* '-' */
2272 add_menu(win
, NO_GLYPH
, &any
, HANDS_SYM
, 0, ATR_NONE
,
2273 xtra_choice
, MENU_UNSELECTED
);
2277 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2278 if (lets
&& !index(lets
, otmp
->invlet
))
2280 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2281 any
= zeroany
; /* all bits zero */
2282 ilet
= otmp
->invlet
;
2283 if (flags
.sortpack
&& !classcount
) {
2284 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2285 let_to_name(*invlet
, FALSE
,
2286 (want_reply
&& iflags
.menu_head_objsym
)),
2291 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2292 doname(otmp
), MENU_UNSELECTED
);
2295 if (flags
.sortpack
) {
2298 if (--invlet
!= venom_inv
) {
2303 end_menu(win
, (char *) 0);
2305 n
= select_menu(win
, want_reply
? PICK_ONE
: PICK_NONE
, &selected
);
2307 ret
= selected
[0].item
.a_char
;
2309 *out_cnt
= selected
[0].count
;
2310 free((genericptr_t
) selected
);
2312 ret
= !n
? '\0' : '\033'; /* cancelled */
2318 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2319 * list all objects with object classes that match the order in lets.
2321 * Returns the letter identifier of a selected item, or 0 if nothing
2325 display_inventory(lets
, want_reply
)
2329 return display_pickinv(lets
, (char *) 0, want_reply
, (long *) 0);
2333 * Show what is current using inventory letters.
2337 display_used_invlets(avoidlet
)
2342 char *invlet
= flags
.inv_order
;
2343 int n
, classcount
, invdone
= 0;
2346 menu_item
*selected
;
2349 win
= create_nhwindow(NHW_MENU
);
2352 any
= zeroany
; /* set all bits to zero */
2354 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2355 ilet
= otmp
->invlet
;
2356 if (ilet
== avoidlet
)
2358 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2359 if (flags
.sortpack
&& !classcount
) {
2360 any
= zeroany
; /* zero */
2361 add_menu(win
, NO_GLYPH
, &any
, 0, 0,
2362 iflags
.menu_headings
,
2363 let_to_name(*invlet
, FALSE
, FALSE
),
2368 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2369 doname(otmp
), MENU_UNSELECTED
);
2372 if (flags
.sortpack
&& *++invlet
)
2376 end_menu(win
, "Inventory letters used:");
2378 n
= select_menu(win
, PICK_ONE
, &selected
);
2380 ret
= selected
[0].item
.a_char
;
2381 free((genericptr_t
) selected
);
2383 ret
= !n
? '\0' : '\033'; /* cancelled */
2384 destroy_nhwindow(win
);
2390 * Returns the number of unpaid items within the given list. This includes
2391 * contained objects.
2402 if (Has_contents(list
))
2403 count
+= count_unpaid(list
->cobj
);
2410 * Returns the number of items with b/u/c/unknown within the given list.
2411 * This does NOT include contained objects.
2413 * Assumes that the hero sees or touches or otherwise senses the objects
2414 * at some point: bknown is forced for priest[ess], like in xname().
2417 count_buc(list
, type
)
2423 for (; list
; list
= list
->nobj
) {
2424 /* coins are "none of the above" as far as BUCX filtering goes */
2425 if (list
->oclass
== COIN_CLASS
)
2427 /* priests always know bless/curse state */
2428 if (Role_if(PM_PRIEST
))
2431 /* check whether this object matches the requested type */
2433 ? (type
== BUC_UNKNOWN
)
2434 : list
->blessed
? (type
== BUC_BLESSED
)
2435 : list
->cursed
? (type
== BUC_CURSED
)
2436 : (type
== BUC_UNCURSED
))
2442 /* similar to count_buc(), but tallies all states at once
2443 rather than looking for a specific type */
2445 tally_BUCX(list
, bcp
, ucp
, ccp
, xcp
, ocp
)
2447 int *bcp
, *ucp
, *ccp
, *xcp
, *ocp
;
2449 *bcp
= *ucp
= *ccp
= *xcp
= *ocp
= 0;
2450 for (; list
; list
= list
->nobj
) {
2451 if (list
->oclass
== COIN_CLASS
) {
2452 ++(*ocp
); /* "other" */
2455 /* priests always know bless/curse state */
2456 if (Role_if(PM_PRIEST
))
2461 else if (list
->blessed
)
2463 else if (list
->cursed
)
2465 else /* neither blessed nor cursed => uncursed */
2471 count_contents(container
, nested
, quantity
, everything
)
2472 struct obj
*container
;
2473 boolean nested
, /* include contents of any nested containers */
2474 quantity
, /* count all vs count separate stacks */
2475 everything
; /* all objects vs only unpaid objects */
2480 for (otmp
= container
->cobj
; otmp
; otmp
= otmp
->nobj
) {
2481 if (nested
&& Has_contents(otmp
))
2482 count
+= count_contents(otmp
, nested
, quantity
, everything
);
2483 if (everything
|| otmp
->unpaid
)
2484 count
+= quantity
? otmp
->quan
: 1L;
2493 struct obj
*otmp
, *marker
;
2495 char *invlet
= flags
.inv_order
;
2496 int classcount
, count
, num_so_far
;
2499 count
= count_unpaid(invent
);
2502 marker
= (struct obj
*) 0;
2503 otmp
= find_unpaid(invent
, &marker
);
2504 cost
= unpaid_cost(otmp
, FALSE
);
2505 iflags
.suppress_price
++; /* suppress "(unpaid)" suffix */
2506 pline1(xprname(otmp
, distant_name(otmp
, doname
),
2507 carried(otmp
) ? otmp
->invlet
: CONTAINED_SYM
, TRUE
,
2509 iflags
.suppress_price
--;
2513 win
= create_nhwindow(NHW_MENU
);
2515 num_so_far
= 0; /* count of # printed so far */
2516 if (!flags
.invlet_constant
)
2521 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2522 ilet
= otmp
->invlet
;
2524 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2525 if (flags
.sortpack
&& !classcount
) {
2526 putstr(win
, 0, let_to_name(*invlet
, TRUE
, FALSE
));
2530 totcost
+= cost
= unpaid_cost(otmp
, FALSE
);
2531 iflags
.suppress_price
++; /* suppress "(unpaid)" suffix */
2532 putstr(win
, 0, xprname(otmp
, distant_name(otmp
, doname
),
2533 ilet
, TRUE
, cost
, 0L));
2534 iflags
.suppress_price
--;
2539 } while (flags
.sortpack
&& (*++invlet
));
2541 if (count
> num_so_far
) {
2542 /* something unpaid is contained */
2544 putstr(win
, 0, let_to_name(CONTAINED_SYM
, TRUE
, FALSE
));
2546 * Search through the container objects in the inventory for
2547 * unpaid items. The top level inventory items have already
2550 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2551 if (Has_contents(otmp
)) {
2554 marker
= (struct obj
*) 0; /* haven't found any */
2555 while (find_unpaid(otmp
->cobj
, &marker
)) {
2556 totcost
+= cost
= unpaid_cost(marker
, FALSE
);
2559 iflags
.suppress_price
++; /* suppress "(unpaid)" sfx */
2561 xprname(marker
, distant_name(marker
, doname
),
2562 CONTAINED_SYM
, TRUE
, cost
, 0L));
2563 iflags
.suppress_price
--;
2566 if (!otmp
->cknown
) {
2567 char contbuf
[BUFSZ
];
2569 /* Shopkeeper knows what to charge for contents */
2570 Sprintf(contbuf
, "%s contents", s_suffix(xname(otmp
)));
2572 xprname((struct obj
*) 0, contbuf
, CONTAINED_SYM
,
2573 TRUE
, contcost
, 0L));
2581 xprname((struct obj
*) 0, "Total:", '*', FALSE
, totcost
, 0L));
2582 display_nhwindow(win
, FALSE
);
2583 destroy_nhwindow(win
);
2586 /* query objlist callback: return TRUE if obj type matches "this_type" */
2587 static int this_type
;
2593 boolean res
= (obj
->oclass
== this_type
);
2595 if (obj
->oclass
!= COIN_CLASS
) {
2596 switch (this_type
) {
2598 res
= (obj
->bknown
&& obj
->blessed
);
2601 res
= (obj
->bknown
&& !(obj
->blessed
|| obj
->cursed
));
2604 res
= (obj
->bknown
&& obj
->cursed
);
2610 break; /* use 'res' as-is */
2616 /* the 'I' command */
2622 char *extra_types
, types
[BUFSZ
];
2623 int class_count
, oclass
, unpaid_count
, itemcount
;
2624 int bcnt
, ccnt
, ucnt
, xcnt
, ocnt
;
2625 boolean billx
= *u
.ushops
&& doinvbill(0);
2626 menu_item
*pick_list
;
2627 boolean traditional
= TRUE
;
2628 const char *prompt
= "What type of object do you want an inventory of?";
2630 if (!invent
&& !billx
) {
2631 You("aren't carrying anything.");
2634 unpaid_count
= count_unpaid(invent
);
2635 tally_BUCX(invent
, &bcnt
, &ucnt
, &ccnt
, &xcnt
, &ocnt
);
2637 if (flags
.menu_style
!= MENU_TRADITIONAL
) {
2638 if (flags
.menu_style
== MENU_FULL
2639 || flags
.menu_style
== MENU_PARTIAL
) {
2640 traditional
= FALSE
;
2652 n
= query_category(prompt
, invent
, i
, &pick_list
, PICK_ONE
);
2655 this_type
= c
= pick_list
[0].item
.a_int
;
2656 free((genericptr_t
) pick_list
);
2660 /* collect a list of classes of objects carried, for use as a prompt
2664 collect_obj_classes(types
, invent
, FALSE
,
2665 (boolean
FDECL((*), (OBJ_P
))) 0, &itemcount
);
2666 if (unpaid_count
|| billx
|| (bcnt
+ ccnt
+ ucnt
+ xcnt
) != 0)
2667 types
[class_count
++] = ' ';
2669 types
[class_count
++] = 'u';
2671 types
[class_count
++] = 'x';
2673 types
[class_count
++] = 'B';
2675 types
[class_count
++] = 'U';
2677 types
[class_count
++] = 'C';
2679 types
[class_count
++] = 'X';
2680 types
[class_count
] = '\0';
2681 /* add everything not already included; user won't see these */
2682 extra_types
= eos(types
);
2683 *extra_types
++ = '\033';
2685 *extra_types
++ = 'u';
2687 *extra_types
++ = 'x';
2689 *extra_types
++ = 'B';
2691 *extra_types
++ = 'U';
2693 *extra_types
++ = 'C';
2695 *extra_types
++ = 'X';
2696 *extra_types
= '\0'; /* for index() */
2697 for (i
= 0; i
< MAXOCLASSES
; i
++)
2698 if (!index(types
, def_oc_syms
[i
].sym
)) {
2699 *extra_types
++ = def_oc_syms
[i
].sym
;
2700 *extra_types
= '\0';
2703 if (class_count
> 1) {
2704 c
= yn_function(prompt
, types
, '\0');
2707 clear_nhwindow(WIN_MESSAGE
);
2711 /* only one thing to itemize */
2720 if (c
== 'x' || (c
== 'X' && billx
&& !xcnt
)) {
2722 (void) doinvbill(1);
2724 pline("No used-up objects%s.",
2725 unpaid_count
? " on your shopping bill" : "");
2728 if (c
== 'u' || (c
== 'U' && unpaid_count
&& !ucnt
)) {
2732 You("are not carrying any unpaid objects.");
2736 if (index("BUCX", c
))
2737 oclass
= c
; /* not a class but understood by this_type_only() */
2739 oclass
= def_char_to_objclass(c
); /* change to object class */
2741 if (oclass
== COIN_CLASS
)
2743 if (index(types
, c
) > index(types
, '\033')) {
2744 /* '> ESC' => hidden choice, something known not to be carried */
2745 const char *which
= 0;
2749 which
= "known to be blessed";
2752 which
= "known to be uncursed";
2755 which
= "known to be cursed";
2759 "have no objects whose blessed/uncursed/cursed status is unknown.");
2760 break; /* better phrasing is desirable */
2766 You("have no %s objects.", which
);
2771 if (query_objlist((char *) 0, &invent
,
2772 ((flags
.invlet_constant
? USE_INVLET
: 0)
2774 &pick_list
, PICK_NONE
, this_type_only
) > 0)
2775 free((genericptr_t
) pick_list
);
2779 /* return a string describing the dungeon feature at <x,y> if there
2780 is one worth mentioning at that location; otherwise null */
2782 dfeature_at(x
, y
, buf
)
2786 struct rm
*lev
= &levl
[x
][y
];
2787 int ltyp
= lev
->typ
, cmap
= -1;
2788 const char *dfeature
= 0;
2789 static char altbuf
[BUFSZ
];
2791 if (IS_DOOR(ltyp
)) {
2792 switch (lev
->doormask
) {
2795 break; /* "doorway" */
2798 break; /* "open door" */
2800 dfeature
= "broken door";
2804 break; /* "closed door" */
2806 /* override door description for open drawbridge */
2807 if (is_drawbridge_wall(x
, y
) >= 0)
2808 dfeature
= "open drawbridge portcullis", cmap
= -1;
2809 } else if (IS_FOUNTAIN(ltyp
))
2810 cmap
= S_fountain
; /* "fountain" */
2811 else if (IS_THRONE(ltyp
))
2812 cmap
= S_throne
; /* "opulent throne" */
2813 else if (is_lava(x
, y
))
2814 cmap
= S_lava
; /* "molten lava" */
2815 else if (is_ice(x
, y
))
2816 cmap
= S_ice
; /* "ice" */
2817 else if (is_pool(x
, y
))
2818 dfeature
= "pool of water";
2819 else if (IS_SINK(ltyp
))
2820 cmap
= S_sink
; /* "sink" */
2821 else if (IS_ALTAR(ltyp
)) {
2822 Sprintf(altbuf
, "%saltar to %s (%s)",
2823 ((lev
->altarmask
& AM_SHRINE
)
2824 && (Is_astralevel(&u
.uz
) || Is_sanctum(&u
.uz
)))
2828 align_str(Amask2align(lev
->altarmask
& ~AM_SHRINE
)));
2830 } else if ((x
== xupstair
&& y
== yupstair
)
2831 || (x
== sstairs
.sx
&& y
== sstairs
.sy
&& sstairs
.up
))
2832 cmap
= S_upstair
; /* "staircase up" */
2833 else if ((x
== xdnstair
&& y
== ydnstair
)
2834 || (x
== sstairs
.sx
&& y
== sstairs
.sy
&& !sstairs
.up
))
2835 cmap
= S_dnstair
; /* "staircase down" */
2836 else if (x
== xupladder
&& y
== yupladder
)
2837 cmap
= S_upladder
; /* "ladder up" */
2838 else if (x
== xdnladder
&& y
== ydnladder
)
2839 cmap
= S_dnladder
; /* "ladder down" */
2840 else if (ltyp
== DRAWBRIDGE_DOWN
)
2841 cmap
= S_vodbridge
; /* "lowered drawbridge" */
2842 else if (ltyp
== DBWALL
)
2843 cmap
= S_vcdbridge
; /* "raised drawbridge" */
2844 else if (IS_GRAVE(ltyp
))
2845 cmap
= S_grave
; /* "grave" */
2846 else if (ltyp
== TREE
)
2847 cmap
= S_tree
; /* "tree" */
2848 else if (ltyp
== IRONBARS
)
2849 dfeature
= "set of iron bars";
2852 dfeature
= defsyms
[cmap
].explanation
;
2854 Strcpy(buf
, dfeature
);
2858 /* look at what is here; if there are many objects (pile_limit or more),
2859 don't show them unless obj_cnt is 0 */
2861 look_here(obj_cnt
, picked_some
)
2862 int obj_cnt
; /* obj_cnt > 0 implies that autopickup is in progress */
2863 boolean picked_some
;
2867 const char *verb
= Blind
? "feel" : "see";
2868 const char *dfeature
= (char *) 0;
2869 char fbuf
[BUFSZ
], fbuf2
[BUFSZ
];
2871 boolean skip_objects
, felt_cockatrice
= FALSE
;
2873 /* default pile_limit is 5; a value of 0 means "never skip"
2874 (and 1 effectively forces "always skip") */
2875 skip_objects
= (flags
.pile_limit
> 0 && obj_cnt
>= flags
.pile_limit
);
2876 if (u
.uswallow
&& u
.ustuck
) {
2877 struct monst
*mtmp
= u
.ustuck
;
2879 Sprintf(fbuf
, "Contents of %s %s", s_suffix(mon_nam(mtmp
)),
2880 mbodypart(mtmp
, STOMACH
));
2881 /* Skip "Contents of " by using fbuf index 12 */
2882 You("%s to %s what is lying in %s.", Blind
? "try" : "look around",
2884 otmp
= mtmp
->minvent
;
2886 for (; otmp
; otmp
= otmp
->nobj
) {
2887 /* If swallower is an animal, it should have become stone
2889 if (otmp
->otyp
== CORPSE
)
2890 feel_cockatrice(otmp
, FALSE
);
2893 Strcpy(fbuf
, "You feel");
2895 (void) display_minventory(mtmp
, MINV_ALL
| PICK_NONE
, fbuf
);
2897 You("%s no objects here.", verb
);
2901 if (!skip_objects
&& (trap
= t_at(u
.ux
, u
.uy
)) && trap
->tseen
)
2902 There("is %s here.",
2903 an(defsyms
[trap_to_defsym(trap
->ttyp
)].explanation
));
2905 otmp
= level
.objects
[u
.ux
][u
.uy
];
2906 dfeature
= dfeature_at(u
.ux
, u
.uy
, fbuf2
);
2907 if (dfeature
&& !strcmp(dfeature
, "pool of water") && Underwater
)
2911 boolean drift
= Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
);
2913 if (dfeature
&& !strncmp(dfeature
, "altar ", 6)) {
2914 /* don't say "altar" twice, dfeature has more info */
2915 You("try to feel what is here.");
2917 const char *where
= (Blind
&& !can_reach_floor(TRUE
))
2918 ? "lying beneath you"
2919 : "lying here on the ",
2920 *onwhat
= (Blind
&& !can_reach_floor(TRUE
))
2922 : surface(u
.ux
, u
.uy
);
2924 You("try to feel what is %s%s.", drift
? "floating here" : where
,
2925 drift
? "" : onwhat
);
2927 if (dfeature
&& !drift
&& !strcmp(dfeature
, surface(u
.ux
, u
.uy
)))
2928 dfeature
= 0; /* ice already identified */
2929 if (!can_reach_floor(TRUE
)) {
2930 pline("But you can't reach it!");
2936 Sprintf(fbuf
, "There is %s here.", an(dfeature
));
2938 if (!otmp
|| is_lava(u
.ux
, u
.uy
)
2939 || (is_pool(u
.ux
, u
.uy
) && !Underwater
)) {
2942 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2943 if (!skip_objects
&& (Blind
|| !dfeature
))
2944 You("%s no objects here.", verb
);
2947 /* we know there is something here */
2952 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2953 if (obj_cnt
== 1 && otmp
->quan
== 1L)
2954 There("is %s object here.", picked_some
? "another" : "an");
2956 There("are %s%s objects here.",
2962 picked_some
? " more" : "");
2963 for (; otmp
; otmp
= otmp
->nexthere
)
2964 if (otmp
->otyp
== CORPSE
&& will_feel_cockatrice(otmp
, FALSE
)) {
2971 corpse_xname(otmp
, (const char *) 0, CXN_ARTICLE
),
2972 poly_when_stoned(youmonst
.data
)
2974 : ", unfortunately");
2975 feel_cockatrice(otmp
, FALSE
);
2978 } else if (!otmp
->nexthere
) {
2979 /* only one object */
2982 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2983 You("%s here %s.", verb
, doname_with_price(otmp
));
2984 iflags
.last_msg
= PLNMSG_ONE_ITEM_HERE
;
2985 if (otmp
->otyp
== CORPSE
)
2986 feel_cockatrice(otmp
, FALSE
);
2990 display_nhwindow(WIN_MESSAGE
, FALSE
);
2991 tmpwin
= create_nhwindow(NHW_MENU
);
2993 putstr(tmpwin
, 0, fbuf
);
2994 putstr(tmpwin
, 0, "");
2996 Sprintf(buf
, "%s that %s here:",
2997 picked_some
? "Other things" : "Things",
2998 Blind
? "you feel" : "are");
2999 putstr(tmpwin
, 0, buf
);
3000 for (; otmp
; otmp
= otmp
->nexthere
) {
3001 if (otmp
->otyp
== CORPSE
&& will_feel_cockatrice(otmp
, FALSE
)) {
3002 felt_cockatrice
= TRUE
;
3003 Sprintf(buf
, "%s...", doname(otmp
));
3004 putstr(tmpwin
, 0, buf
);
3007 putstr(tmpwin
, 0, doname_with_price(otmp
));
3009 display_nhwindow(tmpwin
, TRUE
);
3010 destroy_nhwindow(tmpwin
);
3011 if (felt_cockatrice
)
3012 feel_cockatrice(otmp
, FALSE
);
3013 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
3018 /* the ':' command - explicitly look at what is here, including all objects */
3025 MSGTYPE={norep,noshow} "You see here"
3026 interfere with feedback from the look-here command */
3027 hide_unhide_msgtypes(TRUE
, MSGTYP_MASK_REP_SHOW
);
3028 res
= look_here(0, FALSE
);
3029 /* restore normal msgtype handling */
3030 hide_unhide_msgtypes(FALSE
, MSGTYP_MASK_REP_SHOW
);
3035 will_feel_cockatrice(otmp
, force_touch
)
3037 boolean force_touch
;
3039 if ((Blind
|| force_touch
) && !uarmg
&& !Stone_resistance
3040 && (otmp
->otyp
== CORPSE
&& touch_petrifies(&mons
[otmp
->corpsenm
])))
3046 feel_cockatrice(otmp
, force_touch
)
3048 boolean force_touch
;
3052 if (will_feel_cockatrice(otmp
, force_touch
)) {
3053 /* "the <cockatrice> corpse" */
3054 Strcpy(kbuf
, corpse_xname(otmp
, (const char *) 0, CXN_PFX_THE
));
3056 if (poly_when_stoned(youmonst
.data
))
3057 You("touched %s with your bare %s.", kbuf
,
3058 makeplural(body_part(HAND
)));
3060 pline("Touching %s is a fatal mistake...", kbuf
);
3061 /* normalize body shape here; hand, not body_part(HAND) */
3062 Sprintf(kbuf
, "touching %s bare-handed", killer_xname(otmp
));
3063 /* will call polymon() for the poly_when_stoned() case */
3074 for (otmp
= level
.objects
[obj
->ox
][obj
->oy
]; otmp
; otmp
= otmp
->nexthere
)
3075 if (otmp
!= obj
&& merged(&obj
, &otmp
))
3080 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3083 register struct obj
*otmp
, *obj
;
3085 int objnamelth
= 0, otmpnamelth
= 0;
3088 return FALSE
; /* already the same object */
3089 if (obj
->otyp
!= otmp
->otyp
)
3090 return FALSE
; /* different types */
3091 if (obj
->nomerge
) /* explicitly marked to prevent merge */
3094 /* coins of the same kind will always merge */
3095 if (obj
->oclass
== COIN_CLASS
)
3098 if (obj
->unpaid
!= otmp
->unpaid
|| obj
->spe
!= otmp
->spe
3099 || obj
->cursed
!= otmp
->cursed
|| obj
->blessed
!= otmp
->blessed
3100 || obj
->no_charge
!= otmp
->no_charge
|| obj
->obroken
!= otmp
->obroken
3101 || obj
->otrapped
!= otmp
->otrapped
|| obj
->lamplit
!= otmp
->lamplit
3102 || obj
->bypass
!= otmp
->bypass
)
3107 /* Checks beyond this point either aren't applicable to globs
3108 * or don't inhibit their merger.
3111 if (obj
->oclass
== FOOD_CLASS
3112 && (obj
->oeaten
!= otmp
->oeaten
|| obj
->orotten
!= otmp
->orotten
))
3115 if (obj
->dknown
!= otmp
->dknown
3116 || (obj
->bknown
!= otmp
->bknown
&& !Role_if(PM_PRIEST
))
3117 || obj
->oeroded
!= otmp
->oeroded
|| obj
->oeroded2
!= otmp
->oeroded2
3118 || obj
->greased
!= otmp
->greased
)
3121 if ((obj
->oclass
== WEAPON_CLASS
|| obj
->oclass
== ARMOR_CLASS
)
3122 && (obj
->oerodeproof
!= otmp
->oerodeproof
3123 || obj
->rknown
!= otmp
->rknown
))
3126 if (obj
->otyp
== CORPSE
|| obj
->otyp
== EGG
|| obj
->otyp
== TIN
) {
3127 if (obj
->corpsenm
!= otmp
->corpsenm
)
3131 /* hatching eggs don't merge; ditto for revivable corpses */
3132 if ((obj
->otyp
== EGG
&& (obj
->timed
|| otmp
->timed
))
3133 || (obj
->otyp
== CORPSE
&& otmp
->corpsenm
>= LOW_PM
3134 && is_reviver(&mons
[otmp
->corpsenm
])))
3137 /* allow candle merging only if their ages are close */
3138 /* see begin_burn() for a reference for the magic "25" */
3139 if (Is_candle(obj
) && obj
->age
/ 25 != otmp
->age
/ 25)
3142 /* burning potions of oil never merge */
3143 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
)
3146 /* don't merge surcharged item with base-cost item */
3147 if (obj
->unpaid
&& !same_price(obj
, otmp
))
3150 /* if they have names, make sure they're the same */
3151 objnamelth
= strlen(safe_oname(obj
));
3152 otmpnamelth
= strlen(safe_oname(otmp
));
3153 if ((objnamelth
!= otmpnamelth
3154 && ((objnamelth
&& otmpnamelth
) || obj
->otyp
== CORPSE
))
3155 || (objnamelth
&& otmpnamelth
3156 && strncmp(ONAME(obj
), ONAME(otmp
), objnamelth
)))
3159 /* for the moment, any additional information is incompatible */
3160 if (has_omonst(obj
) || has_omid(obj
) || has_olong(obj
) || has_omonst(otmp
)
3161 || has_omid(otmp
) || has_olong(otmp
))
3164 if (obj
->oartifact
!= otmp
->oartifact
)
3167 if (obj
->known
== otmp
->known
|| !objects
[otmp
->otyp
].oc_uses_known
) {
3168 return (boolean
) objects
[obj
->otyp
].oc_merge
;
3173 /* the '$' command */
3177 /* the messages used to refer to "carrying gold", but that didn't
3178 take containers into account */
3179 long umoney
= money_cnt(invent
);
3181 Your("wallet is empty.");
3183 Your("wallet contains %ld %s.", umoney
, currency(umoney
));
3184 shopper_financial_report();
3188 /* the ')' command */
3193 You("are empty %s.", body_part(HANDED
));
3195 prinv((char *) 0, uwep
, 0L);
3197 prinv((char *) 0, uswapwep
, 0L);
3202 /* caller is responsible for checking !wearing_armor() */
3204 noarmor(report_uskin
)
3205 boolean report_uskin
;
3207 if (!uskin
|| !report_uskin
) {
3208 You("are not wearing any armor.");
3210 char *p
, *uskinname
, buf
[BUFSZ
];
3212 uskinname
= strcpy(buf
, simpleonames(uskin
));
3213 /* shorten "set of <color> dragon scales" to "<color> scales"
3214 and "<color> dragon scale mail" to "<color> scale mail" */
3215 if (!strncmpi(uskinname
, "set of ", 7))
3217 if ((p
= strstri(uskinname
, " dragon ")) != 0)
3218 while ((p
[1] = p
[8]) != '\0')
3221 You("are not wearing armor but have %s embedded in your skin.",
3226 /* the '[' command */
3231 register int ct
= 0;
3233 * Note: players sometimes get here by pressing a function key which
3234 * transmits ''ESC [ <something>'' rather than by pressing '[';
3235 * there's nothing we can--or should-do about that here.
3238 if (!wearing_armor()) {
3242 lets
[ct
++] = obj_to_let(uarmu
);
3244 lets
[ct
++] = obj_to_let(uarm
);
3246 lets
[ct
++] = obj_to_let(uarmc
);
3248 lets
[ct
++] = obj_to_let(uarmh
);
3250 lets
[ct
++] = obj_to_let(uarms
);
3252 lets
[ct
++] = obj_to_let(uarmg
);
3254 lets
[ct
++] = obj_to_let(uarmf
);
3256 (void) display_inventory(lets
, FALSE
);
3261 /* the '=' command */
3265 if (!uleft
&& !uright
)
3266 You("are not wearing any rings.");
3269 register int ct
= 0;
3272 lets
[ct
++] = obj_to_let(uleft
);
3274 lets
[ct
++] = obj_to_let(uright
);
3276 (void) display_inventory(lets
, FALSE
);
3281 /* the '"' command */
3286 You("are not wearing an amulet.");
3288 prinv((char *) 0, uamul
, 0L);
3296 if ((obj
->owornmask
& (W_TOOL
| W_SADDLE
)) != 0L)
3298 if (obj
->oclass
!= TOOL_CLASS
)
3300 return (boolean
) (obj
== uwep
|| obj
->lamplit
3301 || (obj
->otyp
== LEASH
&& obj
->leashmon
));
3304 /* the '(' command */
3312 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3313 if (tool_in_use(otmp
))
3314 lets
[ct
++] = obj_to_let(otmp
);
3317 You("are not using any tools.");
3319 (void) display_inventory(lets
, FALSE
);
3323 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3324 show inventory of all currently wielded, worn, or used objects */
3332 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3333 if (is_worn(otmp
) || tool_in_use(otmp
))
3334 lets
[ct
++] = obj_to_let(otmp
);
3337 You("are not wearing or wielding anything.");
3339 (void) display_inventory(lets
, FALSE
);
3344 * uses up an object that's on the floor, charging for it as necessary
3347 useupf(obj
, numused
)
3348 register struct obj
*obj
;
3351 register struct obj
*otmp
;
3352 boolean at_u
= (obj
->ox
== u
.ux
&& obj
->oy
== u
.uy
);
3354 /* burn_floor_objects() keeps an object pointer that it tries to
3355 * useupf() multiple times, so obj must survive if plural */
3356 if (obj
->quan
> numused
)
3357 otmp
= splitobj(obj
, numused
);
3360 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
3361 if (index(u
.urooms
, *in_rooms(otmp
->ox
, otmp
->oy
, 0)))
3362 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
3364 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
, FALSE
);
3367 if (at_u
&& u
.uundetected
&& hides_under(youmonst
.data
))
3368 (void) hideunder(&youmonst
);
3372 * Conversion from a class to a string for printing.
3373 * This must match the object class order.
3375 STATIC_VAR NEARDATA
const char *names
[] = {
3376 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3377 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3378 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3381 static NEARDATA
const char oth_symbols
[] = { CONTAINED_SYM
, '\0' };
3383 static NEARDATA
const char *oth_names
[] = { "Bagged/Boxed items" };
3385 static NEARDATA
char *invbuf
= (char *) 0;
3386 static NEARDATA
unsigned invbufsiz
= 0;
3389 let_to_name(let
, unpaid
, showsym
)
3391 boolean unpaid
, showsym
;
3393 const char *ocsymfmt
= " ('%c')";
3394 const int invbuf_sympadding
= 8; /* arbitrary */
3395 const char *class_name
;
3397 int oclass
= (let
>= 1 && let
< MAXOCLASSES
) ? let
: 0;
3401 class_name
= names
[oclass
];
3402 else if ((pos
= index(oth_symbols
, let
)) != 0)
3403 class_name
= oth_names
[pos
- oth_symbols
];
3405 class_name
= names
[0];
3407 len
= strlen(class_name
) + (unpaid
? sizeof "unpaid_" : sizeof "")
3408 + (oclass
? (strlen(ocsymfmt
) + invbuf_sympadding
) : 0);
3409 if (len
> invbufsiz
) {
3411 free((genericptr_t
) invbuf
);
3412 invbufsiz
= len
+ 10; /* add slop to reduce incremental realloc */
3413 invbuf
= (char *) alloc(invbufsiz
);
3416 Strcat(strcpy(invbuf
, "Unpaid "), class_name
);
3418 Strcpy(invbuf
, class_name
);
3419 if ((oclass
!= 0) && showsym
) {
3420 char *bp
= eos(invbuf
);
3421 int mlen
= invbuf_sympadding
- strlen(class_name
);
3422 while (--mlen
> 0) {
3427 Sprintf(eos(invbuf
), ocsymfmt
, def_oc_syms
[oclass
].sym
);
3432 /* release the static buffer used by let_to_name() */
3437 free((genericptr_t
) invbuf
), invbuf
= (char *) 0;
3441 /* give consecutive letters to every item in inventory (for !fixinv mode);
3442 gold is always forced to '$' slot at head of list */
3447 struct obj
*obj
, *prevobj
, *goldobj
;
3449 /* first, remove [first instance of] gold from invent, if present */
3450 prevobj
= goldobj
= 0;
3451 for (obj
= invent
; obj
; prevobj
= obj
, obj
= obj
->nobj
)
3452 if (obj
->oclass
== COIN_CLASS
) {
3455 prevobj
->nobj
= goldobj
->nobj
;
3457 invent
= goldobj
->nobj
;
3460 /* second, re-letter the rest of the list */
3461 for (obj
= invent
, i
= 0; obj
; obj
= obj
->nobj
, i
++)
3463 (i
< 26) ? ('a' + i
) : (i
< 52) ? ('A' + i
- 26) : NOINVSYM
;
3464 /* third, assign gold the "letter" '$' and re-insert it at head */
3466 goldobj
->invlet
= GOLD_SYM
;
3467 goldobj
->nobj
= invent
;
3477 * User specifies a 'from' slot for inventory stack to move,
3478 * then a 'to' slot for its destination. Open slots and those
3479 * filled by compatible stacks are listed as likely candidates
3480 * but user can pick any inventory letter (including 'from').
3481 * All compatible items found are gathered into the 'from'
3482 * stack as it is moved. If the 'to' slot isn't empty and
3483 * doesn't merge, then its stack is swapped to the 'from' slot.
3485 * If the user specifies a count when choosing the 'from' slot,
3486 * and that count is less than the full size of the stack,
3487 * then the stack will be split. The 'count' portion is moved
3488 * to the destination, and the only candidate for merging with
3489 * it is the stack already at the 'to' slot, if any. When the
3490 * destination is non-empty but won't merge, whatever is there
3491 * will be moved to an open slot; if there isn't any open slot
3492 * available, the adjustment attempt fails.
3494 * Splitting has one special case: if 'to' slot is non-empty
3495 * and is compatible with 'from' in all respects except for
3496 * user-assigned names, the 'count' portion being moved is
3497 * effectively renamed so that it will merge with 'to' stack.
3500 doorganize() /* inventory organizer by Del Lamb */
3502 struct obj
*obj
, *otmp
, *splitting
, *bumped
;
3503 int ix
, cur
, trycnt
;
3505 char alphabet
[52 + 1], buf
[52 + 1];
3507 char allowall
[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3508 const char *adj_type
;
3511 You("aren't carrying anything to adjust.");
3515 if (!flags
.invlet_constant
)
3517 /* get object the user wants to organize (the 'from' slot) */
3518 allowall
[0] = ALLOW_COUNT
;
3519 allowall
[1] = ALL_CLASSES
;
3521 if (!(obj
= getobj(allowall
, "adjust")))
3524 /* figure out whether user gave a split count to getobj() */
3525 splitting
= bumped
= 0;
3526 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3527 if (otmp
->nobj
== obj
) { /* knowledge of splitobj() operation */
3528 if (otmp
->invlet
== obj
->invlet
)
3533 /* initialize the list with all lower and upper case letters */
3534 for (ix
= 0, let
= 'a'; let
<= 'z';)
3535 alphabet
[ix
++] = let
++;
3536 for (let
= 'A'; let
<= 'Z';)
3537 alphabet
[ix
++] = let
++;
3538 alphabet
[ix
] = '\0';
3539 /* for floating inv letters, truncate list after the first open slot */
3540 if (!flags
.invlet_constant
&& (ix
= inv_cnt(FALSE
)) < 52)
3541 alphabet
[ix
+ (splitting
? 0 : 1)] = '\0';
3543 /* blank out all the letters currently in use in the inventory */
3544 /* except those that will be merged with the selected object */
3545 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3546 if (otmp
!= obj
&& !mergable(otmp
, obj
)) {
3548 if (let
>= 'a' && let
<= 'z')
3549 alphabet
[let
- 'a'] = ' ';
3550 else if (let
>= 'A' && let
<= 'Z')
3551 alphabet
[let
- 'A' + 26] = ' ';
3554 /* compact the list by removing all the blanks */
3555 for (ix
= cur
= 0; alphabet
[ix
]; ix
++)
3556 if (alphabet
[ix
] != ' ')
3557 buf
[cur
++] = alphabet
[ix
];
3558 if (!cur
&& obj
->invlet
== NOINVSYM
)
3559 buf
[cur
++] = NOINVSYM
;
3561 /* and by dashing runs of letters */
3565 /* get 'to' slot to use as destination */
3566 Sprintf(qbuf
, "Adjust letter to what [%s]%s?", buf
,
3567 invent
? " (? see used letters)" : "");
3568 for (trycnt
= 1; ; ++trycnt
) {
3569 let
= yn_function(qbuf
, (char *) 0, '\0');
3570 if (let
== '?' || let
== '*') {
3571 let
= display_used_invlets(splitting
? obj
->invlet
: 0);
3577 if (index(quitchars
, let
)
3578 /* adjusting to same slot is meaningful since all
3579 compatible stacks get collected along the way,
3580 but splitting to same slot is not */
3581 || (splitting
&& let
== obj
->invlet
)) {
3584 (void) merged(&splitting
, &obj
);
3588 if ((letter(let
) && let
!= '@') || index(buf
, let
))
3589 break; /* got one */
3592 pline("Select an inventory slot letter."); /* else try again */
3595 /* change the inventory and print the resulting item */
3596 adj_type
= !splitting
? "Moving:" : "Splitting:";
3599 * don't use freeinv/addinv to avoid double-touching artifacts,
3600 * dousing lamps, losing luck, cursing loadstone, etc.
3602 extract_nobj(obj
, &invent
);
3604 for (otmp
= invent
; otmp
;) {
3606 if (merged(&otmp
, &obj
)) {
3607 adj_type
= "Merging:";
3610 extract_nobj(obj
, &invent
);
3611 continue; /* otmp has already been updated */
3612 } else if (otmp
->invlet
== let
) {
3613 adj_type
= "Swapping:";
3614 otmp
->invlet
= obj
->invlet
;
3617 /* splitting: don't merge extra compatible stacks;
3618 if destination is compatible, do merge with it,
3619 otherwise bump whatever is there to an open slot */
3620 if (otmp
->invlet
== let
) {
3624 olth
= strlen(ONAME(obj
));
3625 /* ugly hack: if these objects aren't going to merge
3626 solely because they have conflicting user-assigned
3627 names, strip off the name of the one being moved */
3628 if (olth
&& !obj
->oartifact
&& !mergable(otmp
, obj
)) {
3629 char *holdname
= ONAME(obj
);
3631 ONAME(obj
) = (char *) 0;
3632 /* restore name iff merging is still not possible */
3633 if (!mergable(otmp
, obj
)) {
3634 ONAME(obj
) = holdname
;
3635 holdname
= (char *) 0;
3637 free((genericptr_t
) holdname
);
3640 if (merged(&otmp
, &obj
)) {
3642 extract_nobj(obj
, &invent
);
3643 } else if (inv_cnt(FALSE
) >= 52) {
3644 (void) merged(&splitting
, &obj
); /* undo split */
3645 /* "knapsack cannot accommodate any more items" */
3646 Your("pack is too full.");
3650 extract_nobj(bumped
, &invent
);
3653 } /* found 'to' slot */
3658 /* inline addinv; insert loose object at beginning of inventory */
3661 obj
->where
= OBJ_INVENT
;
3665 /* splitting the 'from' stack is causing an incompatible
3666 stack in the 'to' slot to be moved into an open one;
3667 we need to do another inline insertion to inventory */
3668 assigninvlet(bumped
);
3669 bumped
->nobj
= invent
;
3670 bumped
->where
= OBJ_INVENT
;
3675 /* messages deferred until inventory has been fully reestablished */
3676 prinv(adj_type
, obj
, 0L);
3678 prinv("Moving:", bumped
, 0L);
3680 clear_splitobjs(); /* reset splitobj context */
3685 /* common to display_minventory and display_cinventory */
3687 invdisp_nothing(hdr
, txt
)
3688 const char *hdr
, *txt
;
3692 menu_item
*selected
;
3695 win
= create_nhwindow(NHW_MENU
);
3697 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, hdr
,
3699 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3700 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, txt
, MENU_UNSELECTED
);
3701 end_menu(win
, (char *) 0);
3702 if (select_menu(win
, PICK_NONE
, &selected
) > 0)
3703 free((genericptr_t
) selected
);
3704 destroy_nhwindow(win
);
3708 /* query_objlist callback: return things that are worn or wielded */
3710 worn_wield_only(obj
)
3714 /* check for things that *are* worn or wielded (only used for monsters,
3715 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3716 return (boolean
) (obj
->owornmask
!= 0L);
3718 /* this used to check for things that *might* be worn or wielded,
3719 but that's not particularly interesting */
3720 if (is_weptool(obj
) || is_wet_towel(obj
) || obj
->otyp
== MEAT_RING
)
3722 return (boolean
) (obj
->oclass
== WEAPON_CLASS
3723 || obj
->oclass
== ARMOR_CLASS
3724 || obj
->oclass
== AMULET_CLASS
3725 || obj
->oclass
== RING_CLASS
);
3730 * Display a monster's inventory.
3731 * Returns a pointer to the object from the monster's inventory selected
3732 * or NULL if nothing was selected.
3734 * By default, only worn and wielded items are displayed. The caller
3735 * can pick one. Modifier flags are:
3737 * PICK_NONE, PICK_ONE - standard menu control
3738 * PICK_ANY - allowed, but we only return a single object
3739 * MINV_NOLET - nothing selectable
3740 * MINV_ALL - display all inventory
3743 display_minventory(mon
, dflags
, title
)
3744 register struct monst
*mon
;
3751 menu_item
*selected
= 0;
3752 int do_all
= (dflags
& MINV_ALL
) != 0,
3753 incl_hero
= (do_all
&& u
.uswallow
&& mon
== u
.ustuck
),
3754 have_inv
= (mon
->minvent
!= 0), have_any
= (have_inv
|| incl_hero
),
3755 pickings
= (dflags
& MINV_PICKMASK
);
3757 Sprintf(tmp
, "%s %s:", s_suffix(noit_Monnam(mon
)),
3758 do_all
? "possessions" : "armament");
3760 if (do_all
? have_any
: (mon
->misc_worn_check
|| MON_WEP(mon
))) {
3761 /* Fool the 'weapon in hand' routine into
3762 * displaying 'weapon in claw', etc. properly.
3764 youmonst
.data
= mon
->data
;
3766 n
= query_objlist(title
? title
: tmp
, &(mon
->minvent
),
3767 (INVORDER_SORT
| (incl_hero
? INCLUDE_HERO
: 0)),
3768 &selected
, pickings
,
3769 do_all
? allow_all
: worn_wield_only
);
3772 invdisp_nothing(title
? title
: tmp
, "(none)");
3777 ret
= selected
[0].item
.a_obj
;
3778 free((genericptr_t
) selected
);
3780 ret
= (struct obj
*) 0;
3785 * Display the contents of a container in inventory style.
3786 * Currently, this is only used for statues, via wand of probing.
3789 display_cinventory(obj
)
3790 register struct obj
*obj
;
3795 menu_item
*selected
= 0;
3797 (void) safe_qbuf(qbuf
, "Contents of ", ":", obj
, doname
, ansimpleoname
,
3801 n
= query_objlist(qbuf
, &(obj
->cobj
), INVORDER_SORT
,
3802 &selected
, PICK_NONE
, allow_all
);
3804 invdisp_nothing(qbuf
, "(empty)");
3808 ret
= selected
[0].item
.a_obj
;
3809 free((genericptr_t
) selected
);
3811 ret
= (struct obj
*) 0;
3816 /* query objlist callback: return TRUE if obj is at given location */
3823 return (obj
->ox
== only
.x
&& obj
->oy
== only
.y
);
3827 * Display a list of buried items in inventory style. Return a non-zero
3828 * value if there were items at that spot.
3830 * Currently, this is only used with a wand of probing zapped downwards.
3833 display_binventory(x
, y
, as_if_seen
)
3838 menu_item
*selected
= 0;
3841 /* count # of objects here */
3842 for (n
= 0, obj
= level
.buriedobjlist
; obj
; obj
= obj
->nobj
)
3843 if (obj
->ox
== x
&& obj
->oy
== y
) {
3852 if (query_objlist("Things that are buried here:",
3853 &level
.buriedobjlist
, INVORDER_SORT
,
3854 &selected
, PICK_NONE
, only_here
) > 0)
3855 free((genericptr_t
) selected
);
3856 only
.x
= only
.y
= 0;