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