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