1 /* $NetBSD: hack.shk.c,v 1.5 2001/03/25 20:44:02 jsm Exp $ */ 2 3 /* 4 * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. 5 */ 6 7 #include <sys/cdefs.h> 8 #ifndef lint 9 __RCSID("$NetBSD: hack.shk.c,v 1.5 2001/03/25 20:44:02 jsm Exp $"); 10 #endif /* not lint */ 11 12 #include <stdlib.h> 13 #include "hack.h" 14 #include "extern.h" 15 16 #ifndef QUEST 17 static void setpaid __P((void)); 18 static void addupbill __P((void)); 19 static void findshk __P((int)); 20 static struct bill_x *onbill __P((struct obj *)); 21 static void pay __P((long, struct monst *)); 22 static int dopayobj __P((struct bill_x *)); 23 static int getprice __P((struct obj *)); 24 static int realhunger __P((void)); 25 #endif 26 27 #ifdef QUEST 28 int shlevel = 0; 29 struct monst *shopkeeper = 0; 30 struct obj *billobjs = 0; 31 void 32 obfree(obj, merge) 33 struct obj *obj, *merge; 34 { 35 free((char *) obj); 36 } 37 int 38 inshop() { 39 return (0); 40 } 41 void 42 shopdig(n) 43 int n; 44 { 45 } 46 void 47 addtobill(obj) 48 struct obj *obj; 49 { 50 } 51 void 52 subfrombill(obj) 53 struct obj *obj; 54 { 55 } 56 void 57 splitbill(o1, o2) 58 struct obj *o1, *o2; 59 { 60 } 61 int 62 dopay() { 63 return (0); 64 } 65 void 66 paybill() 67 { 68 } 69 int 70 doinvbill(n) 71 int n; 72 { 73 return (0); 74 } 75 void 76 shkdead(m) 77 struct monst *m; 78 { 79 } 80 int 81 shkcatch(obj) 82 struct obj *obj; 83 { 84 return (0); 85 } 86 int 87 shk_move(m) 88 struct monst *m; 89 { 90 return (0); 91 } 92 void 93 replshk(mtmp, mtmp2) 94 struct monst *mtmp, *mtmp2; 95 { 96 } 97 char *shkname(m) 98 struct monst *m; 99 { 100 return (""); 101 } 102 103 #else /* QUEST */ 104 #include "hack.mfndpos.h" 105 #include "def.mkroom.h" 106 #include "def.eshk.h" 107 108 #define ESHK(mon) ((struct eshk *)(&(mon->mextra[0]))) 109 #define NOTANGRY(mon) mon->mpeaceful 110 #define ANGRY(mon) !NOTANGRY(mon) 111 112 /* 113 * Descriptor of current shopkeeper. Note that the bill need not be 114 * per-shopkeeper, since it is valid only when in a shop. 115 */ 116 static struct monst *shopkeeper = 0; 117 static struct bill_x *bill; 118 static int shlevel = 0; /* level of this shopkeeper */ 119 struct obj *billobjs; /* objects on bill with bp->useup */ 120 /* only accessed here and by save & restore */ 121 static long int total; /* filled by addupbill() */ 122 static long int followmsg; /* last time of follow message */ 123 124 /* 125 invariants: obj->unpaid iff onbill(obj) [unless bp->useup] 126 obj->quan <= bp->bquan 127 */ 128 129 130 const char shtypes[] = { /* 8 shoptypes: 7 specialized, 1 mixed */ 131 RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, SCROLL_SYM, 132 POTION_SYM, ARMOR_SYM, 0 133 }; 134 135 static const char *const shopnam[] = { 136 "engagement ring", "walking cane", "antique weapon", 137 "delicatessen", "second hand book", "liquor", 138 "used armor", "assorted antiques" 139 }; 140 141 char * 142 shkname(mtmp) /* called in do_name.c */ 143 struct monst *mtmp; 144 { 145 return (ESHK(mtmp)->shknam); 146 } 147 148 void 149 shkdead(mtmp) /* called in mon.c */ 150 struct monst *mtmp; 151 { 152 struct eshk *eshk = ESHK(mtmp); 153 154 if (eshk->shoplevel == dlevel) 155 rooms[eshk->shoproom].rtype = 0; 156 if (mtmp == shopkeeper) { 157 setpaid(); 158 shopkeeper = 0; 159 bill = (struct bill_x *) - 1000; /* dump core when 160 * referenced */ 161 } 162 } 163 164 void 165 replshk(mtmp, mtmp2) 166 struct monst *mtmp, *mtmp2; 167 { 168 if (mtmp == shopkeeper) { 169 shopkeeper = mtmp2; 170 bill = &(ESHK(shopkeeper)->bill[0]); 171 } 172 } 173 174 static void 175 setpaid() 176 { /* caller has checked that shopkeeper exists */ 177 /* either we paid or left the shop or he just died */ 178 struct obj *obj; 179 struct monst *mtmp; 180 for (obj = invent; obj; obj = obj->nobj) 181 obj->unpaid = 0; 182 for (obj = fobj; obj; obj = obj->nobj) 183 obj->unpaid = 0; 184 for (obj = fcobj; obj; obj = obj->nobj) 185 obj->unpaid = 0; 186 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 187 for (obj = mtmp->minvent; obj; obj = obj->nobj) 188 obj->unpaid = 0; 189 for (mtmp = fallen_down; mtmp; mtmp = mtmp->nmon) 190 for (obj = mtmp->minvent; obj; obj = obj->nobj) 191 obj->unpaid = 0; 192 while ((obj = billobjs) != NULL) { 193 billobjs = obj->nobj; 194 free((char *) obj); 195 } 196 ESHK(shopkeeper)->billct = 0; 197 } 198 199 static void 200 addupbill() 201 { /* delivers result in total */ 202 /* caller has checked that shopkeeper exists */ 203 int ct = ESHK(shopkeeper)->billct; 204 struct bill_x *bp = bill; 205 total = 0; 206 while (ct--) { 207 total += bp->price * bp->bquan; 208 bp++; 209 } 210 } 211 212 int 213 inshop() 214 { 215 int roomno = inroom(u.ux, u.uy); 216 217 /* Did we just leave a shop? */ 218 if (u.uinshop && 219 (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) { 220 if (shopkeeper) { 221 if (ESHK(shopkeeper)->billct) { 222 if (inroom(shopkeeper->mx, shopkeeper->my) 223 == u.uinshop - 1) /* ab@unido */ 224 pline("Somehow you escaped the shop without paying!"); 225 addupbill(); 226 pline("You stole for a total worth of %ld zorkmids.", 227 total); 228 ESHK(shopkeeper)->robbed += total; 229 setpaid(); 230 if ((rooms[ESHK(shopkeeper)->shoproom].rtype == GENERAL) 231 == (rn2(3) == 0)) 232 ESHK(shopkeeper)->following = 1; 233 } 234 shopkeeper = 0; 235 shlevel = 0; 236 } 237 u.uinshop = 0; 238 } 239 /* Did we just enter a zoo of some kind? */ 240 if (roomno >= 0) { 241 int rt = rooms[roomno].rtype; 242 struct monst *mtmp; 243 if (rt == ZOO) { 244 pline("Welcome to David's treasure zoo!"); 245 } else if (rt == SWAMP) { 246 pline("It looks rather muddy down here."); 247 } else if (rt == MORGUE) { 248 if (midnight()) 249 pline("Go away! Go away!"); 250 else 251 pline("You get an uncanny feeling ..."); 252 } else 253 rt = 0; 254 if (rt != 0) { 255 rooms[roomno].rtype = 0; 256 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 257 if (rt != ZOO || !rn2(3)) 258 mtmp->msleep = 0; 259 } 260 } 261 /* Did we just enter a shop? */ 262 if (roomno >= 0 && rooms[roomno].rtype >= 8) { 263 if (shlevel != dlevel || !shopkeeper 264 || ESHK(shopkeeper)->shoproom != roomno) 265 findshk(roomno); 266 if (!shopkeeper) { 267 rooms[roomno].rtype = 0; 268 u.uinshop = 0; 269 } else if (!u.uinshop) { 270 if (!ESHK(shopkeeper)->visitct || 271 strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)) { 272 273 /* He seems to be new here */ 274 ESHK(shopkeeper)->visitct = 0; 275 ESHK(shopkeeper)->following = 0; 276 (void) strncpy(ESHK(shopkeeper)->customer, plname, PL_NSIZ); 277 NOTANGRY(shopkeeper) = 1; 278 } 279 if (!ESHK(shopkeeper)->following) { 280 boolean box, pick; 281 282 pline("Hello %s! Welcome%s to %s's %s shop!", 283 plname, 284 ESHK(shopkeeper)->visitct++ ? " again" : "", 285 shkname(shopkeeper), 286 shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]); 287 box = carrying(ICE_BOX); 288 pick = carrying(PICK_AXE); 289 if (box || pick) { 290 if (dochug(shopkeeper)) { 291 u.uinshop = 0; /* he died moving */ 292 return (0); 293 } 294 pline("Will you please leave your %s outside?", 295 (box && pick) ? "box and pick-axe" : 296 box ? "box" : "pick-axe"); 297 } 298 } 299 u.uinshop = roomno + 1; 300 } 301 } 302 return (u.uinshop); 303 } 304 305 static void 306 findshk(roomno) 307 int roomno; 308 { 309 struct monst *mtmp; 310 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 311 if (mtmp->isshk && ESHK(mtmp)->shoproom == roomno 312 && ESHK(mtmp)->shoplevel == dlevel) { 313 shopkeeper = mtmp; 314 bill = &(ESHK(shopkeeper)->bill[0]); 315 shlevel = dlevel; 316 if (ANGRY(shopkeeper) && 317 strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)) 318 NOTANGRY(shopkeeper) = 1; 319 /* 320 * billobjs = 0; -- this is wrong if we save in a 321 * shop 322 */ 323 /* 324 * (and it is harmless to have too many things in 325 * billobjs) 326 */ 327 return; 328 } 329 shopkeeper = 0; 330 shlevel = 0; 331 bill = (struct bill_x *) - 1000; /* dump core when referenced */ 332 } 333 334 static struct bill_x * 335 onbill(obj) 336 struct obj *obj; 337 { 338 struct bill_x *bp; 339 if (!shopkeeper) 340 return (0); 341 for (bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++) 342 if (bp->bo_id == obj->o_id) { 343 if (!obj->unpaid) 344 pline("onbill: paid obj on bill?"); 345 return (bp); 346 } 347 if (obj->unpaid) 348 pline("onbill: unpaid obj not on bill?"); 349 return (0); 350 } 351 352 /* called with two args on merge */ 353 void 354 obfree(obj, merge) 355 struct obj *obj, *merge; 356 { 357 struct bill_x *bp = onbill(obj); 358 struct bill_x *bpm; 359 if (bp) { 360 if (!merge) { 361 bp->useup = 1; 362 obj->unpaid = 0; /* only for doinvbill */ 363 obj->nobj = billobjs; 364 billobjs = obj; 365 return; 366 } 367 bpm = onbill(merge); 368 if (!bpm) { 369 /* this used to be a rename */ 370 impossible("obfree: not on bill??"); 371 return; 372 } else { 373 /* this was a merger */ 374 bpm->bquan += bp->bquan; 375 ESHK(shopkeeper)->billct--; 376 *bp = bill[ESHK(shopkeeper)->billct]; 377 } 378 } 379 free((char *) obj); 380 } 381 382 static void 383 pay(tmp, shkp) 384 long tmp; 385 struct monst *shkp; 386 { 387 long robbed = ESHK(shkp)->robbed; 388 389 u.ugold -= tmp; 390 shkp->mgold += tmp; 391 flags.botl = 1; 392 if (robbed) { 393 robbed -= tmp; 394 if (robbed < 0) 395 robbed = 0; 396 ESHK(shkp)->robbed = robbed; 397 } 398 } 399 400 int 401 dopay() 402 { 403 long ltmp; 404 struct bill_x *bp; 405 struct monst *shkp; 406 int pass, tmp; 407 408 multi = 0; 409 (void) inshop(); 410 for (shkp = fmon; shkp; shkp = shkp->nmon) 411 if (shkp->isshk && dist(shkp->mx, shkp->my) < 3) 412 break; 413 if (!shkp && u.uinshop && 414 inroom(shopkeeper->mx, shopkeeper->my) == ESHK(shopkeeper)->shoproom) 415 shkp = shopkeeper; 416 417 if (!shkp) { 418 pline("There is nobody here to receive your payment."); 419 return (0); 420 } 421 ltmp = ESHK(shkp)->robbed; 422 if (shkp != shopkeeper && NOTANGRY(shkp)) { 423 if (!ltmp) { 424 pline("You do not owe %s anything.", monnam(shkp)); 425 } else if (!u.ugold) { 426 pline("You have no money."); 427 } else { 428 long ugold = u.ugold; 429 430 if (u.ugold > ltmp) { 431 pline("You give %s the %ld gold pieces he asked for.", 432 monnam(shkp), ltmp); 433 pay(ltmp, shkp); 434 } else { 435 pline("You give %s all your gold.", monnam(shkp)); 436 pay(u.ugold, shkp); 437 } 438 if (ugold < ltmp / 2) { 439 pline("Unfortunately, he doesn't look satisfied."); 440 } else { 441 ESHK(shkp)->robbed = 0; 442 ESHK(shkp)->following = 0; 443 if (ESHK(shkp)->shoplevel != dlevel) { 444 /* 445 * For convenience's sake, let him 446 * disappear 447 */ 448 shkp->minvent = 0; /* %% */ 449 shkp->mgold = 0; 450 mondead(shkp); 451 } 452 } 453 } 454 return (1); 455 } 456 if (!ESHK(shkp)->billct) { 457 pline("You do not owe %s anything.", monnam(shkp)); 458 if (!u.ugold) { 459 pline("Moreover, you have no money."); 460 return (1); 461 } 462 if (ESHK(shkp)->robbed) { 463 #define min(a,b) ((a<b)?a:b) 464 pline("But since his shop has been robbed recently,"); 465 pline("you %srepay %s's expenses.", 466 (u.ugold < ESHK(shkp)->robbed) ? "partially " : "", 467 monnam(shkp)); 468 pay(min(u.ugold, ESHK(shkp)->robbed), shkp); 469 ESHK(shkp)->robbed = 0; 470 return (1); 471 } 472 if (ANGRY(shkp)) { 473 pline("But in order to appease %s,", 474 amonnam(shkp, "angry")); 475 if (u.ugold >= 1000) { 476 ltmp = 1000; 477 pline(" you give him 1000 gold pieces."); 478 } else { 479 ltmp = u.ugold; 480 pline(" you give him all your money."); 481 } 482 pay(ltmp, shkp); 483 if (strncmp(ESHK(shkp)->customer, plname, PL_NSIZ) 484 || rn2(3)) { 485 pline("%s calms down.", Monnam(shkp)); 486 NOTANGRY(shkp) = 1; 487 } else 488 pline("%s is as angry as ever.", 489 Monnam(shkp)); 490 } 491 return (1); 492 } 493 if (shkp != shopkeeper) { 494 impossible("dopay: not to shopkeeper?"); 495 if (shopkeeper) 496 setpaid(); 497 return (0); 498 } 499 for (pass = 0; pass <= 1; pass++) { 500 tmp = 0; 501 while (tmp < ESHK(shopkeeper)->billct) { 502 bp = &bill[tmp]; 503 if (!pass && !bp->useup) { 504 tmp++; 505 continue; 506 } 507 if (!dopayobj(bp)) 508 return (1); 509 bill[tmp] = bill[--ESHK(shopkeeper)->billct]; 510 } 511 } 512 pline("Thank you for shopping in %s's %s store!", 513 shkname(shopkeeper), 514 shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]); 515 NOTANGRY(shopkeeper) = 1; 516 return (1); 517 } 518 519 /* return 1 if paid successfully */ 520 /* 0 if not enough money */ 521 /* -1 if object could not be found (but was paid) */ 522 static int 523 dopayobj(bp) 524 struct bill_x *bp; 525 { 526 struct obj *obj; 527 long ltmp; 528 529 /* find the object on one of the lists */ 530 obj = bp_to_obj(bp); 531 532 if (!obj) { 533 impossible("Shopkeeper administration out of order."); 534 setpaid(); /* be nice to the player */ 535 return (0); 536 } 537 if (!obj->unpaid && !bp->useup) { 538 impossible("Paid object on bill??"); 539 return (1); 540 } 541 obj->unpaid = 0; 542 ltmp = bp->price * bp->bquan; 543 if (ANGRY(shopkeeper)) 544 ltmp += ltmp / 3; 545 if (u.ugold < ltmp) { 546 pline("You don't have gold enough to pay %s.", 547 doname(obj)); 548 obj->unpaid = 1; 549 return (0); 550 } 551 pay(ltmp, shopkeeper); 552 pline("You bought %s for %ld gold piece%s.", 553 doname(obj), ltmp, plur(ltmp)); 554 if (bp->useup) { 555 struct obj *otmp = billobjs; 556 if (obj == billobjs) 557 billobjs = obj->nobj; 558 else { 559 while (otmp && otmp->nobj != obj) 560 otmp = otmp->nobj; 561 if (otmp) 562 otmp->nobj = obj->nobj; 563 else 564 pline("Error in shopkeeper administration."); 565 } 566 free((char *) obj); 567 } 568 return (1); 569 } 570 571 /* routine called after dying (or quitting) with nonempty bill */ 572 void 573 paybill() 574 { 575 if (shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct) { 576 addupbill(); 577 if (total > u.ugold) { 578 shopkeeper->mgold += u.ugold; 579 u.ugold = 0; 580 pline("%s comes and takes all your possessions.", 581 Monnam(shopkeeper)); 582 } else { 583 u.ugold -= total; 584 shopkeeper->mgold += total; 585 pline("%s comes and takes the %ld zorkmids you owed him.", 586 Monnam(shopkeeper), total); 587 } 588 setpaid(); /* in case we create bones */ 589 } 590 } 591 592 /* find obj on one of the lists */ 593 struct obj * 594 bp_to_obj(bp) 595 struct bill_x *bp; 596 { 597 struct obj *obj; 598 struct monst *mtmp; 599 unsigned id = bp->bo_id; 600 601 if (bp->useup) 602 obj = o_on(id, billobjs); 603 else if (!(obj = o_on(id, invent)) && 604 !(obj = o_on(id, fobj)) && 605 !(obj = o_on(id, fcobj))) { 606 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 607 if ((obj = o_on(id, mtmp->minvent)) != NULL) 608 break; 609 for (mtmp = fallen_down; mtmp; mtmp = mtmp->nmon) 610 if ((obj = o_on(id, mtmp->minvent)) != NULL) 611 break; 612 } 613 return (obj); 614 } 615 616 /* called in hack.c when we pickup an object */ 617 void 618 addtobill(obj) 619 struct obj *obj; 620 { 621 struct bill_x *bp; 622 if (!inshop() || 623 (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) || 624 (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) || 625 onbill(obj) /* perhaps we threw it away earlier */ 626 ) 627 return; 628 if (ESHK(shopkeeper)->billct == BILLSZ) { 629 pline("You got that for free!"); 630 return; 631 } 632 bp = &bill[ESHK(shopkeeper)->billct]; 633 bp->bo_id = obj->o_id; 634 bp->bquan = obj->quan; 635 bp->useup = 0; 636 bp->price = getprice(obj); 637 ESHK(shopkeeper)->billct++; 638 obj->unpaid = 1; 639 } 640 641 void 642 splitbill(obj, otmp) 643 struct obj *obj, *otmp; 644 { 645 /* otmp has been split off from obj */ 646 struct bill_x *bp; 647 int tmp; 648 bp = onbill(obj); 649 if (!bp) { 650 impossible("splitbill: not on bill?"); 651 return; 652 } 653 if (bp->bquan < otmp->quan) { 654 impossible("Negative quantity on bill??"); 655 } 656 if (bp->bquan == otmp->quan) { 657 impossible("Zero quantity on bill??"); 658 } 659 bp->bquan -= otmp->quan; 660 661 /* addtobill(otmp); */ 662 if (ESHK(shopkeeper)->billct == BILLSZ) 663 otmp->unpaid = 0; 664 else { 665 tmp = bp->price; 666 bp = &bill[ESHK(shopkeeper)->billct]; 667 bp->bo_id = otmp->o_id; 668 bp->bquan = otmp->quan; 669 bp->useup = 0; 670 bp->price = tmp; 671 ESHK(shopkeeper)->billct++; 672 } 673 } 674 675 void 676 subfrombill(obj) 677 struct obj *obj; 678 { 679 long ltmp; 680 int tmp; 681 struct obj *otmp; 682 struct bill_x *bp; 683 if (!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) || 684 (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y)) 685 return; 686 if ((bp = onbill(obj)) != 0) { 687 obj->unpaid = 0; 688 if (bp->bquan > obj->quan) { 689 otmp = newobj(0); 690 *otmp = *obj; 691 bp->bo_id = otmp->o_id = flags.ident++; 692 otmp->quan = (bp->bquan -= obj->quan); 693 otmp->owt = 0; /* superfluous */ 694 otmp->onamelth = 0; 695 bp->useup = 1; 696 otmp->nobj = billobjs; 697 billobjs = otmp; 698 return; 699 } 700 ESHK(shopkeeper)->billct--; 701 *bp = bill[ESHK(shopkeeper)->billct]; 702 return; 703 } 704 if (obj->unpaid) { 705 pline("%s didn't notice.", Monnam(shopkeeper)); 706 obj->unpaid = 0; 707 return; /* %% */ 708 } 709 /* he dropped something of his own - probably wants to sell it */ 710 if (shopkeeper->msleep || shopkeeper->mfroz || 711 inroom(shopkeeper->mx, shopkeeper->my) != ESHK(shopkeeper)->shoproom) 712 return; 713 if (ESHK(shopkeeper)->billct == BILLSZ || 714 ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]) && tmp != obj->olet) 715 || strchr("_0", obj->olet)) { 716 pline("%s seems not interested.", Monnam(shopkeeper)); 717 return; 718 } 719 ltmp = getprice(obj) * obj->quan; 720 if (ANGRY(shopkeeper)) { 721 ltmp /= 3; 722 NOTANGRY(shopkeeper) = 1; 723 } else 724 ltmp /= 2; 725 if (ESHK(shopkeeper)->robbed) { 726 if ((ESHK(shopkeeper)->robbed -= ltmp) < 0) 727 ESHK(shopkeeper)->robbed = 0; 728 pline("Thank you for your contribution to restock this recently plundered shop."); 729 return; 730 } 731 if (ltmp > shopkeeper->mgold) 732 ltmp = shopkeeper->mgold; 733 pay(-ltmp, shopkeeper); 734 if (!ltmp) 735 pline("%s gladly accepts %s but cannot pay you at present.", 736 Monnam(shopkeeper), doname(obj)); 737 else 738 pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp, 739 plur(ltmp)); 740 } 741 742 int 743 doinvbill(mode) 744 int mode; /* 0: deliver count 1: paged */ 745 { 746 struct bill_x *bp; 747 struct obj *obj; 748 long totused, thisused; 749 char buf[BUFSZ]; 750 751 if (mode == 0) { 752 int cnt = 0; 753 754 if (shopkeeper) 755 for (bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) 756 if (bp->useup || 757 ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan)) 758 cnt++; 759 return (cnt); 760 } 761 if (!shopkeeper) { 762 impossible("doinvbill: no shopkeeper?"); 763 return (0); 764 } 765 set_pager(0); 766 if (page_line("Unpaid articles already used up:") || page_line("")) 767 goto quit; 768 769 totused = 0; 770 for (bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) { 771 obj = bp_to_obj(bp); 772 if (!obj) { 773 impossible("Bad shopkeeper administration."); 774 goto quit; 775 } 776 if (bp->useup || bp->bquan > obj->quan) { 777 int cnt, oquan, uquan; 778 779 oquan = obj->quan; 780 uquan = (bp->useup ? bp->bquan : bp->bquan - oquan); 781 thisused = bp->price * uquan; 782 totused += thisused; 783 obj->quan = uquan; /* cheat doname */ 784 (void) sprintf(buf, "x - %s", doname(obj)); 785 obj->quan = oquan; /* restore value */ 786 for (cnt = 0; buf[cnt]; cnt++); 787 while (cnt < 50) 788 buf[cnt++] = ' '; 789 (void) sprintf(&buf[cnt], " %5ld zorkmids", thisused); 790 if (page_line(buf)) 791 goto quit; 792 } 793 } 794 (void) sprintf(buf, "Total:%50ld zorkmids", totused); 795 if (page_line("") || page_line(buf)) 796 goto quit; 797 set_pager(1); 798 return (0); 799 quit: 800 set_pager(2); 801 return (0); 802 } 803 804 static int 805 getprice(obj) 806 struct obj *obj; 807 { 808 int tmp, ac; 809 810 switch (obj->olet) { 811 case AMULET_SYM: 812 tmp = 10 * rnd(500); 813 break; 814 case TOOL_SYM: 815 tmp = 10 * rnd((obj->otyp == EXPENSIVE_CAMERA) ? 150 : 30); 816 break; 817 case RING_SYM: 818 tmp = 10 * rnd(100); 819 break; 820 case WAND_SYM: 821 tmp = 10 * rnd(100); 822 break; 823 case SCROLL_SYM: 824 tmp = 10 * rnd(50); 825 #ifdef MAIL 826 if (obj->otyp == SCR_MAIL) 827 tmp = rnd(5); 828 #endif /* MAIL */ 829 break; 830 case POTION_SYM: 831 tmp = 10 * rnd(50); 832 break; 833 case FOOD_SYM: 834 tmp = 10 * rnd(5 + (2000 / realhunger())); 835 break; 836 case GEM_SYM: 837 tmp = 10 * rnd(20); 838 break; 839 case ARMOR_SYM: 840 ac = ARM_BONUS(obj); 841 if (ac <= -10) /* probably impossible */ 842 ac = -9; 843 tmp = 100 + ac * ac * rnd(10 + ac); 844 break; 845 case WEAPON_SYM: 846 if (obj->otyp < BOOMERANG) 847 tmp = 5 * rnd(10); 848 else if (obj->otyp == LONG_SWORD || 849 obj->otyp == TWO_HANDED_SWORD) 850 tmp = 10 * rnd(150); 851 else 852 tmp = 10 * rnd(75); 853 break; 854 case CHAIN_SYM: 855 pline("Strange ..., carrying a chain?"); 856 case BALL_SYM: 857 tmp = 10; 858 break; 859 default: 860 tmp = 10000; 861 } 862 return (tmp); 863 } 864 865 static int 866 realhunger() 867 { /* not completely foolproof */ 868 int tmp = u.uhunger; 869 struct obj *otmp = invent; 870 while (otmp) { 871 if (otmp->olet == FOOD_SYM && !otmp->unpaid) 872 tmp += objects[otmp->otyp].nutrition; 873 otmp = otmp->nobj; 874 } 875 return ((tmp <= 0) ? 1 : tmp); 876 } 877 878 int 879 shkcatch(obj) 880 struct obj *obj; 881 { 882 struct monst *shkp = shopkeeper; 883 884 if (u.uinshop && shkp && !shkp->mfroz && !shkp->msleep && 885 u.dx && u.dy && 886 inroom(u.ux + u.dx, u.uy + u.dy) + 1 == u.uinshop && 887 shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y && 888 u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) { 889 pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj)); 890 obj->nobj = shkp->minvent; 891 shkp->minvent = obj; 892 return (1); 893 } 894 return (0); 895 } 896 897 /* 898 * shk_move: return 1: he moved 0: he didnt -1: let m_move do it 899 */ 900 int 901 shk_move(shkp) 902 struct monst *shkp; 903 { 904 struct monst *mtmp; 905 const struct permonst *mdat = shkp->data; 906 xchar gx, gy, omx, omy, nx, ny, nix, niy; 907 schar appr, i; 908 int udist; 909 int z; 910 schar shkroom, chi, chcnt, cnt; 911 boolean uondoor = 0, satdoor, avoid = 0, badinv; 912 coord poss[9]; 913 int info[9]; 914 struct obj *ib = 0; 915 916 omx = shkp->mx; 917 omy = shkp->my; 918 919 if ((udist = dist(omx, omy)) < 3) { 920 if (ANGRY(shkp)) { 921 (void) hitu(shkp, d(mdat->damn, mdat->damd) + 1); 922 return (0); 923 } 924 if (ESHK(shkp)->following) { 925 if (strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)) { 926 pline("Hello %s! I was looking for %s.", 927 plname, ESHK(shkp)->customer); 928 ESHK(shkp)->following = 0; 929 return (0); 930 } 931 if (!ESHK(shkp)->robbed) { /* impossible? */ 932 ESHK(shkp)->following = 0; 933 return (0); 934 } 935 if (moves > followmsg + 4) { 936 pline("Hello %s! Didn't you forget to pay?", 937 plname); 938 followmsg = moves; 939 } 940 if (udist < 2) 941 return (0); 942 } 943 } 944 shkroom = inroom(omx, omy); 945 appr = 1; 946 gx = ESHK(shkp)->shk.x; 947 gy = ESHK(shkp)->shk.y; 948 satdoor = (gx == omx && gy == omy); 949 if (ESHK(shkp)->following || ((z = holetime()) >= 0 && z * z <= udist)) { 950 gx = u.ux; 951 gy = u.uy; 952 if (shkroom < 0 || shkroom != inroom(u.ux, u.uy)) 953 if (udist > 4) 954 return (-1); /* leave it to m_move */ 955 } else if (ANGRY(shkp)) { 956 long saveBlind = Blind; 957 Blind = 0; 958 if (shkp->mcansee && !Invis && cansee(omx, omy)) { 959 gx = u.ux; 960 gy = u.uy; 961 } 962 Blind = saveBlind; 963 avoid = FALSE; 964 } else { 965 #define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy)) 966 if (Invis) 967 avoid = FALSE; 968 else { 969 uondoor = (u.ux == ESHK(shkp)->shd.x && 970 u.uy == ESHK(shkp)->shd.y); 971 if (uondoor) { 972 if (ESHK(shkp)->billct) 973 pline("Hello %s! Will you please pay before leaving?", 974 plname); 975 badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); 976 if (satdoor && badinv) 977 return (0); 978 avoid = !badinv; 979 } else { 980 avoid = (u.uinshop && dist(gx, gy) > 8); 981 badinv = FALSE; 982 } 983 984 if (((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) 985 && GDIST(omx, omy) < 3) { 986 if (!badinv && !online(omx, omy)) 987 return (0); 988 if (satdoor) 989 appr = gx = gy = 0; 990 } 991 } 992 } 993 if (omx == gx && omy == gy) 994 return (0); 995 if (shkp->mconf) { 996 avoid = FALSE; 997 appr = 0; 998 } 999 nix = omx; 1000 niy = omy; 1001 cnt = mfndpos(shkp, poss, info, ALLOW_SSM); 1002 if (avoid && uondoor) { /* perhaps we cannot avoid him */ 1003 for (i = 0; i < cnt; i++) 1004 if (!(info[i] & NOTONL)) 1005 goto notonl_ok; 1006 avoid = FALSE; 1007 notonl_ok: 1008 ; 1009 } 1010 chi = -1; 1011 chcnt = 0; 1012 for (i = 0; i < cnt; i++) { 1013 nx = poss[i].x; 1014 ny = poss[i].y; 1015 if (levl[nx][ny].typ == ROOM 1016 || shkroom != ESHK(shkp)->shoproom 1017 || ESHK(shkp)->following) { 1018 #ifdef STUPID 1019 /* cater for stupid compilers */ 1020 int zz; 1021 #endif /* STUPID */ 1022 if (uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { 1023 nix = nx; 1024 niy = ny; 1025 chi = i; 1026 break; 1027 } 1028 if (avoid && (info[i] & NOTONL)) 1029 continue; 1030 if ((!appr && !rn2(++chcnt)) || 1031 #ifdef STUPID 1032 (appr && (zz = GDIST(nix, niy)) && zz > GDIST(nx, ny)) 1033 #else 1034 (appr && GDIST(nx, ny) < GDIST(nix, niy)) 1035 #endif /* STUPID */ 1036 ) { 1037 nix = nx; 1038 niy = ny; 1039 chi = i; 1040 } 1041 } 1042 } 1043 if (nix != omx || niy != omy) { 1044 if (info[chi] & ALLOW_M) { 1045 mtmp = m_at(nix, niy); 1046 if (hitmm(shkp, mtmp) == 1 && rn2(3) && 1047 hitmm(mtmp, shkp) == 2) 1048 return (2); 1049 return (0); 1050 } else if (info[chi] & ALLOW_U) { 1051 (void) hitu(shkp, d(mdat->damn, mdat->damd) + 1); 1052 return (0); 1053 } 1054 shkp->mx = nix; 1055 shkp->my = niy; 1056 pmon(shkp); 1057 if (ib) { 1058 freeobj(ib); 1059 mpickobj(shkp, ib); 1060 } 1061 return (1); 1062 } 1063 return (0); 1064 } 1065 1066 /* He is digging in the shop. */ 1067 void 1068 shopdig(fall) 1069 int fall; 1070 { 1071 if (!fall) { 1072 if (u.utraptype == TT_PIT) 1073 pline("\"Be careful, sir, or you might fall through the floor.\""); 1074 else 1075 pline("\"Please, do not damage the floor here.\""); 1076 } else if (dist(shopkeeper->mx, shopkeeper->my) < 3) { 1077 struct obj *obj, *obj2; 1078 1079 pline("%s grabs your backpack!", shkname(shopkeeper)); 1080 for (obj = invent; obj; obj = obj2) { 1081 obj2 = obj->nobj; 1082 if (obj->owornmask) 1083 continue; 1084 freeinv(obj); 1085 obj->nobj = shopkeeper->minvent; 1086 shopkeeper->minvent = obj; 1087 if (obj->unpaid) 1088 subfrombill(obj); 1089 } 1090 } 1091 } 1092 #endif /* QUEST */ 1093 1094 int 1095 online(int x, int y) 1096 { 1097 return (x == u.ux || y == u.uy || 1098 (x - u.ux) * (x - u.ux) == (y - u.uy) * (y - u.uy)); 1099 } 1100 1101 /* Does this monster follow me downstairs? */ 1102 int 1103 follower(mtmp) 1104 struct monst *mtmp; 1105 { 1106 return (mtmp->mtame || strchr("1TVWZi&, ", mtmp->data->mlet) 1107 #ifndef QUEST 1108 || (mtmp->isshk && ESHK(mtmp)->following) 1109 #endif /* QUEST */ 1110 ); 1111 } 1112