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