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