Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / hack / hack.invent.c
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.invent.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.invent.c,v 1.4 1999/11/16 10:26:36 marcel Exp $ */
4
5 #include        "hack.h"
6 #include        <stdio.h>
7 extern struct obj *splitobj();
8 extern struct obj zeroobj;
9 extern char morc;
10 extern char quitchars[];
11 static char *xprname();
12
13 #ifndef NOWORM
14 #include        "def.wseg.h"
15 extern struct wseg *wsegs[32];
16 #endif NOWORM
17
18 #define NOINVSYM        '#'
19
20 static int lastinvnr = 51;      /* 0 ... 51 */
21 static
22 assigninvlet(otmp)
23 struct obj *otmp;
24 {
25         boolean inuse[52];
26         int i;
27         struct obj *obj;
28
29         for(i = 0; i < 52; i++) inuse[i] = FALSE;
30         for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
31                 i = obj->invlet;
32                 if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
33                 if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
34                 if(i == otmp->invlet) otmp->invlet = 0;
35         }
36         if((i = otmp->invlet) &&
37             (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
38                 return;
39         for(i = lastinvnr+1; i != lastinvnr; i++) {
40                 if(i == 52) { i = -1; continue; }
41                 if(!inuse[i]) break;
42         }
43         otmp->invlet = (inuse[i] ? NOINVSYM :
44                         (i < 26) ? ('a'+i) : ('A'+i-26));
45         lastinvnr = i;
46 }
47
48 struct obj *
49 addinv(obj)
50 struct obj *obj;
51 {
52         struct obj *otmp;
53
54         /* merge or attach to end of chain */
55         if(!invent) {
56                 invent = obj;
57                 otmp = 0;
58         } else
59         for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
60                 if(merged(otmp, obj, 0))
61                         return(otmp);
62                 if(!otmp->nobj) {
63                         otmp->nobj = obj;
64                         break;
65                 }
66         }
67         obj->nobj = 0;
68
69         if(flags.invlet_constant) {
70                 assigninvlet(obj);
71                 /*
72                  * The ordering of the chain is nowhere significant
73                  * so in case you prefer some other order than the
74                  * historical one, change the code below.
75                  */
76                 if(otmp) {      /* find proper place in chain */
77                         otmp->nobj = 0;
78                         if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
79                                 obj->nobj = invent;
80                                 invent = obj;
81                         } else
82                         for(otmp = invent; ; otmp = otmp->nobj) {
83                             if(!otmp->nobj ||
84                                 (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
85                                 obj->nobj = otmp->nobj;
86                                 otmp->nobj = obj;
87                                 break;
88                             }
89                         }
90                 }
91         }
92
93         return(obj);
94 }
95
96 useup(obj)
97 struct obj *obj;
98 {
99         if(obj->quan > 1){
100                 obj->quan--;
101                 obj->owt = weight(obj);
102         } else {
103                 setnotworn(obj);
104                 freeinv(obj);
105                 obfree(obj, (struct obj *) 0);
106         }
107 }
108
109 freeinv(obj)
110 struct obj *obj;
111 {
112         struct obj *otmp;
113
114         if(obj == invent)
115                 invent = invent->nobj;
116         else {
117                 for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
118                         if(!otmp->nobj) panic("freeinv");
119                 otmp->nobj = obj->nobj;
120         }
121 }
122
123 /* destroy object in fobj chain (if unpaid, it remains on the bill) */
124 delobj(obj) struct obj *obj; {
125         freeobj(obj);
126         unpobj(obj);
127         obfree(obj, (struct obj *) 0);
128 }
129
130 /* unlink obj from chain starting with fobj */
131 freeobj(obj) struct obj *obj; {
132         struct obj *otmp;
133
134         if(obj == fobj) fobj = fobj->nobj;
135         else {
136                 for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
137                         if(!otmp) panic("error in freeobj");
138                 otmp->nobj = obj->nobj;
139         }
140 }
141
142 /* Note: freegold throws away its argument! */
143 freegold(gold) struct gold *gold; {
144         struct gold *gtmp;
145
146         if(gold == fgold) fgold = gold->ngold;
147         else {
148                 for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
149                         if(!gtmp) panic("error in freegold");
150                 gtmp->ngold = gold->ngold;
151         }
152         free((char *) gold);
153 }
154
155 deltrap(trap)
156 struct trap *trap;
157 {
158         struct trap *ttmp;
159
160         if(trap == ftrap)
161                 ftrap = ftrap->ntrap;
162         else {
163                 for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
164                 ttmp->ntrap = trap->ntrap;
165         }
166         free((char *) trap);
167 }
168
169 struct wseg *m_atseg;
170
171 struct monst *
172 m_at(x,y)
173 int x,y;
174 {
175         struct monst *mtmp;
176 #ifndef NOWORM
177         struct wseg *wtmp;
178 #endif NOWORM
179
180         m_atseg = 0;
181         for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
182                 if(mtmp->mx == x && mtmp->my == y)
183                         return(mtmp);
184 #ifndef NOWORM
185                 if(mtmp->wormno){
186                     for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
187                     if(wtmp->wx == x && wtmp->wy == y){
188                         m_atseg = wtmp;
189                         return(mtmp);
190                     }
191                 }
192 #endif NOWORM
193         }
194         return(0);
195 }
196
197 struct obj *
198 o_at(x,y)
199 int x,y;
200 {
201         struct obj *otmp;
202
203         for(otmp = fobj; otmp; otmp = otmp->nobj)
204                 if(otmp->ox == x && otmp->oy == y) return(otmp);
205         return(0);
206 }
207
208 struct obj *
209 sobj_at(n,x,y)
210 int n,x,y;
211 {
212         struct obj *otmp;
213
214         for(otmp = fobj; otmp; otmp = otmp->nobj)
215                 if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
216                         return(otmp);
217         return(0);
218 }
219
220 carried(obj) struct obj *obj; {
221 struct obj *otmp;
222         for(otmp = invent; otmp; otmp = otmp->nobj)
223                 if(otmp == obj) return(1);
224         return(0);
225 }
226
227 carrying(type)
228 int type;
229 {
230         struct obj *otmp;
231
232         for(otmp = invent; otmp; otmp = otmp->nobj)
233                 if(otmp->otyp == type)
234                         return(TRUE);
235         return(FALSE);
236 }
237
238 struct obj *
239 o_on(id, objchn) unsigned int id; struct obj *objchn; {
240         while(objchn) {
241                 if(objchn->o_id == id) return(objchn);
242                 objchn = objchn->nobj;
243         }
244         return((struct obj *) 0);
245 }
246
247 struct trap *
248 t_at(x,y)
249 int x,y;
250 {
251         struct trap *trap = ftrap;
252         while(trap) {
253                 if(trap->tx == x && trap->ty == y) return(trap);
254                 trap = trap->ntrap;
255         }
256         return(0);
257 }
258
259 struct gold *
260 g_at(x,y)
261 int x,y;
262 {
263         struct gold *gold = fgold;
264         while(gold) {
265                 if(gold->gx == x && gold->gy == y) return(gold);
266                 gold = gold->ngold;
267         }
268         return(0);
269 }
270
271 /* make dummy object structure containing gold - for temporary use only */
272 struct obj *
273 mkgoldobj(q)
274 long q;
275 {
276         struct obj *otmp;
277
278         otmp = newobj(0);
279         /* should set o_id etc. but otmp will be freed soon */
280         otmp->olet = '$';
281         u.ugold -= q;
282         OGOLD(otmp) = q;
283         flags.botl = 1;
284         return(otmp);
285 }
286
287 /*
288  * getobj returns:
289  *      struct obj *xxx:        object to do something with.
290  *      (struct obj *) 0        error return: no object.
291  *      &zeroobj                explicitly no object (as in w-).
292  */
293 struct obj *
294 getobj(let,word)
295 char *let,*word;
296 {
297         struct obj *otmp;
298         char ilet,ilet1,ilet2;
299         char buf[BUFSZ];
300         char lets[BUFSZ];
301         int foo = 0, foo2;
302         char *bp = buf;
303         xchar allowcnt = 0;     /* 0, 1 or 2 */
304         boolean allowgold = FALSE;
305         boolean allowall = FALSE;
306         boolean allownone = FALSE;
307         xchar foox = 0;
308         long cnt;
309
310         if(*let == '0') let++, allowcnt = 1;
311         if(*let == '$') let++, allowgold = TRUE;
312         if(*let == '#') let++, allowall = TRUE;
313         if(*let == '-') let++, allownone = TRUE;
314         if(allownone) *bp++ = '-';
315         if(allowgold) *bp++ = '$';
316         if(bp > buf && bp[-1] == '-') *bp++ = ' ';
317
318         ilet = 'a';
319         for(otmp = invent; otmp; otmp = otmp->nobj){
320             if(!*let || index(let, otmp->olet)) {
321                 bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
322
323                 /* ugly check: remove inappropriate things */
324                 if((!strcmp(word, "take off") &&
325                     !(otmp->owornmask & (W_ARMOR - W_ARM2)))
326                 || (!strcmp(word, "wear") &&
327                     (otmp->owornmask & (W_ARMOR | W_RING)))
328                 || (!strcmp(word, "wield") &&
329                     (otmp->owornmask & W_WEP))) {
330                         foo--;
331                         foox++;
332                 }
333             }
334             if(ilet == 'z') ilet = 'A'; else ilet++;
335         }
336         bp[foo] = 0;
337         if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
338         (void) strcpy(lets, bp);        /* necessary since we destroy buf */
339         if(foo > 5) {                   /* compactify string */
340                 foo = foo2 = 1;
341                 ilet2 = bp[0];
342                 ilet1 = bp[1];
343                 while(ilet = bp[++foo2] = bp[++foo]){
344                         if(ilet == ilet1+1){
345                                 if(ilet1 == ilet2+1)
346                                         bp[foo2 - 1] = ilet1 = '-';
347                                 else if(ilet2 == '-') {
348                                         bp[--foo2] = ++ilet1;
349                                         continue;
350                                 }
351                         }
352                         ilet2 = ilet1;
353                         ilet1 = ilet;
354                 }
355         }
356         if(!foo && !allowall && !allowgold && !allownone) {
357                 pline("You don't have anything %sto %s.",
358                         foox ? "else " : "", word);
359                 return(0);
360         }
361         for(;;) {
362                 if(!buf[0])
363                         pline("What do you want to %s [*]? ", word);
364                 else
365                         pline("What do you want to %s [%s or ?*]? ",
366                                 word, buf);
367
368                 cnt = 0;
369                 ilet = readchar();
370                 while(digit(ilet) && allowcnt) {
371                         if (cnt < 100000000)
372                             cnt = 10*cnt + (ilet - '0');
373                         else
374                             cnt = 999999999;
375                         allowcnt = 2;   /* signal presence of cnt */
376                         ilet = readchar();
377                 }
378                 if(digit(ilet)) {
379                         pline("No count allowed with this command.");
380                         continue;
381                 }
382                 if(index(quitchars,ilet))
383                         return((struct obj *)0);
384                 if(ilet == '-') {
385                         return(allownone ? &zeroobj : (struct obj *) 0);
386                 }
387                 if(ilet == '$') {
388                         if(!allowgold){
389                                 pline("You cannot %s gold.", word);
390                                 continue;
391                         }
392                         if(!(allowcnt == 2 && cnt < u.ugold))
393                                 cnt = u.ugold;
394                         return(mkgoldobj(cnt));
395                 }
396                 if(ilet == '?') {
397                         doinv(lets);
398                         if(!(ilet = morc)) continue;
399                         /* he typed a letter (not a space) to more() */
400                 } else if(ilet == '*') {
401                         doinv((char *) 0);
402                         if(!(ilet = morc)) continue;
403                         /* ... */
404                 }
405                 if(flags.invlet_constant) {
406                         for(otmp = invent; otmp; otmp = otmp->nobj)
407                                 if(otmp->invlet == ilet) break;
408                 } else {
409                         if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
410                         ilet -= 'a';
411                         for(otmp = invent; otmp && ilet;
412                                         ilet--, otmp = otmp->nobj) ;
413                 }
414                 if(!otmp) {
415                         pline("You don't have that object.");
416                         continue;
417                 }
418                 if(cnt < 0 || otmp->quan < cnt) {
419                         pline("You don't have that many! [You have %u]"
420                         , otmp->quan);
421                         continue;
422                 }
423                 break;
424         }
425         if(!allowall && let && !index(let,otmp->olet)) {
426                 pline("That is a silly thing to %s.",word);
427                 return(0);
428         }
429         if(allowcnt == 2) {     /* cnt given */
430                 if(cnt == 0) return(0);
431                 if(cnt != otmp->quan) {
432                         struct obj *obj;
433                         obj = splitobj(otmp, (int) cnt);
434                         if(otmp == uwep) setuwep(obj);
435                 }
436         }
437         return(otmp);
438 }
439
440 ckunpaid(otmp) struct obj *otmp; {
441         return( otmp->unpaid );
442 }
443
444 /* interactive version of getobj - used for Drop and Identify */
445 /* return the number of times fn was called successfully */
446 ggetobj(word, fn, max)
447 char *word;
448 int (*fn)(),  max;
449 {
450 char buf[BUFSZ];
451 char *ip;
452 char sym;
453 int oletct = 0, iletct = 0;
454 boolean allflag = FALSE;
455 char olets[20], ilets[20];
456 int (*ckfn)() = (int (*)()) 0;
457 xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;   /* BAH */
458         if(!invent && !allowgold){
459                 pline("You have nothing to %s.", word);
460                 return(0);
461         } else {
462                 struct obj *otmp = invent;
463                 int uflg = 0;
464
465                 if(allowgold) ilets[iletct++] = '$';
466                 ilets[iletct] = 0;
467                 while(otmp) {
468                         if(!index(ilets, otmp->olet)){
469                                 ilets[iletct++] = otmp->olet;
470                                 ilets[iletct] = 0;
471                         }
472                         if(otmp->unpaid) uflg = 1;
473                         otmp = otmp->nobj;
474                 }
475                 ilets[iletct++] = ' ';
476                 if(uflg) ilets[iletct++] = 'u';
477                 if(invent) ilets[iletct++] = 'a';
478                 ilets[iletct] = 0;
479         }
480         pline("What kinds of thing do you want to %s? [%s] ",
481                 word, ilets);
482         getlin(buf);
483         if(buf[0] == '\033') {
484                 clrlin();
485                 return(0);
486         }
487         ip = buf;
488         olets[0] = 0;
489         while(sym = *ip++){
490                 if(sym == ' ') continue;
491                 if(sym == '$') {
492                         if(allowgold == 1)
493                                 (*fn)(mkgoldobj(u.ugold));
494                         else if(!u.ugold)
495                                 pline("You have no gold.");
496                         allowgold = 2;
497                 } else
498                 if(sym == 'a' || sym == 'A') allflag = TRUE; else
499                 if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
500                 if(index("!%?[()=*/\"0", sym)){
501                         if(!index(olets, sym)){
502                                 olets[oletct++] = sym;
503                                 olets[oletct] = 0;
504                         }
505                 }
506                 else pline("You don't have any %c's.", sym);
507         }
508         if(allowgold == 2 && !oletct)
509                 return(1);      /* he dropped gold (or at least tried to) */
510         else
511                 return(askchain(invent, olets, allflag, fn, ckfn, max));
512 }
513
514 /*
515  * Walk through the chain starting at objchn and ask for all objects
516  * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
517  * whether the action in question (i.e., fn) has to be performed.
518  * If allflag then no questions are asked. Max gives the max nr of
519  * objects to be treated. Return the number of objects treated.
520  */
521 askchain(objchn, olets, allflag, fn, ckfn, max)
522 struct obj *objchn;
523 char *olets;
524 int allflag;
525 int (*fn)(), (*ckfn)();
526 int max;
527 {
528 struct obj *otmp, *otmp2;
529 char sym, ilet;
530 int cnt = 0;
531         ilet = 'a'-1;
532         for(otmp = objchn; otmp; otmp = otmp2){
533                 if(ilet == 'z') ilet = 'A'; else ilet++;
534                 otmp2 = otmp->nobj;
535                 if(olets && *olets && !index(olets, otmp->olet)) continue;
536                 if(ckfn && !(*ckfn)(otmp)) continue;
537                 if(!allflag) {
538                         pline(xprname(otmp, ilet));
539                         addtopl(" [nyaq]? ");
540                         sym = readchar();
541                 }
542                 else    sym = 'y';
543
544                 switch(sym){
545                 case 'a':
546                         allflag = 1;
547                 case 'y':
548                         cnt += (*fn)(otmp);
549                         if(--max == 0) goto ret;
550                 case 'n':
551                 default:
552                         break;
553                 case 'q':
554                         goto ret;
555                 }
556         }
557         pline(cnt ? "That was all." : "No applicable objects.");
558 ret:
559         return(cnt);
560 }
561
562 obj_to_let(obj) /* should of course only be called for things in invent */
563 struct obj *obj;
564 {
565         struct obj *otmp;
566         char ilet;
567
568         if(flags.invlet_constant)
569                 return(obj->invlet);
570         ilet = 'a';
571         for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
572                 if(++ilet > 'z') ilet = 'A';
573         return(otmp ? ilet : NOINVSYM);
574 }
575
576 prinv(obj)
577 struct obj *obj;
578 {
579         pline(xprname(obj, obj_to_let(obj)));
580 }
581
582 static char *
583 xprname(obj,let)
584 struct obj *obj;
585 char let;
586 {
587         static char li[BUFSZ];
588
589         (void) sprintf(li, "%c - %s.",
590                 flags.invlet_constant ? obj->invlet : let,
591                 doname(obj));
592         return(li);
593 }
594
595 ddoinv()
596 {
597         doinv((char *) 0);
598         return(0);
599 }
600
601 /* called with 0 or "": all objects in inventory */
602 /* otherwise: all objects with (serial) letter in lets */
603 doinv(lets)
604 char *lets;
605 {
606         struct obj *otmp;
607         char ilet;
608         int ct = 0;
609         char any[BUFSZ];
610
611         morc = 0;               /* just to be sure */
612
613         if(!invent){
614                 pline("Not carrying anything.");
615                 return;
616         }
617
618         cornline(0, (char *) 0);
619         ilet = 'a';
620         for(otmp = invent; otmp; otmp = otmp->nobj) {
621             if(flags.invlet_constant) ilet = otmp->invlet;
622             if(!lets || !*lets || index(lets, ilet)) {
623                     cornline(1, xprname(otmp, ilet));
624                     any[ct++] = ilet;
625             }
626             if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
627         }
628         any[ct] = 0;
629         cornline(2, any);
630 }
631
632 dotypeinv ()                            /* free after Robert Viduya */
633 /* Changed to one type only, so he doesnt have to type cr */
634 {
635     char c, ilet;
636     char stuff[BUFSZ];
637     int stct;
638     struct obj *otmp;
639     boolean billx = inshop() && doinvbill(0);
640     boolean unpd = FALSE;
641
642         if (!invent && !u.ugold && !billx) {
643             pline ("You aren't carrying anything.");
644             return(0);
645         }
646
647         stct = 0;
648         if(u.ugold) stuff[stct++] = '$';
649         stuff[stct] = 0;
650         for(otmp = invent; otmp; otmp = otmp->nobj) {
651             if (!index (stuff, otmp->olet)) {
652                 stuff[stct++] = otmp->olet;
653                 stuff[stct] = 0;
654             }
655             if(otmp->unpaid)
656                 unpd = TRUE;
657         }
658         if(unpd) stuff[stct++] = 'u';
659         if(billx) stuff[stct++] = 'x';
660         stuff[stct] = 0;
661
662         if(stct > 1) {
663             pline ("What type of object [%s] do you want an inventory of? ",
664                 stuff);
665             c = readchar();
666             if(index(quitchars,c)) return(0);
667         } else
668             c = stuff[0];
669
670         if(c == '$')
671             return(doprgold());
672
673         if(c == 'x' || c == 'X') {
674             if(billx)
675                 (void) doinvbill(1);
676             else
677                 pline("No used-up objects on the shopping bill.");
678             return(0);
679         }
680
681         if((c == 'u' || c == 'U') && !unpd) {
682                 pline("You are not carrying any unpaid objects.");
683                 return(0);
684         }
685
686         stct = 0;
687         ilet = 'a';
688         for (otmp = invent; otmp; otmp = otmp -> nobj) {
689             if(flags.invlet_constant) ilet = otmp->invlet;
690             if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
691                 stuff[stct++] = ilet;
692             if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
693         }
694         stuff[stct] = '\0';
695         if(stct == 0)
696                 pline("You have no such objects.");
697         else
698                 doinv (stuff);
699
700         return(0);
701 }
702
703 /* look at what is here */
704 dolook() {
705     struct obj *otmp, *otmp0;
706     struct gold *gold;
707     char *verb = Blind ? "feel" : "see";
708     int ct = 0;
709
710     if(!u.uswallow) {
711         if(Blind) {
712             pline("You try to feel what is lying here on the floor.");
713             if(Levitation) {                            /* ab@unido */
714                 pline("You cannot reach the floor!");
715                 return(1);
716             }
717         }
718         otmp0 = o_at(u.ux, u.uy);
719         gold = g_at(u.ux, u.uy);
720     }
721
722     if(u.uswallow || (!otmp0 && !gold)) {
723         pline("You %s no objects here.", verb);
724         return(!!Blind);
725     }
726
727     cornline(0, "Things that are here:");
728     for(otmp = otmp0; otmp; otmp = otmp->nobj) {
729         if(otmp->ox == u.ux && otmp->oy == u.uy) {
730             ct++;
731             cornline(1, doname(otmp));
732             if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
733                 pline("Touching the dead cockatrice is a fatal mistake ...");
734                 pline("You die ...");
735                 killer = "dead cockatrice";
736                 done("died");
737             }
738         }
739     }
740
741     if(gold) {
742         char gbuf[30];
743
744         (void) sprintf(gbuf, "%ld gold piece%s",
745                 gold->amount, plur(gold->amount));
746         if(!ct++)
747             pline("You %s here %s.", verb, gbuf);
748         else
749             cornline(1, gbuf);
750     }
751
752     if(ct == 1 && !gold) {
753         pline("You %s here %s.", verb, doname(otmp0));
754         cornline(3, (char *) 0);
755     }
756     if(ct > 1)
757         cornline(2, (char *) 0);
758     return(!!Blind);
759 }
760
761 stackobj(obj) struct obj *obj; {
762 struct obj *otmp = fobj;
763         for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
764         if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
765                 merged(obj,otmp,1))
766                         return;
767 }
768
769 /* merge obj with otmp and delete obj if types agree */
770 merged(otmp,obj,lose) struct obj *otmp, *obj; {
771         if(obj->otyp == otmp->otyp &&
772           obj->unpaid == otmp->unpaid &&
773           obj->spe == otmp->spe &&
774           obj->dknown == otmp->dknown &&
775           obj->cursed == otmp->cursed &&
776           (index("%*?!", obj->olet) ||
777             (obj->known == otmp->known &&
778                 (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
779                 otmp->quan += obj->quan;
780                 otmp->owt += obj->owt;
781                 if(lose) freeobj(obj);
782                 obfree(obj,otmp);       /* free(obj), bill->otmp */
783                 return(1);
784         } else  return(0);
785 }
786
787 /*
788  * Gold is no longer displayed; in fact, when you have a lot of money,
789  * it may take a while before you have counted it all.
790  * [Bug: d$ and pickup still tell you how much it was.]
791  */
792 extern int (*occupation)();
793 extern char *occtxt;
794 static long goldcounted;
795
796 countgold(){
797         if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
798                 long eps = 0;
799                 if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
800                 pline("You probably have about %ld gold pieces.",
801                         u.ugold + eps);
802                 return(0);      /* done */
803         }
804         return(1);              /* continue */
805 }
806
807 doprgold(){
808         if(!u.ugold)
809                 pline("You do not carry any gold.");
810         else if(u.ugold <= 500)
811                 pline("You are carrying %ld gold pieces.", u.ugold);
812         else {
813                 pline("You sit down in order to count your gold pieces.");
814                 goldcounted = 500;
815                 occupation = countgold;
816                 occtxt = "counting your gold";
817         }
818         return(1);
819 }
820
821 /* --- end of gold counting section --- */
822
823 doprwep(){
824         if(!uwep) pline("You are empty handed.");
825         else prinv(uwep);
826         return(0);
827 }
828
829 doprarm(){
830         if(!uarm && !uarmg && !uarms && !uarmh)
831                 pline("You are not wearing any armor.");
832         else {
833                 char lets[6];
834                 int ct = 0;
835
836                 if(uarm) lets[ct++] = obj_to_let(uarm);
837                 if(uarm2) lets[ct++] = obj_to_let(uarm2);
838                 if(uarmh) lets[ct++] = obj_to_let(uarmh);
839                 if(uarms) lets[ct++] = obj_to_let(uarms);
840                 if(uarmg) lets[ct++] = obj_to_let(uarmg);
841                 lets[ct] = 0;
842                 doinv(lets);
843         }
844         return(0);
845 }
846
847 doprring(){
848         if(!uleft && !uright)
849                 pline("You are not wearing any rings.");
850         else {
851                 char lets[3];
852                 int ct = 0;
853
854                 if(uleft) lets[ct++] = obj_to_let(uleft);
855                 if(uright) lets[ct++] = obj_to_let(uright);
856                 lets[ct] = 0;
857                 doinv(lets);
858         }
859         return(0);
860 }
861
862 digit(c) char c; {
863         return(c >= '0' && c <= '9');
864 }