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