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