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