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