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