pc-hack

PC HACK 3.61 source code (archival)
git clone http://frotz.net/git/pc-hack.git
Log | Files | Refs

shk.c (24295B)


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