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