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