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