jcs's openbsd hax
openbsd
at jcs 951 lines 22 kB view raw
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 70extern struct obj zeroobj; 71extern char morc; 72extern char quitchars[]; 73 74#ifndef NOWORM 75extern struct wseg *wsegs[32]; 76#endif /* NOWORM */ 77 78#define NOINVSYM '#' 79 80static int lastinvnr = 51; /* 0 ... 51 */ 81 82static void assigninvlet(struct obj *); 83static char obj_to_let(struct obj *); 84static char *xprname(struct obj *, char); 85static void doinv(char *); 86static int merged(struct obj *, struct obj *, int); 87 88 89static void 90assigninvlet(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 115struct obj * 116addinv(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 162void 163useup(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 175void 176freeinv(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) */ 190void 191delobj(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 */ 199void 200freeobj(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! */ 213void 214freegold(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 227void 228deltrap(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 241struct wseg *m_atseg; 242 243struct monst * 244m_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 268struct obj * 269o_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 278struct obj * 279sobj_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 289int 290carried(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 299boolean 300carrying(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 310struct obj * 311o_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 320struct trap * 321t_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 332struct gold * 333g_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 */ 345struct obj * 346mkgoldobj(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 */ 365struct obj * 366getobj(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 511int 512ckunpaid(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 */ 519int 520ggetobj(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 */ 596int 597askchain(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."); 631ret: 632 return(cnt); 633} 634 635/* should of course only be called for things in invent */ 636static char 637obj_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 650void 651prinv(struct obj *obj) 652{ 653 pline("%s", xprname(obj, obj_to_let(obj))); 654} 655 656static char * 657xprname(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 667int 668ddoinv(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 */ 676static void 677doinv(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 705int 706dotypeinv(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 */ 778int 779dolook(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 837void 838stackobj(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 */ 849static int 850merged(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 */ 873extern int (*occupation)(void); 874extern char *occtxt; 875static long goldcounted; 876 877int 878countgold(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 890int 891doprgold(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 908int 909doprwep(void) 910{ 911 if(!uwep) pline("You are empty handed."); 912 else prinv(uwep); 913 return(0); 914} 915 916int 917doprarm(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 936int 937doprring(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}