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