xref: /dragonfly/games/hack/hack.shk.c (revision a68e0df0)
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 }
1087