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