xref: /openbsd/games/hack/hack.shk.c (revision 3d8817e4)
1 /*	$OpenBSD: hack.shk.c,v 1.11 2009/10/27 23:59:25 deraadt 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 <stdio.h>
65 #include <stdlib.h>
66 #include "hack.h"
67 
68 #ifdef QUEST
69 int shlevel = 0;
70 struct monst *shopkeeper = 0;
71 struct obj *billobjs = 0;
72 
73 void
74 obfree(struct obj *obj, struct obj *merge)
75 {
76 	free((char *) obj);
77 }
78 
79 int
80 inshop()
81 {
82 	return(0);
83 }
84 
85 void
86 shopdig(int a)
87 {}
88 
89 void
90 addtobill(struct obj *ign)
91 {}
92 
93 void
94 subfrombill(struct obj *ign)
95 {}
96 
97 void
98 splitbill(struct obj *ign, struct obj *ign2)
99 {}
100 
101 int
102 dopay()
103 {
104 	return(0);
105 }
106 
107 void
108 paybill()
109 {}
110 
111 int
112 doinvbill(int a)
113 {
114 	return(0);
115 }
116 
117 void
118 shkdead(struct monst *ign)
119 {}
120 
121 int
122 shkcatch(struct obj *ign)
123 {
124 	return(0);
125 }
126 
127 int
128 shk_move(struct monst *ign)
129 {
130 	return(0);
131 }
132 
133 void
134 replshk(struct monst *mtmp, struct monst *mtmp2)
135 {}
136 
137 char *
138 shkname(struct monst *ign)
139 {
140 	return("");
141 }
142 
143 #else /* QUEST */
144 #include	"hack.mfndpos.h"
145 #include	"def.eshk.h"
146 
147 #define	ESHK(mon)	((struct eshk *)(&(mon->mextra[0])))
148 #define	NOTANGRY(mon)	mon->mpeaceful
149 #define	ANGRY(mon)	!NOTANGRY(mon)
150 
151 extern char plname[];
152 
153 /* Descriptor of current shopkeeper. Note that the bill need not be
154  * per-shopkeeper, since it is valid only when in a shop.
155  */
156 static struct monst *shopkeeper = 0;
157 static struct bill_x *bill;
158 static int shlevel = 0;	/* level of this shopkeeper */
159 struct obj *billobjs;	/* objects on bill with bp->useup */
160 				/* only accessed here and by save & restore */
161 static long int total;		/* filled by addupbill() */
162 static long int followmsg;	/* last time of follow message */
163 
164 /*
165  *	invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
166  *		obj->quan <= bp->bquan
167  */
168 
169 
170 char shtypes[] = {	/* 8 shoptypes: 7 specialized, 1 mixed */
171 	RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, SCROLL_SYM,
172 	POTION_SYM, ARMOR_SYM, 0
173 };
174 
175 static char *shopnam[] = {
176 	"engagement ring", "walking cane", "antique weapon",
177 	"delicatessen", "second hand book", "liquor",
178 	"used armor", "assorted antiques"
179 };
180 
181 static void setpaid(void);
182 static void addupbill(void);
183 static void findshk(int);
184 static struct bill_x *onbill(struct obj *);
185 static void pay(long, struct monst *);
186 static int  dopayobj(struct bill_x *);
187 static struct obj *bp_to_obj(struct bill_x *);
188 static int getprice(struct obj *);
189 static int realhunger();
190 
191 /* called in do_name.c */
192 char *
193 shkname(struct monst *mtmp)
194 {
195 	return(ESHK(mtmp)->shknam);
196 }
197 
198 void
199 shkdead(struct monst *mtmp)				/* called in mon.c */
200 {
201 	struct eshk *eshk = ESHK(mtmp);
202 
203 	if(eshk->shoplevel == dlevel)
204 		rooms[eshk->shoproom].rtype = 0;
205 	if(mtmp == shopkeeper) {
206 		setpaid();
207 		shopkeeper = 0;
208 		bill = (struct bill_x *) -1000;	/* dump core when referenced */
209 	}
210 }
211 
212 void
213 replshk(struct monst *mtmp, struct monst *mtmp2)
214 {
215 	if(mtmp == shopkeeper) {
216 		shopkeeper = mtmp2;
217 		bill = &(ESHK(shopkeeper)->bill[0]);
218 	}
219 }
220 
221 /* caller has checked that shopkeeper exists */
222 /* either we paid or left the shop or he just died */
223 static void
224 setpaid()
225 {
226 	struct obj *obj;
227 	struct monst *mtmp;
228 
229 	for(obj = invent; obj; obj = obj->nobj)
230 		obj->unpaid = 0;
231 	for(obj = fobj; obj; obj = obj->nobj)
232 		obj->unpaid = 0;
233 	for(obj = fcobj; obj; obj = obj->nobj)
234 		obj->unpaid = 0;
235 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
236 		for(obj = mtmp->minvent; obj; obj = obj->nobj)
237 			obj->unpaid = 0;
238 	for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
239 		for(obj = mtmp->minvent; obj; obj = obj->nobj)
240 			obj->unpaid = 0;
241 	while ((obj = billobjs)) {
242 		billobjs = obj->nobj;
243 		free((char *) obj);
244 	}
245 	ESHK(shopkeeper)->billct = 0;
246 }
247 
248 /* delivers result in total */
249 /* caller has checked that shopkeeper exists */
250 static void
251 addupbill()
252 {
253 	int ct = ESHK(shopkeeper)->billct;
254 	struct bill_x *bp = bill;
255 
256 	total = 0;
257 	while(ct--){
258 		total += bp->price * bp->bquan;
259 		bp++;
260 	}
261 }
262 
263 int
264 inshop()
265 {
266 	int roomno = inroom(u.ux,u.uy);
267 
268 	/* Did we just leave a shop? */
269 	if(u.uinshop &&
270 	    (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
271 		if(shopkeeper) {
272 		    if(ESHK(shopkeeper)->billct) {
273  			if(inroom(shopkeeper->mx, shopkeeper->my)
274  			    == u.uinshop - 1)	/* ab@unido */
275  			    pline("Somehow you escaped the shop without paying!");
276 			addupbill();
277 			pline("You stole for a total worth of %ld zorkmids.",
278 				total);
279 			ESHK(shopkeeper)->robbed += total;
280 			setpaid();
281 			if((rooms[ESHK(shopkeeper)->shoproom].rtype == GENERAL)
282 			    == (rn2(3) == 0))
283 			    ESHK(shopkeeper)->following = 1;
284 		    }
285 		    shopkeeper = 0;
286 		    shlevel = 0;
287 		}
288  		u.uinshop = 0;
289 	}
290 
291 	/* Did we just enter a zoo of some kind? */
292 	if(roomno >= 0) {
293 		int rt = rooms[roomno].rtype;
294 		struct monst *mtmp;
295 		if(rt == ZOO) {
296 			pline("Welcome to David's treasure zoo!");
297 		} else
298 		if(rt == SWAMP) {
299 			pline("It looks rather muddy down here.");
300 		} else
301 		if(rt == MORGUE) {
302 			if(midnight())
303 				pline("Go away! Go away!");
304 			else
305 				pline("You get an uncanny feeling ...");
306 		} else
307 			rt = 0;
308 		if(rt != 0) {
309 			rooms[roomno].rtype = 0;
310 			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
311 				if(rt != ZOO || !rn2(3))
312 					mtmp->msleep = 0;
313 		}
314 	}
315 
316 	/* Did we just enter a shop? */
317 	if(roomno >= 0 && rooms[roomno].rtype >= 8) {
318 	    if(shlevel != dlevel || !shopkeeper
319 				 || ESHK(shopkeeper)->shoproom != roomno)
320 		findshk(roomno);
321 	    if(!shopkeeper) {
322 		rooms[roomno].rtype = 0;
323 		u.uinshop = 0;
324 	    } else if(!u.uinshop){
325 		if(!ESHK(shopkeeper)->visitct ||
326 		    strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){
327 
328 		    /* He seems to be new here */
329 		    ESHK(shopkeeper)->visitct = 0;
330 		    ESHK(shopkeeper)->following = 0;
331 		    (void) strlcpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
332 		    NOTANGRY(shopkeeper) = 1;
333 		}
334 		if(!ESHK(shopkeeper)->following) {
335 		    boolean box, pick;
336 
337 		    pline("Hello %s! Welcome%s to %s's %s shop!",
338 			plname,
339 			ESHK(shopkeeper)->visitct++ ? " again" : "",
340 			shkname(shopkeeper),
341 			shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8] );
342 		    box = carrying(ICE_BOX);
343 		    pick = carrying(PICK_AXE);
344 		    if(box || pick) {
345 			if(dochug(shopkeeper)) {
346 				u.uinshop = 0;	/* he died moving */
347 				return(0);
348 			}
349 			pline("Will you please leave your %s outside?",
350 			    (box && pick) ? "box and pick-axe" :
351 			    box ? "box" : "pick-axe");
352 		    }
353 		}
354 		u.uinshop = roomno + 1;
355 	    }
356 	}
357 	return(u.uinshop);
358 }
359 
360 static void
361 findshk(int roomno)
362 {
363 	struct monst *mtmp;
364 
365 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
366 	    if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
367 			   && ESHK(mtmp)->shoplevel == dlevel) {
368 		shopkeeper = mtmp;
369 		bill = &(ESHK(shopkeeper)->bill[0]);
370 		shlevel = dlevel;
371 		if(ANGRY(shopkeeper) &&
372 		   strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
373 			NOTANGRY(shopkeeper) = 1;
374 		/* billobjs = 0; -- this is wrong if we save in a shop */
375 		/* (and it is harmless to have too many things in billobjs) */
376 		return;
377 	}
378 	shopkeeper = 0;
379 	shlevel = 0;
380 	bill = (struct bill_x *) -1000;	/* dump core when referenced */
381 }
382 
383 static struct bill_x *
384 onbill(struct obj *obj)
385 {
386 	struct bill_x *bp;
387 
388 	if(!shopkeeper) return(NULL);
389 	for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
390 		if(bp->bo_id == obj->o_id) {
391 			if(!obj->unpaid) pline("onbill: paid obj on bill?");
392 			return(bp);
393 		}
394 	if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
395 	return(NULL);
396 }
397 
398 /* called with two args on merge */
399 void
400 obfree(struct obj *obj, struct obj *merge)
401 {
402 	struct bill_x *bp = onbill(obj);
403 	struct bill_x *bpm;
404 
405 	if(bp) {
406 		if(!merge){
407 			bp->useup = 1;
408 			obj->unpaid = 0;	/* only for doinvbill */
409 			obj->nobj = billobjs;
410 			billobjs = obj;
411 			return;
412 		}
413 		bpm = onbill(merge);
414 		if(!bpm){
415 			/* this used to be a rename */
416 			impossible("obfree: not on bill??");
417 			return;
418 		} else {
419 			/* this was a merger */
420 			bpm->bquan += bp->bquan;
421 			ESHK(shopkeeper)->billct--;
422 			*bp = bill[ESHK(shopkeeper)->billct];
423 		}
424 	}
425 	free((char *) obj);
426 }
427 
428 static void
429 pay(long tmp, struct monst *shkp)
430 {
431 	long robbed = ESHK(shkp)->robbed;
432 
433 	u.ugold -= tmp;
434 	shkp->mgold += tmp;
435 	flags.botl = 1;
436 	if(robbed) {
437 		robbed -= tmp;
438 		if(robbed < 0) robbed = 0;
439 		ESHK(shkp)->robbed = robbed;
440 	}
441 }
442 
443 int
444 dopay()
445 {
446 	long ltmp;
447 	struct bill_x *bp;
448 	struct monst *shkp;
449 	int pass, tmp;
450 
451 	multi = 0;
452 	(void) inshop();
453 	for(shkp = fmon; shkp; shkp = shkp->nmon)
454 		if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
455 			break;
456 	if(!shkp && u.uinshop &&
457 	   inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom)
458 		shkp = shopkeeper;
459 
460 	if(!shkp) {
461 		pline("There is nobody here to receive your payment.");
462 		return(0);
463 	}
464 	ltmp = ESHK(shkp)->robbed;
465 	if(shkp != shopkeeper && NOTANGRY(shkp)) {
466 		if(!ltmp) {
467 			pline("You do not owe %s anything.", monnam(shkp));
468 		} else
469 		if(!u.ugold) {
470 			pline("You have no money.");
471 		} else {
472 		    long ugold = u.ugold;
473 
474 		    if(u.ugold > ltmp) {
475 			pline("You give %s the %ld gold pieces he asked for.",
476 				monnam(shkp), ltmp);
477 			pay(ltmp, shkp);
478 		    } else {
479 			pline("You give %s all your gold.", monnam(shkp));
480 			pay(u.ugold, shkp);
481 		    }
482 		    if(ugold < ltmp/2) {
483 			pline("Unfortunately, he doesn't look satisfied.");
484 		    } else {
485 			ESHK(shkp)->robbed = 0;
486 			ESHK(shkp)->following = 0;
487 			if(ESHK(shkp)->shoplevel != dlevel) {
488 			/* For convenience's sake, let him disappear */
489 			    shkp->minvent = 0;		/* %% */
490 			    shkp->mgold = 0;
491 			    mondead(shkp);
492 			}
493 		    }
494 		}
495 		return(1);
496 	}
497 
498 	if(!ESHK(shkp)->billct){
499 		pline("You do not owe %s anything.", monnam(shkp));
500 		if(!u.ugold){
501 			pline("Moreover, you have no money.");
502 			return(1);
503 		}
504 		if(ESHK(shkp)->robbed){
505 #define min(a,b)	((a<b)?a:b)
506 		    pline("But since his shop has been robbed recently,");
507 		    pline("you %srepay %s's expenses.",
508 		      (u.ugold < ESHK(shkp)->robbed) ? "partially " : "",
509 		      monnam(shkp));
510 		    pay(min(u.ugold, ESHK(shkp)->robbed), shkp);
511 		    ESHK(shkp)->robbed = 0;
512 		    return(1);
513 		}
514 		if(ANGRY(shkp)){
515 			pline("But in order to appease %s,",
516 				amonnam(shkp, "angry"));
517 			if(u.ugold >= 1000){
518 				ltmp = 1000;
519 				pline(" you give him 1000 gold pieces.");
520 			} else {
521 				ltmp = u.ugold;
522 				pline(" you give him all your money.");
523 			}
524 			pay(ltmp, shkp);
525 			if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
526 			   || rn2(3)){
527 				pline("%s calms down.", Monnam(shkp));
528 				NOTANGRY(shkp) = 1;
529 			} else	pline("%s is as angry as ever.",
530 					Monnam(shkp));
531 		}
532 		return(1);
533 	}
534 	if(shkp != shopkeeper) {
535 		impossible("dopay: not to shopkeeper?");
536 		if(shopkeeper) 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)) return(1);
548 			bill[tmp] = bill[--ESHK(shopkeeper)->billct];
549 		}
550 	}
551 	pline("Thank you for shopping in %s's %s store!",
552 		shkname(shopkeeper),
553 		shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]);
554 	NOTANGRY(shopkeeper) = 1;
555 	return(1);
556 }
557 
558 /* return 1 if paid successfully */
559 /*	  0 if not enough money */
560 /*	 -1 if object could not be found (but was paid) */
561 static int
562 dopayobj(struct bill_x *bp)
563 {
564 	struct obj *obj;
565 	long ltmp;
566 
567 	/* find the object on one of the lists */
568 	obj = bp_to_obj(bp);
569 
570 	if(!obj) {
571 		impossible("Shopkeeper administration out of order.");
572 		setpaid();	/* be nice to the player */
573 		return(0);
574 	}
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)) ltmp += ltmp/3;
583 	if(u.ugold < ltmp){
584 		pline("You don't have gold enough to pay %s.",
585 			doname(obj));
586 		obj->unpaid = 1;
587 		return(0);
588 	}
589 	pay(ltmp, shopkeeper);
590 	pline("You bought %s for %ld gold piece%s.",
591 		doname(obj), ltmp, plur(ltmp));
592 	if(bp->useup) {
593 		struct obj *otmp = billobjs;
594 		if(obj == billobjs)
595 			billobjs = obj->nobj;
596 		else {
597 			while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
598 			if(otmp) otmp->nobj = obj->nobj;
599 			else pline("Error in shopkeeper administration.");
600 		}
601 		free((char *) obj);
602 	}
603 	return(1);
604 }
605 
606 /* routine called after dying (or quitting) with nonempty bill */
607 void
608 paybill()
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)))
642 			    break;
643 		    for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
644 			if ((obj = o_on(id, mtmp->minvent)))
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 
656 	if(!inshop() ||
657 	(u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
658 	(u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) ||
659 		onbill(obj) /* perhaps we threw it away earlier */
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) otmp->unpaid = 0;
695 	else {
696 		tmp = bp->price;
697 		bp = &bill[ESHK(shopkeeper)->billct];
698 		bp->bo_id = otmp->o_id;
699 		bp->bquan = otmp->quan;
700 		bp->useup = 0;
701 		bp->price = tmp;
702 		ESHK(shopkeeper)->billct++;
703 	}
704 }
705 
706 void
707 subfrombill(struct obj *obj)
708 {
709 	long ltmp;
710 	int tmp;
711 	struct obj *otmp;
712 	struct bill_x *bp;
713 
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	ltmp /= 2;
755 	if(ESHK(shopkeeper)->robbed){
756 		if((ESHK(shopkeeper)->robbed -= ltmp) < 0)
757 			ESHK(shopkeeper)->robbed = 0;
758 pline("Thank you for your contribution to restock this recently plundered shop.");
759 		return;
760 	}
761 	if(ltmp > shopkeeper->mgold)
762 		ltmp = shopkeeper->mgold;
763 	pay(-ltmp, shopkeeper);
764 	if(!ltmp)
765 	pline("%s gladly accepts %s but cannot pay you at present.",
766 		Monnam(shopkeeper), doname(obj));
767 	else
768 	pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
769 		plur(ltmp));
770 }
771 
772 int
773 doinvbill(int mode)
774 /* int mode;		0: deliver count 1: paged */
775 {
776 	struct bill_x *bp;
777 	struct obj *obj;
778 	long totused, thisused;
779 	char buf[BUFSZ];
780 
781 	if(mode == 0) {
782 	    int cnt = 0;
783 
784 	    if(shopkeeper)
785 		for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
786 		    if(bp->useup ||
787 		      ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
788 			cnt++;
789 	    return(cnt);
790 	}
791 
792 	if(!shopkeeper) {
793 		impossible("doinvbill: no shopkeeper?");
794 		return(0);
795 	}
796 
797 	set_pager(0);
798 	if(page_line("Unpaid articles already used up:") || page_line(""))
799 	    goto quit;
800 
801 	totused = 0;
802 	for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
803 	    obj = bp_to_obj(bp);
804 	    if(!obj) {
805 		impossible("Bad shopkeeper administration.");
806 		goto quit;
807 	    }
808 	    if(bp->useup || bp->bquan > obj->quan) {
809 		int cnt, oquan, uquan;
810 
811 		oquan = obj->quan;
812 		uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
813 		thisused = bp->price * uquan;
814 		totused += thisused;
815 		obj->quan = uquan;		/* cheat doname */
816 		(void) snprintf(buf, sizeof buf, "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	tmp = 10*rnd(75);
884 		break;
885 	case CHAIN_SYM:
886 		pline("Strange ..., carrying a chain?");
887 	case BALL_SYM:
888 		tmp = 10;
889 		break;
890 	default:
891 		tmp = 10000;
892 	}
893 	return(tmp);
894 }
895 
896 /* not completely foolproof */
897 static int
898 realhunger()
899 {
900 	int tmp = u.uhunger;
901 	struct obj *otmp = invent;
902 
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 	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, satdoor, avoid, 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 
976 	shkroom = inroom(omx,omy);
977 	appr = 1;
978 	gx = ESHK(shkp)->shk.x;
979 	gy = ESHK(shkp)->shk.y;
980 	satdoor = (gx == omx && gy == omy);
981 	if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
982 		gx = u.ux;
983 		gy = u.uy;
984 		if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
985 		    if(udist > 4)
986 			return(-1);	/* leave it to m_move */
987 	} else if(ANGRY(shkp)) {
988 		long saveBlind = Blind;
989 		Blind = 0;
990 		if(shkp->mcansee && !Invis && cansee(omx,omy)) {
991 			gx = u.ux;
992 			gy = u.uy;
993 		}
994 		Blind = saveBlind;
995 		avoid = FALSE;
996 	} else {
997 #define	GDIST(x,y)	((x-gx)*(x-gx)+(y-gy)*(y-gy))
998 		if(Invis)
999 		  avoid = FALSE;
1000 		else {
1001 		  uondoor = (u.ux == ESHK(shkp)->shd.x &&
1002 				u.uy == ESHK(shkp)->shd.y);
1003 		  if(uondoor) {
1004 		    if(ESHK(shkp)->billct)
1005 			pline("Hello %s! Will you please pay before leaving?",
1006 				plname);
1007 		    badinv = (carrying(PICK_AXE) || carrying(ICE_BOX));
1008 		    if(satdoor && badinv)
1009 			return(0);
1010 		    avoid = !badinv;
1011 		  } else {
1012 		    avoid = (u.uinshop && dist(gx,gy) > 8);
1013 		    badinv = FALSE;
1014 		  }
1015 
1016 		  if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid)
1017 		  	&& GDIST(omx,omy) < 3){
1018 		  	if(!badinv && !online(omx,omy))
1019 				return(0);
1020 		  	if(satdoor)
1021 		  		appr = gx = gy = 0;
1022 		  }
1023 		}
1024 	}
1025 	if(omx == gx && omy == gy)
1026 		return(0);
1027 	if(shkp->mconf) {
1028 		avoid = FALSE;
1029 		appr = 0;
1030 	}
1031 	nix = omx;
1032 	niy = omy;
1033 	cnt = mfndpos(shkp,poss,info,ALLOW_SSM);
1034 	if(avoid && uondoor) {		/* perhaps we cannot avoid him */
1035 		for(i=0; i<cnt; i++)
1036 			if(!(info[(int)i] & NOTONL)) 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[(int)i].x;
1045 		ny = poss[(int)i].y;
1046 	   	if(levl[(int)nx][(int)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; niy = ny; chi = i; break;
1055 		    }
1056 		    if(avoid && (info[(int)i] & NOTONL))
1057 			continue;
1058 		    if((!appr && !rn2(++chcnt)) ||
1059 #ifdef STUPID
1060 			(appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))
1061 #else
1062 			(appr && GDIST(nx,ny) < GDIST(nix,niy))
1063 #endif /* STUPID */
1064 			) {
1065 			    nix = nx;
1066 			    niy = ny;
1067 			    chi = i;
1068 		    }
1069 		}
1070 	}
1071 	if(nix != omx || niy != omy){
1072 		if(info[(int)chi] & ALLOW_M){
1073 			mtmp = m_at(nix,niy);
1074 			if(hitmm(shkp,mtmp) == 1 && rn2(3) &&
1075 			   hitmm(mtmp,shkp) == 2) return(2);
1076 			return(0);
1077 		} else if(info[(int)chi] & ALLOW_U){
1078 			(void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
1079 			return(0);
1080 		}
1081 		shkp->mx = nix;
1082 		shkp->my = niy;
1083 		pmon(shkp);
1084 		if(ib) {
1085 			freeobj(ib);
1086 			mpickobj(shkp, ib);
1087 		}
1088 		return(1);
1089 	}
1090 	return(0);
1091 }
1092 
1093 /* He is digging in the shop. */
1094 void
1095 shopdig(int fall)
1096 {
1097     if(!fall) {
1098 	if(u.utraptype == TT_PIT)
1099 	    pline("\"Be careful, sir, or you might fall through the floor.\"");
1100 	else
1101 	    pline("\"Please, do not damage the floor here.\"");
1102     } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) {
1103 	struct obj *obj, *obj2;
1104 
1105 	pline("%s grabs your backpack!", shkname(shopkeeper));
1106 	for(obj = invent; obj; obj = obj2) {
1107 		obj2 = obj->nobj;
1108 		if(obj->owornmask) continue;
1109 		freeinv(obj);
1110 		obj->nobj = shopkeeper->minvent;
1111 		shopkeeper->minvent = obj;
1112 		if(obj->unpaid)
1113 			subfrombill(obj);
1114 	}
1115     }
1116 }
1117 #endif /* QUEST */
1118 
1119 int
1120 online(int x, int y)
1121 {
1122 	return(x==u.ux || y==u.uy ||
1123 		(x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
1124 }
1125 
1126 /* Does this monster follow me downstairs? */
1127 int
1128 follower(struct monst *mtmp)
1129 {
1130 	return( mtmp->mtame || strchr("1TVWZi&, ", mtmp->data->mlet)
1131 #ifndef QUEST
1132 		|| (mtmp->isshk && ESHK(mtmp)->following)
1133 #endif /* QUEST */
1134 		);
1135 }
1136