xref: /netbsd/games/hack/hack.shk.c (revision bf9ec67e)
1 /*	$NetBSD: hack.shk.c,v 1.5 2001/03/25 20:44:02 jsm 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.5 2001/03/25 20:44:02 jsm 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 const 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 const char    *const 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 	const 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(int x, int 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 }
1112