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