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