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