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