1
/* SCCS Id: @(#)invent.c 3.4 2003/12/02 */
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 void NDECL(reorder_invent);
12
STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *));
13
STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *));
14
STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
15
STATIC_DCL boolean FDECL(only_here, (struct obj *));
17
STATIC_DCL void FDECL(compactify,(char *));
18
STATIC_DCL boolean FDECL(taking_off, (const char *));
19
STATIC_DCL boolean FDECL(putting_on, (const char *));
20
STATIC_PTR int FDECL(ckunpaid,(struct obj *));
21
STATIC_PTR int FDECL(ckvalidcat,(struct obj *));
23
static char FDECL(display_pickinv,
24
(const char *,BOOLEAN_P, long *, BOOLEAN_P));
26
static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *));
29
STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
30
STATIC_DCL void NDECL(dounpaid);
31
STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
32
STATIC_DCL void FDECL(menu_identify, (int));
33
STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
35
STATIC_DCL char FDECL(obj_to_let,(struct obj *));
39
static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
42
/* wizards can wish for venom, which will become an invisible inventory
43
* item without this. putting it in inv_order would mean venom would
44
* suddenly become a choice for all the inventory-class commands, which
45
* would probably cause mass confusion. the test for inventory venom
46
* is only WIZARD and not wizard because the wizard can leave venom lying
47
* around on a bones level for normal players to find.
49
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
54
register struct obj *otmp;
58
register struct obj *obj;
61
/* There is only one of these in inventory... */
62
if (otmp->oclass == COIN_CLASS) {
63
otmp->invlet = GOLD_SYM;
68
for(i = 0; i < 52; i++) inuse[i] = FALSE;
69
for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
71
if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
72
if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
73
if(i == otmp->invlet) otmp->invlet = 0;
75
if((i = otmp->invlet) &&
76
(('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
78
for(i = lastinvnr+1; i != lastinvnr; i++) {
79
if(i == 52) { i = -1; continue; }
82
otmp->invlet = (inuse[i] ? NOINVSYM :
83
(i < 26) ? ('a'+i) : ('A'+i-26));
90
/* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
91
#define inv_rank(o) ((o)->invlet ^ 040)
93
/* sort the inventory; used by addinv() and doorganize() */
97
struct obj *otmp, *prev, *next;
98
boolean need_more_sorting;
102
* We expect at most one item to be out of order, so this
103
* isn't nearly as inefficient as it may first appear.
105
need_more_sorting = FALSE;
106
for (otmp = invent, prev = 0; otmp; ) {
108
if (next && inv_rank(next) < inv_rank(otmp)) {
109
need_more_sorting = TRUE;
110
if (prev) prev->nobj = next;
112
otmp->nobj = next->nobj;
120
} while (need_more_sorting);
125
/* scan a list of objects to see whether another object will merge with
126
one of them; used in pickup.c when all 52 inventory slots are in use,
127
to figure out whether another object could still be picked up */
129
merge_choice(objlist, obj)
130
struct obj *objlist, *obj;
135
if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
136
return (struct obj *)0;
137
/* if this is an item on the shop floor, the attributes it will
138
have when carried are different from what they are now; prevent
139
that from eliciting an incorrect result from mergable() */
140
save_nocharge = obj->no_charge;
141
if (objlist == invent && obj->where == OBJ_FLOOR &&
142
(shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
143
if (obj->no_charge) obj->no_charge = 0;
144
/* A billable object won't have its `unpaid' bit set, so would
145
erroneously seem to be a candidate to merge with a similar
146
ordinary object. That's no good, because once it's really
147
picked up, it won't merge after all. It might merge with
148
another unpaid object, but we can't check that here (depends
149
too much upon shk's bill) and if it doesn't merge it would
150
end up in the '#' overflow inventory slot, so reject it now. */
151
else if (inhishop(shkp)) return (struct obj *)0;
154
if (mergable(objlist, obj)) break;
155
objlist = objlist->nobj;
157
obj->no_charge = save_nocharge;
161
/* merge obj with otmp and delete obj if types agree */
164
struct obj **potmp, **pobj;
166
register struct obj *otmp = *potmp, *obj = *pobj;
168
if(mergable(otmp, obj)) {
169
/* Approximate age: we do it this way because if we were to
170
* do it "accurately" (merge only when ages are identical)
171
* we'd wind up never merging any corpses.
172
* otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
174
* Don't do the age manipulation if lit. We would need
175
* to stop the burn on both items, then merge the age,
176
* then restart the burn.
179
otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
180
/ (otmp->quan + obj->quan);
182
otmp->quan += obj->quan;
184
/* temporary special case for gold objects!!!! */
186
if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp);
187
else otmp->owt += obj->owt;
188
if(!otmp->onamelth && obj->onamelth)
189
otmp = *potmp = oname(otmp, ONAME(obj));
190
obj_extract_self(obj);
192
/* really should merge the timeouts */
193
if (obj->lamplit) obj_merge_light_sources(obj, otmp);
194
if (obj->timed) obj_stop_timers(obj); /* follows lights */
196
/* fixup for `#adjust' merging wielded darts, daggers, &c */
197
if (obj->owornmask && carried(otmp)) {
198
long wmask = otmp->owornmask | obj->owornmask;
200
/* Both the items might be worn in competing slots;
201
merger preference (regardless of which is which):
202
primary weapon + alternate weapon -> primary weapon;
203
primary weapon + quiver -> primary weapon;
204
alternate weapon + quiver -> alternate weapon.
205
(Prior to 3.3.0, it was not possible for the two
206
stacks to be worn in different slots and `obj'
207
didn't need to be unworn when merging.) */
208
if (wmask & W_WEP) wmask = W_WEP;
209
else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP;
210
else if (wmask & W_QUIVER) wmask = W_QUIVER;
212
impossible("merging strangely worn items (%lx)", wmask);
213
wmask = otmp->owornmask;
215
if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp);
216
setworn(otmp, wmask);
220
/* (this should not be necessary, since items
221
already in a monster's inventory don't ever get
222
merged into other objects [only vice versa]) */
223
else if (obj->owornmask && mcarried(otmp)) {
224
if (obj == MON_WEP(otmp->ocarry)) {
225
MON_WEP(otmp->ocarry) = otmp;
226
otmp->owornmask = W_WEP;
231
obfree(obj,otmp); /* free(obj), bill->otmp */
238
Adjust hero intrinsics as if this object was being added to the hero's
239
inventory. Called _before_ the object has been added to the hero's
242
This is called when adding objects to the hero's inventory normally (via
243
addinv) or when an object in the hero's inventory has been polymorphed
246
It may be valid to merge this code with with addinv_core2().
252
if (obj->oclass == COIN_CLASS) {
254
u.ugold += obj->quan;
258
} else if (obj->otyp == AMULET_OF_YENDOR) {
259
if (u.uhave.amulet) impossible("already have amulet?");
261
} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
262
if (u.uhave.menorah) impossible("already have candelabrum?");
264
} else if (obj->otyp == BELL_OF_OPENING) {
265
if (u.uhave.bell) impossible("already have silver bell?");
267
} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
268
if (u.uhave.book) impossible("already have the book?");
270
} else if (obj->oartifact) {
271
if (is_quest_artifact(obj)) {
272
if (u.uhave.questart)
273
impossible("already have quest artifact?");
274
u.uhave.questart = 1;
277
set_artifact_intrinsic(obj, 1, W_ART);
282
Adjust hero intrinsics as if this object was being added to the hero's
283
inventory. Called _after_ the object has been added to the hero's
286
This is called when adding objects to the hero's inventory normally (via
287
addinv) or when an object in the hero's inventory has been polymorphed
294
if (confers_luck(obj)) {
295
/* new luckstone must be in inventory by this point
296
* for correct calculation */
302
Add obj to the hero's inventory. Make sure the object is "free".
303
Adjust hero attributes as necessary.
309
struct obj *otmp, *prev;
311
if (obj->where != OBJ_FREE)
312
panic("addinv: obj not free");
313
obj->no_charge = 0; /* not meaningful for invent */
317
/* if handed gold, we're done */
318
if (obj->oclass == COIN_CLASS)
322
/* merge if possible; find end of chain in the process */
323
for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
324
if (merged(&otmp, &obj)) {
328
/* didn't merge, so insert into chain */
329
if (flags.invlet_constant || !prev) {
330
if (flags.invlet_constant) assigninvlet(obj);
331
obj->nobj = invent; /* insert at beginning */
333
if (flags.invlet_constant) reorder_invent();
335
prev->nobj = obj; /* insert at end */
338
obj->where = OBJ_INVENT;
342
carry_obj_effects(obj); /* carrying affects the obj */
348
* Some objects are affected by being carried.
349
* Make those adjustments here. Called _after_ the object
350
* has been added to the hero's or monster's inventory,
351
* and after hero's intrinsics have been updated.
354
carry_obj_effects(obj)
357
/* Cursed figurines can spontaneously transform
359
if (obj->otyp == FIGURINE) {
361
&& obj->corpsenm != NON_PM
362
&& !dead_species(obj->corpsenm,TRUE)) {
363
attach_fig_transform_timeout(obj);
371
/* Add an item to the inventory unless we're fumbling or it refuses to be
372
* held (via touch_artifact), and give a message.
373
* If there aren't any free inventory slots, we'll drop it instead.
374
* If both success and failure messages are NULL, then we're just doing the
375
* fumbling/slot-limit checking for a silent grab. In any case,
376
* touch_artifact will print its own messages if they are warranted.
379
hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
381
const char *drop_fmt, *drop_arg, *hold_msg;
385
if (!Blind) obj->dknown = 1; /* maximize mergibility */
386
if (obj->oartifact) {
387
/* place_object may change these */
388
boolean crysknife = (obj->otyp == CRYSKNIFE);
389
int oerode = obj->oerodeproof;
390
boolean wasUpolyd = Upolyd;
392
/* in case touching this object turns out to be fatal */
393
place_object(obj, u.ux, u.uy);
395
if (!touch_artifact(obj, &youmonst)) {
396
obj_extract_self(obj); /* remove it from the floor */
397
dropy(obj); /* now put it back again :-) */
399
} else if (wasUpolyd && !Upolyd) {
400
/* loose your grip if you revert your form */
401
if (drop_fmt) pline(drop_fmt, drop_arg);
402
obj_extract_self(obj);
406
obj_extract_self(obj);
408
obj->otyp = CRYSKNIFE;
409
obj->oerodeproof = oerode;
413
if (drop_fmt) pline(drop_fmt, drop_arg);
416
long oquan = obj->quan;
417
int prev_encumbr = near_capacity(); /* before addinv() */
419
/* encumbrance only matters if it would now become worse
420
than max( current_value, stressed ) */
421
if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
422
/* addinv() may redraw the entire inventory, overwriting
423
drop_arg when it comes from something like doname() */
424
if (drop_arg) drop_arg = strcpy(buf, drop_arg);
428
|| ((obj->otyp != LOADSTONE || !obj->cursed)
429
&& near_capacity() > prev_encumbr)) {
430
if (drop_fmt) pline(drop_fmt, drop_arg);
431
/* undo any merge which took place */
432
if (obj->quan > oquan) obj = splitobj(obj, oquan);
435
if (flags.autoquiver && !uquiver && !obj->owornmask &&
437
ammo_and_launcher(obj, uwep) ||
438
ammo_and_launcher(obj, uswapwep)))
440
if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
446
/* useup() all of an item regardless of its quantity */
453
obfree(obj, (struct obj *)0); /* deletes contents also */
458
register struct obj *obj;
460
/* Note: This works correctly for containers because they */
461
/* (containers) don't merge. */
462
if (obj->quan > 1L) {
463
obj->in_use = FALSE; /* no longer in use */
465
obj->owt = weight(obj);
472
/* use one charge from an item and possibly incur shop debt for it */
474
consume_obj_charge(obj, maybe_unpaid)
476
boolean maybe_unpaid; /* false if caller handles shop billing */
478
if (maybe_unpaid) check_unpaid(obj);
480
if (obj->known) update_inventory();
487
Adjust hero's attributes as if this object was being removed from the
488
hero's inventory. This should only be called from freeinv() and
489
where we are polymorphing an object already in the hero's inventory.
491
Should think of a better name...
497
if (obj->oclass == COIN_CLASS) {
499
u.ugold -= obj->quan;
504
} else if (obj->otyp == AMULET_OF_YENDOR) {
505
if (!u.uhave.amulet) impossible("don't have amulet?");
507
} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
508
if (!u.uhave.menorah) impossible("don't have candelabrum?");
510
} else if (obj->otyp == BELL_OF_OPENING) {
511
if (!u.uhave.bell) impossible("don't have silver bell?");
513
} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
514
if (!u.uhave.book) impossible("don't have the book?");
516
} else if (obj->oartifact) {
517
if (is_quest_artifact(obj)) {
518
if (!u.uhave.questart)
519
impossible("don't have quest artifact?");
520
u.uhave.questart = 0;
522
set_artifact_intrinsic(obj, 0, W_ART);
525
if (obj->otyp == LOADSTONE) {
527
} else if (confers_luck(obj)) {
530
} else if (obj->otyp == FIGURINE && obj->timed) {
531
(void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
535
/* remove an object from the hero's inventory */
538
register struct obj *obj;
540
extract_nobj(obj, &invent);
549
struct obj *otmp, *otmp2;
551
for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
554
/* after unpunish(), or might get deallocated chain */
555
otmp2 = otmp->nexthere;
565
/* destroy object in fobj chain (if unpaid, it remains on the bill) */
568
register struct obj *obj;
572
if (obj->otyp == AMULET_OF_YENDOR ||
573
obj->otyp == CANDELABRUM_OF_INVOCATION ||
574
obj->otyp == BELL_OF_OPENING ||
575
obj->otyp == SPE_BOOK_OF_THE_DEAD) {
576
/* player might be doing something stupid, but we
577
* can't guarantee that. assume special artifacts
578
* are indestructible via drawbridges, and exploding
579
* chests, and golem creation, and ...
583
update_map = (obj->where == OBJ_FLOOR);
584
obj_extract_self(obj);
585
if (update_map) newsym(obj->ox, obj->oy);
586
obfree(obj, (struct obj *) 0); /* frees contents also */
594
register int n, x, y;
596
register struct obj *otmp;
598
for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
601
return((struct obj *)0);
611
register struct obj *otmp;
613
for(otmp = invent; otmp; otmp = otmp->nobj)
614
if(otmp->otyp == type)
616
return((struct obj *) 0);
623
if (amount == 1L) return "zorkmid";
624
else return "zorkmids";
630
register struct obj *otmp;
632
for(otmp = invent; otmp; otmp = otmp->nobj)
633
if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
641
register struct obj *objchn;
646
if(objchn->o_id == id) return(objchn);
647
if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
649
objchn = objchn->nobj;
651
return((struct obj *) 0);
656
register struct obj *obj;
659
register struct obj *otmp;
661
for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
662
if(obj == otmp) return(TRUE);
673
register struct obj *obj = level.objects[x][y];
675
if (obj->oclass == COIN_CLASS) return obj;
678
return((struct obj *)0);
684
/* Make a gold object from the hero's gold. */
689
register struct obj *otmp;
691
otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
694
otmp->owt = weight(otmp);
705
/* compact a string of inventory letters by dashing runs of letters */
707
register int i1 = 1, i2 = 1;
708
register char ilet, ilet1, ilet2;
712
buf[++i2] = buf[++i1];
715
if(ilet == ilet1+1) {
717
buf[i2 - 1] = ilet1 = '-';
718
else if(ilet2 == '-') {
719
buf[i2 - 1] = ++ilet1;
727
buf[++i2] = buf[++i1];
732
/* match the prompt for either 'T' or 'R' command */
737
return !strcmp(action, "take off") || !strcmp(action, "remove");
740
/* match the prompt for either 'W' or 'P' command */
745
return !strcmp(action, "wear") || !strcmp(action, "put on");
750
* struct obj *xxx: object to do something with.
751
* (struct obj *) 0 error return: no object.
752
* &zeroobj explicitly no object (as in w-).
754
!!!! test if gold can be used in unusual ways (eaten etc.)
755
!!!! may be able to remove "usegold"
760
register const char *let,*word;
762
register struct obj *otmp;
764
char buf[BUFSZ], qbuf[QBUFSZ];
765
char lets[BUFSZ], altlets[BUFSZ], *ap;
766
register int foo = 0;
767
register char *bp = buf;
768
xchar allowcnt = 0; /* 0, 1 or 2 */
770
boolean allowgold = FALSE; /* can't use gold because they don't have any */
772
boolean usegold = FALSE; /* can't use gold because its illegal */
773
boolean allowall = FALSE;
774
boolean allownone = FALSE;
775
boolean useboulder = FALSE;
778
boolean prezero = FALSE;
781
if(*let == ALLOW_COUNT) let++, allowcnt = 1;
783
if(*let == COIN_CLASS) let++,
784
usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
786
if(*let == COIN_CLASS) let++, usegold = TRUE;
789
/* Equivalent of an "ugly check" for gold */
790
if (usegold && !strcmp(word, "eat") &&
791
(!metallivorous(youmonst.data)
792
|| youmonst.data == &mons[PM_RUST_MONSTER]))
794
usegold = allowgold = FALSE;
799
if(*let == ALL_CLASSES) let++, allowall = TRUE;
800
if(*let == ALLOW_NONE) let++, allownone = TRUE;
801
/* "ugly check" for reading fortune cookies, part 1 */
802
/* The normal 'ugly check' keeps the object on the inventory list.
803
* We don't want to do that for shirts/cookies, so the check for
804
* them is handled a bit differently (and also requires that we set
805
* allowall in the caller)
807
if(allowall && !strcmp(word, "read")) allowall = FALSE;
809
/* another ugly check: show boulders (not statues) */
810
if(*let == WEAPON_CLASS &&
811
!strcmp(word, "throw") && throws_rocks(youmonst.data))
814
if(allownone) *bp++ = '-';
816
if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
818
if(bp > buf && bp[-1] == '-') *bp++ = ' ';
822
for (otmp = invent; otmp; otmp = otmp->nobj) {
823
if (!flags.invlet_constant)
825
if (otmp->invlet != GOLD_SYM) /* don't reassign this */
827
otmp->invlet = ilet; /* reassign() */
828
if (!*let || index(let, otmp->oclass)
830
|| (usegold && otmp->invlet == GOLD_SYM)
832
|| (useboulder && otmp->otyp == BOULDER)
834
register int otyp = otmp->otyp;
835
bp[foo++] = otmp->invlet;
837
/* ugly check: remove inappropriate things */
838
if ((taking_off(word) &&
839
(!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
840
|| (otmp==uarm && uarmc)
842
|| (otmp==uarmu && (uarm || uarmc))
845
|| (putting_on(word) &&
846
(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
848
#if 0 /* 3.4.1 -- include currently wielded weapon among the choices */
849
|| (!strcmp(word, "wield") &&
850
(otmp->owornmask & W_WEP))
852
|| (!strcmp(word, "ready") &&
853
(otmp == uwep || (otmp == uswapwep && u.twoweap)))
859
/* Second ugly check; unlike the first it won't trigger an
860
* "else" in "you don't have anything else to ___".
862
else if ((putting_on(word) &&
863
((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
864
(otmp->oclass == TOOL_CLASS &&
865
otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
866
|| (!strcmp(word, "wield") &&
867
(otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
868
|| (!strcmp(word, "eat") && !is_edible(otmp))
869
|| (!strcmp(word, "sacrifice") &&
871
otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
872
|| (!strcmp(word, "write with") &&
873
(otmp->oclass == TOOL_CLASS &&
874
otyp != MAGIC_MARKER && otyp != TOWEL))
875
|| (!strcmp(word, "tin") &&
876
(otyp != CORPSE || !tinnable(otmp)))
877
|| (!strcmp(word, "rub") &&
878
((otmp->oclass == TOOL_CLASS &&
879
otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
880
otyp != BRASS_LANTERN) ||
881
(otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
882
|| (!strncmp(word, "rub on the stone", 16) &&
883
*let == GEM_CLASS && /* using known touchstone */
884
otmp->dknown && objects[otyp].oc_name_known)
885
|| ((!strcmp(word, "use or apply") ||
886
!strcmp(word, "untrap with")) &&
887
/* Picks, axes, pole-weapons, bullwhips */
888
((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
889
!is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
890
(otmp->oclass == POTION_CLASS &&
891
/* only applicable potion is oil, and it will only
892
be offered as a choice when already discovered */
893
(otyp != POT_OIL || !otmp->dknown ||
894
!objects[POT_OIL].oc_name_known)) ||
895
(otmp->oclass == FOOD_CLASS &&
896
otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
897
(otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
898
|| (!strcmp(word, "invoke") &&
899
(!otmp->oartifact && !objects[otyp].oc_unique &&
900
(otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
901
otyp != CRYSTAL_BALL && /* #invoke synonym for apply */
902
/* note: presenting the possibility of invoking non-artifact
903
mirrors and/or lamps is a simply a cruel deception... */
904
otyp != MIRROR && otyp != MAGIC_LAMP &&
905
(otyp != OIL_LAMP || /* don't list known oil lamp */
906
(otmp->dknown && objects[OIL_LAMP].oc_name_known))))
907
|| (!strcmp(word, "untrap with") &&
908
(otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
909
|| (!strcmp(word, "charge") && !is_chargeable(otmp))
912
/* ugly check for unworn armor that can't be worn */
913
else if (putting_on(word) && *let == ARMOR_CLASS &&
914
!canwearobj(otmp, &dummymask, FALSE)) {
917
*ap++ = otmp->invlet;
921
/* "ugly check" for reading fortune cookies, part 2 */
922
if ((!strcmp(word, "read") &&
923
(otmp->otyp == FORTUNE_COOKIE
925
|| otmp->otyp == T_SHIRT
931
if(ilet == 'z') ilet = 'A'; else ilet++;
934
if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
935
Strcpy(lets, bp); /* necessary since we destroy buf */
936
if(foo > 5) /* compactify string */
941
if(!foo && !allowall && !allowgold && !allownone) {
943
if(!foo && !allowall && !allownone) {
945
You("don't have anything %sto %s.",
946
foox ? "else " : "", word);
947
return((struct obj *)0);
951
if (allowcnt == 2) allowcnt = 1; /* abort previous count */
953
Sprintf(qbuf, "What do you want to %s? [*]", word);
955
Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
963
ilet = yn_function(qbuf, (char *)0, '\0');
964
if(ilet == '0') prezero = TRUE;
965
while(digit(ilet) && allowcnt) {
967
if (ilet != '?' && ilet != '*') savech(ilet);
969
cnt = 10*cnt + (ilet - '0');
970
allowcnt = 2; /* signal presence of cnt */
974
pline("No count allowed with this command.");
977
if(index(quitchars,ilet)) {
980
return((struct obj *)0);
983
return(allownone ? &zeroobj : (struct obj *) 0);
985
if(ilet == def_oc_syms[COIN_CLASS]) {
987
if (!strncmp(word, "rub on ", 7)) {
988
/* the dangers of building sentences... */
989
You("cannot rub gold%s.", word + 3);
991
You("cannot %s gold.", word);
993
return(struct obj *)0;
995
} else if (!allowgold) {
996
You("are not carrying any gold.");
997
return(struct obj *)0;
1000
if(cnt == 0 && prezero) return((struct obj *)0);
1001
/* Historic note: early Nethack had a bug which was
1002
* first reported for Larn, where trying to drop 2^32-n
1003
* gold pieces was allowed, and did interesting things
1004
* to your money supply. The LRS is the tax bureau
1008
pline_The("LRS would be very interested to know you have that much.");
1009
return(struct obj *)0;
1013
if(!(allowcnt == 2 && cnt < u.ugold))
1015
return(mkgoldobj(cnt));
1018
if(ilet == '?' || ilet == '*') {
1019
char *allowed_choices = (ilet == '?') ? lets : (char *)0;
1022
if (ilet == '?' && !*lets && *altlets)
1023
allowed_choices = altlets;
1024
ilet = display_pickinv(allowed_choices, TRUE,
1025
allowcnt ? &ctmp : (long *)0
1031
if (allowcnt && ctmp >= 0) {
1033
if (!cnt) prezero = TRUE;
1036
if(ilet == '\033') {
1039
return((struct obj *)0);
1041
/* they typed a letter (not a space) at the prompt */
1043
if(allowcnt == 2 && !strcmp(word,"throw")) {
1044
/* permit counts for throwing gold, but don't accept
1045
* counts for other things since the throw code will
1046
* split off a single item anyway */
1048
if (ilet != def_oc_syms[COIN_CLASS])
1051
if(cnt == 0 && prezero) return((struct obj *)0);
1053
You("can only throw one item at a time.");
1058
flags.botl = 1; /* May have changed the amount of money */
1063
for (otmp = invent; otmp; otmp = otmp->nobj)
1064
if (otmp->invlet == ilet) break;
1066
You("don't have that object.");
1068
if (in_doagain) return((struct obj *) 0);
1071
} else if (cnt < 0 || otmp->quan < cnt) {
1072
You("don't have that many! You have only %ld.",
1075
if (in_doagain) return((struct obj *) 0);
1081
if(!allowall && let && !index(let,otmp->oclass)
1083
&& !(usegold && otmp->oclass == COIN_CLASS)
1086
silly_thing(word, otmp);
1087
return((struct obj *)0);
1089
if(allowcnt == 2) { /* cnt given */
1090
if(cnt == 0) return (struct obj *)0;
1091
if(cnt != otmp->quan) {
1092
/* don't split a stack of cursed loadstones */
1093
if (otmp->otyp == LOADSTONE && otmp->cursed)
1094
/* kludge for canletgo()'s can't-drop-this message */
1095
otmp->corpsenm = (int) cnt;
1097
otmp = splitobj(otmp, cnt);
1104
silly_thing(word, otmp)
1108
const char *s1, *s2, *s3, *what;
1109
int ocls = otmp->oclass, otyp = otmp->otyp;
1112
/* check for attempted use of accessory commands ('P','R') on armor
1113
and for corresponding armor commands ('W','T') on accessories */
1114
if (ocls == ARMOR_CLASS) {
1115
if (!strcmp(word, "put on"))
1116
s1 = "W", s2 = "wear", s3 = "";
1117
else if (!strcmp(word, "remove"))
1118
s1 = "T", s2 = "take", s3 = " off";
1119
} else if ((ocls == RING_CLASS || otyp == MEAT_RING) ||
1120
ocls == AMULET_CLASS ||
1121
(otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
1122
if (!strcmp(word, "wear"))
1123
s1 = "P", s2 = "put", s3 = " on";
1124
else if (!strcmp(word, "take off"))
1125
s1 = "R", s2 = "remove", s3 = "";
1129
/* quantity for armor and accessory objects is always 1,
1130
but some things should be referred to as plural */
1131
if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
1133
pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
1135
pline(silly_thing_to, word);
1144
register struct obj *otmp;
1146
/* use allow_category() from pickup.c */
1147
return((int)allow_category(otmp));
1152
register struct obj *otmp;
1154
return((int)(otmp->unpaid));
1160
return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
1169
register struct obj *otmp;
1171
return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
1175
W_WEP | W_SWAPWEP | W_QUIVER))));
1178
static NEARDATA const char removeables[] =
1179
{ ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
1181
/* interactive version of getobj - used for Drop, Identify and */
1182
/* Takeoff (A). Return the number of times fn was called successfully */
1183
/* If combo is TRUE, we just use this to get a category list */
1185
ggetobj(word, fn, mx, combo, resultflags)
1187
int FDECL((*fn),(OBJ_P)), mx;
1188
boolean combo; /* combination menu flag */
1189
unsigned *resultflags;
1191
int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
1192
boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
1193
boolean takeoff, ident, allflag, m_seen;
1196
int oletct, iletct, allowgold, unpaid, oc_of_sym;
1198
int oletct, iletct, unpaid, oc_of_sym;
1200
char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
1201
char extra_removeables[3+1]; /* uwep,uswapwep,uquiver */
1202
char buf[BUFSZ], qbuf[QBUFSZ];
1204
if (resultflags) *resultflags = 0;
1206
allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
1208
takeoff = ident = allflag = m_seen = FALSE;
1210
if(!invent && !allowgold){
1214
You("have nothing to %s.", word);
1217
add_valid_menu_class(0); /* reset */
1218
if (taking_off(word)) {
1221
} else if (!strcmp(word, "identify")) {
1223
filter = not_fully_identified;
1226
iletct = collect_obj_classes(ilets, invent,
1231
filter, &itemcount);
1232
unpaid = count_unpaid(invent);
1234
if (ident && !iletct) {
1235
return -1; /* no further identifications */
1236
} else if (!takeoff && (unpaid || invent)) {
1237
ilets[iletct++] = ' ';
1238
if (unpaid) ilets[iletct++] = 'u';
1239
if (count_buc(invent, BUC_BLESSED)) ilets[iletct++] = 'B';
1240
if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U';
1241
if (count_buc(invent, BUC_CURSED)) ilets[iletct++] = 'C';
1242
if (count_buc(invent, BUC_UNKNOWN)) ilets[iletct++] = 'X';
1243
if (invent) ilets[iletct++] = 'a';
1244
} else if (takeoff && invent) {
1245
ilets[iletct++] = ' ';
1247
ilets[iletct++] = 'i';
1249
ilets[iletct++] = 'm'; /* allow menu presentation on request */
1250
ilets[iletct] = '\0';
1253
Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
1256
if (buf[0] == '\033') return(0);
1257
if (index(buf, 'i')) {
1258
if (display_inventory((char *)0, TRUE) == '\033') return 0;
1263
extra_removeables[0] = '\0';
1265
/* arbitrary types of items can be placed in the weapon slots
1266
[any duplicate entries in extra_removeables[] won't matter] */
1267
if (uwep) (void)strkitten(extra_removeables, uwep->oclass);
1268
if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass);
1269
if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass);
1273
olets[oletct = 0] = '\0';
1274
while ((sym = *ip++) != '\0') {
1275
if (sym == ' ') continue;
1276
oc_of_sym = def_char_to_objclass(sym);
1277
if (takeoff && oc_of_sym != MAXOCLASSES) {
1278
if (index(extra_removeables, oc_of_sym)) {
1279
; /* skip rest of takeoff checks */
1280
} else if (!index(removeables, oc_of_sym)) {
1281
pline("Not applicable.");
1283
} else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
1284
You("are not wearing any armor.");
1286
} else if (oc_of_sym == WEAPON_CLASS &&
1287
!uwep && !uswapwep && !uquiver) {
1288
You("are not wielding anything.");
1290
} else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
1291
You("are not wearing rings.");
1293
} else if (oc_of_sym == AMULET_CLASS && !uamul) {
1294
You("are not wearing an amulet.");
1296
} else if (oc_of_sym == TOOL_CLASS && !ublindf) {
1297
You("are not wearing a blindfold.");
1302
if (oc_of_sym == COIN_CLASS && !combo) {
1305
(*fn)(mkgoldobj(u.ugold));
1307
You("have no gold.");
1312
} else if (sym == 'a') {
1314
} else if (sym == 'A') {
1315
/* same as the default */ ;
1316
} else if (sym == 'u') {
1317
add_valid_menu_class('u');
1319
} else if (sym == 'B') {
1320
add_valid_menu_class('B');
1322
} else if (sym == 'U') {
1323
add_valid_menu_class('U');
1325
} else if (sym == 'C') {
1326
add_valid_menu_class('C');
1328
} else if (sym == 'X') {
1329
add_valid_menu_class('X');
1331
} else if (sym == 'm') {
1333
} else if (oc_of_sym == MAXOCLASSES) {
1334
You("don't have any %c's.", sym);
1335
} else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
1336
if (!index(olets, oc_of_sym)) {
1337
add_valid_menu_class(oc_of_sym);
1338
olets[oletct++] = oc_of_sym;
1345
return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
1346
else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
1349
else if (allowgold == 2 && !oletct)
1350
return 1; /* you dropped gold (or at least tried to) */
1353
else /*!!!! if (allowgold == 2 && !oletct)
1354
!!!! return 1; you dropped gold (or at least tried to)
1355
!!!! test gold dropping
1358
int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
1360
* askchain() has already finished the job in this case
1361
* so set a special flag to convey that back to the caller
1362
* so that it won't continue processing.
1363
* Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
1365
if (combo && allflag && resultflags)
1366
*resultflags |= ALL_FINISHED;
1372
* Walk through the chain starting at objchn and ask for all objects
1373
* with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
1374
* whether the action in question (i.e., fn) has to be performed.
1375
* If allflag then no questions are asked. Max gives the max nr of
1376
* objects to be treated. Return the number of objects treated.
1379
askchain(objchn, olets, allflag, fn, ckfn, mx, word)
1380
struct obj **objchn;
1381
register int allflag, mx;
1382
register const char *olets, *word; /* olets is an Obj Class char array */
1383
register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
1385
struct obj *otmp, *otmp2, *otmpo;
1386
register char sym, ilet;
1387
register int cnt = 0, dud = 0, tmp;
1388
boolean takeoff, nodot, ident, ininv;
1391
takeoff = taking_off(word);
1392
ident = !strcmp(word, "identify");
1393
nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
1395
ininv = (*objchn == invent);
1396
/* Changed so the askchain is interrogated in the order specified.
1397
* For example, if a person specifies =/ then first all rings will be
1398
* asked about followed by all wands -dgk
1402
if (*objchn && (*objchn)->oclass == COIN_CLASS)
1403
ilet--; /* extra iteration */
1404
for (otmp = *objchn; otmp; otmp = otmp2) {
1405
if(ilet == 'z') ilet = 'A'; else ilet++;
1407
if (olets && *olets && otmp->oclass != *olets) continue;
1408
if (takeoff && !is_worn(otmp)) continue;
1409
if (ident && !not_fully_identified(otmp)) continue;
1410
if (ckfn && !(*ckfn)(otmp)) continue;
1412
Strcpy(qbuf, !ininv ? doname(otmp) :
1413
xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
1415
sym = (takeoff || ident || otmp->quan < 2L) ?
1416
nyaq(qbuf) : nyNaq(qbuf);
1422
/* Number was entered; split the object unless it corresponds
1423
to 'none' or 'all'. 2 special cases: cursed loadstones and
1424
welded weapons (eg, multiple daggers) will remain as merged
1425
unit; done to avoid splitting an object that won't be
1426
droppable (even if we're picking up rather than dropping).
1432
if (yn_number < otmp->quan && !welded(otmp) &&
1433
(!otmp->cursed || otmp->otyp != LOADSTONE)) {
1434
otmp = splitobj(otmp, yn_number);
1444
if (otmp != otmpo) {
1445
/* split occurred, merge again */
1446
(void) merged(&otmpo, &otmp);
1451
if(--mx == 0) goto ret;
1457
/* special case for seffects() */
1458
if (ident) cnt = -1;
1462
if (olets && *olets && *++olets)
1464
if(!takeoff && (dud || cnt)) pline("That was all.");
1465
else if(!dud && !cnt) pline("No applicable objects.");
1472
* Object identification routines:
1475
/* make an object actually be identified; no display updating */
1477
fully_identify_obj(otmp)
1480
makeknown(otmp->otyp);
1481
if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact);
1482
otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
1483
if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
1484
learn_egg_type(otmp->corpsenm);
1487
/* ggetobj callback routine; identify an object and give immediate feedback */
1492
fully_identify_obj(otmp);
1493
prinv((char *)0, otmp, 0L);
1497
/* menu of unidentified objects; select and identify up to id_limit of them */
1499
menu_identify(id_limit)
1502
menu_item *pick_list;
1503
int n, i, first = 1;
1505
/* assumptions: id_limit > 0 and at least one unID'd item is present */
1508
Sprintf(buf, "What would you like to identify %s?",
1509
first ? "first" : "next");
1510
n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
1511
&pick_list, PICK_ANY, not_fully_identified);
1514
if (n > id_limit) n = id_limit;
1515
for (i = 0; i < n; i++, id_limit--)
1516
(void) identify(pick_list[i].item.a_obj);
1517
free((genericptr_t) pick_list);
1518
mark_synch(); /* Before we loop to pop open another menu */
1520
if (n < 0) pline("That was all.");
1521
id_limit = 0; /* Stop now */
1527
/* dialog with user to identify a given number of items; 0 means all */
1529
identify_pack(id_limit)
1532
struct obj *obj, *the_obj;
1536
the_obj = 0; /* if unid_cnt ends up 1, this will be it */
1537
for (obj = invent; obj; obj = obj->nobj)
1538
if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;
1541
You("have already identified all of your possessions.");
1542
} else if (!id_limit) {
1543
/* identify everything */
1544
if (unid_cnt == 1) {
1545
(void) identify(the_obj);
1548
/* TODO: use fully_identify_obj and cornline/menu/whatever here */
1549
for (obj = invent; obj; obj = obj->nobj)
1550
if (not_fully_identified(obj)) (void) identify(obj);
1554
/* identify up to `id_limit' items */
1556
if (flags.menu_style == MENU_TRADITIONAL)
1558
n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0);
1559
if (n < 0) break; /* quit or no eligible items */
1560
} while ((id_limit -= n) > 0);
1561
if (n == 0 || n < -1)
1562
menu_identify(id_limit);
1571
obj_to_let(obj) /* should of course only be called for things in invent */
1572
register struct obj *obj;
1575
if (obj->oclass == COIN_CLASS)
1578
if (!flags.invlet_constant) {
1579
obj->invlet = NOINVSYM;
1586
* Print the indicated quantity of the given object. If quan == 0L then use
1587
* the current quantity.
1590
prinv(prefix, obj, quan)
1592
register struct obj *obj;
1595
if (!prefix) prefix = "";
1597
prefix, *prefix ? " " : "",
1598
xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
1605
xprname(obj, txt, let, dot, cost, quan)
1607
const char *txt; /* text to print instead of obj */
1608
char let; /* inventory letter */
1609
boolean dot; /* append period; (dot && cost => Iu) */
1610
long cost; /* cost (for inventory of unpaid or expended items) */
1611
long quan; /* if non-0, print this quantity, not obj->quan */
1613
#ifdef LINT /* handle static char li[BUFSZ]; */
1616
static char li[BUFSZ];
1618
boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
1622
savequan = obj->quan;
1628
* * Then obj == null and we are printing a total amount.
1629
* > Then the object is contained and doesn't have an inventory letter.
1631
if (cost != 0 || let == '*') {
1632
/* if dot is true, we're doing Iu, otherwise Ix */
1633
Sprintf(li, "%c - %-45s %6ld %s",
1634
(dot && use_invlet ? obj->invlet : let),
1635
(txt ? txt : doname(obj)), cost, currency(cost));
1637
} else if (obj && obj->oclass == COIN_CLASS) {
1638
Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
1642
/* ordinary inventory display or pickup message */
1643
Sprintf(li, "%c - %s%s",
1644
(use_invlet ? obj->invlet : let),
1645
(txt ? txt : doname(obj)), (dot ? "." : ""));
1647
if (savequan) obj->quan = savequan;
1655
/* the 'i' command */
1659
(void) display_inventory((char *)0, FALSE);
1666
* Scan the given list of objects. If last_found is NULL, return the first
1667
* unpaid object found. If last_found is not NULL, then skip over unpaid
1668
* objects until last_found is reached, then set last_found to NULL so the
1669
* next unpaid object is returned. This routine recursively follows
1672
STATIC_OVL struct obj *
1673
find_unpaid(list, last_found)
1674
struct obj *list, **last_found;
1681
/* still looking for previous unpaid object */
1682
if (list == *last_found)
1683
*last_found = (struct obj *) 0;
1685
return (*last_found = list);
1687
if (Has_contents(list)) {
1688
if ((obj = find_unpaid(list->cobj, last_found)) != 0)
1693
return (struct obj *) 0;
1697
* Internal function used by display_inventory and getobj that can display
1698
* inventory and return a count as well as a letter. If out_cnt is not null,
1699
* any count returned from the menu selection is placed here.
1703
display_pickinv(lets, want_reply, out_cnt, want_dump)
1704
register const char *lets;
1710
display_pickinv(lets, want_reply, out_cnt)
1711
register const char *lets;
1718
struct obj **oarray;
1722
char *invlet = flags.inv_order;
1724
winid win; /* windows being used */
1725
static winid local_win = WIN_ERR; /* window for partial menus */
1727
menu_item *selected;
1729
/* overriden by global flag */
1730
if (flags.perm_invent) {
1731
win = (lets && *lets) ? local_win : WIN_INVEN;
1732
/* create the first time used */
1734
win = local_win = create_nhwindow(NHW_MENU);
1739
if (want_dump) dump("", "Your inventory");
1743
Exit early if no inventory -- but keep going if we are doing
1744
a permanent inventory update. We need to keep going so the
1745
permanent inventory window updates itself to remove the last
1746
item(s) dropped. One down side: the addition of the exception
1747
for permanent inventory window updates _can_ pop the window
1748
up when it's not displayed -- even if it's empty -- because we
1749
don't know at this level if its up or not. This may not be
1750
an issue if empty checks are done before hand and the call
1751
to here is short circuited away.
1753
if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
1755
pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
1757
pline("Not carrying anything.");
1762
dump(" ", "Not carrying anything");
1764
dump(" Not carrying anything",
1765
u.ugold ? " except gold." : ".");
1772
/* oxymoron? temporarily assign permanent inventory letters */
1773
if (!flags.invlet_constant) reassign();
1775
if (lets && strlen(lets) == 1) {
1776
/* when only one item of interest, use pline instead of menus;
1777
we actually use a fake message-line menu in order to allow
1778
the user to perform selection at the --More-- prompt for tty */
1780
for (otmp = invent; otmp; otmp = otmp->nobj) {
1781
if (otmp->invlet == lets[0]) {
1782
ret = message_menu(lets[0],
1783
want_reply ? PICK_ONE : PICK_NONE,
1784
xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
1785
if (out_cnt) *out_cnt = -1L; /* select all */
1789
sprintf(letbuf, " %c - ", lets[0]);
1791
xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
1801
/* count the number of items */
1802
for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
1803
if(!lets || !*lets || index(lets, otmp->invlet)) n++;
1805
/* Make a temporary array to store the objects sorted */
1806
oarray = (struct obj **)alloc(n*sizeof(struct obj*));
1808
/* Add objects to the array */
1810
for(otmp = invent; otmp; otmp = otmp->nobj)
1811
if(!lets || !*lets || index(lets, otmp->invlet)) {
1812
if (iflags.sortloot == 'f') {
1813
/* Insert object at correct index */
1814
for (j = i; j; j--) {
1815
if (strcmpi(cxname2(otmp), cxname2(oarray[j-1]))>0) break;
1816
oarray[j] = oarray[j-1];
1821
/* Just add it to the array */
1825
#endif /* SORTLOOT */
1830
any.a_void = 0; /* set all bits to zero */
1832
for(i = 0; i < n; i++) {
1834
ilet = otmp->invlet;
1835
if (!flags.sortpack || otmp->oclass == *invlet) {
1836
if (flags.sortpack && !classcount) {
1837
any.a_void = 0; /* zero */
1838
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE,
1839
let_to_name(*invlet, FALSE), MENU_UNSELECTED);
1842
dump(" ", let_to_name(*invlet, FALSE));
1847
add_menu(win, obj_to_glyph(otmp),
1848
&any, ilet, 0, ATR_NONE, doname(otmp),
1853
sprintf(letbuf, " %c - ", ilet);
1854
dump(letbuf, doname(otmp));
1859
#else /* SORTLOOT */
1860
for(otmp = invent; otmp; otmp = otmp->nobj) {
1861
ilet = otmp->invlet;
1862
if(!lets || !*lets || index(lets, ilet)) {
1863
if (!flags.sortpack || otmp->oclass == *invlet) {
1864
if (flags.sortpack && !classcount) {
1865
any.a_void = 0; /* zero */
1866
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
1867
let_to_name(*invlet, FALSE), MENU_UNSELECTED);
1870
dump(" ", let_to_name(*invlet, FALSE));
1875
add_menu(win, obj_to_glyph(otmp),
1876
&any, ilet, 0, ATR_NONE, doname(otmp),
1881
sprintf(letbuf, " %c - ", ilet);
1882
dump(letbuf, doname(otmp));
1888
#endif /* SORTLOOT */
1889
if (flags.sortpack) {
1890
if (*++invlet) goto nextclass;
1892
if (--invlet != venom_inv) {
1901
end_menu(win, (char *) 0);
1903
n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
1905
ret = selected[0].item.a_char;
1906
if (out_cnt) *out_cnt = selected[0].count;
1907
free((genericptr_t)selected);
1909
ret = !n ? '\0' : '\033'; /* cancelled */
1911
if (want_dump) dump("", "");
1918
* If lets == NULL or "", list all objects in the inventory. Otherwise,
1919
* list all objects with object classes that match the order in lets.
1921
* Returns the letter identifier of a selected item, or 0 if nothing
1925
display_inventory(lets, want_reply)
1926
register const char *lets;
1929
return display_pickinv(lets, want_reply, (long *)0
1937
/* See display_inventory. This is the same thing WITH dumpfile creation */
1939
dump_inventory(lets, want_reply)
1940
register const char *lets;
1943
return display_pickinv(lets, want_reply, (long *)0, TRUE);
1948
* Returns the number of unpaid items within the given list. This includes
1949
* contained objects.
1958
if (list->unpaid) count++;
1959
if (Has_contents(list))
1960
count += count_unpaid(list->cobj);
1967
* Returns the number of items with b/u/c/unknown within the given list.
1968
* This does NOT include contained objects.
1971
count_buc(list, type)
1978
if (Role_if(PM_PRIEST)) list->bknown = TRUE;
1981
if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
1985
if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
1989
if (list->oclass != COIN_CLASS &&
1990
list->bknown && !list->blessed && !list->cursed)
1994
if (list->oclass != COIN_CLASS && !list->bknown)
1998
impossible("need count of curse status %d?", type);
2010
struct obj *otmp, *marker;
2012
char *invlet = flags.inv_order;
2013
int classcount, count, num_so_far;
2014
int save_unpaid = 0; /* lint init */
2017
count = count_unpaid(invent);
2020
marker = (struct obj *) 0;
2021
otmp = find_unpaid(invent, &marker);
2023
/* see if the unpaid item is in the top level inventory */
2024
for (marker = invent; marker; marker = marker->nobj)
2025
if (marker == otmp) break;
2027
pline("%s", xprname(otmp, distant_name(otmp, doname),
2028
marker ? otmp->invlet : CONTAINED_SYM,
2029
TRUE, unpaid_cost(otmp), 0L));
2033
win = create_nhwindow(NHW_MENU);
2035
num_so_far = 0; /* count of # printed so far */
2036
if (!flags.invlet_constant) reassign();
2040
for (otmp = invent; otmp; otmp = otmp->nobj) {
2041
ilet = otmp->invlet;
2043
if (!flags.sortpack || otmp->oclass == *invlet) {
2044
if (flags.sortpack && !classcount) {
2045
putstr(win, 0, let_to_name(*invlet, TRUE));
2049
totcost += cost = unpaid_cost(otmp);
2050
/* suppress "(unpaid)" suffix */
2051
save_unpaid = otmp->unpaid;
2053
putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
2054
ilet, TRUE, cost, 0L));
2055
otmp->unpaid = save_unpaid;
2060
} while (flags.sortpack && (*++invlet));
2062
if (count > num_so_far) {
2063
/* something unpaid is contained */
2065
putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
2067
* Search through the container objects in the inventory for
2068
* unpaid items. The top level inventory items have already
2071
for (otmp = invent; otmp; otmp = otmp->nobj) {
2072
if (Has_contents(otmp)) {
2073
marker = (struct obj *) 0; /* haven't found any */
2074
while (find_unpaid(otmp->cobj, &marker)) {
2075
totcost += cost = unpaid_cost(marker);
2076
save_unpaid = marker->unpaid;
2077
marker->unpaid = 0; /* suppress "(unpaid)" suffix */
2079
xprname(marker, distant_name(marker, doname),
2080
CONTAINED_SYM, TRUE, cost, 0L));
2081
marker->unpaid = save_unpaid;
2088
putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
2089
display_nhwindow(win, FALSE);
2090
destroy_nhwindow(win);
2094
/* query objlist callback: return TRUE if obj type matches "this_type" */
2095
static int this_type;
2101
return (obj->oclass == this_type);
2104
/* the 'I' command */
2110
char *extra_types, types[BUFSZ];
2111
int class_count, oclass, unpaid_count, itemcount;
2112
boolean billx = *u.ushops && doinvbill(0);
2113
menu_item *pick_list;
2114
boolean traditional = TRUE;
2115
const char *prompt = "What type of object do you want an inventory of?";
2118
if (!invent && !u.ugold && !billx) {
2120
if (!invent && !billx) {
2122
You("aren't carrying anything.");
2125
unpaid_count = count_unpaid(invent);
2126
if (flags.menu_style != MENU_TRADITIONAL) {
2127
if (flags.menu_style == MENU_FULL ||
2128
flags.menu_style == MENU_PARTIAL) {
2129
traditional = FALSE;
2131
if (billx) i |= BILLED_TYPES;
2132
n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
2134
this_type = c = pick_list[0].item.a_int;
2135
free((genericptr_t) pick_list);
2139
/* collect a list of classes of objects carried, for use as a prompt */
2141
class_count = collect_obj_classes(types, invent,
2146
(boolean FDECL((*),(OBJ_P))) 0, &itemcount);
2155
/* add everything not already included; user won't see these */
2156
extra_types = eos(types);
2157
*extra_types++ = '\033';
2158
if (!unpaid_count) *extra_types++ = 'u';
2159
if (!billx) *extra_types++ = 'x';
2160
*extra_types = '\0'; /* for index() */
2161
for (i = 0; i < MAXOCLASSES; i++)
2162
if (!index(types, def_oc_syms[i])) {
2163
*extra_types++ = def_oc_syms[i];
2164
*extra_types = '\0';
2167
if(class_count > 1) {
2168
c = yn_function(prompt, types, '\0');
2173
clear_nhwindow(WIN_MESSAGE);
2177
/* only one thing to itemize */
2188
(void) doinvbill(1);
2190
pline("No used-up objects on your shopping bill.");
2197
You("are not carrying any unpaid objects.");
2201
oclass = def_char_to_objclass(c); /* change to object class */
2202
if (oclass == COIN_CLASS) {
2204
} else if (index(types, c) > index(types, '\033')) {
2205
You("have no such objects.");
2210
if (query_objlist((char *) 0, invent,
2211
(flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
2212
&pick_list, PICK_NONE, this_type_only) > 0)
2213
free((genericptr_t)pick_list);
2217
/* return a string describing the dungeon feature at <x,y> if there
2218
is one worth mentioning at that location; otherwise null */
2220
dfeature_at(x, y, buf)
2224
struct rm *lev = &levl[x][y];
2225
int ltyp = lev->typ, cmap = -1;
2226
const char *dfeature = 0;
2227
static char altbuf[BUFSZ];
2229
if (IS_DOOR(ltyp)) {
2230
switch (lev->doormask) {
2231
case D_NODOOR: cmap = S_ndoor; break; /* "doorway" */
2232
case D_ISOPEN: cmap = S_vodoor; break; /* "open door" */
2233
case D_BROKEN: dfeature = "broken door"; break;
2234
default: cmap = S_vcdoor; break; /* "closed door" */
2236
/* override door description for open drawbridge */
2237
if (is_drawbridge_wall(x, y) >= 0)
2238
dfeature = "open drawbridge portcullis", cmap = -1;
2239
} else if (IS_FOUNTAIN(ltyp))
2240
cmap = S_fountain; /* "fountain" */
2241
else if (IS_THRONE(ltyp))
2242
cmap = S_throne; /* "opulent throne" */
2243
else if (is_lava(x,y))
2244
cmap = S_lava; /* "molten lava" */
2245
else if (is_ice(x,y))
2246
cmap = S_ice; /* "ice" */
2247
else if (is_pool(x,y))
2248
dfeature = "pool of water";
2250
else if (IS_SINK(ltyp))
2251
cmap = S_sink; /* "sink" */
2253
else if (IS_ALTAR(ltyp)) {
2254
Sprintf(altbuf, "altar to %s (%s)", a_gname(),
2255
align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
2257
} else if ((x == xupstair && y == yupstair) ||
2258
(x == sstairs.sx && y == sstairs.sy && sstairs.up))
2259
cmap = S_upstair; /* "staircase up" */
2260
else if ((x == xdnstair && y == ydnstair) ||
2261
(x == sstairs.sx && y == sstairs.sy && !sstairs.up))
2262
cmap = S_dnstair; /* "staircase down" */
2263
else if (x == xupladder && y == yupladder)
2264
cmap = S_upladder; /* "ladder up" */
2265
else if (x == xdnladder && y == ydnladder)
2266
cmap = S_dnladder; /* "ladder down" */
2267
else if (ltyp == DRAWBRIDGE_DOWN)
2268
cmap = S_vodbridge; /* "lowered drawbridge" */
2269
else if (ltyp == DBWALL)
2270
cmap = S_vcdbridge; /* "raised drawbridge" */
2271
else if (IS_GRAVE(ltyp))
2272
cmap = S_grave; /* "grave" */
2273
else if (ltyp == TREE)
2274
cmap = S_tree; /* "tree" */
2275
else if (ltyp == IRONBARS)
2276
dfeature = "set of iron bars";
2278
if (cmap >= 0) dfeature = defsyms[cmap].explanation;
2279
if (dfeature) Strcpy(buf, dfeature);
2283
/* look at what is here; if there are many objects (5 or more),
2284
don't show them unless obj_cnt is 0 */
2286
look_here(obj_cnt, picked_some)
2287
int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progess */
2288
boolean picked_some;
2292
const char *verb = Blind ? "feel" : "see";
2293
const char *dfeature = (char *)0;
2294
char fbuf[BUFSZ], fbuf2[BUFSZ];
2296
boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE;
2298
if (u.uswallow && u.ustuck) {
2299
struct monst *mtmp = u.ustuck;
2300
Sprintf(fbuf, "Contents of %s %s",
2301
s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH));
2302
/* Skip "Contents of " by using fbuf index 12 */
2303
You("%s to %s what is lying in %s.",
2304
Blind ? "try" : "look around", verb, &fbuf[12]);
2305
otmp = mtmp->minvent;
2307
for ( ; otmp; otmp = otmp->nobj) {
2308
/* If swallower is an animal, it should have become stone but... */
2309
if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2311
if (Blind) Strcpy(fbuf, "You feel");
2313
(void) display_minventory(mtmp, MINV_ALL, fbuf);
2315
You("%s no objects here.", verb);
2319
if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen)
2320
There("is %s here.",
2321
an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
2323
otmp = level.objects[u.ux][u.uy];
2324
dfeature = dfeature_at(u.ux, u.uy, fbuf2);
2325
if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
2329
boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
2330
if (dfeature && !strncmp(dfeature, "altar ", 6)) {
2331
/* don't say "altar" twice, dfeature has more info */
2332
You("try to feel what is here.");
2334
You("try to feel what is %s%s.",
2335
drift ? "floating here" : "lying here on the ",
2336
drift ? "" : surface(u.ux, u.uy));
2338
if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
2339
dfeature = 0; /* ice already identifed */
2340
if (!can_reach_floor()) {
2341
pline("But you can't reach it!");
2347
Sprintf(fbuf, "There is %s here.", an(dfeature));
2349
if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) {
2350
if (dfeature) pline(fbuf);
2351
read_engr_at(u.ux, u.uy); /* Eric Backus */
2352
if (!skip_objects && (Blind || !dfeature))
2353
You("%s no objects here.", verb);
2356
/* we know there is something here */
2359
if (dfeature) pline(fbuf);
2360
read_engr_at(u.ux, u.uy); /* Eric Backus */
2361
There("are %s%s objects here.",
2362
(obj_cnt <= 10) ? "several" : "many",
2363
picked_some ? " more" : "");
2364
} else if (!otmp->nexthere) {
2365
/* only one object */
2366
if (dfeature) pline(fbuf);
2367
read_engr_at(u.ux, u.uy); /* Eric Backus */
2368
#ifdef INVISIBLE_OBJECTS
2369
if (otmp->oinvis && !See_invisible) verb = "feel";
2371
You("%s here %s.", verb, doname(otmp));
2372
if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
2374
display_nhwindow(WIN_MESSAGE, FALSE);
2375
tmpwin = create_nhwindow(NHW_MENU);
2377
putstr(tmpwin, 0, fbuf);
2378
putstr(tmpwin, 0, "");
2380
putstr(tmpwin, 0, Blind ? "Things that you feel here:" :
2381
"Things that are here:");
2382
for ( ; otmp; otmp = otmp->nexthere) {
2383
if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
2385
felt_cockatrice = TRUE;
2386
Strcpy(buf, doname(otmp));
2388
putstr(tmpwin, 0, buf);
2391
putstr(tmpwin, 0, doname(otmp));
2393
display_nhwindow(tmpwin, TRUE);
2394
destroy_nhwindow(tmpwin);
2395
if (felt_cockatrice) feel_cockatrice(otmp, FALSE);
2396
read_engr_at(u.ux, u.uy); /* Eric Backus */
2401
/* explicilty look at what is here, including all objects */
2405
return look_here(0, FALSE);
2409
will_feel_cockatrice(otmp, force_touch)
2411
boolean force_touch;
2413
if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
2414
(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
2420
feel_cockatrice(otmp, force_touch)
2422
boolean force_touch;
2426
if (will_feel_cockatrice(otmp, force_touch)) {
2427
if(poly_when_stoned(youmonst.data))
2428
You("touched the %s corpse with your bare %s.",
2429
mons[otmp->corpsenm].mname, makeplural(body_part(HAND)));
2431
pline("Touching the %s corpse is a fatal mistake...",
2432
mons[otmp->corpsenm].mname);
2433
Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname));
2447
for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
2448
if(otmp != obj && merged(&obj,&otmp))
2454
mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */
2455
register struct obj *otmp, *obj;
2457
if (obj->otyp != otmp->otyp) return FALSE;
2459
/* coins of the same kind will always merge */
2460
if (obj->oclass == COIN_CLASS) return TRUE;
2462
if (obj->unpaid != otmp->unpaid ||
2463
obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
2464
(obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) ||
2465
obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
2466
obj->no_charge != otmp->no_charge ||
2467
obj->obroken != otmp->obroken ||
2468
obj->otrapped != otmp->otrapped ||
2469
obj->lamplit != otmp->lamplit ||
2470
#ifdef INVISIBLE_OBJECTS
2471
obj->oinvis != otmp->oinvis ||
2473
obj->greased != otmp->greased ||
2474
obj->oeroded != otmp->oeroded ||
2475
obj->oeroded2 != otmp->oeroded2 ||
2476
obj->bypass != otmp->bypass)
2479
if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
2480
(obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
2483
if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
2484
obj->orotten != otmp->orotten))
2487
if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
2488
if (obj->corpsenm != otmp->corpsenm)
2492
/* hatching eggs don't merge; ditto for revivable corpses */
2493
if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
2494
(obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
2495
is_reviver(&mons[otmp->corpsenm])))
2498
/* allow candle merging only if their ages are close */
2499
/* see begin_burn() for a reference for the magic "25" */
2500
if (Is_candle(obj) && obj->age/25 != otmp->age/25)
2503
/* burning potions of oil never merge */
2504
if (obj->otyp == POT_OIL && obj->lamplit)
2507
/* don't merge surcharged item with base-cost item */
2508
if (obj->unpaid && !same_price(obj, otmp))
2511
/* if they have names, make sure they're the same */
2512
if ( (obj->onamelth != otmp->onamelth &&
2513
((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
2515
(obj->onamelth && otmp->onamelth &&
2516
strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
2519
/* for the moment, any additional information is incompatible */
2520
if (obj->oxlth || otmp->oxlth) return FALSE;
2522
if(obj->oartifact != otmp->oartifact) return FALSE;
2524
if(obj->known == otmp->known ||
2525
!objects[otmp->otyp].oc_uses_known) {
2526
return((boolean)(objects[obj->otyp].oc_merge));
2527
} else return(FALSE);
2533
/* the messages used to refer to "carrying gold", but that didn't
2534
take containers into account */
2537
Your("wallet is empty.");
2539
Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
2541
long umoney = money_cnt(invent);
2543
Your("wallet is empty.");
2545
Your("wallet contains %ld %s.", umoney, currency(umoney));
2547
shopper_financial_report();
2558
You("are empty %s.", body_part(HANDED));
2560
prinv((char *)0, uwep, 0L);
2561
if (u.twoweap) prinv((char *)0, uswapwep, 0L);
2569
if(!wearing_armor())
2570
You("are not wearing any armor.");
2577
register int ct = 0;
2580
if(uarmu) lets[ct++] = obj_to_let(uarmu);
2582
if(uarm) lets[ct++] = obj_to_let(uarm);
2583
if(uarmc) lets[ct++] = obj_to_let(uarmc);
2584
if(uarmh) lets[ct++] = obj_to_let(uarmh);
2585
if(uarms) lets[ct++] = obj_to_let(uarms);
2586
if(uarmg) lets[ct++] = obj_to_let(uarmg);
2587
if(uarmf) lets[ct++] = obj_to_let(uarmf);
2589
(void) display_inventory(lets, FALSE);
2597
if(!uleft && !uright)
2598
You("are not wearing any rings.");
2601
register int ct = 0;
2603
if(uleft) lets[ct++] = obj_to_let(uleft);
2604
if(uright) lets[ct++] = obj_to_let(uright);
2606
(void) display_inventory(lets, FALSE);
2615
You("are not wearing an amulet.");
2617
prinv((char *)0, uamul, 0L);
2625
if ((obj->owornmask & (W_TOOL
2629
)) != 0L) return TRUE;
2630
if (obj->oclass != TOOL_CLASS) return FALSE;
2631
return (boolean)(obj == uwep || obj->lamplit ||
2632
(obj->otyp == LEASH && obj->leashmon));
2642
for (otmp = invent; otmp; otmp = otmp->nobj)
2643
if (tool_in_use(otmp))
2644
lets[ct++] = obj_to_let(otmp);
2646
if (!ct) You("are not using any tools.");
2647
else (void) display_inventory(lets, FALSE);
2651
/* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
2652
show inventory of all currently wielded, worn, or used objects */
2660
for (otmp = invent; otmp; otmp = otmp->nobj)
2661
if (is_worn(otmp) || tool_in_use(otmp))
2662
lets[ct++] = obj_to_let(otmp);
2664
if (!ct) You("are not wearing or wielding anything.");
2665
else (void) display_inventory(lets, FALSE);
2670
* uses up an object that's on the floor, charging for it as necessary
2673
useupf(obj, numused)
2674
register struct obj *obj;
2677
register struct obj *otmp;
2678
boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
2680
/* burn_floor_paper() keeps an object pointer that it tries to
2681
* useupf() multiple times, so obj must survive if plural */
2682
if (obj->quan > numused)
2683
otmp = splitobj(obj, numused);
2686
if(costly_spot(otmp->ox, otmp->oy)) {
2687
if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
2688
addtobill(otmp, FALSE, FALSE, FALSE);
2689
else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
2692
if (at_u && u.uundetected && hides_under(youmonst.data))
2693
u.uundetected = OBJ_AT(u.ux, u.uy);
2702
* Conversion from a class to a string for printing.
2703
* This must match the object class order.
2705
STATIC_VAR NEARDATA const char *names[] = { 0,
2706
"Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
2707
"Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
2708
"Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
2712
static NEARDATA const char oth_symbols[] = {
2717
static NEARDATA const char *oth_names[] = {
2718
"Bagged/Boxed items"
2721
static NEARDATA char *invbuf = (char *)0;
2722
static NEARDATA unsigned invbufsiz = 0;
2725
let_to_name(let,unpaid)
2729
const char *class_name;
2731
int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
2735
class_name = names[oclass];
2736
else if ((pos = index(oth_symbols, let)) != 0)
2737
class_name = oth_names[pos - oth_symbols];
2739
class_name = names[0];
2741
len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");
2742
if (len > invbufsiz) {
2743
if (invbuf) free((genericptr_t)invbuf);
2744
invbufsiz = len + 10; /* add slop to reduce incremental realloc */
2745
invbuf = (char *) alloc(invbufsiz);
2748
Strcat(strcpy(invbuf, "Unpaid "), class_name);
2750
Strcpy(invbuf, class_name);
2757
if (invbuf) free((genericptr_t)invbuf), invbuf = (char *)0;
2768
register struct obj *obj;
2770
for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
2771
obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
2779
doorganize() /* inventory organizer by Del Lamb */
2781
struct obj *obj, *otmp;
2782
register int ix, cur;
2784
char alphabet[52+1], buf[52+1];
2787
const char *adj_type;
2789
if (!flags.invlet_constant) reassign();
2790
/* get a pointer to the object the user wants to organize */
2791
allowall[0] = ALL_CLASSES; allowall[1] = '\0';
2792
if (!(obj = getobj(allowall,"adjust"))) return(0);
2794
/* initialize the list with all upper and lower case letters */
2795
for (let = 'a', ix = 0; let <= 'z';) alphabet[ix++] = let++;
2796
for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
2799
/* blank out all the letters currently in use in the inventory */
2800
/* except those that will be merged with the selected object */
2801
for (otmp = invent; otmp; otmp = otmp->nobj)
2802
if (otmp != obj && !mergable(otmp,obj)) {
2803
if (otmp->invlet <= 'Z')
2804
alphabet[(otmp->invlet) - 'A' + 26] = ' ';
2805
else alphabet[(otmp->invlet) - 'a'] = ' ';
2808
/* compact the list by removing all the blanks */
2809
for (ix = cur = 0; ix <= 52; ix++)
2810
if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
2812
/* and by dashing runs of letters */
2813
if(cur > 5) compactify(buf);
2815
/* get new letter to use as inventory letter */
2817
Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
2818
let = yn_function(qbuf, (char *)0, '\0');
2819
if(index(quitchars,let)) {
2823
if (let == '@' || !letter(let))
2824
pline("Select an inventory slot letter.");
2829
/* change the inventory and print the resulting item */
2830
adj_type = "Moving:";
2833
* don't use freeinv/addinv to avoid double-touching artifacts,
2834
* dousing lamps, losing luck, cursing loadstone, etc.
2836
extract_nobj(obj, &invent);
2838
for (otmp = invent; otmp;)
2839
if (merged(&otmp,&obj)) {
2840
adj_type = "Merging:";
2843
extract_nobj(obj, &invent);
2845
if (otmp->invlet == let) {
2846
adj_type = "Swapping:";
2847
otmp->invlet = obj->invlet;
2852
/* inline addinv (assuming flags.invlet_constant and !merged) */
2854
obj->nobj = invent; /* insert at beginning */
2855
obj->where = OBJ_INVENT;
2859
prinv(adj_type, obj, 0L);
2864
/* common to display_minventory and display_cinventory */
2866
invdisp_nothing(hdr, txt)
2867
const char *hdr, *txt;
2871
menu_item *selected;
2874
win = create_nhwindow(NHW_MENU);
2876
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED);
2877
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
2878
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
2879
end_menu(win, (char *)0);
2880
if (select_menu(win, PICK_NONE, &selected) > 0)
2881
free((genericptr_t)selected);
2882
destroy_nhwindow(win);
2886
/* query_objlist callback: return things that could possibly be worn/wielded */
2888
worn_wield_only(obj)
2891
return (obj->oclass == WEAPON_CLASS
2892
|| obj->oclass == ARMOR_CLASS
2893
|| obj->oclass == AMULET_CLASS
2894
|| obj->oclass == RING_CLASS
2895
|| obj->oclass == TOOL_CLASS);
2899
* Display a monster's inventory.
2900
* Returns a pointer to the object from the monster's inventory selected
2901
* or NULL if nothing was selected.
2903
* By default, only worn and wielded items are displayed. The caller
2904
* can pick one. Modifier flags are:
2906
* MINV_NOLET - nothing selectable
2907
* MINV_ALL - display all inventory
2910
display_minventory(mon, dflags, title)
2911
register struct monst *mon;
2921
menu_item *selected = 0;
2923
int do_all = (dflags & MINV_ALL) != 0,
2924
do_gold = (do_all && mon->mgold);
2926
int do_all = (dflags & MINV_ALL) != 0;
2929
Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
2930
do_all ? "possessions" : "armament");
2933
if (do_all ? (mon->minvent || mon->mgold)
2935
if (do_all ? (mon->minvent != 0)
2937
: (mon->misc_worn_check || MON_WEP(mon))) {
2938
/* Fool the 'weapon in hand' routine into
2939
* displaying 'weapon in claw', etc. properly.
2941
youmonst.data = mon->data;
2946
* Make temporary gold object and insert at the head of
2947
* the mon's inventory. We can get away with using a
2948
* stack variable object because monsters don't carry
2949
* gold in their inventory, so it won't merge.
2952
m_gold.otyp = GOLD_PIECE; m_gold.oclass = COIN_CLASS;
2953
m_gold.quan = mon->mgold; m_gold.dknown = 1;
2954
m_gold.where = OBJ_FREE;
2955
/* we had better not merge and free this object... */
2956
if (add_to_minv(mon, &m_gold))
2957
panic("display_minventory: static object freed.");
2961
n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT, &selected,
2962
(dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
2963
do_all ? allow_all : worn_wield_only);
2966
if (do_gold) obj_extract_self(&m_gold);
2971
invdisp_nothing(title ? title : tmp, "(none)");
2976
ret = selected[0].item.a_obj;
2977
free((genericptr_t)selected);
2980
* Unfortunately, we can't return a pointer to our temporary
2981
* gold object. We'll have to work out a scheme where this
2982
* can happen. Maybe even put gold in the inventory list...
2984
if (ret == &m_gold) ret = (struct obj *) 0;
2987
ret = (struct obj *) 0;
2992
* Display the contents of a container in inventory style.
2993
* Currently, this is only used for statues, via wand of probing.
2996
display_cinventory(obj)
2997
register struct obj *obj;
3002
menu_item *selected = 0;
3004
Sprintf(tmp,"Contents of %s:", doname(obj));
3007
n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
3008
PICK_NONE, allow_all);
3010
invdisp_nothing(tmp, "(empty)");
3014
ret = selected[0].item.a_obj;
3015
free((genericptr_t)selected);
3017
ret = (struct obj *) 0;
3021
/* query objlist callback: return TRUE if obj is at given location */
3028
return (obj->ox == only.x && obj->oy == only.y);
3032
* Display a list of buried items in inventory style. Return a non-zero
3033
* value if there were items at that spot.
3035
* Currently, this is only used with a wand of probing zapped downwards.
3038
display_binventory(x, y, as_if_seen)
3043
menu_item *selected = 0;
3046
/* count # of objects here */
3047
for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
3048
if (obj->ox == x && obj->oy == y) {
3049
if (as_if_seen) obj->dknown = 1;
3056
if (query_objlist("Things that are buried here:",
3057
level.buriedobjlist, INVORDER_SORT,
3058
&selected, PICK_NONE, only_here) > 0)
3059
free((genericptr_t)selected);
3060
only.x = only.y = 0;