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