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 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 * 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 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 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 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 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 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 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 * 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 * 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 * 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 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 697 prinv(struct obj *obj) 698 { 699 pline("%s", xprname(obj, obj_to_let(obj))); 700 } 701 702 static char * 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 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 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 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 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 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 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 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 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 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 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 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 1015 digit(int c) 1016 { 1017 return (c >= '0' && c <= '9'); 1018 } 1019