~ubuntu-branches/ubuntu/vivid/nethack/vivid

« back to all changes in this revision

Viewing changes to .pc/0016-fix-non-constant-format-strings.patch/src/invent.c

  • Committer: Package Import Robot
  • Author(s): Vincent Cheng, Bernhard R. Link, Vincent Cheng
  • Date: 2012-06-11 00:47:38 UTC
  • mfrom: (3.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20120611004738-3fy8b3wi0j45y2oq
Tags: 3.4.3-14
* Team upload.

[ Bernhard R. Link ]
* switch to "3.0 (quilt)"
* bump Standards-Version
* modernize debian/rules:
- use dpkg-buildflags
- support build-arch/-indep
- make parallel safe
- don't avoid make errors
* add patch so it can compile with -Werror=format-security
* drop no longer needed patches (-qt and -gnome are gone)
* don't use /dev/null as install template (Closes: 644647)
* drop nethack-common menu (both -console and -x11 have one)

[ Vincent Cheng ]
* Adopt package. (Closes: #673584)
  - Change Maintainer to Debian Games Team.
  - Add myself to Uploaders.
* Modify 0006-Common-config.h-for-all-binary-packages.patch to enable
  AUTOPICKUP_EXCEPTIONS. (Closes: #329318)
* Modify 0011-Pasi-Kallinen-s-patch-to-add-colors-to-inventory-ite.patch
  and 0017-Debian-and-Linux-specifics-defined-in-unixconf.h.patch; add
  0021-fix-kfreebsd-ftbfs.patch to fix FTBFS on kfreebsd.
* Convert debian/copyright to DEP-5 machine-readable format.
* Use dh_lintian to install overrides instead of manually installing them
  in debian/rules.
* Add watch file.
* Add Homepage field in debian/control.
* Add Vcs-* fields in debian/control.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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. */
 
4
 
 
5
#include "hack.h"
 
6
 
 
7
#define NOINVSYM        '#'
 
8
#define CONTAINED_SYM   '>'     /* designator for inside a container */
 
9
 
 
10
#ifdef OVL1
 
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 *));
 
16
#endif /* OVL1 */
 
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 *));
 
22
#ifdef DUMP_LOG
 
23
static char FDECL(display_pickinv,
 
24
                 (const char *,BOOLEAN_P, long *, BOOLEAN_P));
 
25
#else
 
26
static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *));
 
27
#endif /* DUMP_LOG */
 
28
#ifdef OVLB
 
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 *));
 
34
#endif /* OVLB */
 
35
STATIC_DCL char FDECL(obj_to_let,(struct obj *));
 
36
 
 
37
#ifdef OVLB
 
38
 
 
39
static int lastinvnr = 51;      /* 0 ... 51 (never saved&restored) */
 
40
 
 
41
#ifdef WIZARD
 
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.
 
48
 */
 
49
static char venom_inv[] = { VENOM_CLASS, 0 };   /* (constant) */
 
50
#endif
 
51
 
 
52
void
 
53
assigninvlet(otmp)
 
54
register struct obj *otmp;
 
55
{
 
56
        boolean inuse[52];
 
57
        register int i;
 
58
        register struct obj *obj;
 
59
 
 
60
#ifdef GOLDOBJ
 
61
        /* There is only one of these in inventory... */        
 
62
        if (otmp->oclass == COIN_CLASS) {
 
63
            otmp->invlet = GOLD_SYM;
 
64
            return;
 
65
        }
 
66
#endif
 
67
 
 
68
        for(i = 0; i < 52; i++) inuse[i] = FALSE;
 
69
        for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
 
70
                i = obj->invlet;
 
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;
 
74
        }
 
75
        if((i = otmp->invlet) &&
 
76
            (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
 
77
                return;
 
78
        for(i = lastinvnr+1; i != lastinvnr; i++) {
 
79
                if(i == 52) { i = -1; continue; }
 
80
                if(!inuse[i]) break;
 
81
        }
 
82
        otmp->invlet = (inuse[i] ? NOINVSYM :
 
83
                        (i < 26) ? ('a'+i) : ('A'+i-26));
 
84
        lastinvnr = i;
 
85
}
 
86
 
 
87
#endif /* OVLB */
 
88
#ifdef OVL1
 
89
 
 
90
/* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
 
91
#define inv_rank(o) ((o)->invlet ^ 040)
 
92
 
 
93
/* sort the inventory; used by addinv() and doorganize() */
 
94
STATIC_OVL void
 
95
reorder_invent()
 
96
{
 
97
        struct obj *otmp, *prev, *next;
 
98
        boolean need_more_sorting;
 
99
 
 
100
        do {
 
101
            /*
 
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.
 
104
             */
 
105
            need_more_sorting = FALSE;
 
106
            for (otmp = invent, prev = 0; otmp; ) {
 
107
                next = otmp->nobj;
 
108
                if (next && inv_rank(next) < inv_rank(otmp)) {
 
109
                    need_more_sorting = TRUE;
 
110
                    if (prev) prev->nobj = next;
 
111
                    else      invent = next;
 
112
                    otmp->nobj = next->nobj;
 
113
                    next->nobj = otmp;
 
114
                    prev = next;
 
115
                } else {
 
116
                    prev = otmp;
 
117
                    otmp = next;
 
118
                }
 
119
            }
 
120
        } while (need_more_sorting);
 
121
}
 
122
 
 
123
#undef inv_rank
 
124
 
 
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 */
 
128
struct obj *
 
129
merge_choice(objlist, obj)
 
130
struct obj *objlist, *obj;
 
131
{
 
132
        struct monst *shkp;
 
133
        int save_nocharge;
 
134
 
 
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;
 
152
        }
 
153
        while (objlist) {
 
154
            if (mergable(objlist, obj)) break;
 
155
            objlist = objlist->nobj;
 
156
        }
 
157
        obj->no_charge = save_nocharge;
 
158
        return objlist;
 
159
}
 
160
 
 
161
/* merge obj with otmp and delete obj if types agree */
 
162
int
 
163
merged(potmp, pobj)
 
164
struct obj **potmp, **pobj;
 
165
{
 
166
        register struct obj *otmp = *potmp, *obj = *pobj;
 
167
 
 
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;
 
173
                 *
 
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.
 
177
                 */
 
178
                if (!obj->lamplit)
 
179
                    otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
 
180
                            / (otmp->quan + obj->quan);
 
181
 
 
182
                otmp->quan += obj->quan;
 
183
#ifdef GOLDOBJ
 
184
                /* temporary special case for gold objects!!!! */
 
185
#endif
 
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);
 
191
 
 
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 */
 
195
 
 
196
                /* fixup for `#adjust' merging wielded darts, daggers, &c */
 
197
                if (obj->owornmask && carried(otmp)) {
 
198
                    long wmask = otmp->owornmask | obj->owornmask;
 
199
 
 
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;
 
211
                    else {
 
212
                        impossible("merging strangely worn items (%lx)", wmask);
 
213
                        wmask = otmp->owornmask;
 
214
                    }
 
215
                    if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp);
 
216
                    setworn(otmp, wmask);
 
217
                    setnotworn(obj);
 
218
                }
 
219
#if 0
 
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;
 
227
                    }
 
228
                }
 
229
#endif /*0*/
 
230
 
 
231
                obfree(obj,otmp);       /* free(obj), bill->otmp */
 
232
                return(1);
 
233
        }
 
234
        return 0;
 
235
}
 
236
 
 
237
/*
 
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
 
240
inventory.
 
241
 
 
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
 
244
in-place.
 
245
 
 
246
It may be valid to merge this code with with addinv_core2().
 
247
*/
 
248
void
 
249
addinv_core1(obj)
 
250
struct obj *obj;
 
251
{
 
252
        if (obj->oclass == COIN_CLASS) {
 
253
#ifndef GOLDOBJ
 
254
                u.ugold += obj->quan;
 
255
#else
 
256
                flags.botl = 1;
 
257
#endif
 
258
        } else if (obj->otyp == AMULET_OF_YENDOR) {
 
259
                if (u.uhave.amulet) impossible("already have amulet?");
 
260
                u.uhave.amulet = 1;
 
261
        } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
 
262
                if (u.uhave.menorah) impossible("already have candelabrum?");
 
263
                u.uhave.menorah = 1;
 
264
        } else if (obj->otyp == BELL_OF_OPENING) {
 
265
                if (u.uhave.bell) impossible("already have silver bell?");
 
266
                u.uhave.bell = 1;
 
267
        } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
 
268
                if (u.uhave.book) impossible("already have the book?");
 
269
                u.uhave.book = 1;
 
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;
 
275
                    artitouch();
 
276
                }
 
277
                set_artifact_intrinsic(obj, 1, W_ART);
 
278
        }
 
279
}
 
280
 
 
281
/*
 
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
 
284
inventory.
 
285
 
 
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
 
288
in-place.
 
289
*/
 
290
void
 
291
addinv_core2(obj)
 
292
struct obj *obj;
 
293
{
 
294
        if (confers_luck(obj)) {
 
295
                /* new luckstone must be in inventory by this point
 
296
                 * for correct calculation */
 
297
                set_moreluck();
 
298
        }
 
299
}
 
300
 
 
301
/*
 
302
Add obj to the hero's inventory.  Make sure the object is "free".
 
303
Adjust hero attributes as necessary.
 
304
*/
 
305
struct obj *
 
306
addinv(obj)
 
307
struct obj *obj;
 
308
{
 
309
        struct obj *otmp, *prev;
 
310
 
 
311
        if (obj->where != OBJ_FREE)
 
312
            panic("addinv: obj not free");
 
313
        obj->no_charge = 0;     /* not meaningful for invent */
 
314
 
 
315
        addinv_core1(obj);
 
316
#ifndef GOLDOBJ
 
317
        /* if handed gold, we're done */
 
318
        if (obj->oclass == COIN_CLASS)
 
319
            return obj;
 
320
#endif
 
321
 
 
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)) {
 
325
                obj = otmp;
 
326
                goto added;
 
327
            }
 
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 */
 
332
            invent = obj;
 
333
            if (flags.invlet_constant) reorder_invent();
 
334
        } else {
 
335
            prev->nobj = obj;           /* insert at end */
 
336
            obj->nobj = 0;
 
337
        }
 
338
        obj->where = OBJ_INVENT;
 
339
 
 
340
added:
 
341
        addinv_core2(obj);
 
342
        carry_obj_effects(obj);         /* carrying affects the obj */
 
343
        update_inventory();
 
344
        return(obj);
 
345
}
 
346
 
 
347
/*
 
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.
 
352
 */
 
353
void
 
354
carry_obj_effects(obj)
 
355
struct obj *obj;
 
356
{
 
357
        /* Cursed figurines can spontaneously transform
 
358
           when carried. */
 
359
        if (obj->otyp == FIGURINE) {
 
360
                if (obj->cursed
 
361
                    && obj->corpsenm != NON_PM
 
362
                    && !dead_species(obj->corpsenm,TRUE)) {
 
363
                        attach_fig_transform_timeout(obj);
 
364
                    }
 
365
        }
 
366
}
 
367
 
 
368
#endif /* OVL1 */
 
369
#ifdef OVLB
 
370
 
 
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.
 
377
 */
 
378
struct obj *
 
379
hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
 
380
struct obj *obj;
 
381
const char *drop_fmt, *drop_arg, *hold_msg;
 
382
{
 
383
        char buf[BUFSZ];
 
384
 
 
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;
 
391
 
 
392
            /* in case touching this object turns out to be fatal */
 
393
            place_object(obj, u.ux, u.uy);
 
394
 
 
395
            if (!touch_artifact(obj, &youmonst)) {
 
396
                obj_extract_self(obj);  /* remove it from the floor */
 
397
                dropy(obj);             /* now put it back again :-) */
 
398
                return obj;
 
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);
 
403
                dropy(obj);
 
404
                return obj;
 
405
            }
 
406
            obj_extract_self(obj);
 
407
            if (crysknife) {
 
408
                obj->otyp = CRYSKNIFE;
 
409
                obj->oerodeproof = oerode;
 
410
            }
 
411
        }
 
412
        if (Fumbling) {
 
413
            if (drop_fmt) pline(drop_fmt, drop_arg);
 
414
            dropy(obj);
 
415
        } else {
 
416
            long oquan = obj->quan;
 
417
            int prev_encumbr = near_capacity(); /* before addinv() */
 
418
 
 
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);
 
425
 
 
426
            obj = addinv(obj);
 
427
            if (inv_cnt() > 52
 
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);
 
433
                dropx(obj);
 
434
            } else {
 
435
                if (flags.autoquiver && !uquiver && !obj->owornmask &&
 
436
                        (is_missile(obj) ||
 
437
                            ammo_and_launcher(obj, uwep) ||
 
438
                            ammo_and_launcher(obj, uswapwep)))
 
439
                    setuqwep(obj);
 
440
                if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
 
441
            }
 
442
        }
 
443
        return obj;
 
444
}
 
445
 
 
446
/* useup() all of an item regardless of its quantity */
 
447
void
 
448
useupall(obj)
 
449
struct obj *obj;
 
450
{
 
451
        setnotworn(obj);
 
452
        freeinv(obj);
 
453
        obfree(obj, (struct obj *)0);   /* deletes contents also */
 
454
}
 
455
 
 
456
void
 
457
useup(obj)
 
458
register struct obj *obj;
 
459
{
 
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 */
 
464
                obj->quan--;
 
465
                obj->owt = weight(obj);
 
466
                update_inventory();
 
467
        } else {
 
468
                useupall(obj);
 
469
        }
 
470
}
 
471
 
 
472
/* use one charge from an item and possibly incur shop debt for it */
 
473
void
 
474
consume_obj_charge(obj, maybe_unpaid)
 
475
struct obj *obj;
 
476
boolean maybe_unpaid;   /* false if caller handles shop billing */
 
477
{
 
478
        if (maybe_unpaid) check_unpaid(obj);
 
479
        obj->spe -= 1;
 
480
        if (obj->known) update_inventory();
 
481
}
 
482
 
 
483
#endif /* OVLB */
 
484
#ifdef OVL3
 
485
 
 
486
/*
 
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.
 
490
 
 
491
Should think of a better name...
 
492
*/
 
493
void
 
494
freeinv_core(obj)
 
495
struct obj *obj;
 
496
{
 
497
        if (obj->oclass == COIN_CLASS) {
 
498
#ifndef GOLDOBJ
 
499
                u.ugold -= obj->quan;
 
500
                obj->in_use = FALSE;
 
501
#endif
 
502
                flags.botl = 1;
 
503
                return;
 
504
        } else if (obj->otyp == AMULET_OF_YENDOR) {
 
505
                if (!u.uhave.amulet) impossible("don't have amulet?");
 
506
                u.uhave.amulet = 0;
 
507
        } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
 
508
                if (!u.uhave.menorah) impossible("don't have candelabrum?");
 
509
                u.uhave.menorah = 0;
 
510
        } else if (obj->otyp == BELL_OF_OPENING) {
 
511
                if (!u.uhave.bell) impossible("don't have silver bell?");
 
512
                u.uhave.bell = 0;
 
513
        } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
 
514
                if (!u.uhave.book) impossible("don't have the book?");
 
515
                u.uhave.book = 0;
 
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;
 
521
                }
 
522
                set_artifact_intrinsic(obj, 0, W_ART);
 
523
        }
 
524
 
 
525
        if (obj->otyp == LOADSTONE) {
 
526
                curse(obj);
 
527
        } else if (confers_luck(obj)) {
 
528
                set_moreluck();
 
529
                flags.botl = 1;
 
530
        } else if (obj->otyp == FIGURINE && obj->timed) {
 
531
                (void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj);
 
532
        }
 
533
}
 
534
 
 
535
/* remove an object from the hero's inventory */
 
536
void
 
537
freeinv(obj)
 
538
register struct obj *obj;
 
539
{
 
540
        extract_nobj(obj, &invent);
 
541
        freeinv_core(obj);
 
542
        update_inventory();
 
543
}
 
544
 
 
545
void
 
546
delallobj(x, y)
 
547
int x, y;
 
548
{
 
549
        struct obj *otmp, *otmp2;
 
550
 
 
551
        for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
 
552
                if (otmp == uball)
 
553
                        unpunish();
 
554
                /* after unpunish(), or might get deallocated chain */
 
555
                otmp2 = otmp->nexthere;
 
556
                if (otmp == uchain)
 
557
                        continue;
 
558
                delobj(otmp);
 
559
        }
 
560
}
 
561
 
 
562
#endif /* OVL3 */
 
563
#ifdef OVL2
 
564
 
 
565
/* destroy object in fobj chain (if unpaid, it remains on the bill) */
 
566
void
 
567
delobj(obj)
 
568
register struct obj *obj;
 
569
{
 
570
        boolean update_map;
 
571
 
 
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 ...
 
580
                 */
 
581
                return;
 
582
        }
 
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 */
 
587
}
 
588
 
 
589
#endif /* OVL2 */
 
590
#ifdef OVL0
 
591
 
 
592
struct obj *
 
593
sobj_at(n,x,y)
 
594
register int n, x, y;
 
595
{
 
596
        register struct obj *otmp;
 
597
 
 
598
        for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
 
599
                if(otmp->otyp == n)
 
600
                    return(otmp);
 
601
        return((struct obj *)0);
 
602
}
 
603
 
 
604
#endif /* OVL0 */
 
605
#ifdef OVLB
 
606
 
 
607
struct obj *
 
608
carrying(type)
 
609
register int type;
 
610
{
 
611
        register struct obj *otmp;
 
612
 
 
613
        for(otmp = invent; otmp; otmp = otmp->nobj)
 
614
                if(otmp->otyp == type)
 
615
                        return(otmp);
 
616
        return((struct obj *) 0);
 
617
}
 
618
 
 
619
const char *
 
620
currency(amount)
 
621
long amount;
 
622
{
 
623
        if (amount == 1L) return "zorkmid";
 
624
        else return "zorkmids";
 
625
}
 
626
 
 
627
boolean
 
628
have_lizard()
 
629
{
 
630
        register struct obj *otmp;
 
631
 
 
632
        for(otmp = invent; otmp; otmp = otmp->nobj)
 
633
                if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
 
634
                        return(TRUE);
 
635
        return(FALSE);
 
636
}
 
637
 
 
638
struct obj *
 
639
o_on(id, objchn)
 
640
unsigned int id;
 
641
register struct obj *objchn;
 
642
{
 
643
        struct obj *temp;
 
644
 
 
645
        while(objchn) {
 
646
                if(objchn->o_id == id) return(objchn);
 
647
                if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
 
648
                        return temp;
 
649
                objchn = objchn->nobj;
 
650
        }
 
651
        return((struct obj *) 0);
 
652
}
 
653
 
 
654
boolean
 
655
obj_here(obj, x, y)
 
656
register struct obj *obj;
 
657
int x, y;
 
658
{
 
659
        register struct obj *otmp;
 
660
 
 
661
        for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
 
662
                if(obj == otmp) return(TRUE);
 
663
        return(FALSE);
 
664
}
 
665
 
 
666
#endif /* OVLB */
 
667
#ifdef OVL2
 
668
 
 
669
struct obj *
 
670
g_at(x,y)
 
671
register int x, y;
 
672
{
 
673
        register struct obj *obj = level.objects[x][y];
 
674
        while(obj) {
 
675
            if (obj->oclass == COIN_CLASS) return obj;
 
676
            obj = obj->nexthere;
 
677
        }
 
678
        return((struct obj *)0);
 
679
}
 
680
 
 
681
#endif /* OVL2 */
 
682
#ifdef OVLB
 
683
#ifndef GOLDOBJ
 
684
/* Make a gold object from the hero's gold. */
 
685
struct obj *
 
686
mkgoldobj(q)
 
687
register long q;
 
688
{
 
689
        register struct obj *otmp;
 
690
 
 
691
        otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
 
692
        u.ugold -= q;
 
693
        otmp->quan = q;
 
694
        otmp->owt = weight(otmp);
 
695
        flags.botl = 1;
 
696
        return(otmp);
 
697
}
 
698
#endif
 
699
#endif /* OVLB */
 
700
#ifdef OVL1
 
701
 
 
702
STATIC_OVL void
 
703
compactify(buf)
 
704
register char *buf;
 
705
/* compact a string of inventory letters by dashing runs of letters */
 
706
{
 
707
        register int i1 = 1, i2 = 1;
 
708
        register char ilet, ilet1, ilet2;
 
709
 
 
710
        ilet2 = buf[0];
 
711
        ilet1 = buf[1];
 
712
        buf[++i2] = buf[++i1];
 
713
        ilet = buf[i1];
 
714
        while(ilet) {
 
715
                if(ilet == ilet1+1) {
 
716
                        if(ilet1 == ilet2+1)
 
717
                                buf[i2 - 1] = ilet1 = '-';
 
718
                        else if(ilet2 == '-') {
 
719
                                buf[i2 - 1] = ++ilet1;
 
720
                                buf[i2] = buf[++i1];
 
721
                                ilet = buf[i1];
 
722
                                continue;
 
723
                        }
 
724
                }
 
725
                ilet2 = ilet1;
 
726
                ilet1 = ilet;
 
727
                buf[++i2] = buf[++i1];
 
728
                ilet = buf[i1];
 
729
        }
 
730
}
 
731
 
 
732
/* match the prompt for either 'T' or 'R' command */
 
733
STATIC_OVL boolean
 
734
taking_off(action)
 
735
const char *action;
 
736
{
 
737
    return !strcmp(action, "take off") || !strcmp(action, "remove");
 
738
}
 
739
 
 
740
/* match the prompt for either 'W' or 'P' command */
 
741
STATIC_OVL boolean
 
742
putting_on(action)
 
743
const char *action;
 
744
{
 
745
    return !strcmp(action, "wear") || !strcmp(action, "put on");
 
746
}
 
747
 
 
748
/*
 
749
 * getobj returns:
 
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-).
 
753
#ifdef GOLDOBJ
 
754
!!!! test if gold can be used in unusual ways (eaten etc.)
 
755
!!!! may be able to remove "usegold"
 
756
#endif
 
757
 */
 
758
struct obj *
 
759
getobj(let,word)
 
760
register const char *let,*word;
 
761
{
 
762
        register struct obj *otmp;
 
763
        register char ilet;
 
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 */
 
769
#ifndef GOLDOBJ
 
770
        boolean allowgold = FALSE;      /* can't use gold because they don't have any */
 
771
#endif
 
772
        boolean usegold = FALSE;        /* can't use gold because its illegal */
 
773
        boolean allowall = FALSE;
 
774
        boolean allownone = FALSE;
 
775
        boolean useboulder = FALSE;
 
776
        xchar foox = 0;
 
777
        long cnt;
 
778
        boolean prezero = FALSE;
 
779
        long dummymask;
 
780
 
 
781
        if(*let == ALLOW_COUNT) let++, allowcnt = 1;
 
782
#ifndef GOLDOBJ
 
783
        if(*let == COIN_CLASS) let++,
 
784
                usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
 
785
#else
 
786
        if(*let == COIN_CLASS) let++, usegold = TRUE;
 
787
#endif
 
788
 
 
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]))
 
793
#ifndef GOLDOBJ
 
794
                usegold = allowgold = FALSE;
 
795
#else
 
796
                usegold = FALSE;
 
797
#endif
 
798
 
 
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)
 
806
         */
 
807
        if(allowall && !strcmp(word, "read")) allowall = FALSE;
 
808
 
 
809
        /* another ugly check: show boulders (not statues) */
 
810
        if(*let == WEAPON_CLASS &&
 
811
           !strcmp(word, "throw") && throws_rocks(youmonst.data))
 
812
            useboulder = TRUE;
 
813
 
 
814
        if(allownone) *bp++ = '-';
 
815
#ifndef GOLDOBJ
 
816
        if(allowgold) *bp++ = def_oc_syms[COIN_CLASS];
 
817
#endif
 
818
        if(bp > buf && bp[-1] == '-') *bp++ = ' ';
 
819
        ap = altlets;
 
820
 
 
821
        ilet = 'a';
 
822
        for (otmp = invent; otmp; otmp = otmp->nobj) {
 
823
            if (!flags.invlet_constant)
 
824
#ifdef GOLDOBJ
 
825
                if (otmp->invlet != GOLD_SYM) /* don't reassign this */
 
826
#endif
 
827
                otmp->invlet = ilet;    /* reassign() */
 
828
            if (!*let || index(let, otmp->oclass)
 
829
#ifdef GOLDOBJ
 
830
                || (usegold && otmp->invlet == GOLD_SYM)
 
831
#endif
 
832
                || (useboulder && otmp->otyp == BOULDER)
 
833
                ) {
 
834
                register int otyp = otmp->otyp;
 
835
                bp[foo++] = otmp->invlet;
 
836
 
 
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)
 
841
#ifdef TOURIST
 
842
                     || (otmp==uarmu && (uarm || uarmc))
 
843
#endif
 
844
                    ))
 
845
                || (putting_on(word) &&
 
846
                     (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 
847
                                                        /* already worn */
 
848
#if 0   /* 3.4.1 -- include currently wielded weapon among the choices */
 
849
                || (!strcmp(word, "wield") &&
 
850
                    (otmp->owornmask & W_WEP))
 
851
#endif
 
852
                || (!strcmp(word, "ready") &&
 
853
                    (otmp == uwep || (otmp == uswapwep && u.twoweap)))
 
854
                    ) {
 
855
                        foo--;
 
856
                        foox++;
 
857
                }
 
858
 
 
859
                /* Second ugly check; unlike the first it won't trigger an
 
860
                 * "else" in "you don't have anything else to ___".
 
861
                 */
 
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") &&
 
870
                    (otyp != CORPSE &&
 
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))
 
910
                    )
 
911
                        foo--;
 
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)) {
 
915
                        foo--;
 
916
                        allowall = TRUE;
 
917
                        *ap++ = otmp->invlet;
 
918
                }
 
919
            } else {
 
920
 
 
921
                /* "ugly check" for reading fortune cookies, part 2 */
 
922
                if ((!strcmp(word, "read") &&
 
923
                    (otmp->otyp == FORTUNE_COOKIE
 
924
#ifdef TOURIST
 
925
                        || otmp->otyp == T_SHIRT
 
926
#endif
 
927
                    )))
 
928
                        allowall = TRUE;
 
929
            }
 
930
 
 
931
            if(ilet == 'z') ilet = 'A'; else ilet++;
 
932
        }
 
933
        bp[foo] = 0;
 
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 */
 
937
                compactify(bp);
 
938
        *ap = '\0';
 
939
 
 
940
#ifndef GOLDOBJ
 
941
        if(!foo && !allowall && !allowgold && !allownone) {
 
942
#else
 
943
        if(!foo && !allowall && !allownone) {
 
944
#endif
 
945
                You("don't have anything %sto %s.",
 
946
                        foox ? "else " : "", word);
 
947
                return((struct obj *)0);
 
948
        }
 
949
        for(;;) {
 
950
                cnt = 0;
 
951
                if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
 
952
                if(!buf[0]) {
 
953
                        Sprintf(qbuf, "What do you want to %s? [*]", word);
 
954
                } else {
 
955
                        Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
 
956
                                word, buf);
 
957
                }
 
958
#ifdef REDO
 
959
                if (in_doagain)
 
960
                    ilet = readchar();
 
961
                else
 
962
#endif
 
963
                    ilet = yn_function(qbuf, (char *)0, '\0');
 
964
                if(ilet == '0') prezero = TRUE;
 
965
                while(digit(ilet) && allowcnt) {
 
966
#ifdef REDO
 
967
                        if (ilet != '?' && ilet != '*') savech(ilet);
 
968
#endif
 
969
                        cnt = 10*cnt + (ilet - '0');
 
970
                        allowcnt = 2;   /* signal presence of cnt */
 
971
                        ilet = readchar();
 
972
                }
 
973
                if(digit(ilet)) {
 
974
                        pline("No count allowed with this command.");
 
975
                        continue;
 
976
                }
 
977
                if(index(quitchars,ilet)) {
 
978
                    if(flags.verbose)
 
979
                        pline(Never_mind);
 
980
                    return((struct obj *)0);
 
981
                }
 
982
                if(ilet == '-') {
 
983
                        return(allownone ? &zeroobj : (struct obj *) 0);
 
984
                }
 
985
                if(ilet == def_oc_syms[COIN_CLASS]) {
 
986
                        if (!usegold) {
 
987
                            if (!strncmp(word, "rub on ", 7)) {
 
988
                                /* the dangers of building sentences... */
 
989
                                You("cannot rub gold%s.", word + 3);
 
990
                            } else {
 
991
                                You("cannot %s gold.", word);
 
992
                            }
 
993
                            return(struct obj *)0;
 
994
#ifndef GOLDOBJ
 
995
                        } else if (!allowgold) {
 
996
                                You("are not carrying any gold.");
 
997
                                return(struct obj *)0;
 
998
#endif
 
999
                        } 
 
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
 
1005
                         * from Larn.
 
1006
                         */
 
1007
                        if(cnt < 0) {
 
1008
        pline_The("LRS would be very interested to know you have that much.");
 
1009
                                return(struct obj *)0;
 
1010
                        }
 
1011
 
 
1012
#ifndef GOLDOBJ
 
1013
                        if(!(allowcnt == 2 && cnt < u.ugold))
 
1014
                                cnt = u.ugold;
 
1015
                        return(mkgoldobj(cnt));
 
1016
#endif
 
1017
                }
 
1018
                if(ilet == '?' || ilet == '*') {
 
1019
                    char *allowed_choices = (ilet == '?') ? lets : (char *)0;
 
1020
                    long ctmp = 0;
 
1021
 
 
1022
                    if (ilet == '?' && !*lets && *altlets)
 
1023
                        allowed_choices = altlets;
 
1024
                    ilet = display_pickinv(allowed_choices, TRUE,
 
1025
                                           allowcnt ? &ctmp : (long *)0
 
1026
#ifdef DUMP_LOG
 
1027
                                           , FALSE
 
1028
#endif
 
1029
                                           );
 
1030
                    if(!ilet) continue;
 
1031
                    if (allowcnt && ctmp >= 0) {
 
1032
                        cnt = ctmp;
 
1033
                        if (!cnt) prezero = TRUE;
 
1034
                        allowcnt = 2;
 
1035
                    }
 
1036
                    if(ilet == '\033') {
 
1037
                        if(flags.verbose)
 
1038
                            pline(Never_mind);
 
1039
                        return((struct obj *)0);
 
1040
                    }
 
1041
                    /* they typed a letter (not a space) at the prompt */
 
1042
                }
 
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 */
 
1047
#ifdef GOLDOBJ
 
1048
                    if (ilet != def_oc_syms[COIN_CLASS])
 
1049
#endif
 
1050
                        allowcnt = 1;
 
1051
                    if(cnt == 0 && prezero) return((struct obj *)0);
 
1052
                    if(cnt > 1) {
 
1053
                        You("can only throw one item at a time.");
 
1054
                        continue;
 
1055
                    }
 
1056
                }
 
1057
#ifdef GOLDOBJ
 
1058
                flags.botl = 1; /* May have changed the amount of money */
 
1059
#endif
 
1060
#ifdef REDO
 
1061
                savech(ilet);
 
1062
#endif
 
1063
                for (otmp = invent; otmp; otmp = otmp->nobj)
 
1064
                        if (otmp->invlet == ilet) break;
 
1065
                if(!otmp) {
 
1066
                        You("don't have that object.");
 
1067
#ifdef REDO
 
1068
                        if (in_doagain) return((struct obj *) 0);
 
1069
#endif
 
1070
                        continue;
 
1071
                } else if (cnt < 0 || otmp->quan < cnt) {
 
1072
                        You("don't have that many!  You have only %ld.",
 
1073
                            otmp->quan);
 
1074
#ifdef REDO
 
1075
                        if (in_doagain) return((struct obj *) 0);
 
1076
#endif
 
1077
                        continue;
 
1078
                }
 
1079
                break;
 
1080
        }
 
1081
        if(!allowall && let && !index(let,otmp->oclass)
 
1082
#ifdef GOLDOBJ
 
1083
           && !(usegold && otmp->oclass == COIN_CLASS)
 
1084
#endif
 
1085
           ) {
 
1086
                silly_thing(word, otmp);
 
1087
                return((struct obj *)0);
 
1088
        }
 
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;
 
1096
                else
 
1097
                    otmp = splitobj(otmp, cnt);
 
1098
            }
 
1099
        }
 
1100
        return(otmp);
 
1101
}
 
1102
 
 
1103
void
 
1104
silly_thing(word, otmp)
 
1105
const char *word;
 
1106
struct obj *otmp;
 
1107
{
 
1108
        const char *s1, *s2, *s3, *what;
 
1109
        int ocls = otmp->oclass, otyp = otmp->otyp;
 
1110
 
 
1111
        s1 = s2 = s3 = 0;
 
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 = "";
 
1126
        }
 
1127
        if (s1) {
 
1128
            what = "that";
 
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))
 
1132
                what = "those";
 
1133
            pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
 
1134
        } else {
 
1135
            pline(silly_thing_to, word);
 
1136
        }
 
1137
}
 
1138
 
 
1139
#endif /* OVL1 */
 
1140
#ifdef OVLB
 
1141
 
 
1142
STATIC_PTR int
 
1143
ckvalidcat(otmp)
 
1144
register struct obj *otmp;
 
1145
{
 
1146
        /* use allow_category() from pickup.c */
 
1147
        return((int)allow_category(otmp));
 
1148
}
 
1149
 
 
1150
STATIC_PTR int
 
1151
ckunpaid(otmp)
 
1152
register struct obj *otmp;
 
1153
{
 
1154
        return((int)(otmp->unpaid));
 
1155
}
 
1156
 
 
1157
boolean
 
1158
wearing_armor()
 
1159
{
 
1160
        return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
 
1161
#ifdef TOURIST
 
1162
                || uarmu
 
1163
#endif
 
1164
                ));
 
1165
}
 
1166
 
 
1167
boolean
 
1168
is_worn(otmp)
 
1169
register struct obj *otmp;
 
1170
{
 
1171
    return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL |
 
1172
#ifdef STEED
 
1173
                        W_SADDLE |
 
1174
#endif
 
1175
                        W_WEP | W_SWAPWEP | W_QUIVER))));
 
1176
}
 
1177
 
 
1178
static NEARDATA const char removeables[] =
 
1179
        { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
 
1180
 
 
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 */
 
1184
int
 
1185
ggetobj(word, fn, mx, combo, resultflags)
 
1186
const char *word;
 
1187
int FDECL((*fn),(OBJ_P)), mx;
 
1188
boolean combo;          /* combination menu flag */
 
1189
unsigned *resultflags;
 
1190
{
 
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;
 
1194
        int itemcount;
 
1195
#ifndef GOLDOBJ
 
1196
        int oletct, iletct, allowgold, unpaid, oc_of_sym;
 
1197
#else
 
1198
        int oletct, iletct, unpaid, oc_of_sym;
 
1199
#endif
 
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];
 
1203
 
 
1204
        if (resultflags) *resultflags = 0;
 
1205
#ifndef GOLDOBJ
 
1206
        allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;
 
1207
#endif
 
1208
        takeoff = ident = allflag = m_seen = FALSE;
 
1209
#ifndef GOLDOBJ
 
1210
        if(!invent && !allowgold){
 
1211
#else
 
1212
        if(!invent){
 
1213
#endif
 
1214
                You("have nothing to %s.", word);
 
1215
                return(0);
 
1216
        }
 
1217
        add_valid_menu_class(0);        /* reset */
 
1218
        if (taking_off(word)) {
 
1219
            takeoff = TRUE;
 
1220
            filter = is_worn;
 
1221
        } else if (!strcmp(word, "identify")) {
 
1222
            ident = TRUE;
 
1223
            filter = not_fully_identified;
 
1224
        }
 
1225
 
 
1226
        iletct = collect_obj_classes(ilets, invent,
 
1227
                                        FALSE,
 
1228
#ifndef GOLDOBJ
 
1229
                                        (allowgold != 0),
 
1230
#endif
 
1231
                                        filter, &itemcount);
 
1232
        unpaid = count_unpaid(invent);
 
1233
 
 
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++] = ' ';
 
1246
        }
 
1247
        ilets[iletct++] = 'i';
 
1248
        if (!combo)
 
1249
            ilets[iletct++] = 'm';      /* allow menu presentation on request */
 
1250
        ilets[iletct] = '\0';
 
1251
 
 
1252
        for (;;) {
 
1253
            Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
 
1254
                    word, ilets);
 
1255
            getlin(qbuf, buf);
 
1256
            if (buf[0] == '\033') return(0);
 
1257
            if (index(buf, 'i')) {
 
1258
                if (display_inventory((char *)0, TRUE) == '\033') return 0;
 
1259
            } else
 
1260
                break;
 
1261
        }
 
1262
 
 
1263
        extra_removeables[0] = '\0';
 
1264
        if (takeoff) {
 
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);
 
1270
        }
 
1271
 
 
1272
        ip = buf;
 
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.");
 
1282
                    return 0;
 
1283
                } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
 
1284
                    You("are not wearing any armor.");
 
1285
                    return 0;
 
1286
                } else if (oc_of_sym == WEAPON_CLASS &&
 
1287
                        !uwep && !uswapwep && !uquiver) {
 
1288
                    You("are not wielding anything.");
 
1289
                    return 0;
 
1290
                } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
 
1291
                    You("are not wearing rings.");
 
1292
                    return 0;
 
1293
                } else if (oc_of_sym == AMULET_CLASS && !uamul) {
 
1294
                    You("are not wearing an amulet.");
 
1295
                    return 0;
 
1296
                } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
 
1297
                    You("are not wearing a blindfold.");
 
1298
                    return 0;
 
1299
                }
 
1300
            }
 
1301
 
 
1302
            if (oc_of_sym == COIN_CLASS && !combo) {
 
1303
#ifndef GOLDOBJ
 
1304
                if (allowgold == 1)
 
1305
                    (*fn)(mkgoldobj(u.ugold));
 
1306
                else if (!u.ugold)
 
1307
                    You("have no gold.");
 
1308
                allowgold = 2;
 
1309
#else
 
1310
                flags.botl = 1;
 
1311
#endif
 
1312
            } else if (sym == 'a') {
 
1313
                allflag = TRUE;
 
1314
            } else if (sym == 'A') {
 
1315
                /* same as the default */ ;
 
1316
            } else if (sym == 'u') {
 
1317
                add_valid_menu_class('u');
 
1318
                ckfn = ckunpaid;
 
1319
            } else if (sym == 'B') {
 
1320
                add_valid_menu_class('B');
 
1321
                ckfn = ckvalidcat;
 
1322
            } else if (sym == 'U') {
 
1323
                add_valid_menu_class('U');
 
1324
                ckfn = ckvalidcat;
 
1325
            } else if (sym == 'C') {
 
1326
                add_valid_menu_class('C');
 
1327
                ckfn = ckvalidcat;
 
1328
            } else if (sym == 'X') {
 
1329
                add_valid_menu_class('X');
 
1330
                ckfn = ckvalidcat;
 
1331
            } else if (sym == 'm') {
 
1332
                m_seen = TRUE;
 
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;
 
1339
                    olets[oletct] = 0;
 
1340
                }
 
1341
            }
 
1342
        }
 
1343
 
 
1344
        if (m_seen)
 
1345
            return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
 
1346
        else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
 
1347
            return 0;
 
1348
#ifndef GOLDOBJ
 
1349
        else if (allowgold == 2 && !oletct)
 
1350
            return 1;   /* you dropped gold (or at least tried to) */
 
1351
        else {
 
1352
#else
 
1353
        else /*!!!! if (allowgold == 2 && !oletct)
 
1354
            !!!! return 1;       you dropped gold (or at least tried to) 
 
1355
            !!!! test gold dropping
 
1356
        else*/ {
 
1357
#endif
 
1358
            int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); 
 
1359
            /*
 
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. 
 
1364
             */
 
1365
            if (combo && allflag && resultflags)
 
1366
                *resultflags |= ALL_FINISHED; 
 
1367
            return cnt;
 
1368
        }
 
1369
}
 
1370
 
 
1371
/*
 
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.
 
1377
 */
 
1378
int
 
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));
 
1384
{
 
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;
 
1389
        char qbuf[QBUFSZ];
 
1390
 
 
1391
        takeoff = taking_off(word);
 
1392
        ident = !strcmp(word, "identify");
 
1393
        nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
 
1394
                 ident || takeoff);
 
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
 
1399
         */
 
1400
nextclass:
 
1401
        ilet = 'a'-1;
 
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++;
 
1406
                otmp2 = otmp->nobj;
 
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;
 
1411
                if (!allflag) {
 
1412
                        Strcpy(qbuf, !ininv ? doname(otmp) :
 
1413
                                xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L));
 
1414
                        Strcat(qbuf, "?");
 
1415
                        sym = (takeoff || ident || otmp->quan < 2L) ?
 
1416
                                nyaq(qbuf) : nyNaq(qbuf);
 
1417
                }
 
1418
                else    sym = 'y';
 
1419
 
 
1420
                otmpo = otmp;
 
1421
                if (sym == '#') {
 
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).
 
1427
                  */
 
1428
                    if (!yn_number)
 
1429
                        sym = 'n';
 
1430
                    else {
 
1431
                        sym = 'y';
 
1432
                        if (yn_number < otmp->quan && !welded(otmp) &&
 
1433
                            (!otmp->cursed || otmp->otyp != LOADSTONE)) {
 
1434
                            otmp = splitobj(otmp, yn_number);
 
1435
                        }
 
1436
                    }
 
1437
                }
 
1438
                switch(sym){
 
1439
                case 'a':
 
1440
                        allflag = 1;
 
1441
                case 'y':
 
1442
                        tmp = (*fn)(otmp);
 
1443
                        if(tmp < 0) {
 
1444
                            if (otmp != otmpo) {
 
1445
                                /* split occurred, merge again */
 
1446
                                (void) merged(&otmpo, &otmp);
 
1447
                            }
 
1448
                            goto ret;
 
1449
                        }
 
1450
                        cnt += tmp;
 
1451
                        if(--mx == 0) goto ret;
 
1452
                case 'n':
 
1453
                        if(nodot) dud++;
 
1454
                default:
 
1455
                        break;
 
1456
                case 'q':
 
1457
                        /* special case for seffects() */
 
1458
                        if (ident) cnt = -1;
 
1459
                        goto ret;
 
1460
                }
 
1461
        }
 
1462
        if (olets && *olets && *++olets)
 
1463
                goto nextclass;
 
1464
        if(!takeoff && (dud || cnt)) pline("That was all.");
 
1465
        else if(!dud && !cnt) pline("No applicable objects.");
 
1466
ret:
 
1467
        return(cnt);
 
1468
}
 
1469
 
 
1470
 
 
1471
/*
 
1472
 *      Object identification routines:
 
1473
 */
 
1474
 
 
1475
/* make an object actually be identified; no display updating */
 
1476
void
 
1477
fully_identify_obj(otmp)
 
1478
struct obj *otmp;
 
1479
{
 
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);
 
1485
}
 
1486
 
 
1487
/* ggetobj callback routine; identify an object and give immediate feedback */
 
1488
int
 
1489
identify(otmp)
 
1490
struct obj *otmp;
 
1491
{
 
1492
    fully_identify_obj(otmp);
 
1493
    prinv((char *)0, otmp, 0L);
 
1494
    return 1;
 
1495
}
 
1496
 
 
1497
/* menu of unidentified objects; select and identify up to id_limit of them */
 
1498
STATIC_OVL void
 
1499
menu_identify(id_limit)
 
1500
int id_limit;
 
1501
{
 
1502
    menu_item *pick_list;
 
1503
    int n, i, first = 1;
 
1504
    char buf[BUFSZ];
 
1505
    /* assumptions:  id_limit > 0 and at least one unID'd item is present */
 
1506
 
 
1507
    while (id_limit) {
 
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);
 
1512
 
 
1513
        if (n > 0) {
 
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 */
 
1519
        } else {
 
1520
            if (n < 0) pline("That was all.");
 
1521
            id_limit = 0; /* Stop now */
 
1522
        }
 
1523
        first = 0;
 
1524
    }
 
1525
}
 
1526
 
 
1527
/* dialog with user to identify a given number of items; 0 means all */
 
1528
void
 
1529
identify_pack(id_limit)
 
1530
int id_limit;
 
1531
{
 
1532
    struct obj *obj, *the_obj;
 
1533
    int n, unid_cnt;
 
1534
 
 
1535
    unid_cnt = 0;
 
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;
 
1539
 
 
1540
    if (!unid_cnt) {
 
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);
 
1546
        } else {
 
1547
 
 
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);
 
1551
 
 
1552
        }
 
1553
    } else {
 
1554
        /* identify up to `id_limit' items */
 
1555
        n = 0;
 
1556
        if (flags.menu_style == MENU_TRADITIONAL)
 
1557
            do {
 
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);
 
1563
    }
 
1564
    update_inventory();
 
1565
}
 
1566
 
 
1567
#endif /* OVLB */
 
1568
#ifdef OVL2
 
1569
 
 
1570
STATIC_OVL char
 
1571
obj_to_let(obj) /* should of course only be called for things in invent */
 
1572
register struct obj *obj;
 
1573
{
 
1574
#ifndef GOLDOBJ
 
1575
        if (obj->oclass == COIN_CLASS)
 
1576
                return GOLD_SYM;
 
1577
#endif
 
1578
        if (!flags.invlet_constant) {
 
1579
                obj->invlet = NOINVSYM;
 
1580
                reassign();
 
1581
        }
 
1582
        return obj->invlet;
 
1583
}
 
1584
 
 
1585
/*
 
1586
 * Print the indicated quantity of the given object.  If quan == 0L then use
 
1587
 * the current quantity.
 
1588
 */
 
1589
void
 
1590
prinv(prefix, obj, quan)
 
1591
const char *prefix;
 
1592
register struct obj *obj;
 
1593
long quan;
 
1594
{
 
1595
        if (!prefix) prefix = "";
 
1596
        pline("%s%s%s",
 
1597
              prefix, *prefix ? " " : "",
 
1598
              xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan));
 
1599
}
 
1600
 
 
1601
#endif /* OVL2 */
 
1602
#ifdef OVL1
 
1603
 
 
1604
char *
 
1605
xprname(obj, txt, let, dot, cost, quan)
 
1606
struct obj *obj;
 
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 */
 
1612
{
 
1613
#ifdef LINT     /* handle static char li[BUFSZ]; */
 
1614
    char li[BUFSZ];
 
1615
#else
 
1616
    static char li[BUFSZ];
 
1617
#endif
 
1618
    boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
 
1619
    long savequan = 0;
 
1620
 
 
1621
    if (quan && obj) {
 
1622
        savequan = obj->quan;
 
1623
        obj->quan = quan;
 
1624
    }
 
1625
 
 
1626
    /*
 
1627
     * If let is:
 
1628
     *  *  Then obj == null and we are printing a total amount.
 
1629
     *  >  Then the object is contained and doesn't have an inventory letter.
 
1630
     */
 
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));
 
1636
#ifndef GOLDOBJ
 
1637
    } else if (obj && obj->oclass == COIN_CLASS) {
 
1638
        Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
 
1639
                (dot ? "." : ""));
 
1640
#endif
 
1641
    } else {
 
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 ? "." : ""));
 
1646
    }
 
1647
    if (savequan) obj->quan = savequan;
 
1648
 
 
1649
    return li;
 
1650
}
 
1651
 
 
1652
#endif /* OVL1 */
 
1653
#ifdef OVLB
 
1654
 
 
1655
/* the 'i' command */
 
1656
int
 
1657
ddoinv()
 
1658
{
 
1659
        (void) display_inventory((char *)0, FALSE);
 
1660
        return 0;
 
1661
}
 
1662
 
 
1663
/*
 
1664
 * find_unpaid()
 
1665
 *
 
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
 
1670
 * containers.
 
1671
 */
 
1672
STATIC_OVL struct obj *
 
1673
find_unpaid(list, last_found)
 
1674
    struct obj *list, **last_found;
 
1675
{
 
1676
    struct obj *obj;
 
1677
 
 
1678
    while (list) {
 
1679
        if (list->unpaid) {
 
1680
            if (*last_found) {
 
1681
                /* still looking for previous unpaid object */
 
1682
                if (list == *last_found)
 
1683
                    *last_found = (struct obj *) 0;
 
1684
            } else
 
1685
                return (*last_found = list);
 
1686
        }
 
1687
        if (Has_contents(list)) {
 
1688
            if ((obj = find_unpaid(list->cobj, last_found)) != 0)
 
1689
                return obj;
 
1690
        }
 
1691
        list = list->nobj;
 
1692
    }
 
1693
    return (struct obj *) 0;
 
1694
}
 
1695
 
 
1696
/*
 
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.
 
1700
 */
 
1701
#ifdef DUMP_LOG
 
1702
static char
 
1703
display_pickinv(lets, want_reply, out_cnt, want_dump)
 
1704
register const char *lets;
 
1705
boolean want_reply;
 
1706
long* out_cnt;
 
1707
boolean want_dump;
 
1708
#else
 
1709
static char
 
1710
display_pickinv(lets, want_reply, out_cnt)
 
1711
register const char *lets;
 
1712
boolean want_reply;
 
1713
long* out_cnt;
 
1714
#endif
 
1715
{
 
1716
        struct obj *otmp;
 
1717
#ifdef SORTLOOT
 
1718
        struct obj **oarray;
 
1719
        int i, j;
 
1720
#endif
 
1721
        char ilet, ret;
 
1722
        char *invlet = flags.inv_order;
 
1723
        int n, classcount;
 
1724
        winid win;                              /* windows being used */
 
1725
        static winid local_win = WIN_ERR;       /* window for partial menus */
 
1726
        anything any;
 
1727
        menu_item *selected;
 
1728
 
 
1729
        /* overriden by global flag */
 
1730
        if (flags.perm_invent) {
 
1731
            win = (lets && *lets) ? local_win : WIN_INVEN;
 
1732
            /* create the first time used */
 
1733
            if (win == WIN_ERR)
 
1734
                win = local_win = create_nhwindow(NHW_MENU);
 
1735
        } else
 
1736
            win = WIN_INVEN;
 
1737
 
 
1738
#ifdef DUMP_LOG
 
1739
        if (want_dump)   dump("", "Your inventory");
 
1740
#endif
 
1741
 
 
1742
        /*
 
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.
 
1752
        */
 
1753
        if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
 
1754
#ifndef GOLDOBJ
 
1755
            pline("Not carrying anything%s.", u.ugold ? " except gold" : "");
 
1756
#else
 
1757
            pline("Not carrying anything.");
 
1758
#endif
 
1759
#ifdef DUMP_LOG
 
1760
            if (want_dump) {
 
1761
#ifdef GOLDOBJ
 
1762
                dump("  ", "Not carrying anything");
 
1763
#else
 
1764
                dump("  Not carrying anything",
 
1765
                    u.ugold ? " except gold." : ".");
 
1766
#endif
 
1767
            }
 
1768
#endif
 
1769
            return 0;
 
1770
        }
 
1771
 
 
1772
        /* oxymoron? temporarily assign permanent inventory letters */
 
1773
        if (!flags.invlet_constant) reassign();
 
1774
 
 
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 */
 
1779
            ret = '\0';
 
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 */
 
1786
#ifdef DUMP_LOG
 
1787
                    if (want_dump) {
 
1788
                      char letbuf[7];
 
1789
                      sprintf(letbuf, "  %c - ", lets[0]);
 
1790
                      dump(letbuf,
 
1791
                           xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L));
 
1792
                    }
 
1793
#endif
 
1794
                    break;
 
1795
                }
 
1796
            }
 
1797
            return ret;
 
1798
        }
 
1799
 
 
1800
#ifdef SORTLOOT
 
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++;
 
1804
 
 
1805
        /* Make a temporary array to store the objects sorted */
 
1806
        oarray = (struct obj **)alloc(n*sizeof(struct obj*));
 
1807
 
 
1808
        /* Add objects to the array */
 
1809
        i = 0;
 
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];
 
1817
              }
 
1818
              oarray[j] = otmp;
 
1819
              i++;
 
1820
            } else {
 
1821
              /* Just add it to the array */
 
1822
              oarray[i++] = otmp;
 
1823
            }
 
1824
          }
 
1825
#endif /* SORTLOOT */
 
1826
 
 
1827
        start_menu(win);
 
1828
nextclass:
 
1829
        classcount = 0;
 
1830
        any.a_void = 0;         /* set all bits to zero */
 
1831
#ifdef SORTLOOT
 
1832
        for(i = 0; i < n; i++) {
 
1833
          otmp = oarray[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);
 
1840
#ifdef DUMP_LOG
 
1841
              if (want_dump)
 
1842
                dump("  ", let_to_name(*invlet, FALSE));
 
1843
#endif
 
1844
              classcount++;
 
1845
            }
 
1846
            any.a_char = ilet;
 
1847
            add_menu(win, obj_to_glyph(otmp),
 
1848
                     &any, ilet, 0, ATR_NONE, doname(otmp),
 
1849
                     MENU_UNSELECTED);
 
1850
#ifdef DUMP_LOG
 
1851
            if (want_dump) {
 
1852
              char letbuf[7];
 
1853
              sprintf(letbuf, "  %c - ", ilet);
 
1854
              dump(letbuf, doname(otmp));
 
1855
            }
 
1856
#endif
 
1857
          }
 
1858
        }
 
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);
 
1868
#ifdef DUMP_LOG
 
1869
                                if (want_dump)
 
1870
                                    dump("  ", let_to_name(*invlet, FALSE));
 
1871
#endif
 
1872
                                classcount++;
 
1873
                            }
 
1874
                            any.a_char = ilet;
 
1875
                            add_menu(win, obj_to_glyph(otmp),
 
1876
                                        &any, ilet, 0, ATR_NONE, doname(otmp),
 
1877
                                        MENU_UNSELECTED);
 
1878
#ifdef DUMP_LOG
 
1879
                            if (want_dump) {
 
1880
                              char letbuf[7];
 
1881
                              sprintf(letbuf, "  %c - ", ilet);
 
1882
                              dump(letbuf, doname(otmp));
 
1883
                            }
 
1884
#endif
 
1885
                        }
 
1886
                }
 
1887
        }
 
1888
#endif /* SORTLOOT */
 
1889
        if (flags.sortpack) {
 
1890
                if (*++invlet) goto nextclass;
 
1891
#ifdef WIZARD
 
1892
                if (--invlet != venom_inv) {
 
1893
                        invlet = venom_inv;
 
1894
                        goto nextclass;
 
1895
                }
 
1896
#endif
 
1897
        }
 
1898
#ifdef SORTLOOT
 
1899
        free(oarray);
 
1900
#endif
 
1901
        end_menu(win, (char *) 0);
 
1902
 
 
1903
        n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
 
1904
        if (n > 0) {
 
1905
            ret = selected[0].item.a_char;
 
1906
            if (out_cnt) *out_cnt = selected[0].count;
 
1907
            free((genericptr_t)selected);
 
1908
        } else
 
1909
            ret = !n ? '\0' : '\033';   /* cancelled */
 
1910
#ifdef DUMP_LOG
 
1911
        if (want_dump)  dump("", "");
 
1912
#endif
 
1913
 
 
1914
        return ret;
 
1915
}
 
1916
 
 
1917
/*
 
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.
 
1920
 *
 
1921
 * Returns the letter identifier of a selected item, or 0 if nothing
 
1922
 * was selected.
 
1923
 */
 
1924
char
 
1925
display_inventory(lets, want_reply)
 
1926
register const char *lets;
 
1927
boolean want_reply;
 
1928
{
 
1929
        return display_pickinv(lets, want_reply, (long *)0
 
1930
#ifdef DUMP_LOG
 
1931
                                , FALSE
 
1932
#endif
 
1933
        );
 
1934
}
 
1935
 
 
1936
#ifdef DUMP_LOG
 
1937
/* See display_inventory. This is the same thing WITH dumpfile creation */
 
1938
char
 
1939
dump_inventory(lets, want_reply)
 
1940
register const char *lets;
 
1941
boolean want_reply;
 
1942
{
 
1943
  return display_pickinv(lets, want_reply, (long *)0, TRUE);
 
1944
}
 
1945
#endif
 
1946
 
 
1947
/*
 
1948
 * Returns the number of unpaid items within the given list.  This includes
 
1949
 * contained objects.
 
1950
 */
 
1951
int
 
1952
count_unpaid(list)
 
1953
    struct obj *list;
 
1954
{
 
1955
    int count = 0;
 
1956
 
 
1957
    while (list) {
 
1958
        if (list->unpaid) count++;
 
1959
        if (Has_contents(list))
 
1960
            count += count_unpaid(list->cobj);
 
1961
        list = list->nobj;
 
1962
    }
 
1963
    return count;
 
1964
}
 
1965
 
 
1966
/*
 
1967
 * Returns the number of items with b/u/c/unknown within the given list.  
 
1968
 * This does NOT include contained objects.
 
1969
 */
 
1970
int
 
1971
count_buc(list, type)
 
1972
    struct obj *list;
 
1973
    int type;
 
1974
{
 
1975
    int count = 0;
 
1976
 
 
1977
    while (list) {
 
1978
        if (Role_if(PM_PRIEST)) list->bknown = TRUE;
 
1979
        switch(type) {
 
1980
            case BUC_BLESSED:
 
1981
                if (list->oclass != COIN_CLASS && list->bknown && list->blessed)
 
1982
                    count++;
 
1983
                break;
 
1984
            case BUC_CURSED:
 
1985
                if (list->oclass != COIN_CLASS && list->bknown && list->cursed)
 
1986
                    count++;
 
1987
                break;
 
1988
            case BUC_UNCURSED:
 
1989
                if (list->oclass != COIN_CLASS &&
 
1990
                        list->bknown && !list->blessed && !list->cursed)
 
1991
                    count++;
 
1992
                break;
 
1993
            case BUC_UNKNOWN:
 
1994
                if (list->oclass != COIN_CLASS && !list->bknown)
 
1995
                    count++;
 
1996
                break;
 
1997
            default:
 
1998
                impossible("need count of curse status %d?", type);
 
1999
                return 0;
 
2000
        }
 
2001
        list = list->nobj;
 
2002
    }
 
2003
    return count;
 
2004
}
 
2005
 
 
2006
STATIC_OVL void
 
2007
dounpaid()
 
2008
{
 
2009
    winid win;
 
2010
    struct obj *otmp, *marker;
 
2011
    register char ilet;
 
2012
    char *invlet = flags.inv_order;
 
2013
    int classcount, count, num_so_far;
 
2014
    int save_unpaid = 0;        /* lint init */
 
2015
    long cost, totcost;
 
2016
 
 
2017
    count = count_unpaid(invent);
 
2018
 
 
2019
    if (count == 1) {
 
2020
        marker = (struct obj *) 0;
 
2021
        otmp = find_unpaid(invent, &marker);
 
2022
 
 
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;
 
2026
 
 
2027
        pline("%s", xprname(otmp, distant_name(otmp, doname),
 
2028
                            marker ? otmp->invlet : CONTAINED_SYM,
 
2029
                            TRUE, unpaid_cost(otmp), 0L));
 
2030
        return;
 
2031
    }
 
2032
 
 
2033
    win = create_nhwindow(NHW_MENU);
 
2034
    cost = totcost = 0;
 
2035
    num_so_far = 0;     /* count of # printed so far */
 
2036
    if (!flags.invlet_constant) reassign();
 
2037
 
 
2038
    do {
 
2039
        classcount = 0;
 
2040
        for (otmp = invent; otmp; otmp = otmp->nobj) {
 
2041
            ilet = otmp->invlet;
 
2042
            if (otmp->unpaid) {
 
2043
                if (!flags.sortpack || otmp->oclass == *invlet) {
 
2044
                    if (flags.sortpack && !classcount) {
 
2045
                        putstr(win, 0, let_to_name(*invlet, TRUE));
 
2046
                        classcount++;
 
2047
                    }
 
2048
 
 
2049
                    totcost += cost = unpaid_cost(otmp);
 
2050
                    /* suppress "(unpaid)" suffix */
 
2051
                    save_unpaid = otmp->unpaid;
 
2052
                    otmp->unpaid = 0;
 
2053
                    putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
 
2054
                                           ilet, TRUE, cost, 0L));
 
2055
                    otmp->unpaid = save_unpaid;
 
2056
                    num_so_far++;
 
2057
                }
 
2058
            }
 
2059
        }
 
2060
    } while (flags.sortpack && (*++invlet));
 
2061
 
 
2062
    if (count > num_so_far) {
 
2063
        /* something unpaid is contained */
 
2064
        if (flags.sortpack)
 
2065
            putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
 
2066
        /*
 
2067
         * Search through the container objects in the inventory for
 
2068
         * unpaid items.  The top level inventory items have already
 
2069
         * been listed.
 
2070
         */
 
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 */
 
2078
                    putstr(win, 0,
 
2079
                           xprname(marker, distant_name(marker, doname),
 
2080
                                   CONTAINED_SYM, TRUE, cost, 0L));
 
2081
                    marker->unpaid = save_unpaid;
 
2082
                }
 
2083
            }
 
2084
        }
 
2085
    }
 
2086
 
 
2087
    putstr(win, 0, "");
 
2088
    putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L));
 
2089
    display_nhwindow(win, FALSE);
 
2090
    destroy_nhwindow(win);
 
2091
}
 
2092
 
 
2093
 
 
2094
/* query objlist callback: return TRUE if obj type matches "this_type" */
 
2095
static int this_type;
 
2096
 
 
2097
STATIC_OVL boolean
 
2098
this_type_only(obj)
 
2099
    struct obj *obj;
 
2100
{
 
2101
    return (obj->oclass == this_type);
 
2102
}
 
2103
 
 
2104
/* the 'I' command */
 
2105
int
 
2106
dotypeinv()
 
2107
{
 
2108
        char c = '\0';
 
2109
        int n, i = 0;
 
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?";
 
2116
 
 
2117
#ifndef GOLDOBJ
 
2118
        if (!invent && !u.ugold && !billx) {
 
2119
#else
 
2120
        if (!invent && !billx) {
 
2121
#endif
 
2122
            You("aren't carrying anything.");
 
2123
            return 0;
 
2124
        }
 
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;
 
2130
                i = UNPAID_TYPES;
 
2131
                if (billx) i |= BILLED_TYPES;
 
2132
                n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
 
2133
                if (!n) return 0;
 
2134
                this_type = c = pick_list[0].item.a_int;
 
2135
                free((genericptr_t) pick_list);
 
2136
            }
 
2137
        }
 
2138
        if (traditional) {
 
2139
            /* collect a list of classes of objects carried, for use as a prompt */
 
2140
            types[0] = 0;
 
2141
            class_count = collect_obj_classes(types, invent,
 
2142
                                              FALSE,
 
2143
#ifndef GOLDOBJ
 
2144
                                              (u.ugold != 0),
 
2145
#endif
 
2146
                                              (boolean FDECL((*),(OBJ_P))) 0, &itemcount);
 
2147
            if (unpaid_count) {
 
2148
                Strcat(types, "u");
 
2149
                class_count++;
 
2150
            }
 
2151
            if (billx) {
 
2152
                Strcat(types, "x");
 
2153
                class_count++;
 
2154
            }
 
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';
 
2165
                }
 
2166
 
 
2167
            if(class_count > 1) {
 
2168
                c = yn_function(prompt, types, '\0');
 
2169
#ifdef REDO
 
2170
                savech(c);
 
2171
#endif
 
2172
                if(c == '\0') {
 
2173
                        clear_nhwindow(WIN_MESSAGE);
 
2174
                        return 0;
 
2175
                }
 
2176
            } else {
 
2177
                /* only one thing to itemize */
 
2178
                if (unpaid_count)
 
2179
                    c = 'u';
 
2180
                else if (billx)
 
2181
                    c = 'x';
 
2182
                else
 
2183
                    c = types[0];
 
2184
            }
 
2185
        }
 
2186
        if (c == 'x') {
 
2187
            if (billx)
 
2188
                (void) doinvbill(1);
 
2189
            else
 
2190
                pline("No used-up objects on your shopping bill.");
 
2191
            return 0;
 
2192
        }
 
2193
        if (c == 'u') {
 
2194
            if (unpaid_count)
 
2195
                dounpaid();
 
2196
            else
 
2197
                You("are not carrying any unpaid objects.");
 
2198
            return 0;
 
2199
        }
 
2200
        if (traditional) {
 
2201
            oclass = def_char_to_objclass(c); /* change to object class */
 
2202
            if (oclass == COIN_CLASS) {
 
2203
                return doprgold();
 
2204
            } else if (index(types, c) > index(types, '\033')) {
 
2205
                You("have no such objects.");
 
2206
                return 0;
 
2207
            }
 
2208
            this_type = oclass;
 
2209
        }
 
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);
 
2214
        return 0;
 
2215
}
 
2216
 
 
2217
/* return a string describing the dungeon feature at <x,y> if there
 
2218
   is one worth mentioning at that location; otherwise null */
 
2219
const char *
 
2220
dfeature_at(x, y, buf)
 
2221
int x, y;
 
2222
char *buf;
 
2223
{
 
2224
        struct rm *lev = &levl[x][y];
 
2225
        int ltyp = lev->typ, cmap = -1;
 
2226
        const char *dfeature = 0;
 
2227
        static char altbuf[BUFSZ];
 
2228
 
 
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" */
 
2235
            }
 
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";
 
2249
#ifdef SINKS
 
2250
        else if (IS_SINK(ltyp))
 
2251
            cmap = S_sink;                              /* "sink" */
 
2252
#endif
 
2253
        else if (IS_ALTAR(ltyp)) {
 
2254
            Sprintf(altbuf, "altar to %s (%s)", a_gname(),
 
2255
                    align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
 
2256
            dfeature = altbuf;
 
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";
 
2277
 
 
2278
        if (cmap >= 0) dfeature = defsyms[cmap].explanation;
 
2279
        if (dfeature) Strcpy(buf, dfeature);
 
2280
        return dfeature;
 
2281
}
 
2282
 
 
2283
/* look at what is here; if there are many objects (5 or more),
 
2284
   don't show them unless obj_cnt is 0 */
 
2285
int
 
2286
look_here(obj_cnt, picked_some)
 
2287
int obj_cnt;    /* obj_cnt > 0 implies that autopickup is in progess */
 
2288
boolean picked_some;
 
2289
{
 
2290
        struct obj *otmp;
 
2291
        struct trap *trap;
 
2292
        const char *verb = Blind ? "feel" : "see";
 
2293
        const char *dfeature = (char *)0;
 
2294
        char fbuf[BUFSZ], fbuf2[BUFSZ];
 
2295
        winid tmpwin;
 
2296
        boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE;
 
2297
 
 
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;
 
2306
            if (otmp) {
 
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);
 
2310
                }
 
2311
                if (Blind) Strcpy(fbuf, "You feel");
 
2312
                Strcat(fbuf,":");
 
2313
                (void) display_minventory(mtmp, MINV_ALL, fbuf);
 
2314
            } else {
 
2315
                You("%s no objects here.", verb);
 
2316
            }
 
2317
            return(!!Blind);
 
2318
        }
 
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));
 
2322
 
 
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)
 
2326
                dfeature = 0;
 
2327
 
 
2328
        if (Blind) {
 
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.");
 
2333
                } else {
 
2334
                    You("try to feel what is %s%s.",
 
2335
                        drift ? "floating here" : "lying here on the ",
 
2336
                        drift ? ""              : surface(u.ux, u.uy));
 
2337
                }
 
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!");
 
2342
                        return(0);
 
2343
                }
 
2344
        }
 
2345
 
 
2346
        if (dfeature)
 
2347
                Sprintf(fbuf, "There is %s here.", an(dfeature));
 
2348
 
 
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);
 
2354
                return(!!Blind);
 
2355
        }
 
2356
        /* we know there is something here */
 
2357
 
 
2358
        if (skip_objects) {
 
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";
 
2370
#endif
 
2371
            You("%s here %s.", verb, doname(otmp));
 
2372
            if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE);
 
2373
        } else {
 
2374
            display_nhwindow(WIN_MESSAGE, FALSE);
 
2375
            tmpwin = create_nhwindow(NHW_MENU);
 
2376
            if(dfeature) {
 
2377
                putstr(tmpwin, 0, fbuf);
 
2378
                putstr(tmpwin, 0, "");
 
2379
            }
 
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)) {
 
2384
                        char buf[BUFSZ];
 
2385
                        felt_cockatrice = TRUE;
 
2386
                        Strcpy(buf, doname(otmp));
 
2387
                        Strcat(buf, "...");
 
2388
                        putstr(tmpwin, 0, buf);
 
2389
                        break;
 
2390
                }
 
2391
                putstr(tmpwin, 0, doname(otmp));
 
2392
            }
 
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 */
 
2397
        }
 
2398
        return(!!Blind);
 
2399
}
 
2400
 
 
2401
/* explicilty look at what is here, including all objects */
 
2402
int
 
2403
dolook()
 
2404
{
 
2405
        return look_here(0, FALSE);
 
2406
}
 
2407
 
 
2408
boolean
 
2409
will_feel_cockatrice(otmp, force_touch)
 
2410
struct obj *otmp;
 
2411
boolean force_touch;
 
2412
{
 
2413
        if ((Blind || force_touch) && !uarmg && !Stone_resistance &&
 
2414
                (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
 
2415
                        return TRUE;
 
2416
        return FALSE;
 
2417
}
 
2418
 
 
2419
void
 
2420
feel_cockatrice(otmp, force_touch)
 
2421
struct obj *otmp;
 
2422
boolean force_touch;
 
2423
{
 
2424
        char kbuf[BUFSZ];
 
2425
 
 
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)));
 
2430
            else
 
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));
 
2434
                instapetrify(kbuf);
 
2435
        }
 
2436
}
 
2437
 
 
2438
#endif /* OVLB */
 
2439
#ifdef OVL1
 
2440
 
 
2441
void
 
2442
stackobj(obj)
 
2443
struct obj *obj;
 
2444
{
 
2445
        struct obj *otmp;
 
2446
 
 
2447
        for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
 
2448
                if(otmp != obj && merged(&obj,&otmp))
 
2449
                        break;
 
2450
        return;
 
2451
}
 
2452
 
 
2453
STATIC_OVL boolean
 
2454
mergable(otmp, obj)     /* returns TRUE if obj  & otmp can be merged */
 
2455
        register struct obj *otmp, *obj;
 
2456
{
 
2457
        if (obj->otyp != otmp->otyp) return FALSE;
 
2458
#ifdef GOLDOBJ
 
2459
        /* coins of the same kind will always merge */
 
2460
        if (obj->oclass == COIN_CLASS) return TRUE;
 
2461
#endif
 
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 ||
 
2472
#endif
 
2473
            obj->greased != otmp->greased ||
 
2474
            obj->oeroded != otmp->oeroded ||
 
2475
            obj->oeroded2 != otmp->oeroded2 ||
 
2476
            obj->bypass != otmp->bypass)
 
2477
            return(FALSE);
 
2478
 
 
2479
        if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
 
2480
            (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
 
2481
            return FALSE;
 
2482
 
 
2483
        if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
 
2484
                                          obj->orotten != otmp->orotten))
 
2485
            return(FALSE);
 
2486
 
 
2487
        if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
 
2488
                if (obj->corpsenm != otmp->corpsenm)
 
2489
                                return FALSE;
 
2490
        }
 
2491
 
 
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])))
 
2496
            return FALSE;
 
2497
 
 
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)
 
2501
            return(FALSE);
 
2502
 
 
2503
        /* burning potions of oil never merge */
 
2504
        if (obj->otyp == POT_OIL && obj->lamplit)
 
2505
            return FALSE;
 
2506
 
 
2507
        /* don't merge surcharged item with base-cost item */
 
2508
        if (obj->unpaid && !same_price(obj, otmp))
 
2509
            return FALSE;
 
2510
 
 
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)
 
2514
             ) ||
 
2515
            (obj->onamelth && otmp->onamelth &&
 
2516
                    strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
 
2517
                return FALSE;
 
2518
 
 
2519
        /* for the moment, any additional information is incompatible */
 
2520
        if (obj->oxlth || otmp->oxlth) return FALSE;
 
2521
 
 
2522
        if(obj->oartifact != otmp->oartifact) return FALSE;
 
2523
 
 
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);
 
2528
}
 
2529
 
 
2530
int
 
2531
doprgold()
 
2532
{
 
2533
        /* the messages used to refer to "carrying gold", but that didn't
 
2534
           take containers into account */
 
2535
#ifndef GOLDOBJ
 
2536
        if(!u.ugold)
 
2537
            Your("wallet is empty.");
 
2538
        else
 
2539
            Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));
 
2540
#else
 
2541
        long umoney = money_cnt(invent);
 
2542
        if(!umoney)
 
2543
            Your("wallet is empty.");
 
2544
        else
 
2545
            Your("wallet contains %ld %s.", umoney, currency(umoney));
 
2546
#endif
 
2547
        shopper_financial_report();
 
2548
        return 0;
 
2549
}
 
2550
 
 
2551
#endif /* OVL1 */
 
2552
#ifdef OVLB
 
2553
 
 
2554
int
 
2555
doprwep()
 
2556
{
 
2557
    if (!uwep) {
 
2558
        You("are empty %s.", body_part(HANDED));
 
2559
    } else {
 
2560
        prinv((char *)0, uwep, 0L);
 
2561
        if (u.twoweap) prinv((char *)0, uswapwep, 0L);
 
2562
    }
 
2563
    return 0;
 
2564
}
 
2565
 
 
2566
int
 
2567
doprarm()
 
2568
{
 
2569
        if(!wearing_armor())
 
2570
                You("are not wearing any armor.");
 
2571
        else {
 
2572
#ifdef TOURIST
 
2573
                char lets[8];
 
2574
#else
 
2575
                char lets[7];
 
2576
#endif
 
2577
                register int ct = 0;
 
2578
 
 
2579
#ifdef TOURIST
 
2580
                if(uarmu) lets[ct++] = obj_to_let(uarmu);
 
2581
#endif
 
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);
 
2588
                lets[ct] = 0;
 
2589
                (void) display_inventory(lets, FALSE);
 
2590
        }
 
2591
        return 0;
 
2592
}
 
2593
 
 
2594
int
 
2595
doprring()
 
2596
{
 
2597
        if(!uleft && !uright)
 
2598
                You("are not wearing any rings.");
 
2599
        else {
 
2600
                char lets[3];
 
2601
                register int ct = 0;
 
2602
 
 
2603
                if(uleft) lets[ct++] = obj_to_let(uleft);
 
2604
                if(uright) lets[ct++] = obj_to_let(uright);
 
2605
                lets[ct] = 0;
 
2606
                (void) display_inventory(lets, FALSE);
 
2607
        }
 
2608
        return 0;
 
2609
}
 
2610
 
 
2611
int
 
2612
dopramulet()
 
2613
{
 
2614
        if (!uamul)
 
2615
                You("are not wearing an amulet.");
 
2616
        else
 
2617
                prinv((char *)0, uamul, 0L);
 
2618
        return 0;
 
2619
}
 
2620
 
 
2621
STATIC_OVL boolean
 
2622
tool_in_use(obj)
 
2623
struct obj *obj;
 
2624
{
 
2625
        if ((obj->owornmask & (W_TOOL
 
2626
#ifdef STEED
 
2627
                        | W_SADDLE
 
2628
#endif
 
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));
 
2633
}
 
2634
 
 
2635
int
 
2636
doprtool()
 
2637
{
 
2638
        struct obj *otmp;
 
2639
        int ct = 0;
 
2640
        char lets[52+1];
 
2641
 
 
2642
        for (otmp = invent; otmp; otmp = otmp->nobj)
 
2643
            if (tool_in_use(otmp))
 
2644
                lets[ct++] = obj_to_let(otmp);
 
2645
        lets[ct] = '\0';
 
2646
        if (!ct) You("are not using any tools.");
 
2647
        else (void) display_inventory(lets, FALSE);
 
2648
        return 0;
 
2649
}
 
2650
 
 
2651
/* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
 
2652
   show inventory of all currently wielded, worn, or used objects */
 
2653
int
 
2654
doprinuse()
 
2655
{
 
2656
        struct obj *otmp;
 
2657
        int ct = 0;
 
2658
        char lets[52+1];
 
2659
 
 
2660
        for (otmp = invent; otmp; otmp = otmp->nobj)
 
2661
            if (is_worn(otmp) || tool_in_use(otmp))
 
2662
                lets[ct++] = obj_to_let(otmp);
 
2663
        lets[ct] = '\0';
 
2664
        if (!ct) You("are not wearing or wielding anything.");
 
2665
        else (void) display_inventory(lets, FALSE);
 
2666
        return 0;
 
2667
}
 
2668
 
 
2669
/*
 
2670
 * uses up an object that's on the floor, charging for it as necessary
 
2671
 */
 
2672
void
 
2673
useupf(obj, numused)
 
2674
register struct obj *obj;
 
2675
long numused;
 
2676
{
 
2677
        register struct obj *otmp;
 
2678
        boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
 
2679
 
 
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);
 
2684
        else
 
2685
                otmp = obj;
 
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);
 
2690
        }
 
2691
        delobj(otmp);
 
2692
        if (at_u && u.uundetected && hides_under(youmonst.data))
 
2693
            u.uundetected = OBJ_AT(u.ux, u.uy);
 
2694
}
 
2695
 
 
2696
#endif /* OVLB */
 
2697
 
 
2698
 
 
2699
#ifdef OVL1
 
2700
 
 
2701
/*
 
2702
 * Conversion from a class to a string for printing.
 
2703
 * This must match the object class order.
 
2704
 */
 
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",
 
2709
        "Chains", "Venoms"
 
2710
};
 
2711
 
 
2712
static NEARDATA const char oth_symbols[] = {
 
2713
        CONTAINED_SYM,
 
2714
        '\0'
 
2715
};
 
2716
 
 
2717
static NEARDATA const char *oth_names[] = {
 
2718
        "Bagged/Boxed items"
 
2719
};
 
2720
 
 
2721
static NEARDATA char *invbuf = (char *)0;
 
2722
static NEARDATA unsigned invbufsiz = 0;
 
2723
 
 
2724
char *
 
2725
let_to_name(let,unpaid)
 
2726
char let;
 
2727
boolean unpaid;
 
2728
{
 
2729
        const char *class_name;
 
2730
        const char *pos;
 
2731
        int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
 
2732
        unsigned len;
 
2733
 
 
2734
        if (oclass)
 
2735
            class_name = names[oclass];
 
2736
        else if ((pos = index(oth_symbols, let)) != 0)
 
2737
            class_name = oth_names[pos - oth_symbols];
 
2738
        else
 
2739
            class_name = names[0];
 
2740
 
 
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);
 
2746
        }
 
2747
        if (unpaid)
 
2748
            Strcat(strcpy(invbuf, "Unpaid "), class_name);
 
2749
        else
 
2750
            Strcpy(invbuf, class_name);
 
2751
        return invbuf;
 
2752
}
 
2753
 
 
2754
void
 
2755
free_invbuf()
 
2756
{
 
2757
        if (invbuf) free((genericptr_t)invbuf),  invbuf = (char *)0;
 
2758
        invbufsiz = 0;
 
2759
}
 
2760
 
 
2761
#endif /* OVL1 */
 
2762
#ifdef OVLB
 
2763
 
 
2764
void
 
2765
reassign()
 
2766
{
 
2767
        register int i;
 
2768
        register struct obj *obj;
 
2769
 
 
2770
        for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
 
2771
                obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
 
2772
        lastinvnr = i;
 
2773
}
 
2774
 
 
2775
#endif /* OVLB */
 
2776
#ifdef OVL1
 
2777
 
 
2778
int
 
2779
doorganize()    /* inventory organizer by Del Lamb */
 
2780
{
 
2781
        struct obj *obj, *otmp;
 
2782
        register int ix, cur;
 
2783
        register char let;
 
2784
        char alphabet[52+1], buf[52+1];
 
2785
        char qbuf[QBUFSZ];
 
2786
        char allowall[2];
 
2787
        const char *adj_type;
 
2788
 
 
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);
 
2793
 
 
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++;
 
2797
        alphabet[52] = 0;
 
2798
 
 
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']      = ' ';
 
2806
                }
 
2807
 
 
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];
 
2811
 
 
2812
        /* and by dashing runs of letters */
 
2813
        if(cur > 5) compactify(buf);
 
2814
 
 
2815
        /* get new letter to use as inventory letter */
 
2816
        for (;;) {
 
2817
                Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
 
2818
                let = yn_function(qbuf, (char *)0, '\0');
 
2819
                if(index(quitchars,let)) {
 
2820
                        pline(Never_mind);
 
2821
                        return(0);
 
2822
                }
 
2823
                if (let == '@' || !letter(let))
 
2824
                        pline("Select an inventory slot letter.");
 
2825
                else
 
2826
                        break;
 
2827
        }
 
2828
 
 
2829
        /* change the inventory and print the resulting item */
 
2830
        adj_type = "Moving:";
 
2831
 
 
2832
        /*
 
2833
         * don't use freeinv/addinv to avoid double-touching artifacts,
 
2834
         * dousing lamps, losing luck, cursing loadstone, etc.
 
2835
         */
 
2836
        extract_nobj(obj, &invent);
 
2837
 
 
2838
        for (otmp = invent; otmp;)
 
2839
                if (merged(&otmp,&obj)) {
 
2840
                        adj_type = "Merging:";
 
2841
                        obj = otmp;
 
2842
                        otmp = otmp->nobj;
 
2843
                        extract_nobj(obj, &invent);
 
2844
                } else {
 
2845
                        if (otmp->invlet == let) {
 
2846
                                adj_type = "Swapping:";
 
2847
                                otmp->invlet = obj->invlet;
 
2848
                        }
 
2849
                        otmp = otmp->nobj;
 
2850
                }
 
2851
 
 
2852
        /* inline addinv (assuming flags.invlet_constant and !merged) */
 
2853
        obj->invlet = let;
 
2854
        obj->nobj = invent; /* insert at beginning */
 
2855
        obj->where = OBJ_INVENT;
 
2856
        invent = obj;
 
2857
        reorder_invent();
 
2858
 
 
2859
        prinv(adj_type, obj, 0L);
 
2860
        update_inventory();
 
2861
        return(0);
 
2862
}
 
2863
 
 
2864
/* common to display_minventory and display_cinventory */
 
2865
STATIC_OVL void
 
2866
invdisp_nothing(hdr, txt)
 
2867
const char *hdr, *txt;
 
2868
{
 
2869
        winid win;
 
2870
        anything any;
 
2871
        menu_item *selected;
 
2872
 
 
2873
        any.a_void = 0;
 
2874
        win = create_nhwindow(NHW_MENU);
 
2875
        start_menu(win);
 
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);
 
2883
        return;
 
2884
}
 
2885
 
 
2886
/* query_objlist callback: return things that could possibly be worn/wielded */
 
2887
STATIC_OVL boolean
 
2888
worn_wield_only(obj)
 
2889
struct obj *obj;
 
2890
{
 
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);
 
2896
}
 
2897
 
 
2898
/*
 
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.
 
2902
 *
 
2903
 * By default, only worn and wielded items are displayed.  The caller
 
2904
 * can pick one.  Modifier flags are:
 
2905
 *
 
2906
 *      MINV_NOLET      - nothing selectable
 
2907
 *      MINV_ALL        - display all inventory
 
2908
 */
 
2909
struct obj *
 
2910
display_minventory(mon, dflags, title)
 
2911
register struct monst *mon;
 
2912
int dflags;
 
2913
char *title;
 
2914
{
 
2915
        struct obj *ret;
 
2916
#ifndef GOLDOBJ
 
2917
        struct obj m_gold;
 
2918
#endif
 
2919
        char tmp[QBUFSZ];
 
2920
        int n;
 
2921
        menu_item *selected = 0;
 
2922
#ifndef GOLDOBJ
 
2923
        int do_all = (dflags & MINV_ALL) != 0,
 
2924
            do_gold = (do_all && mon->mgold);
 
2925
#else
 
2926
        int do_all = (dflags & MINV_ALL) != 0;
 
2927
#endif
 
2928
 
 
2929
        Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)),
 
2930
                do_all ? "possessions" : "armament");
 
2931
 
 
2932
#ifndef GOLDOBJ
 
2933
        if (do_all ? (mon->minvent || mon->mgold)
 
2934
#else
 
2935
        if (do_all ? (mon->minvent != 0)
 
2936
#endif
 
2937
                   : (mon->misc_worn_check || MON_WEP(mon))) {
 
2938
            /* Fool the 'weapon in hand' routine into
 
2939
             * displaying 'weapon in claw', etc. properly.
 
2940
             */
 
2941
            youmonst.data = mon->data;
 
2942
 
 
2943
#ifndef GOLDOBJ
 
2944
            if (do_gold) {
 
2945
                /*
 
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.
 
2950
                 */
 
2951
                m_gold = zeroobj;
 
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.");
 
2958
            }
 
2959
 
 
2960
#endif
 
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);
 
2964
 
 
2965
#ifndef GOLDOBJ
 
2966
            if (do_gold) obj_extract_self(&m_gold);
 
2967
#endif
 
2968
 
 
2969
            set_uasmon();
 
2970
        } else {
 
2971
            invdisp_nothing(title ? title : tmp, "(none)");
 
2972
            n = 0;
 
2973
        }
 
2974
 
 
2975
        if (n > 0) {
 
2976
            ret = selected[0].item.a_obj;
 
2977
            free((genericptr_t)selected);
 
2978
#ifndef GOLDOBJ
 
2979
            /*
 
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...
 
2983
             */
 
2984
            if (ret == &m_gold) ret = (struct obj *) 0;
 
2985
#endif
 
2986
        } else
 
2987
            ret = (struct obj *) 0;
 
2988
        return ret;
 
2989
}
 
2990
 
 
2991
/*
 
2992
 * Display the contents of a container in inventory style.
 
2993
 * Currently, this is only used for statues, via wand of probing.
 
2994
 */
 
2995
struct obj *
 
2996
display_cinventory(obj)
 
2997
register struct obj *obj;
 
2998
{
 
2999
        struct obj *ret;
 
3000
        char tmp[QBUFSZ];
 
3001
        int n;
 
3002
        menu_item *selected = 0;
 
3003
 
 
3004
        Sprintf(tmp,"Contents of %s:", doname(obj));
 
3005
 
 
3006
        if (obj->cobj) {
 
3007
            n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
 
3008
                            PICK_NONE, allow_all);
 
3009
        } else {
 
3010
            invdisp_nothing(tmp, "(empty)");
 
3011
            n = 0;
 
3012
        }
 
3013
        if (n > 0) {
 
3014
            ret = selected[0].item.a_obj;
 
3015
            free((genericptr_t)selected);
 
3016
        } else
 
3017
            ret = (struct obj *) 0;
 
3018
        return ret;
 
3019
}
 
3020
 
 
3021
/* query objlist callback: return TRUE if obj is at given location */
 
3022
static coord only;
 
3023
 
 
3024
STATIC_OVL boolean
 
3025
only_here(obj)
 
3026
    struct obj *obj;
 
3027
{
 
3028
    return (obj->ox == only.x && obj->oy == only.y);
 
3029
}
 
3030
 
 
3031
/*
 
3032
 * Display a list of buried items in inventory style.  Return a non-zero
 
3033
 * value if there were items at that spot.
 
3034
 *
 
3035
 * Currently, this is only used with a wand of probing zapped downwards.
 
3036
 */
 
3037
int
 
3038
display_binventory(x, y, as_if_seen)
 
3039
int x, y;
 
3040
boolean as_if_seen;
 
3041
{
 
3042
        struct obj *obj;
 
3043
        menu_item *selected = 0;
 
3044
        int n;
 
3045
 
 
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;
 
3050
                n++;
 
3051
            }
 
3052
 
 
3053
        if (n) {
 
3054
            only.x = x;
 
3055
            only.y = y;
 
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;
 
3061
        }
 
3062
        return n;
 
3063
}
 
3064
 
 
3065
#endif /* OVL1 */
 
3066
 
 
3067
/*invent.c*/