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