1 /* NetHack 3.6 invent.c $NHDT-Date: 1461967848 2016/04/29 22:10:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.208 $ */
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
) ? "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
];
1578 takeoff
= ident
= allflag
= m_seen
= FALSE
;
1580 You("have nothing to %s.", word
);
1583 add_valid_menu_class(0); /* reset */
1584 if (taking_off(word
)) {
1587 } else if (!strcmp(word
, "identify")) {
1589 ofilter
= not_fully_identified
;
1592 iletct
= collect_obj_classes(ilets
, invent
, FALSE
, ofilter
, &itemcount
);
1593 unpaid
= count_unpaid(invent
);
1595 if (ident
&& !iletct
) {
1596 return -1; /* no further identifications */
1597 } else if (!takeoff
&& (unpaid
|| invent
)) {
1598 ilets
[iletct
++] = ' ';
1600 ilets
[iletct
++] = 'u';
1601 if (count_buc(invent
, BUC_BLESSED
))
1602 ilets
[iletct
++] = 'B';
1603 if (count_buc(invent
, BUC_UNCURSED
))
1604 ilets
[iletct
++] = 'U';
1605 if (count_buc(invent
, BUC_CURSED
))
1606 ilets
[iletct
++] = 'C';
1607 if (count_buc(invent
, BUC_UNKNOWN
))
1608 ilets
[iletct
++] = 'X';
1610 ilets
[iletct
++] = 'a';
1611 } else if (takeoff
&& invent
) {
1612 ilets
[iletct
++] = ' ';
1614 ilets
[iletct
++] = 'i';
1616 ilets
[iletct
++] = 'm'; /* allow menu presentation on request */
1617 ilets
[iletct
] = '\0';
1620 Sprintf(qbuf
, "What kinds of thing do you want to %s? [%s]",
1623 if (buf
[0] == '\033')
1625 if (index(buf
, 'i')) {
1626 char ailets
[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
1629 /* applicable inventory letters; if empty, show entire invent */
1632 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
1633 /* index() check: limit overflow items to one '#' */
1634 if ((*ofilter
)(otmp
) && !index(ailets
, otmp
->invlet
))
1635 (void) strkitten(ailets
, otmp
->invlet
);
1636 if (display_inventory(ailets
, TRUE
) == '\033')
1642 extra_removeables
[0] = '\0';
1644 /* arbitrary types of items can be placed in the weapon slots
1645 [any duplicate entries in extra_removeables[] won't matter] */
1647 (void) strkitten(extra_removeables
, uwep
->oclass
);
1649 (void) strkitten(extra_removeables
, uswapwep
->oclass
);
1651 (void) strkitten(extra_removeables
, uquiver
->oclass
);
1655 olets
[oletct
= 0] = '\0';
1656 while ((sym
= *ip
++) != '\0') {
1659 oc_of_sym
= def_char_to_objclass(sym
);
1660 if (takeoff
&& oc_of_sym
!= MAXOCLASSES
) {
1661 if (index(extra_removeables
, oc_of_sym
)) {
1662 ; /* skip rest of takeoff checks */
1663 } else if (!index(removeables
, oc_of_sym
)) {
1664 pline("Not applicable.");
1666 } else if (oc_of_sym
== ARMOR_CLASS
&& !wearing_armor()) {
1669 } else if (oc_of_sym
== WEAPON_CLASS
&& !uwep
&& !uswapwep
1671 You("are not wielding anything.");
1673 } else if (oc_of_sym
== RING_CLASS
&& !uright
&& !uleft
) {
1674 You("are not wearing rings.");
1676 } else if (oc_of_sym
== AMULET_CLASS
&& !uamul
) {
1677 You("are not wearing an amulet.");
1679 } else if (oc_of_sym
== TOOL_CLASS
&& !ublindf
) {
1680 You("are not wearing a blindfold.");
1685 if (oc_of_sym
== COIN_CLASS
&& !combo
) {
1687 } else if (sym
== 'a') {
1689 } else if (sym
== 'A') {
1690 /* same as the default */;
1691 } else if (sym
== 'u') {
1692 add_valid_menu_class('u');
1694 } else if (sym
== 'B') {
1695 add_valid_menu_class('B');
1697 } else if (sym
== 'U') {
1698 add_valid_menu_class('U');
1700 } else if (sym
== 'C') {
1701 add_valid_menu_class('C');
1703 } else if (sym
== 'X') {
1704 add_valid_menu_class('X');
1706 } else if (sym
== 'm') {
1708 } else if (oc_of_sym
== MAXOCLASSES
) {
1709 You("don't have any %c's.", sym
);
1710 } else if (oc_of_sym
!= VENOM_CLASS
) { /* suppress venom */
1711 if (!index(olets
, oc_of_sym
)) {
1712 add_valid_menu_class(oc_of_sym
);
1713 olets
[oletct
++] = oc_of_sym
;
1721 || (!oletct
&& ckfn
!= ckunpaid
&& ckfn
!= ckvalidcat
))
1723 } else if (flags
.menu_style
!= MENU_TRADITIONAL
&& combo
&& !allflag
) {
1726 /* !!!! test gold dropping */
1727 } else if (allowgold
== 2 && !oletct
) {
1728 return 1; /* you dropped gold (or at least tried to) */
1731 int cnt
= askchain(&invent
, olets
, allflag
, fn
, ckfn
, mx
, word
);
1733 * askchain() has already finished the job in this case
1734 * so set a special flag to convey that back to the caller
1735 * so that it won't continue processing.
1736 * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1738 if (combo
&& allflag
&& resultflags
)
1739 *resultflags
|= ALL_FINISHED
;
1745 * Walk through the chain starting at objchn and ask for all objects
1746 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1747 * whether the action in question (i.e., fn) has to be performed.
1748 * If allflag then no questions are asked. Mx gives the max number
1749 * of objects to be treated. Return the number of objects treated.
1752 askchain(objchn
, olets
, allflag
, fn
, ckfn
, mx
, word
)
1753 struct obj
**objchn
;
1755 const char *olets
, *word
; /* olets is an Obj Class char array */
1756 int FDECL((*fn
), (OBJ_P
)), FDECL((*ckfn
), (OBJ_P
));
1758 struct obj
*otmp
, *otmpo
;
1759 register char sym
, ilet
;
1760 register int cnt
= 0, dud
= 0, tmp
;
1761 boolean takeoff
, nodot
, ident
, take_out
, put_in
, first
, ininv
;
1762 char qbuf
[QBUFSZ
], qpfx
[QBUFSZ
];
1764 takeoff
= taking_off(word
);
1765 ident
= !strcmp(word
, "identify");
1766 take_out
= !strcmp(word
, "take out");
1767 put_in
= !strcmp(word
, "put in");
1768 nodot
= (!strcmp(word
, "nodot") || !strcmp(word
, "drop") || ident
1769 || takeoff
|| take_out
|| put_in
);
1770 ininv
= (*objchn
== invent
);
1772 /* someday maybe we'll sort by 'olets' too (temporarily replace
1773 flags.packorder and pass SORTLOOT_PACK), but not yet... */
1774 sortloot(objchn
, SORTLOOT_INVLET
, FALSE
);
1778 * Interrogate in the object class order specified.
1779 * For example, if a person specifies =/ then first all rings
1780 * will be asked about followed by all wands. -dgk
1784 if (*objchn
&& (*objchn
)->oclass
== COIN_CLASS
)
1785 ilet
--; /* extra iteration */
1787 * Multiple Drop can change the invent chain while it operates
1788 * (dropping a burning potion of oil while levitating creates
1789 * an explosion which can destroy inventory items), so simple
1791 * for (otmp = *objchn; otmp; otmp = otmp2) {
1792 * otmp2 = otmp->nobj;
1795 * is inadequate here. Use each object's bypass bit to keep
1796 * track of which list elements have already been processed.
1798 bypass_objlist(*objchn
, FALSE
); /* clear chain's bypass bits */
1799 while ((otmp
= nxt_unbypassed_obj(*objchn
)) != 0) {
1804 if (olets
&& *olets
&& otmp
->oclass
!= *olets
)
1806 if (takeoff
&& !is_worn(otmp
))
1808 if (ident
&& !not_fully_identified(otmp
))
1810 if (ckfn
&& !(*ckfn
)(otmp
))
1813 safeq_xprn_ctx
.let
= ilet
;
1814 safeq_xprn_ctx
.dot
= !nodot
;
1817 /* traditional_loot() skips prompting when only one
1818 class of objects is involved, so prefix the first
1819 object being queried here with an explanation why */
1820 if (take_out
|| put_in
)
1821 Sprintf(qpfx
, "%s: ", word
), *qpfx
= highc(*qpfx
);
1824 (void) safe_qbuf(qbuf
, qpfx
, "?", otmp
,
1825 ininv
? safeq_xprname
: doname
,
1826 ininv
? safeq_shortxprname
: ansimpleoname
,
1828 sym
= (takeoff
|| ident
|| otmp
->quan
< 2L) ? nyaq(qbuf
)
1835 /* Number was entered; split the object unless it corresponds
1836 to 'none' or 'all'. 2 special cases: cursed loadstones and
1837 welded weapons (eg, multiple daggers) will remain as merged
1838 unit; done to avoid splitting an object that won't be
1839 droppable (even if we're picking up rather than dropping). */
1844 if (yn_number
< otmp
->quan
&& splittable(otmp
))
1845 otmp
= splitobj(otmp
, yn_number
);
1854 if (container_gone(fn
)) {
1855 /* otmp caused magic bag to explode;
1856 both are now gone */
1857 otmp
= 0; /* and return */
1858 } else if (otmp
&& otmp
!= otmpo
) {
1859 /* split occurred, merge again */
1860 (void) merged(&otmpo
, &otmp
);
1873 /* special case for seffects() */
1879 if (olets
&& *olets
&& *++olets
)
1881 if (!takeoff
&& (dud
|| cnt
))
1882 pline("That was all.");
1883 else if (!dud
&& !cnt
)
1884 pline("No applicable objects.");
1886 bypass_objlist(*objchn
, FALSE
);
1891 * Object identification routines:
1894 /* make an object actually be identified; no display updating */
1896 fully_identify_obj(otmp
)
1899 makeknown(otmp
->otyp
);
1900 if (otmp
->oartifact
)
1901 discover_artifact((xchar
) otmp
->oartifact
);
1902 otmp
->known
= otmp
->dknown
= otmp
->bknown
= otmp
->rknown
= 1;
1903 if (Is_container(otmp
) || otmp
->otyp
== STATUE
)
1904 otmp
->cknown
= otmp
->lknown
= 1;
1905 if (otmp
->otyp
== EGG
&& otmp
->corpsenm
!= NON_PM
)
1906 learn_egg_type(otmp
->corpsenm
);
1909 /* ggetobj callback routine; identify an object and give immediate feedback */
1914 fully_identify_obj(otmp
);
1915 prinv((char *) 0, otmp
, 0L);
1919 /* menu of unidentified objects; select and identify up to id_limit of them */
1921 menu_identify(id_limit
)
1924 menu_item
*pick_list
;
1925 int n
, i
, first
= 1, tryct
= 5;
1927 /* assumptions: id_limit > 0 and at least one unID'd item is present */
1930 Sprintf(buf
, "What would you like to identify %s?",
1931 first
? "first" : "next");
1932 n
= query_objlist(buf
, &invent
, (SIGNAL_NOMENU
| SIGNAL_ESCAPE
1933 | USE_INVLET
| INVORDER_SORT
),
1934 &pick_list
, PICK_ANY
, not_fully_identified
);
1939 for (i
= 0; i
< n
; i
++, id_limit
--)
1940 (void) identify(pick_list
[i
].item
.a_obj
);
1941 free((genericptr_t
) pick_list
);
1942 mark_synch(); /* Before we loop to pop open another menu */
1944 } else if (n
== -2) { /* player used ESC to quit menu */
1946 } else if (n
== -1) { /* no eligible items found */
1947 pline("That was all.");
1949 } else if (!--tryct
) { /* stop re-prompting */
1950 pline1(thats_enough_tries
);
1952 } else { /* try again */
1953 pline("Choose an item; use ESC to decline.");
1958 /* dialog with user to identify a given number of items; 0 means all */
1960 identify_pack(id_limit
, learning_id
)
1962 boolean learning_id
; /* true if we just read unknown identify scroll */
1964 struct obj
*obj
, *the_obj
;
1968 the_obj
= 0; /* if unid_cnt ends up 1, this will be it */
1969 for (obj
= invent
; obj
; obj
= obj
->nobj
)
1970 if (not_fully_identified(obj
))
1971 ++unid_cnt
, the_obj
= obj
;
1974 You("have already identified all %sof your possessions.",
1975 learning_id
? "the rest " : "");
1976 } else if (!id_limit
|| id_limit
>= unid_cnt
) {
1977 /* identify everything */
1978 if (unid_cnt
== 1) {
1979 (void) identify(the_obj
);
1981 /* TODO: use fully_identify_obj and cornline/menu/whatever here
1983 for (obj
= invent
; obj
; obj
= obj
->nobj
)
1984 if (not_fully_identified(obj
))
1985 (void) identify(obj
);
1988 /* identify up to `id_limit' items */
1990 if (flags
.menu_style
== MENU_TRADITIONAL
)
1992 n
= ggetobj("identify", identify
, id_limit
, FALSE
,
1995 break; /* quit or no eligible items */
1996 } while ((id_limit
-= n
) > 0);
1997 if (n
== 0 || n
< -1)
1998 menu_identify(id_limit
);
2003 /* called when regaining sight; mark inventory objects which were picked
2004 up while blind as now having been seen */
2006 learn_unseen_invent()
2011 return; /* sanity check */
2013 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2015 continue; /* already seen */
2016 /* set dknown, perhaps bknown (for priest[ess]) */
2019 * If object->eknown gets implemented (see learnwand(zap.c)),
2020 * handle deferred discovery here.
2026 /* should of course only be called for things in invent */
2031 if (!flags
.invlet_constant
) {
2032 obj
->invlet
= NOINVSYM
;
2039 * Print the indicated quantity of the given object. If quan == 0L then use
2040 * the current quantity.
2043 prinv(prefix
, obj
, quan
)
2050 pline("%s%s%s", prefix
, *prefix
? " " : "",
2051 xprname(obj
, (char *) 0, obj_to_let(obj
), TRUE
, 0L, quan
));
2055 xprname(obj
, txt
, let
, dot
, cost
, quan
)
2057 const char *txt
; /* text to print instead of obj */
2058 char let
; /* inventory letter */
2059 boolean dot
; /* append period; (dot && cost => Iu) */
2060 long cost
; /* cost (for inventory of unpaid or expended items) */
2061 long quan
; /* if non-0, print this quantity, not obj->quan */
2063 #ifdef LINT /* handle static char li[BUFSZ]; */
2066 static char li
[BUFSZ
];
2068 boolean use_invlet
= (flags
.invlet_constant
2069 && let
!= CONTAINED_SYM
&& let
!= HANDS_SYM
);
2073 savequan
= obj
->quan
;
2078 * - Then obj == null and 'txt' refers to hands or fingers.
2079 * * Then obj == null and we are printing a total amount.
2080 * > Then the object is contained and doesn't have an inventory letter.
2082 if (cost
!= 0 || let
== '*') {
2083 /* if dot is true, we're doing Iu, otherwise Ix */
2085 iflags
.menu_tab_sep
? "%c - %s\t%6ld %s"
2086 : "%c - %-45s %6ld %s",
2087 (dot
&& use_invlet
? obj
->invlet
: let
),
2088 (txt
? txt
: doname(obj
)), cost
, currency(cost
));
2090 /* ordinary inventory display or pickup message */
2091 Sprintf(li
, "%c - %s%s", (use_invlet
? obj
->invlet
: let
),
2092 (txt
? txt
: doname(obj
)), (dot
? "." : ""));
2095 obj
->quan
= savequan
;
2100 /* the 'i' command */
2104 (void) display_inventory((char *) 0, FALSE
);
2111 * Scan the given list of objects. If last_found is NULL, return the first
2112 * unpaid object found. If last_found is not NULL, then skip over unpaid
2113 * objects until last_found is reached, then set last_found to NULL so the
2114 * next unpaid object is returned. This routine recursively follows
2117 STATIC_OVL
struct obj
*
2118 find_unpaid(list
, last_found
)
2119 struct obj
*list
, **last_found
;
2126 /* still looking for previous unpaid object */
2127 if (list
== *last_found
)
2128 *last_found
= (struct obj
*) 0;
2130 return ((*last_found
= list
));
2132 if (Has_contents(list
)) {
2133 if ((obj
= find_unpaid(list
->cobj
, last_found
)) != 0)
2138 return (struct obj
*) 0;
2141 /* for perm_invent when operating on a partial inventory display, so that
2142 the persistent one doesn't get shrunk during filtering for item selection
2143 then regrown to full inventory, possibly being resized in the process */
2144 static winid cached_pickinv_win
= WIN_ERR
;
2147 free_pickinv_cache()
2149 if (cached_pickinv_win
!= WIN_ERR
) {
2150 destroy_nhwindow(cached_pickinv_win
);
2151 cached_pickinv_win
= WIN_ERR
;
2156 * Internal function used by display_inventory and getobj that can display
2157 * inventory and return a count as well as a letter. If out_cnt is not null,
2158 * any count returned from the menu selection is placed here.
2161 display_pickinv(lets
, xtra_choice
, want_reply
, out_cnt
)
2162 register const char *lets
;
2163 const char *xtra_choice
; /* "fingers", pick hands rather than an object */
2169 char *invlet
= flags
.inv_order
;
2171 winid win
; /* windows being used */
2173 menu_item
*selected
;
2176 lets
= 0; /* simplify tests: (lets) instead of (lets && *lets) */
2178 if (flags
.perm_invent
&& (lets
|| xtra_choice
)) {
2179 /* partial inventory in perm_invent setting; don't operate on
2180 full inventory window, use an alternate one instead; create
2181 the first time needed and keep it for re-use as needed later */
2182 if (cached_pickinv_win
== WIN_ERR
)
2183 cached_pickinv_win
= create_nhwindow(NHW_MENU
);
2184 win
= cached_pickinv_win
;
2189 * Exit early if no inventory -- but keep going if we are doing
2190 * a permanent inventory update. We need to keep going so the
2191 * permanent inventory window updates itself to remove the last
2192 * item(s) dropped. One down side: the addition of the exception
2193 * for permanent inventory window updates _can_ pop the window
2194 * up when it's not displayed -- even if it's empty -- because we
2195 * don't know at this level if its up or not. This may not be
2196 * an issue if empty checks are done before hand and the call
2197 * to here is short circuited away.
2199 * 2: our count here is only to distinguish between 0 and 1 and
2200 * more than 1; for the last one, we don't need a precise number.
2201 * For perm_invent update we force 'more than 1'.
2203 n
= (flags
.perm_invent
&& !lets
&& !want_reply
) ? 2
2204 : lets
? (int) strlen(lets
)
2205 : !invent
? 0 : !invent
->nobj
? 1 : 2;
2206 /* for xtra_choice, there's another 'item' not included in initial 'n';
2207 for !lets (full invent) and for override_ID (wizard mode identify),
2208 skip message_menu handling of single item even if item count was 1 */
2209 if (xtra_choice
|| (n
== 1 && (!lets
|| iflags
.override_ID
)))
2213 pline("Not carrying anything.");
2217 /* oxymoron? temporarily assign permanent inventory letters */
2218 if (!flags
.invlet_constant
)
2222 /* when only one item of interest, use pline instead of menus;
2223 we actually use a fake message-line menu in order to allow
2224 the user to perform selection at the --More-- prompt for tty */
2227 /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
2228 "nothing" (ready Quiver), or "fingers" (apply grease) */
2229 ret
= message_menu(HANDS_SYM
, PICK_ONE
,
2230 xprname((struct obj
*) 0, xtra_choice
,
2231 HANDS_SYM
, TRUE
, 0L, 0L)); /* '-' */
2233 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2234 if (!lets
|| otmp
->invlet
== lets
[0])
2237 ret
= message_menu(otmp
->invlet
,
2238 want_reply
? PICK_ONE
: PICK_NONE
,
2239 xprname(otmp
, (char *) 0, lets
[0],
2243 *out_cnt
= -1L; /* select all */
2248 (((flags
.sortloot
== 'f') ? SORTLOOT_LOOT
: SORTLOOT_INVLET
)
2249 | (flags
.sortpack
? SORTLOOT_PACK
: 0)),
2254 if (wizard
&& iflags
.override_ID
) {
2255 char prompt
[QBUFSZ
];
2258 /* wiz_identify stuffed the wiz_identify command character (^I)
2259 into iflags.override_ID for our use as an accelerator */
2260 Sprintf(prompt
, "Debug Identify (%s to permanently identify)",
2261 visctrl(iflags
.override_ID
));
2262 add_menu(win
, NO_GLYPH
, &any
, '_', iflags
.override_ID
, ATR_NONE
,
2263 prompt
, MENU_UNSELECTED
);
2264 } else if (xtra_choice
) {
2265 /* wizard override ID and xtra_choice are mutually exclusive */
2267 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2268 "Miscellaneous", MENU_UNSELECTED
);
2269 any
.a_char
= HANDS_SYM
; /* '-' */
2270 add_menu(win
, NO_GLYPH
, &any
, HANDS_SYM
, 0, ATR_NONE
,
2271 xtra_choice
, MENU_UNSELECTED
);
2275 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2276 if (lets
&& !index(lets
, otmp
->invlet
))
2278 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2279 any
= zeroany
; /* all bits zero */
2280 ilet
= otmp
->invlet
;
2281 if (flags
.sortpack
&& !classcount
) {
2282 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
,
2283 let_to_name(*invlet
, FALSE
,
2284 (want_reply
&& iflags
.menu_head_objsym
)),
2289 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2290 doname(otmp
), MENU_UNSELECTED
);
2293 if (flags
.sortpack
) {
2296 if (--invlet
!= venom_inv
) {
2301 end_menu(win
, (char *) 0);
2303 n
= select_menu(win
, want_reply
? PICK_ONE
: PICK_NONE
, &selected
);
2305 ret
= selected
[0].item
.a_char
;
2307 *out_cnt
= selected
[0].count
;
2308 free((genericptr_t
) selected
);
2310 ret
= !n
? '\0' : '\033'; /* cancelled */
2316 * If lets == NULL or "", list all objects in the inventory. Otherwise,
2317 * list all objects with object classes that match the order in lets.
2319 * Returns the letter identifier of a selected item, or 0 if nothing
2323 display_inventory(lets
, want_reply
)
2327 return display_pickinv(lets
, (char *) 0, want_reply
, (long *) 0);
2331 * Show what is current using inventory letters.
2335 display_used_invlets(avoidlet
)
2340 char *invlet
= flags
.inv_order
;
2341 int n
, classcount
, invdone
= 0;
2344 menu_item
*selected
;
2347 win
= create_nhwindow(NHW_MENU
);
2350 any
= zeroany
; /* set all bits to zero */
2352 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2353 ilet
= otmp
->invlet
;
2354 if (ilet
== avoidlet
)
2356 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2357 if (flags
.sortpack
&& !classcount
) {
2358 any
= zeroany
; /* zero */
2359 add_menu(win
, NO_GLYPH
, &any
, 0, 0,
2360 iflags
.menu_headings
,
2361 let_to_name(*invlet
, FALSE
, FALSE
),
2366 add_menu(win
, obj_to_glyph(otmp
), &any
, ilet
, 0, ATR_NONE
,
2367 doname(otmp
), MENU_UNSELECTED
);
2370 if (flags
.sortpack
&& *++invlet
)
2374 end_menu(win
, "Inventory letters used:");
2376 n
= select_menu(win
, PICK_ONE
, &selected
);
2378 ret
= selected
[0].item
.a_char
;
2379 free((genericptr_t
) selected
);
2381 ret
= !n
? '\0' : '\033'; /* cancelled */
2382 destroy_nhwindow(win
);
2388 * Returns the number of unpaid items within the given list. This includes
2389 * contained objects.
2400 if (Has_contents(list
))
2401 count
+= count_unpaid(list
->cobj
);
2408 * Returns the number of items with b/u/c/unknown within the given list.
2409 * This does NOT include contained objects.
2411 * Assumes that the hero sees or touches or otherwise senses the objects
2412 * at some point: bknown is forced for priest[ess], like in xname().
2415 count_buc(list
, type
)
2421 for (; list
; list
= list
->nobj
) {
2422 /* coins are "none of the above" as far as BUCX filtering goes */
2423 if (list
->oclass
== COIN_CLASS
)
2425 /* priests always know bless/curse state */
2426 if (Role_if(PM_PRIEST
))
2429 /* check whether this object matches the requested type */
2431 ? (type
== BUC_UNKNOWN
)
2432 : list
->blessed
? (type
== BUC_BLESSED
)
2433 : list
->cursed
? (type
== BUC_CURSED
)
2434 : (type
== BUC_UNCURSED
))
2440 /* similar to count_buc(), but tallies all states at once
2441 rather than looking for a specific type */
2443 tally_BUCX(list
, bcp
, ucp
, ccp
, xcp
, ocp
)
2445 int *bcp
, *ucp
, *ccp
, *xcp
, *ocp
;
2447 *bcp
= *ucp
= *ccp
= *xcp
= *ocp
= 0;
2448 for (; list
; list
= list
->nobj
) {
2449 if (list
->oclass
== COIN_CLASS
) {
2450 ++(*ocp
); /* "other" */
2453 /* priests always know bless/curse state */
2454 if (Role_if(PM_PRIEST
))
2459 else if (list
->blessed
)
2461 else if (list
->cursed
)
2463 else /* neither blessed nor cursed => uncursed */
2469 count_contents(container
, nested
, quantity
, everything
)
2470 struct obj
*container
;
2471 boolean nested
, /* include contents of any nested containers */
2472 quantity
, /* count all vs count separate stacks */
2473 everything
; /* all objects vs only unpaid objects */
2478 for (otmp
= container
->cobj
; otmp
; otmp
= otmp
->nobj
) {
2479 if (nested
&& Has_contents(otmp
))
2480 count
+= count_contents(otmp
, nested
, quantity
, everything
);
2481 if (everything
|| otmp
->unpaid
)
2482 count
+= quantity
? otmp
->quan
: 1L;
2491 struct obj
*otmp
, *marker
;
2493 char *invlet
= flags
.inv_order
;
2494 int classcount
, count
, num_so_far
;
2497 count
= count_unpaid(invent
);
2500 marker
= (struct obj
*) 0;
2501 otmp
= find_unpaid(invent
, &marker
);
2502 cost
= unpaid_cost(otmp
, FALSE
);
2503 iflags
.suppress_price
++; /* suppress "(unpaid)" suffix */
2504 pline1(xprname(otmp
, distant_name(otmp
, doname
),
2505 carried(otmp
) ? otmp
->invlet
: CONTAINED_SYM
, TRUE
,
2507 iflags
.suppress_price
--;
2511 win
= create_nhwindow(NHW_MENU
);
2513 num_so_far
= 0; /* count of # printed so far */
2514 if (!flags
.invlet_constant
)
2519 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2520 ilet
= otmp
->invlet
;
2522 if (!flags
.sortpack
|| otmp
->oclass
== *invlet
) {
2523 if (flags
.sortpack
&& !classcount
) {
2524 putstr(win
, 0, let_to_name(*invlet
, TRUE
, FALSE
));
2528 totcost
+= cost
= unpaid_cost(otmp
, FALSE
);
2529 iflags
.suppress_price
++; /* suppress "(unpaid)" suffix */
2530 putstr(win
, 0, xprname(otmp
, distant_name(otmp
, doname
),
2531 ilet
, TRUE
, cost
, 0L));
2532 iflags
.suppress_price
--;
2537 } while (flags
.sortpack
&& (*++invlet
));
2539 if (count
> num_so_far
) {
2540 /* something unpaid is contained */
2542 putstr(win
, 0, let_to_name(CONTAINED_SYM
, TRUE
, FALSE
));
2544 * Search through the container objects in the inventory for
2545 * unpaid items. The top level inventory items have already
2548 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2549 if (Has_contents(otmp
)) {
2552 marker
= (struct obj
*) 0; /* haven't found any */
2553 while (find_unpaid(otmp
->cobj
, &marker
)) {
2554 totcost
+= cost
= unpaid_cost(marker
, FALSE
);
2557 iflags
.suppress_price
++; /* suppress "(unpaid)" sfx */
2559 xprname(marker
, distant_name(marker
, doname
),
2560 CONTAINED_SYM
, TRUE
, cost
, 0L));
2561 iflags
.suppress_price
--;
2564 if (!otmp
->cknown
) {
2565 char contbuf
[BUFSZ
];
2567 /* Shopkeeper knows what to charge for contents */
2568 Sprintf(contbuf
, "%s contents", s_suffix(xname(otmp
)));
2570 xprname((struct obj
*) 0, contbuf
, CONTAINED_SYM
,
2571 TRUE
, contcost
, 0L));
2579 xprname((struct obj
*) 0, "Total:", '*', FALSE
, totcost
, 0L));
2580 display_nhwindow(win
, FALSE
);
2581 destroy_nhwindow(win
);
2584 /* query objlist callback: return TRUE if obj type matches "this_type" */
2585 static int this_type
;
2591 boolean res
= (obj
->oclass
== this_type
);
2593 if (obj
->oclass
!= COIN_CLASS
) {
2594 switch (this_type
) {
2596 res
= (obj
->bknown
&& obj
->blessed
);
2599 res
= (obj
->bknown
&& !(obj
->blessed
|| obj
->cursed
));
2602 res
= (obj
->bknown
&& obj
->cursed
);
2608 break; /* use 'res' as-is */
2614 /* the 'I' command */
2620 char *extra_types
, types
[BUFSZ
];
2621 int class_count
, oclass
, unpaid_count
, itemcount
;
2622 int bcnt
, ccnt
, ucnt
, xcnt
, ocnt
;
2623 boolean billx
= *u
.ushops
&& doinvbill(0);
2624 menu_item
*pick_list
;
2625 boolean traditional
= TRUE
;
2626 const char *prompt
= "What type of object do you want an inventory of?";
2628 if (!invent
&& !billx
) {
2629 You("aren't carrying anything.");
2632 unpaid_count
= count_unpaid(invent
);
2633 tally_BUCX(invent
, &bcnt
, &ucnt
, &ccnt
, &xcnt
, &ocnt
);
2635 if (flags
.menu_style
!= MENU_TRADITIONAL
) {
2636 if (flags
.menu_style
== MENU_FULL
2637 || flags
.menu_style
== MENU_PARTIAL
) {
2638 traditional
= FALSE
;
2650 n
= query_category(prompt
, invent
, i
, &pick_list
, PICK_ONE
);
2653 this_type
= c
= pick_list
[0].item
.a_int
;
2654 free((genericptr_t
) pick_list
);
2658 /* collect a list of classes of objects carried, for use as a prompt
2662 collect_obj_classes(types
, invent
, FALSE
,
2663 (boolean
FDECL((*), (OBJ_P
))) 0, &itemcount
);
2664 if (unpaid_count
|| billx
|| (bcnt
+ ccnt
+ ucnt
+ xcnt
) != 0)
2665 types
[class_count
++] = ' ';
2667 types
[class_count
++] = 'u';
2669 types
[class_count
++] = 'x';
2671 types
[class_count
++] = 'B';
2673 types
[class_count
++] = 'U';
2675 types
[class_count
++] = 'C';
2677 types
[class_count
++] = 'X';
2678 types
[class_count
] = '\0';
2679 /* add everything not already included; user won't see these */
2680 extra_types
= eos(types
);
2681 *extra_types
++ = '\033';
2683 *extra_types
++ = 'u';
2685 *extra_types
++ = 'x';
2687 *extra_types
++ = 'B';
2689 *extra_types
++ = 'U';
2691 *extra_types
++ = 'C';
2693 *extra_types
++ = 'X';
2694 *extra_types
= '\0'; /* for index() */
2695 for (i
= 0; i
< MAXOCLASSES
; i
++)
2696 if (!index(types
, def_oc_syms
[i
].sym
)) {
2697 *extra_types
++ = def_oc_syms
[i
].sym
;
2698 *extra_types
= '\0';
2701 if (class_count
> 1) {
2702 c
= yn_function(prompt
, types
, '\0');
2705 clear_nhwindow(WIN_MESSAGE
);
2709 /* only one thing to itemize */
2718 if (c
== 'x' || (c
== 'X' && billx
&& !xcnt
)) {
2720 (void) doinvbill(1);
2722 pline("No used-up objects%s.",
2723 unpaid_count
? " on your shopping bill" : "");
2726 if (c
== 'u' || (c
== 'U' && unpaid_count
&& !ucnt
)) {
2730 You("are not carrying any unpaid objects.");
2734 if (index("BUCX", c
))
2735 oclass
= c
; /* not a class but understood by this_type_only() */
2737 oclass
= def_char_to_objclass(c
); /* change to object class */
2739 if (oclass
== COIN_CLASS
)
2741 if (index(types
, c
) > index(types
, '\033')) {
2742 /* '> ESC' => hidden choice, something known not to be carried */
2743 const char *which
= 0;
2747 which
= "known to be blessed";
2750 which
= "known to be uncursed";
2753 which
= "known to be cursed";
2757 "have no objects whose blessed/uncursed/cursed status is unknown.");
2758 break; /* better phrasing is desirable */
2764 You("have no %s objects.", which
);
2769 if (query_objlist((char *) 0, &invent
,
2770 ((flags
.invlet_constant
? USE_INVLET
: 0)
2772 &pick_list
, PICK_NONE
, this_type_only
) > 0)
2773 free((genericptr_t
) pick_list
);
2777 /* return a string describing the dungeon feature at <x,y> if there
2778 is one worth mentioning at that location; otherwise null */
2780 dfeature_at(x
, y
, buf
)
2784 struct rm
*lev
= &levl
[x
][y
];
2785 int ltyp
= lev
->typ
, cmap
= -1;
2786 const char *dfeature
= 0;
2787 static char altbuf
[BUFSZ
];
2789 if (IS_DOOR(ltyp
)) {
2790 switch (lev
->doormask
) {
2793 break; /* "doorway" */
2796 break; /* "open door" */
2798 dfeature
= "broken door";
2802 break; /* "closed door" */
2804 /* override door description for open drawbridge */
2805 if (is_drawbridge_wall(x
, y
) >= 0)
2806 dfeature
= "open drawbridge portcullis", cmap
= -1;
2807 } else if (IS_FOUNTAIN(ltyp
))
2808 cmap
= S_fountain
; /* "fountain" */
2809 else if (IS_THRONE(ltyp
))
2810 cmap
= S_throne
; /* "opulent throne" */
2811 else if (is_lava(x
, y
))
2812 cmap
= S_lava
; /* "molten lava" */
2813 else if (is_ice(x
, y
))
2814 cmap
= S_ice
; /* "ice" */
2815 else if (is_pool(x
, y
))
2816 dfeature
= "pool of water";
2817 else if (IS_SINK(ltyp
))
2818 cmap
= S_sink
; /* "sink" */
2819 else if (IS_ALTAR(ltyp
)) {
2820 Sprintf(altbuf
, "%saltar to %s (%s)",
2821 ((lev
->altarmask
& AM_SHRINE
)
2822 && (Is_astralevel(&u
.uz
) || Is_sanctum(&u
.uz
)))
2826 align_str(Amask2align(lev
->altarmask
& ~AM_SHRINE
)));
2828 } else if ((x
== xupstair
&& y
== yupstair
)
2829 || (x
== sstairs
.sx
&& y
== sstairs
.sy
&& sstairs
.up
))
2830 cmap
= S_upstair
; /* "staircase up" */
2831 else if ((x
== xdnstair
&& y
== ydnstair
)
2832 || (x
== sstairs
.sx
&& y
== sstairs
.sy
&& !sstairs
.up
))
2833 cmap
= S_dnstair
; /* "staircase down" */
2834 else if (x
== xupladder
&& y
== yupladder
)
2835 cmap
= S_upladder
; /* "ladder up" */
2836 else if (x
== xdnladder
&& y
== ydnladder
)
2837 cmap
= S_dnladder
; /* "ladder down" */
2838 else if (ltyp
== DRAWBRIDGE_DOWN
)
2839 cmap
= S_vodbridge
; /* "lowered drawbridge" */
2840 else if (ltyp
== DBWALL
)
2841 cmap
= S_vcdbridge
; /* "raised drawbridge" */
2842 else if (IS_GRAVE(ltyp
))
2843 cmap
= S_grave
; /* "grave" */
2844 else if (ltyp
== TREE
)
2845 cmap
= S_tree
; /* "tree" */
2846 else if (ltyp
== IRONBARS
)
2847 dfeature
= "set of iron bars";
2850 dfeature
= defsyms
[cmap
].explanation
;
2852 Strcpy(buf
, dfeature
);
2856 /* look at what is here; if there are many objects (pile_limit or more),
2857 don't show them unless obj_cnt is 0 */
2859 look_here(obj_cnt
, picked_some
)
2860 int obj_cnt
; /* obj_cnt > 0 implies that autopickup is in progress */
2861 boolean picked_some
;
2865 const char *verb
= Blind
? "feel" : "see";
2866 const char *dfeature
= (char *) 0;
2867 char fbuf
[BUFSZ
], fbuf2
[BUFSZ
];
2869 boolean skip_objects
, felt_cockatrice
= FALSE
;
2871 /* default pile_limit is 5; a value of 0 means "never skip"
2872 (and 1 effectively forces "always skip") */
2873 skip_objects
= (flags
.pile_limit
> 0 && obj_cnt
>= flags
.pile_limit
);
2874 if (u
.uswallow
&& u
.ustuck
) {
2875 struct monst
*mtmp
= u
.ustuck
;
2877 Sprintf(fbuf
, "Contents of %s %s", s_suffix(mon_nam(mtmp
)),
2878 mbodypart(mtmp
, STOMACH
));
2879 /* Skip "Contents of " by using fbuf index 12 */
2880 You("%s to %s what is lying in %s.", Blind
? "try" : "look around",
2882 otmp
= mtmp
->minvent
;
2884 for (; otmp
; otmp
= otmp
->nobj
) {
2885 /* If swallower is an animal, it should have become stone
2887 if (otmp
->otyp
== CORPSE
)
2888 feel_cockatrice(otmp
, FALSE
);
2891 Strcpy(fbuf
, "You feel");
2893 (void) display_minventory(mtmp
, MINV_ALL
| PICK_NONE
, fbuf
);
2895 You("%s no objects here.", verb
);
2899 if (!skip_objects
&& (trap
= t_at(u
.ux
, u
.uy
)) && trap
->tseen
)
2900 There("is %s here.",
2901 an(defsyms
[trap_to_defsym(trap
->ttyp
)].explanation
));
2903 otmp
= level
.objects
[u
.ux
][u
.uy
];
2904 dfeature
= dfeature_at(u
.ux
, u
.uy
, fbuf2
);
2905 if (dfeature
&& !strcmp(dfeature
, "pool of water") && Underwater
)
2909 boolean drift
= Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
);
2911 if (dfeature
&& !strncmp(dfeature
, "altar ", 6)) {
2912 /* don't say "altar" twice, dfeature has more info */
2913 You("try to feel what is here.");
2915 const char *where
= (Blind
&& !can_reach_floor(TRUE
))
2916 ? "lying beneath you"
2917 : "lying here on the ",
2918 *onwhat
= (Blind
&& !can_reach_floor(TRUE
))
2920 : surface(u
.ux
, u
.uy
);
2922 You("try to feel what is %s%s.", drift
? "floating here" : where
,
2923 drift
? "" : onwhat
);
2925 if (dfeature
&& !drift
&& !strcmp(dfeature
, surface(u
.ux
, u
.uy
)))
2926 dfeature
= 0; /* ice already identified */
2927 if (!can_reach_floor(TRUE
)) {
2928 pline("But you can't reach it!");
2934 Sprintf(fbuf
, "There is %s here.", an(dfeature
));
2936 if (!otmp
|| is_lava(u
.ux
, u
.uy
)
2937 || (is_pool(u
.ux
, u
.uy
) && !Underwater
)) {
2940 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2941 if (!skip_objects
&& (Blind
|| !dfeature
))
2942 You("%s no objects here.", verb
);
2945 /* we know there is something here */
2950 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2951 if (obj_cnt
== 1 && otmp
->quan
== 1L)
2952 There("is %s object here.", picked_some
? "another" : "an");
2954 There("are %s%s objects here.",
2960 picked_some
? " more" : "");
2961 for (; otmp
; otmp
= otmp
->nexthere
)
2962 if (otmp
->otyp
== CORPSE
&& will_feel_cockatrice(otmp
, FALSE
)) {
2969 corpse_xname(otmp
, (const char *) 0, CXN_ARTICLE
),
2970 poly_when_stoned(youmonst
.data
)
2972 : ", unfortunately");
2973 feel_cockatrice(otmp
, FALSE
);
2976 } else if (!otmp
->nexthere
) {
2977 /* only one object */
2980 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
2981 You("%s here %s.", verb
, doname_with_price(otmp
));
2982 iflags
.last_msg
= PLNMSG_ONE_ITEM_HERE
;
2983 if (otmp
->otyp
== CORPSE
)
2984 feel_cockatrice(otmp
, FALSE
);
2988 display_nhwindow(WIN_MESSAGE
, FALSE
);
2989 tmpwin
= create_nhwindow(NHW_MENU
);
2991 putstr(tmpwin
, 0, fbuf
);
2992 putstr(tmpwin
, 0, "");
2994 Sprintf(buf
, "%s that %s here:",
2995 picked_some
? "Other things" : "Things",
2996 Blind
? "you feel" : "are");
2997 putstr(tmpwin
, 0, buf
);
2998 for (; otmp
; otmp
= otmp
->nexthere
) {
2999 if (otmp
->otyp
== CORPSE
&& will_feel_cockatrice(otmp
, FALSE
)) {
3000 felt_cockatrice
= TRUE
;
3001 Sprintf(buf
, "%s...", doname(otmp
));
3002 putstr(tmpwin
, 0, buf
);
3005 putstr(tmpwin
, 0, doname_with_price(otmp
));
3007 display_nhwindow(tmpwin
, TRUE
);
3008 destroy_nhwindow(tmpwin
);
3009 if (felt_cockatrice
)
3010 feel_cockatrice(otmp
, FALSE
);
3011 read_engr_at(u
.ux
, u
.uy
); /* Eric Backus */
3016 /* the ':' command - explicitly look at what is here, including all objects */
3023 MSGTYPE={norep,noshow} "You see here"
3024 interfere with feedback from the look-here command */
3025 hide_unhide_msgtypes(TRUE
, MSGTYP_MASK_REP_SHOW
);
3026 res
= look_here(0, FALSE
);
3027 /* restore normal msgtype handling */
3028 hide_unhide_msgtypes(FALSE
, MSGTYP_MASK_REP_SHOW
);
3033 will_feel_cockatrice(otmp
, force_touch
)
3035 boolean force_touch
;
3037 if ((Blind
|| force_touch
) && !uarmg
&& !Stone_resistance
3038 && (otmp
->otyp
== CORPSE
&& touch_petrifies(&mons
[otmp
->corpsenm
])))
3044 feel_cockatrice(otmp
, force_touch
)
3046 boolean force_touch
;
3050 if (will_feel_cockatrice(otmp
, force_touch
)) {
3051 /* "the <cockatrice> corpse" */
3052 Strcpy(kbuf
, corpse_xname(otmp
, (const char *) 0, CXN_PFX_THE
));
3054 if (poly_when_stoned(youmonst
.data
))
3055 You("touched %s with your bare %s.", kbuf
,
3056 makeplural(body_part(HAND
)));
3058 pline("Touching %s is a fatal mistake...", kbuf
);
3059 /* normalize body shape here; hand, not body_part(HAND) */
3060 Sprintf(kbuf
, "touching %s bare-handed", killer_xname(otmp
));
3061 /* will call polymon() for the poly_when_stoned() case */
3072 for (otmp
= level
.objects
[obj
->ox
][obj
->oy
]; otmp
; otmp
= otmp
->nexthere
)
3073 if (otmp
!= obj
&& merged(&obj
, &otmp
))
3078 /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
3081 register struct obj
*otmp
, *obj
;
3083 int objnamelth
= 0, otmpnamelth
= 0;
3086 return FALSE
; /* already the same object */
3087 if (obj
->otyp
!= otmp
->otyp
)
3088 return FALSE
; /* different types */
3089 if (obj
->nomerge
) /* explicitly marked to prevent merge */
3092 /* coins of the same kind will always merge */
3093 if (obj
->oclass
== COIN_CLASS
)
3096 if (obj
->unpaid
!= otmp
->unpaid
|| obj
->spe
!= otmp
->spe
3097 || obj
->cursed
!= otmp
->cursed
|| obj
->blessed
!= otmp
->blessed
3098 || obj
->no_charge
!= otmp
->no_charge
|| obj
->obroken
!= otmp
->obroken
3099 || obj
->otrapped
!= otmp
->otrapped
|| obj
->lamplit
!= otmp
->lamplit
3100 || obj
->bypass
!= otmp
->bypass
)
3105 /* Checks beyond this point either aren't applicable to globs
3106 * or don't inhibit their merger.
3109 if (obj
->oclass
== FOOD_CLASS
3110 && (obj
->oeaten
!= otmp
->oeaten
|| obj
->orotten
!= otmp
->orotten
))
3113 if (obj
->dknown
!= otmp
->dknown
3114 || (obj
->bknown
!= otmp
->bknown
&& !Role_if(PM_PRIEST
))
3115 || obj
->oeroded
!= otmp
->oeroded
|| obj
->oeroded2
!= otmp
->oeroded2
3116 || obj
->greased
!= otmp
->greased
)
3119 if ((obj
->oclass
== WEAPON_CLASS
|| obj
->oclass
== ARMOR_CLASS
)
3120 && (obj
->oerodeproof
!= otmp
->oerodeproof
3121 || obj
->rknown
!= otmp
->rknown
))
3124 if (obj
->otyp
== CORPSE
|| obj
->otyp
== EGG
|| obj
->otyp
== TIN
) {
3125 if (obj
->corpsenm
!= otmp
->corpsenm
)
3129 /* hatching eggs don't merge; ditto for revivable corpses */
3130 if ((obj
->otyp
== EGG
&& (obj
->timed
|| otmp
->timed
))
3131 || (obj
->otyp
== CORPSE
&& otmp
->corpsenm
>= LOW_PM
3132 && is_reviver(&mons
[otmp
->corpsenm
])))
3135 /* allow candle merging only if their ages are close */
3136 /* see begin_burn() for a reference for the magic "25" */
3137 if (Is_candle(obj
) && obj
->age
/ 25 != otmp
->age
/ 25)
3140 /* burning potions of oil never merge */
3141 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
)
3144 /* don't merge surcharged item with base-cost item */
3145 if (obj
->unpaid
&& !same_price(obj
, otmp
))
3148 /* if they have names, make sure they're the same */
3149 objnamelth
= strlen(safe_oname(obj
));
3150 otmpnamelth
= strlen(safe_oname(otmp
));
3151 if ((objnamelth
!= otmpnamelth
3152 && ((objnamelth
&& otmpnamelth
) || obj
->otyp
== CORPSE
))
3153 || (objnamelth
&& otmpnamelth
3154 && strncmp(ONAME(obj
), ONAME(otmp
), objnamelth
)))
3157 /* for the moment, any additional information is incompatible */
3158 if (has_omonst(obj
) || has_omid(obj
) || has_olong(obj
) || has_omonst(otmp
)
3159 || has_omid(otmp
) || has_olong(otmp
))
3162 if (obj
->oartifact
!= otmp
->oartifact
)
3165 if (obj
->known
== otmp
->known
|| !objects
[otmp
->otyp
].oc_uses_known
) {
3166 return (boolean
) objects
[obj
->otyp
].oc_merge
;
3171 /* the '$' command */
3175 /* the messages used to refer to "carrying gold", but that didn't
3176 take containers into account */
3177 long umoney
= money_cnt(invent
);
3179 Your("wallet is empty.");
3181 Your("wallet contains %ld %s.", umoney
, currency(umoney
));
3182 shopper_financial_report();
3186 /* the ')' command */
3191 You("are empty %s.", body_part(HANDED
));
3193 prinv((char *) 0, uwep
, 0L);
3195 prinv((char *) 0, uswapwep
, 0L);
3200 /* caller is responsible for checking !wearing_armor() */
3202 noarmor(report_uskin
)
3203 boolean report_uskin
;
3205 if (!uskin
|| !report_uskin
) {
3206 You("are not wearing any armor.");
3208 char *p
, *uskinname
, buf
[BUFSZ
];
3210 uskinname
= strcpy(buf
, simpleonames(uskin
));
3211 /* shorten "set of <color> dragon scales" to "<color> scales"
3212 and "<color> dragon scale mail" to "<color> scale mail" */
3213 if (!strncmpi(uskinname
, "set of ", 7))
3215 if ((p
= strstri(uskinname
, " dragon ")) != 0)
3216 while ((p
[1] = p
[8]) != '\0')
3219 You("are not wearing armor but have %s embedded in your skin.",
3224 /* the '[' command */
3229 register int ct
= 0;
3231 * Note: players sometimes get here by pressing a function key which
3232 * transmits ''ESC [ <something>'' rather than by pressing '[';
3233 * there's nothing we can--or should-do about that here.
3236 if (!wearing_armor()) {
3240 lets
[ct
++] = obj_to_let(uarmu
);
3242 lets
[ct
++] = obj_to_let(uarm
);
3244 lets
[ct
++] = obj_to_let(uarmc
);
3246 lets
[ct
++] = obj_to_let(uarmh
);
3248 lets
[ct
++] = obj_to_let(uarms
);
3250 lets
[ct
++] = obj_to_let(uarmg
);
3252 lets
[ct
++] = obj_to_let(uarmf
);
3254 (void) display_inventory(lets
, FALSE
);
3259 /* the '=' command */
3263 if (!uleft
&& !uright
)
3264 You("are not wearing any rings.");
3267 register int ct
= 0;
3270 lets
[ct
++] = obj_to_let(uleft
);
3272 lets
[ct
++] = obj_to_let(uright
);
3274 (void) display_inventory(lets
, FALSE
);
3279 /* the '"' command */
3284 You("are not wearing an amulet.");
3286 prinv((char *) 0, uamul
, 0L);
3294 if ((obj
->owornmask
& (W_TOOL
| W_SADDLE
)) != 0L)
3296 if (obj
->oclass
!= TOOL_CLASS
)
3298 return (boolean
) (obj
== uwep
|| obj
->lamplit
3299 || (obj
->otyp
== LEASH
&& obj
->leashmon
));
3302 /* the '(' command */
3310 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3311 if (tool_in_use(otmp
))
3312 lets
[ct
++] = obj_to_let(otmp
);
3315 You("are not using any tools.");
3317 (void) display_inventory(lets
, FALSE
);
3321 /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
3322 show inventory of all currently wielded, worn, or used objects */
3330 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3331 if (is_worn(otmp
) || tool_in_use(otmp
))
3332 lets
[ct
++] = obj_to_let(otmp
);
3335 You("are not wearing or wielding anything.");
3337 (void) display_inventory(lets
, FALSE
);
3342 * uses up an object that's on the floor, charging for it as necessary
3345 useupf(obj
, numused
)
3346 register struct obj
*obj
;
3349 register struct obj
*otmp
;
3350 boolean at_u
= (obj
->ox
== u
.ux
&& obj
->oy
== u
.uy
);
3352 /* burn_floor_objects() keeps an object pointer that it tries to
3353 * useupf() multiple times, so obj must survive if plural */
3354 if (obj
->quan
> numused
)
3355 otmp
= splitobj(obj
, numused
);
3358 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
3359 if (index(u
.urooms
, *in_rooms(otmp
->ox
, otmp
->oy
, 0)))
3360 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
3362 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
, FALSE
);
3365 if (at_u
&& u
.uundetected
&& hides_under(youmonst
.data
))
3366 (void) hideunder(&youmonst
);
3370 * Conversion from a class to a string for printing.
3371 * This must match the object class order.
3373 STATIC_VAR NEARDATA
const char *names
[] = {
3374 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
3375 "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
3376 "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
3379 static NEARDATA
const char oth_symbols
[] = { CONTAINED_SYM
, '\0' };
3381 static NEARDATA
const char *oth_names
[] = { "Bagged/Boxed items" };
3383 static NEARDATA
char *invbuf
= (char *) 0;
3384 static NEARDATA
unsigned invbufsiz
= 0;
3387 let_to_name(let
, unpaid
, showsym
)
3389 boolean unpaid
, showsym
;
3391 const char *ocsymfmt
= " ('%c')";
3392 const int invbuf_sympadding
= 8; /* arbitrary */
3393 const char *class_name
;
3395 int oclass
= (let
>= 1 && let
< MAXOCLASSES
) ? let
: 0;
3399 class_name
= names
[oclass
];
3400 else if ((pos
= index(oth_symbols
, let
)) != 0)
3401 class_name
= oth_names
[pos
- oth_symbols
];
3403 class_name
= names
[0];
3405 len
= strlen(class_name
) + (unpaid
? sizeof "unpaid_" : sizeof "")
3406 + (oclass
? (strlen(ocsymfmt
) + invbuf_sympadding
) : 0);
3407 if (len
> invbufsiz
) {
3409 free((genericptr_t
) invbuf
);
3410 invbufsiz
= len
+ 10; /* add slop to reduce incremental realloc */
3411 invbuf
= (char *) alloc(invbufsiz
);
3414 Strcat(strcpy(invbuf
, "Unpaid "), class_name
);
3416 Strcpy(invbuf
, class_name
);
3417 if ((oclass
!= 0) && showsym
) {
3418 char *bp
= eos(invbuf
);
3419 int mlen
= invbuf_sympadding
- strlen(class_name
);
3420 while (--mlen
> 0) {
3425 Sprintf(eos(invbuf
), ocsymfmt
, def_oc_syms
[oclass
].sym
);
3430 /* release the static buffer used by let_to_name() */
3435 free((genericptr_t
) invbuf
), invbuf
= (char *) 0;
3439 /* give consecutive letters to every item in inventory (for !fixinv mode);
3440 gold is always forced to '$' slot at head of list */
3445 struct obj
*obj
, *prevobj
, *goldobj
;
3447 /* first, remove [first instance of] gold from invent, if present */
3448 prevobj
= goldobj
= 0;
3449 for (obj
= invent
; obj
; prevobj
= obj
, obj
= obj
->nobj
)
3450 if (obj
->oclass
== COIN_CLASS
) {
3453 prevobj
->nobj
= goldobj
->nobj
;
3455 invent
= goldobj
->nobj
;
3458 /* second, re-letter the rest of the list */
3459 for (obj
= invent
, i
= 0; obj
; obj
= obj
->nobj
, i
++)
3461 (i
< 26) ? ('a' + i
) : (i
< 52) ? ('A' + i
- 26) : NOINVSYM
;
3462 /* third, assign gold the "letter" '$' and re-insert it at head */
3464 goldobj
->invlet
= GOLD_SYM
;
3465 goldobj
->nobj
= invent
;
3475 * User specifies a 'from' slot for inventory stack to move,
3476 * then a 'to' slot for its destination. Open slots and those
3477 * filled by compatible stacks are listed as likely candidates
3478 * but user can pick any inventory letter (including 'from').
3479 * All compatible items found are gathered into the 'from'
3480 * stack as it is moved. If the 'to' slot isn't empty and
3481 * doesn't merge, then its stack is swapped to the 'from' slot.
3483 * If the user specifies a count when choosing the 'from' slot,
3484 * and that count is less than the full size of the stack,
3485 * then the stack will be split. The 'count' portion is moved
3486 * to the destination, and the only candidate for merging with
3487 * it is the stack already at the 'to' slot, if any. When the
3488 * destination is non-empty but won't merge, whatever is there
3489 * will be moved to an open slot; if there isn't any open slot
3490 * available, the adjustment attempt fails.
3492 * Splitting has one special case: if 'to' slot is non-empty
3493 * and is compatible with 'from' in all respects except for
3494 * user-assigned names, the 'count' portion being moved is
3495 * effectively renamed so that it will merge with 'to' stack.
3498 doorganize() /* inventory organizer by Del Lamb */
3500 struct obj
*obj
, *otmp
, *splitting
, *bumped
;
3501 int ix
, cur
, trycnt
;
3503 char alphabet
[52 + 1], buf
[52 + 1];
3505 char allowall
[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
3506 const char *adj_type
;
3509 You("aren't carrying anything to adjust.");
3513 if (!flags
.invlet_constant
)
3515 /* get object the user wants to organize (the 'from' slot) */
3516 allowall
[0] = ALLOW_COUNT
;
3517 allowall
[1] = ALL_CLASSES
;
3519 if (!(obj
= getobj(allowall
, "adjust")))
3522 /* figure out whether user gave a split count to getobj() */
3523 splitting
= bumped
= 0;
3524 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3525 if (otmp
->nobj
== obj
) { /* knowledge of splitobj() operation */
3526 if (otmp
->invlet
== obj
->invlet
)
3531 /* initialize the list with all lower and upper case letters */
3532 for (ix
= 0, let
= 'a'; let
<= 'z';)
3533 alphabet
[ix
++] = let
++;
3534 for (let
= 'A'; let
<= 'Z';)
3535 alphabet
[ix
++] = let
++;
3536 alphabet
[ix
] = '\0';
3537 /* for floating inv letters, truncate list after the first open slot */
3538 if (!flags
.invlet_constant
&& (ix
= inv_cnt(FALSE
)) < 52)
3539 alphabet
[ix
+ (splitting
? 0 : 1)] = '\0';
3541 /* blank out all the letters currently in use in the inventory */
3542 /* except those that will be merged with the selected object */
3543 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
3544 if (otmp
!= obj
&& !mergable(otmp
, obj
)) {
3546 if (let
>= 'a' && let
<= 'z')
3547 alphabet
[let
- 'a'] = ' ';
3548 else if (let
>= 'A' && let
<= 'Z')
3549 alphabet
[let
- 'A' + 26] = ' ';
3552 /* compact the list by removing all the blanks */
3553 for (ix
= cur
= 0; alphabet
[ix
]; ix
++)
3554 if (alphabet
[ix
] != ' ')
3555 buf
[cur
++] = alphabet
[ix
];
3556 if (!cur
&& obj
->invlet
== NOINVSYM
)
3557 buf
[cur
++] = NOINVSYM
;
3559 /* and by dashing runs of letters */
3563 /* get 'to' slot to use as destination */
3564 Sprintf(qbuf
, "Adjust letter to what [%s]%s?", buf
,
3565 invent
? " (? see used letters)" : "");
3566 for (trycnt
= 1; ; ++trycnt
) {
3567 let
= yn_function(qbuf
, (char *) 0, '\0');
3568 if (let
== '?' || let
== '*') {
3569 let
= display_used_invlets(splitting
? obj
->invlet
: 0);
3575 if (index(quitchars
, let
)
3576 /* adjusting to same slot is meaningful since all
3577 compatible stacks get collected along the way,
3578 but splitting to same slot is not */
3579 || (splitting
&& let
== obj
->invlet
)) {
3582 (void) merged(&splitting
, &obj
);
3586 if ((letter(let
) && let
!= '@') || index(buf
, let
))
3587 break; /* got one */
3590 pline("Select an inventory slot letter."); /* else try again */
3593 /* change the inventory and print the resulting item */
3594 adj_type
= !splitting
? "Moving:" : "Splitting:";
3597 * don't use freeinv/addinv to avoid double-touching artifacts,
3598 * dousing lamps, losing luck, cursing loadstone, etc.
3600 extract_nobj(obj
, &invent
);
3602 for (otmp
= invent
; otmp
;) {
3604 if (merged(&otmp
, &obj
)) {
3605 adj_type
= "Merging:";
3608 extract_nobj(obj
, &invent
);
3609 continue; /* otmp has already been updated */
3610 } else if (otmp
->invlet
== let
) {
3611 adj_type
= "Swapping:";
3612 otmp
->invlet
= obj
->invlet
;
3615 /* splitting: don't merge extra compatible stacks;
3616 if destination is compatible, do merge with it,
3617 otherwise bump whatever is there to an open slot */
3618 if (otmp
->invlet
== let
) {
3622 olth
= strlen(ONAME(obj
));
3623 /* ugly hack: if these objects aren't going to merge
3624 solely because they have conflicting user-assigned
3625 names, strip off the name of the one being moved */
3626 if (olth
&& !obj
->oartifact
&& !mergable(otmp
, obj
)) {
3627 char *holdname
= ONAME(obj
);
3629 ONAME(obj
) = (char *) 0;
3630 /* restore name iff merging is still not possible */
3631 if (!mergable(otmp
, obj
)) {
3632 ONAME(obj
) = holdname
;
3633 holdname
= (char *) 0;
3635 free((genericptr_t
) holdname
);
3638 if (merged(&otmp
, &obj
)) {
3640 extract_nobj(obj
, &invent
);
3641 } else if (inv_cnt(FALSE
) >= 52) {
3642 (void) merged(&splitting
, &obj
); /* undo split */
3643 /* "knapsack cannot accommodate any more items" */
3644 Your("pack is too full.");
3648 extract_nobj(bumped
, &invent
);
3651 } /* found 'to' slot */
3656 /* inline addinv; insert loose object at beginning of inventory */
3659 obj
->where
= OBJ_INVENT
;
3663 /* splitting the 'from' stack is causing an incompatible
3664 stack in the 'to' slot to be moved into an open one;
3665 we need to do another inline insertion to inventory */
3666 assigninvlet(bumped
);
3667 bumped
->nobj
= invent
;
3668 bumped
->where
= OBJ_INVENT
;
3673 /* messages deferred until inventory has been fully reestablished */
3674 prinv(adj_type
, obj
, 0L);
3676 prinv("Moving:", bumped
, 0L);
3678 clear_splitobjs(); /* reset splitobj context */
3683 /* common to display_minventory and display_cinventory */
3685 invdisp_nothing(hdr
, txt
)
3686 const char *hdr
, *txt
;
3690 menu_item
*selected
;
3693 win
= create_nhwindow(NHW_MENU
);
3695 add_menu(win
, NO_GLYPH
, &any
, 0, 0, iflags
.menu_headings
, hdr
,
3697 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, "", MENU_UNSELECTED
);
3698 add_menu(win
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, txt
, MENU_UNSELECTED
);
3699 end_menu(win
, (char *) 0);
3700 if (select_menu(win
, PICK_NONE
, &selected
) > 0)
3701 free((genericptr_t
) selected
);
3702 destroy_nhwindow(win
);
3706 /* query_objlist callback: return things that are worn or wielded */
3708 worn_wield_only(obj
)
3712 /* check for things that *are* worn or wielded (only used for monsters,
3713 so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
3714 return (boolean
) (obj
->owornmask
!= 0L);
3716 /* this used to check for things that *might* be worn or wielded,
3717 but that's not particularly interesting */
3718 if (is_weptool(obj
) || is_wet_towel(obj
) || obj
->otyp
== MEAT_RING
)
3720 return (boolean
) (obj
->oclass
== WEAPON_CLASS
3721 || obj
->oclass
== ARMOR_CLASS
3722 || obj
->oclass
== AMULET_CLASS
3723 || obj
->oclass
== RING_CLASS
);
3728 * Display a monster's inventory.
3729 * Returns a pointer to the object from the monster's inventory selected
3730 * or NULL if nothing was selected.
3732 * By default, only worn and wielded items are displayed. The caller
3733 * can pick one. Modifier flags are:
3735 * PICK_NONE, PICK_ONE - standard menu control
3736 * PICK_ANY - allowed, but we only return a single object
3737 * MINV_NOLET - nothing selectable
3738 * MINV_ALL - display all inventory
3741 display_minventory(mon
, dflags
, title
)
3742 register struct monst
*mon
;
3749 menu_item
*selected
= 0;
3750 int do_all
= (dflags
& MINV_ALL
) != 0,
3751 incl_hero
= (do_all
&& u
.uswallow
&& mon
== u
.ustuck
),
3752 have_inv
= (mon
->minvent
!= 0), have_any
= (have_inv
|| incl_hero
),
3753 pickings
= (dflags
& MINV_PICKMASK
);
3755 Sprintf(tmp
, "%s %s:", s_suffix(noit_Monnam(mon
)),
3756 do_all
? "possessions" : "armament");
3758 if (do_all
? have_any
: (mon
->misc_worn_check
|| MON_WEP(mon
))) {
3759 /* Fool the 'weapon in hand' routine into
3760 * displaying 'weapon in claw', etc. properly.
3762 youmonst
.data
= mon
->data
;
3764 n
= query_objlist(title
? title
: tmp
, &(mon
->minvent
),
3765 (INVORDER_SORT
| (incl_hero
? INCLUDE_HERO
: 0)),
3766 &selected
, pickings
,
3767 do_all
? allow_all
: worn_wield_only
);
3770 invdisp_nothing(title
? title
: tmp
, "(none)");
3775 ret
= selected
[0].item
.a_obj
;
3776 free((genericptr_t
) selected
);
3778 ret
= (struct obj
*) 0;
3783 * Display the contents of a container in inventory style.
3784 * Currently, this is only used for statues, via wand of probing.
3787 display_cinventory(obj
)
3788 register struct obj
*obj
;
3793 menu_item
*selected
= 0;
3795 (void) safe_qbuf(qbuf
, "Contents of ", ":", obj
, doname
, ansimpleoname
,
3799 n
= query_objlist(qbuf
, &(obj
->cobj
), INVORDER_SORT
,
3800 &selected
, PICK_NONE
, allow_all
);
3802 invdisp_nothing(qbuf
, "(empty)");
3806 ret
= selected
[0].item
.a_obj
;
3807 free((genericptr_t
) selected
);
3809 ret
= (struct obj
*) 0;
3814 /* query objlist callback: return TRUE if obj is at given location */
3821 return (obj
->ox
== only
.x
&& obj
->oy
== only
.y
);
3825 * Display a list of buried items in inventory style. Return a non-zero
3826 * value if there were items at that spot.
3828 * Currently, this is only used with a wand of probing zapped downwards.
3831 display_binventory(x
, y
, as_if_seen
)
3836 menu_item
*selected
= 0;
3839 /* count # of objects here */
3840 for (n
= 0, obj
= level
.buriedobjlist
; obj
; obj
= obj
->nobj
)
3841 if (obj
->ox
== x
&& obj
->oy
== y
) {
3850 if (query_objlist("Things that are buried here:",
3851 &level
.buriedobjlist
, INVORDER_SORT
,
3852 &selected
, PICK_NONE
, only_here
) > 0)
3853 free((genericptr_t
) selected
);
3854 only
.x
= only
.y
= 0;