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