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