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