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