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