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