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