xref: /openbsd-src/games/hack/hack.shk.c (revision aed906e4b20d9afbda31247cdb6acf6f29da8819)
1*aed906e4Smestre /*	$OpenBSD: hack.shk.c,v 1.13 2016/01/09 18:33:15 mestre Exp $	*/
2d0b779f3Sniklas 
3df930be7Sderaadt /*
4d25013f2Scamield  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5d25013f2Scamield  * Amsterdam
6d25013f2Scamield  * All rights reserved.
7d25013f2Scamield  *
8d25013f2Scamield  * Redistribution and use in source and binary forms, with or without
9d25013f2Scamield  * modification, are permitted provided that the following conditions are
10d25013f2Scamield  * met:
11d25013f2Scamield  *
12d25013f2Scamield  * - Redistributions of source code must retain the above copyright notice,
13d25013f2Scamield  * this list of conditions and the following disclaimer.
14d25013f2Scamield  *
15d25013f2Scamield  * - Redistributions in binary form must reproduce the above copyright
16d25013f2Scamield  * notice, this list of conditions and the following disclaimer in the
17d25013f2Scamield  * documentation and/or other materials provided with the distribution.
18d25013f2Scamield  *
19d25013f2Scamield  * - Neither the name of the Stichting Centrum voor Wiskunde en
20d25013f2Scamield  * Informatica, nor the names of its contributors may be used to endorse or
21d25013f2Scamield  * promote products derived from this software without specific prior
22d25013f2Scamield  * written permission.
23d25013f2Scamield  *
24d25013f2Scamield  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25d25013f2Scamield  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26d25013f2Scamield  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27d25013f2Scamield  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28d25013f2Scamield  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29d25013f2Scamield  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30d25013f2Scamield  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31d25013f2Scamield  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32d25013f2Scamield  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33d25013f2Scamield  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34d25013f2Scamield  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35d25013f2Scamield  */
36d25013f2Scamield 
37d25013f2Scamield /*
38d25013f2Scamield  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39d25013f2Scamield  * All rights reserved.
40d25013f2Scamield  *
41d25013f2Scamield  * Redistribution and use in source and binary forms, with or without
42d25013f2Scamield  * modification, are permitted provided that the following conditions
43d25013f2Scamield  * are met:
44d25013f2Scamield  * 1. Redistributions of source code must retain the above copyright
45d25013f2Scamield  *    notice, this list of conditions and the following disclaimer.
46d25013f2Scamield  * 2. Redistributions in binary form must reproduce the above copyright
47d25013f2Scamield  *    notice, this list of conditions and the following disclaimer in the
48d25013f2Scamield  *    documentation and/or other materials provided with the distribution.
49d25013f2Scamield  * 3. The name of the author may not be used to endorse or promote products
50d25013f2Scamield  *    derived from this software without specific prior written permission.
51d25013f2Scamield  *
52d25013f2Scamield  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53d25013f2Scamield  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54d25013f2Scamield  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55d25013f2Scamield  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56d25013f2Scamield  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57d25013f2Scamield  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58d25013f2Scamield  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59d25013f2Scamield  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60d25013f2Scamield  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61d25013f2Scamield  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62df930be7Sderaadt  */
63df930be7Sderaadt 
644a5fbbc4Spjanzen #include <stdio.h>
654a5fbbc4Spjanzen #include <stdlib.h>
66*aed906e4Smestre 
67df930be7Sderaadt #include "hack.h"
684a5fbbc4Spjanzen 
69df930be7Sderaadt #ifdef QUEST
70df930be7Sderaadt int shlevel = 0;
71df930be7Sderaadt struct monst *shopkeeper = 0;
72df930be7Sderaadt struct obj *billobjs = 0;
734a5fbbc4Spjanzen 
744a5fbbc4Spjanzen void
obfree(struct obj * obj,struct obj * merge)754a5fbbc4Spjanzen obfree(struct obj *obj, struct obj *merge)
764a5fbbc4Spjanzen {
77ebf3d589Sguenther 	free(obj);
78df930be7Sderaadt }
794a5fbbc4Spjanzen 
804a5fbbc4Spjanzen int
inshop(void)81*aed906e4Smestre inshop(void)
824a5fbbc4Spjanzen {
834a5fbbc4Spjanzen 	return(0);
844a5fbbc4Spjanzen }
854a5fbbc4Spjanzen 
864a5fbbc4Spjanzen void
shopdig(int a)874a5fbbc4Spjanzen shopdig(int a)
884a5fbbc4Spjanzen {}
894a5fbbc4Spjanzen 
904a5fbbc4Spjanzen void
addtobill(struct obj * ign)914a5fbbc4Spjanzen addtobill(struct obj *ign)
924a5fbbc4Spjanzen {}
934a5fbbc4Spjanzen 
944a5fbbc4Spjanzen void
subfrombill(struct obj * ign)954a5fbbc4Spjanzen subfrombill(struct obj *ign)
964a5fbbc4Spjanzen {}
974a5fbbc4Spjanzen 
984a5fbbc4Spjanzen void
splitbill(struct obj * ign,struct obj * ign2)994a5fbbc4Spjanzen splitbill(struct obj *ign, struct obj *ign2)
1004a5fbbc4Spjanzen {}
1014a5fbbc4Spjanzen 
1024a5fbbc4Spjanzen int
dopay(void)103*aed906e4Smestre dopay(void)
1044a5fbbc4Spjanzen {
1054a5fbbc4Spjanzen 	return(0);
1064a5fbbc4Spjanzen }
1074a5fbbc4Spjanzen 
1084a5fbbc4Spjanzen void
paybill(void)109*aed906e4Smestre paybill(void)
1104a5fbbc4Spjanzen {}
1114a5fbbc4Spjanzen 
1124a5fbbc4Spjanzen int
doinvbill(int a)1134a5fbbc4Spjanzen doinvbill(int a)
1144a5fbbc4Spjanzen {
1154a5fbbc4Spjanzen 	return(0);
1164a5fbbc4Spjanzen }
1174a5fbbc4Spjanzen 
1184a5fbbc4Spjanzen void
shkdead(struct monst * ign)1194a5fbbc4Spjanzen shkdead(struct monst *ign)
1204a5fbbc4Spjanzen {}
1214a5fbbc4Spjanzen 
1224a5fbbc4Spjanzen int
shkcatch(struct obj * ign)1234a5fbbc4Spjanzen shkcatch(struct obj *ign)
1244a5fbbc4Spjanzen {
1254a5fbbc4Spjanzen 	return(0);
1264a5fbbc4Spjanzen }
1274a5fbbc4Spjanzen 
1284a5fbbc4Spjanzen int
shk_move(struct monst * ign)1294a5fbbc4Spjanzen shk_move(struct monst *ign)
1304a5fbbc4Spjanzen {
1314a5fbbc4Spjanzen 	return(0);
1324a5fbbc4Spjanzen }
1334a5fbbc4Spjanzen 
1344a5fbbc4Spjanzen void
replshk(struct monst * mtmp,struct monst * mtmp2)1354a5fbbc4Spjanzen replshk(struct monst *mtmp, struct monst *mtmp2)
1364a5fbbc4Spjanzen {}
1374a5fbbc4Spjanzen 
1384a5fbbc4Spjanzen char *
shkname(struct monst * ign)1394a5fbbc4Spjanzen shkname(struct monst *ign)
1404a5fbbc4Spjanzen {
1414a5fbbc4Spjanzen 	return("");
1424a5fbbc4Spjanzen }
143df930be7Sderaadt 
14454da88e4Spjanzen #else /* QUEST */
145df930be7Sderaadt #include "hack.mfndpos.h"
146df930be7Sderaadt #include "def.eshk.h"
147df930be7Sderaadt 
148df930be7Sderaadt #define	ESHK(mon)	((struct eshk *)(&(mon->mextra[0])))
149df930be7Sderaadt #define	NOTANGRY(mon)	mon->mpeaceful
150df930be7Sderaadt #define	ANGRY(mon)	!NOTANGRY(mon)
151df930be7Sderaadt 
1524a5fbbc4Spjanzen extern char plname[];
153df930be7Sderaadt 
154df930be7Sderaadt /* Descriptor of current shopkeeper. Note that the bill need not be
1554a5fbbc4Spjanzen  * per-shopkeeper, since it is valid only when in a shop.
1564a5fbbc4Spjanzen  */
157df930be7Sderaadt static struct monst *shopkeeper = 0;
158df930be7Sderaadt static struct bill_x *bill;
159df930be7Sderaadt static int shlevel = 0;	/* level of this shopkeeper */
160df930be7Sderaadt struct obj *billobjs;	/* objects on bill with bp->useup */
161df930be7Sderaadt 				/* only accessed here and by save & restore */
162df930be7Sderaadt static long int total;		/* filled by addupbill() */
163df930be7Sderaadt static long int followmsg;	/* last time of follow message */
164df930be7Sderaadt 
165df930be7Sderaadt /*
1664a5fbbc4Spjanzen  *	invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
1674a5fbbc4Spjanzen  *		obj->quan <= bp->bquan
168df930be7Sderaadt  */
169df930be7Sderaadt 
170df930be7Sderaadt 
171df930be7Sderaadt char shtypes[] = {	/* 8 shoptypes: 7 specialized, 1 mixed */
172df930be7Sderaadt 	RING_SYM, WAND_SYM, WEAPON_SYM, FOOD_SYM, SCROLL_SYM,
173df930be7Sderaadt 	POTION_SYM, ARMOR_SYM, 0
174df930be7Sderaadt };
175df930be7Sderaadt 
176df930be7Sderaadt static char *shopnam[] = {
177df930be7Sderaadt 	"engagement ring", "walking cane", "antique weapon",
178df930be7Sderaadt 	"delicatessen", "second hand book", "liquor",
179df930be7Sderaadt 	"used armor", "assorted antiques"
180df930be7Sderaadt };
181df930be7Sderaadt 
1824a5fbbc4Spjanzen static void setpaid(void);
1834a5fbbc4Spjanzen static void addupbill(void);
1844a5fbbc4Spjanzen static void findshk(int);
1854a5fbbc4Spjanzen static struct bill_x *onbill(struct obj *);
1864a5fbbc4Spjanzen static void pay(long, struct monst *);
1874a5fbbc4Spjanzen static int  dopayobj(struct bill_x *);
1884a5fbbc4Spjanzen static struct obj *bp_to_obj(struct bill_x *);
1894a5fbbc4Spjanzen static int getprice(struct obj *);
190*aed906e4Smestre static int realhunger(void);
1914a5fbbc4Spjanzen 
1924a5fbbc4Spjanzen /* called in do_name.c */
193df930be7Sderaadt char *
shkname(struct monst * mtmp)1944a5fbbc4Spjanzen shkname(struct monst *mtmp)
195df930be7Sderaadt {
196df930be7Sderaadt 	return(ESHK(mtmp)->shknam);
197df930be7Sderaadt }
198df930be7Sderaadt 
1994a5fbbc4Spjanzen void
shkdead(struct monst * mtmp)2004a5fbbc4Spjanzen shkdead(struct monst *mtmp)				/* called in mon.c */
201df930be7Sderaadt {
2024a5fbbc4Spjanzen 	struct eshk *eshk = ESHK(mtmp);
203df930be7Sderaadt 
204df930be7Sderaadt 	if(eshk->shoplevel == dlevel)
205df930be7Sderaadt 		rooms[eshk->shoproom].rtype = 0;
206df930be7Sderaadt 	if(mtmp == shopkeeper) {
207df930be7Sderaadt 		setpaid();
208df930be7Sderaadt 		shopkeeper = 0;
209df930be7Sderaadt 		bill = (struct bill_x *) -1000;	/* dump core when referenced */
210df930be7Sderaadt 	}
211df930be7Sderaadt }
212df930be7Sderaadt 
2134a5fbbc4Spjanzen void
replshk(struct monst * mtmp,struct monst * mtmp2)2144a5fbbc4Spjanzen replshk(struct monst *mtmp, struct monst *mtmp2)
215df930be7Sderaadt {
216df930be7Sderaadt 	if(mtmp == shopkeeper) {
217df930be7Sderaadt 		shopkeeper = mtmp2;
218df930be7Sderaadt 		bill = &(ESHK(shopkeeper)->bill[0]);
219df930be7Sderaadt 	}
220df930be7Sderaadt }
221df930be7Sderaadt 
2224a5fbbc4Spjanzen /* caller has checked that shopkeeper exists */
223df930be7Sderaadt /* either we paid or left the shop or he just died */
2244a5fbbc4Spjanzen static void
setpaid(void)225*aed906e4Smestre setpaid(void)
2264a5fbbc4Spjanzen {
2274a5fbbc4Spjanzen 	struct obj *obj;
2284a5fbbc4Spjanzen 	struct monst *mtmp;
2294a5fbbc4Spjanzen 
230df930be7Sderaadt 	for(obj = invent; obj; obj = obj->nobj)
231df930be7Sderaadt 		obj->unpaid = 0;
232df930be7Sderaadt 	for(obj = fobj; obj; obj = obj->nobj)
233df930be7Sderaadt 		obj->unpaid = 0;
234df930be7Sderaadt 	for(obj = fcobj; obj; obj = obj->nobj)
235df930be7Sderaadt 		obj->unpaid = 0;
236df930be7Sderaadt 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
237df930be7Sderaadt 		for(obj = mtmp->minvent; obj; obj = obj->nobj)
238df930be7Sderaadt 			obj->unpaid = 0;
239df930be7Sderaadt 	for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
240df930be7Sderaadt 		for(obj = mtmp->minvent; obj; obj = obj->nobj)
241df930be7Sderaadt 			obj->unpaid = 0;
2424a5fbbc4Spjanzen 	while ((obj = billobjs)) {
243df930be7Sderaadt 		billobjs = obj->nobj;
244ebf3d589Sguenther 		free(obj);
245df930be7Sderaadt 	}
246df930be7Sderaadt 	ESHK(shopkeeper)->billct = 0;
247df930be7Sderaadt }
248df930be7Sderaadt 
2494a5fbbc4Spjanzen /* delivers result in total */
250df930be7Sderaadt /* caller has checked that shopkeeper exists */
2514a5fbbc4Spjanzen static void
addupbill(void)252*aed906e4Smestre addupbill(void)
2534a5fbbc4Spjanzen {
2544a5fbbc4Spjanzen 	int ct = ESHK(shopkeeper)->billct;
2554a5fbbc4Spjanzen 	struct bill_x *bp = bill;
2564a5fbbc4Spjanzen 
257df930be7Sderaadt 	total = 0;
258df930be7Sderaadt 	while(ct--){
259df930be7Sderaadt 		total += bp->price * bp->bquan;
260df930be7Sderaadt 		bp++;
261df930be7Sderaadt 	}
262df930be7Sderaadt }
263df930be7Sderaadt 
2644a5fbbc4Spjanzen int
inshop(void)265*aed906e4Smestre inshop(void)
2664a5fbbc4Spjanzen {
2674a5fbbc4Spjanzen 	int roomno = inroom(u.ux,u.uy);
268df930be7Sderaadt 
269df930be7Sderaadt 	/* Did we just leave a shop? */
270df930be7Sderaadt 	if(u.uinshop &&
271df930be7Sderaadt 	    (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
272df930be7Sderaadt 		if(shopkeeper) {
273df930be7Sderaadt 		    if(ESHK(shopkeeper)->billct) {
274df930be7Sderaadt  			if(inroom(shopkeeper->mx, shopkeeper->my)
275df930be7Sderaadt  			    == u.uinshop - 1)	/* ab@unido */
276df930be7Sderaadt  			    pline("Somehow you escaped the shop without paying!");
277df930be7Sderaadt 			addupbill();
278df930be7Sderaadt 			pline("You stole for a total worth of %ld zorkmids.",
279df930be7Sderaadt 				total);
280df930be7Sderaadt 			ESHK(shopkeeper)->robbed += total;
281df930be7Sderaadt 			setpaid();
282df930be7Sderaadt 			if((rooms[ESHK(shopkeeper)->shoproom].rtype == GENERAL)
283df930be7Sderaadt 			    == (rn2(3) == 0))
284df930be7Sderaadt 			    ESHK(shopkeeper)->following = 1;
285df930be7Sderaadt 		    }
286df930be7Sderaadt 		    shopkeeper = 0;
287df930be7Sderaadt 		    shlevel = 0;
288df930be7Sderaadt 		}
289df930be7Sderaadt  		u.uinshop = 0;
290df930be7Sderaadt 	}
291df930be7Sderaadt 
292df930be7Sderaadt 	/* Did we just enter a zoo of some kind? */
293df930be7Sderaadt 	if(roomno >= 0) {
2944a5fbbc4Spjanzen 		int rt = rooms[roomno].rtype;
2954a5fbbc4Spjanzen 		struct monst *mtmp;
296df930be7Sderaadt 		if(rt == ZOO) {
297df930be7Sderaadt 			pline("Welcome to David's treasure zoo!");
298df930be7Sderaadt 		} else
299df930be7Sderaadt 		if(rt == SWAMP) {
300df930be7Sderaadt 			pline("It looks rather muddy down here.");
301df930be7Sderaadt 		} else
302df930be7Sderaadt 		if(rt == MORGUE) {
303df930be7Sderaadt 			if(midnight())
304df930be7Sderaadt 				pline("Go away! Go away!");
305df930be7Sderaadt 			else
306df930be7Sderaadt 				pline("You get an uncanny feeling ...");
307df930be7Sderaadt 		} else
308df930be7Sderaadt 			rt = 0;
309df930be7Sderaadt 		if(rt != 0) {
310df930be7Sderaadt 			rooms[roomno].rtype = 0;
311df930be7Sderaadt 			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
312df930be7Sderaadt 				if(rt != ZOO || !rn2(3))
313df930be7Sderaadt 					mtmp->msleep = 0;
314df930be7Sderaadt 		}
315df930be7Sderaadt 	}
316df930be7Sderaadt 
317df930be7Sderaadt 	/* Did we just enter a shop? */
318df930be7Sderaadt 	if(roomno >= 0 && rooms[roomno].rtype >= 8) {
319df930be7Sderaadt 	    if(shlevel != dlevel || !shopkeeper
320df930be7Sderaadt 				 || ESHK(shopkeeper)->shoproom != roomno)
321df930be7Sderaadt 		findshk(roomno);
322df930be7Sderaadt 	    if(!shopkeeper) {
323df930be7Sderaadt 		rooms[roomno].rtype = 0;
324df930be7Sderaadt 		u.uinshop = 0;
325df930be7Sderaadt 	    } else if(!u.uinshop){
326df930be7Sderaadt 		if(!ESHK(shopkeeper)->visitct ||
327df930be7Sderaadt 		    strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){
328df930be7Sderaadt 
329df930be7Sderaadt 		    /* He seems to be new here */
330df930be7Sderaadt 		    ESHK(shopkeeper)->visitct = 0;
331df930be7Sderaadt 		    ESHK(shopkeeper)->following = 0;
332479daa62Savsm 		    (void) strlcpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
333df930be7Sderaadt 		    NOTANGRY(shopkeeper) = 1;
334df930be7Sderaadt 		}
335df930be7Sderaadt 		if(!ESHK(shopkeeper)->following) {
336df930be7Sderaadt 		    boolean box, pick;
337df930be7Sderaadt 
338df930be7Sderaadt 		    pline("Hello %s! Welcome%s to %s's %s shop!",
339df930be7Sderaadt 			plname,
340df930be7Sderaadt 			ESHK(shopkeeper)->visitct++ ? " again" : "",
341df930be7Sderaadt 			shkname(shopkeeper),
342df930be7Sderaadt 			shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8] );
343df930be7Sderaadt 		    box = carrying(ICE_BOX);
344df930be7Sderaadt 		    pick = carrying(PICK_AXE);
345df930be7Sderaadt 		    if(box || pick) {
346df930be7Sderaadt 			if(dochug(shopkeeper)) {
347df930be7Sderaadt 				u.uinshop = 0;	/* he died moving */
348df930be7Sderaadt 				return(0);
349df930be7Sderaadt 			}
350df930be7Sderaadt 			pline("Will you please leave your %s outside?",
351df930be7Sderaadt 			    (box && pick) ? "box and pick-axe" :
352df930be7Sderaadt 			    box ? "box" : "pick-axe");
353df930be7Sderaadt 		    }
354df930be7Sderaadt 		}
355df930be7Sderaadt 		u.uinshop = roomno + 1;
356df930be7Sderaadt 	    }
357df930be7Sderaadt 	}
358df930be7Sderaadt 	return(u.uinshop);
359df930be7Sderaadt }
360df930be7Sderaadt 
361df930be7Sderaadt static void
findshk(int roomno)3624a5fbbc4Spjanzen findshk(int roomno)
363df930be7Sderaadt {
3644a5fbbc4Spjanzen 	struct monst *mtmp;
3654a5fbbc4Spjanzen 
366df930be7Sderaadt 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
367df930be7Sderaadt 	    if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
368df930be7Sderaadt 			   && ESHK(mtmp)->shoplevel == dlevel) {
369df930be7Sderaadt 		shopkeeper = mtmp;
370df930be7Sderaadt 		bill = &(ESHK(shopkeeper)->bill[0]);
371df930be7Sderaadt 		shlevel = dlevel;
372df930be7Sderaadt 		if(ANGRY(shopkeeper) &&
373df930be7Sderaadt 		   strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
374df930be7Sderaadt 			NOTANGRY(shopkeeper) = 1;
375df930be7Sderaadt 		/* billobjs = 0; -- this is wrong if we save in a shop */
376df930be7Sderaadt 		/* (and it is harmless to have too many things in billobjs) */
377df930be7Sderaadt 		return;
378df930be7Sderaadt 	}
379df930be7Sderaadt 	shopkeeper = 0;
380df930be7Sderaadt 	shlevel = 0;
381df930be7Sderaadt 	bill = (struct bill_x *) -1000;	/* dump core when referenced */
382df930be7Sderaadt }
383df930be7Sderaadt 
384df930be7Sderaadt static struct bill_x *
onbill(struct obj * obj)3854a5fbbc4Spjanzen onbill(struct obj *obj)
3864a5fbbc4Spjanzen {
3874a5fbbc4Spjanzen 	struct bill_x *bp;
3884a5fbbc4Spjanzen 
3894a5fbbc4Spjanzen 	if(!shopkeeper) return(NULL);
390df930be7Sderaadt 	for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
391df930be7Sderaadt 		if(bp->bo_id == obj->o_id) {
392df930be7Sderaadt 			if(!obj->unpaid) pline("onbill: paid obj on bill?");
393df930be7Sderaadt 			return(bp);
394df930be7Sderaadt 		}
395df930be7Sderaadt 	if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
3964a5fbbc4Spjanzen 	return(NULL);
397df930be7Sderaadt }
398df930be7Sderaadt 
399df930be7Sderaadt /* called with two args on merge */
4004a5fbbc4Spjanzen void
obfree(struct obj * obj,struct obj * merge)4014a5fbbc4Spjanzen obfree(struct obj *obj, struct obj *merge)
4024a5fbbc4Spjanzen {
4034a5fbbc4Spjanzen 	struct bill_x *bp = onbill(obj);
4044a5fbbc4Spjanzen 	struct bill_x *bpm;
4054a5fbbc4Spjanzen 
406df930be7Sderaadt 	if(bp) {
407df930be7Sderaadt 		if(!merge){
408df930be7Sderaadt 			bp->useup = 1;
409df930be7Sderaadt 			obj->unpaid = 0;	/* only for doinvbill */
410df930be7Sderaadt 			obj->nobj = billobjs;
411df930be7Sderaadt 			billobjs = obj;
412df930be7Sderaadt 			return;
413df930be7Sderaadt 		}
414df930be7Sderaadt 		bpm = onbill(merge);
415df930be7Sderaadt 		if(!bpm){
416df930be7Sderaadt 			/* this used to be a rename */
417df930be7Sderaadt 			impossible("obfree: not on bill??");
418df930be7Sderaadt 			return;
419df930be7Sderaadt 		} else {
420df930be7Sderaadt 			/* this was a merger */
421df930be7Sderaadt 			bpm->bquan += bp->bquan;
422df930be7Sderaadt 			ESHK(shopkeeper)->billct--;
423df930be7Sderaadt 			*bp = bill[ESHK(shopkeeper)->billct];
424df930be7Sderaadt 		}
425df930be7Sderaadt 	}
426ebf3d589Sguenther 	free(obj);
427df930be7Sderaadt }
428df930be7Sderaadt 
4294a5fbbc4Spjanzen static void
pay(long tmp,struct monst * shkp)4304a5fbbc4Spjanzen pay(long tmp, struct monst *shkp)
431df930be7Sderaadt {
432df930be7Sderaadt 	long robbed = ESHK(shkp)->robbed;
433df930be7Sderaadt 
434df930be7Sderaadt 	u.ugold -= tmp;
435df930be7Sderaadt 	shkp->mgold += tmp;
436df930be7Sderaadt 	flags.botl = 1;
437df930be7Sderaadt 	if(robbed) {
438df930be7Sderaadt 		robbed -= tmp;
439df930be7Sderaadt 		if(robbed < 0) robbed = 0;
440df930be7Sderaadt 		ESHK(shkp)->robbed = robbed;
441df930be7Sderaadt 	}
442df930be7Sderaadt }
443df930be7Sderaadt 
4444a5fbbc4Spjanzen int
dopay(void)445*aed906e4Smestre dopay(void)
4464a5fbbc4Spjanzen {
447df930be7Sderaadt 	long ltmp;
4484a5fbbc4Spjanzen 	struct bill_x *bp;
4494a5fbbc4Spjanzen 	struct monst *shkp;
450df930be7Sderaadt 	int pass, tmp;
451df930be7Sderaadt 
452df930be7Sderaadt 	multi = 0;
453df930be7Sderaadt 	(void) inshop();
454df930be7Sderaadt 	for(shkp = fmon; shkp; shkp = shkp->nmon)
455df930be7Sderaadt 		if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
456df930be7Sderaadt 			break;
457df930be7Sderaadt 	if(!shkp && u.uinshop &&
458df930be7Sderaadt 	   inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom)
459df930be7Sderaadt 		shkp = shopkeeper;
460df930be7Sderaadt 
461df930be7Sderaadt 	if(!shkp) {
462df930be7Sderaadt 		pline("There is nobody here to receive your payment.");
463df930be7Sderaadt 		return(0);
464df930be7Sderaadt 	}
465df930be7Sderaadt 	ltmp = ESHK(shkp)->robbed;
466df930be7Sderaadt 	if(shkp != shopkeeper && NOTANGRY(shkp)) {
467df930be7Sderaadt 		if(!ltmp) {
468df930be7Sderaadt 			pline("You do not owe %s anything.", monnam(shkp));
469df930be7Sderaadt 		} else
470df930be7Sderaadt 		if(!u.ugold) {
471df930be7Sderaadt 			pline("You have no money.");
472df930be7Sderaadt 		} else {
473df930be7Sderaadt 		    long ugold = u.ugold;
474df930be7Sderaadt 
475df930be7Sderaadt 		    if(u.ugold > ltmp) {
476df930be7Sderaadt 			pline("You give %s the %ld gold pieces he asked for.",
477df930be7Sderaadt 				monnam(shkp), ltmp);
478df930be7Sderaadt 			pay(ltmp, shkp);
479df930be7Sderaadt 		    } else {
480df930be7Sderaadt 			pline("You give %s all your gold.", monnam(shkp));
481df930be7Sderaadt 			pay(u.ugold, shkp);
482df930be7Sderaadt 		    }
483df930be7Sderaadt 		    if(ugold < ltmp/2) {
484df930be7Sderaadt 			pline("Unfortunately, he doesn't look satisfied.");
485df930be7Sderaadt 		    } else {
486df930be7Sderaadt 			ESHK(shkp)->robbed = 0;
487df930be7Sderaadt 			ESHK(shkp)->following = 0;
488df930be7Sderaadt 			if(ESHK(shkp)->shoplevel != dlevel) {
489df930be7Sderaadt 			/* For convenience's sake, let him disappear */
490df930be7Sderaadt 			    shkp->minvent = 0;		/* %% */
491df930be7Sderaadt 			    shkp->mgold = 0;
492df930be7Sderaadt 			    mondead(shkp);
493df930be7Sderaadt 			}
494df930be7Sderaadt 		    }
495df930be7Sderaadt 		}
496df930be7Sderaadt 		return(1);
497df930be7Sderaadt 	}
498df930be7Sderaadt 
499df930be7Sderaadt 	if(!ESHK(shkp)->billct){
500df930be7Sderaadt 		pline("You do not owe %s anything.", monnam(shkp));
501df930be7Sderaadt 		if(!u.ugold){
502df930be7Sderaadt 			pline("Moreover, you have no money.");
503df930be7Sderaadt 			return(1);
504df930be7Sderaadt 		}
505df930be7Sderaadt 		if(ESHK(shkp)->robbed){
506df930be7Sderaadt #define min(a,b)	((a<b)?a:b)
507df930be7Sderaadt 		    pline("But since his shop has been robbed recently,");
508df930be7Sderaadt 		    pline("you %srepay %s's expenses.",
509df930be7Sderaadt 		      (u.ugold < ESHK(shkp)->robbed) ? "partially " : "",
510df930be7Sderaadt 		      monnam(shkp));
511df930be7Sderaadt 		    pay(min(u.ugold, ESHK(shkp)->robbed), shkp);
512df930be7Sderaadt 		    ESHK(shkp)->robbed = 0;
513df930be7Sderaadt 		    return(1);
514df930be7Sderaadt 		}
515df930be7Sderaadt 		if(ANGRY(shkp)){
516df930be7Sderaadt 			pline("But in order to appease %s,",
517df930be7Sderaadt 				amonnam(shkp, "angry"));
518df930be7Sderaadt 			if(u.ugold >= 1000){
519df930be7Sderaadt 				ltmp = 1000;
520df930be7Sderaadt 				pline(" you give him 1000 gold pieces.");
521df930be7Sderaadt 			} else {
522df930be7Sderaadt 				ltmp = u.ugold;
523df930be7Sderaadt 				pline(" you give him all your money.");
524df930be7Sderaadt 			}
525df930be7Sderaadt 			pay(ltmp, shkp);
526df930be7Sderaadt 			if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
527df930be7Sderaadt 			   || rn2(3)){
528df930be7Sderaadt 				pline("%s calms down.", Monnam(shkp));
529df930be7Sderaadt 				NOTANGRY(shkp) = 1;
530df930be7Sderaadt 			} else	pline("%s is as angry as ever.",
531df930be7Sderaadt 					Monnam(shkp));
532df930be7Sderaadt 		}
533df930be7Sderaadt 		return(1);
534df930be7Sderaadt 	}
535df930be7Sderaadt 	if(shkp != shopkeeper) {
536df930be7Sderaadt 		impossible("dopay: not to shopkeeper?");
537df930be7Sderaadt 		if(shopkeeper) setpaid();
538df930be7Sderaadt 		return(0);
539df930be7Sderaadt 	}
540df930be7Sderaadt 	for(pass = 0; pass <= 1; pass++) {
541df930be7Sderaadt 		tmp = 0;
542df930be7Sderaadt 		while(tmp < ESHK(shopkeeper)->billct) {
543df930be7Sderaadt 			bp = &bill[tmp];
544df930be7Sderaadt 			if(!pass && !bp->useup) {
545df930be7Sderaadt 				tmp++;
546df930be7Sderaadt 				continue;
547df930be7Sderaadt 			}
548df930be7Sderaadt 			if(!dopayobj(bp)) return(1);
549df930be7Sderaadt 			bill[tmp] = bill[--ESHK(shopkeeper)->billct];
550df930be7Sderaadt 		}
551df930be7Sderaadt 	}
552df930be7Sderaadt 	pline("Thank you for shopping in %s's %s store!",
553df930be7Sderaadt 		shkname(shopkeeper),
554df930be7Sderaadt 		shopnam[rooms[ESHK(shopkeeper)->shoproom].rtype - 8]);
555df930be7Sderaadt 	NOTANGRY(shopkeeper) = 1;
556df930be7Sderaadt 	return(1);
557df930be7Sderaadt }
558df930be7Sderaadt 
559df930be7Sderaadt /* return 1 if paid successfully */
560df930be7Sderaadt /*	  0 if not enough money */
561df930be7Sderaadt /*	 -1 if object could not be found (but was paid) */
5624a5fbbc4Spjanzen static int
dopayobj(struct bill_x * bp)5634a5fbbc4Spjanzen dopayobj(struct bill_x *bp)
5644a5fbbc4Spjanzen {
5654a5fbbc4Spjanzen 	struct obj *obj;
566df930be7Sderaadt 	long ltmp;
567df930be7Sderaadt 
568df930be7Sderaadt 	/* find the object on one of the lists */
569df930be7Sderaadt 	obj = bp_to_obj(bp);
570df930be7Sderaadt 
571df930be7Sderaadt 	if(!obj) {
572df930be7Sderaadt 		impossible("Shopkeeper administration out of order.");
573df930be7Sderaadt 		setpaid();	/* be nice to the player */
574df930be7Sderaadt 		return(0);
575df930be7Sderaadt 	}
576df930be7Sderaadt 
577df930be7Sderaadt 	if(!obj->unpaid && !bp->useup){
578df930be7Sderaadt 		impossible("Paid object on bill??");
579df930be7Sderaadt 		return(1);
580df930be7Sderaadt 	}
581df930be7Sderaadt 	obj->unpaid = 0;
582df930be7Sderaadt 	ltmp = bp->price * bp->bquan;
583df930be7Sderaadt 	if(ANGRY(shopkeeper)) ltmp += ltmp/3;
584df930be7Sderaadt 	if(u.ugold < ltmp){
585df930be7Sderaadt 		pline("You don't have gold enough to pay %s.",
586df930be7Sderaadt 			doname(obj));
587df930be7Sderaadt 		obj->unpaid = 1;
588df930be7Sderaadt 		return(0);
589df930be7Sderaadt 	}
590df930be7Sderaadt 	pay(ltmp, shopkeeper);
591df930be7Sderaadt 	pline("You bought %s for %ld gold piece%s.",
592df930be7Sderaadt 		doname(obj), ltmp, plur(ltmp));
593df930be7Sderaadt 	if(bp->useup) {
5944a5fbbc4Spjanzen 		struct obj *otmp = billobjs;
595df930be7Sderaadt 		if(obj == billobjs)
596df930be7Sderaadt 			billobjs = obj->nobj;
597df930be7Sderaadt 		else {
598df930be7Sderaadt 			while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
599df930be7Sderaadt 			if(otmp) otmp->nobj = obj->nobj;
600df930be7Sderaadt 			else pline("Error in shopkeeper administration.");
601df930be7Sderaadt 		}
602ebf3d589Sguenther 		free(obj);
603df930be7Sderaadt 	}
604df930be7Sderaadt 	return(1);
605df930be7Sderaadt }
606df930be7Sderaadt 
607df930be7Sderaadt /* routine called after dying (or quitting) with nonempty bill */
6084a5fbbc4Spjanzen void
paybill(void)609*aed906e4Smestre paybill(void)
6104a5fbbc4Spjanzen {
611df930be7Sderaadt 	if(shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct){
612df930be7Sderaadt 		addupbill();
613df930be7Sderaadt 		if(total > u.ugold){
614df930be7Sderaadt 			shopkeeper->mgold += u.ugold;
615df930be7Sderaadt 			u.ugold = 0;
616df930be7Sderaadt 		pline("%s comes and takes all your possessions.",
617df930be7Sderaadt 			Monnam(shopkeeper));
618df930be7Sderaadt 		} else {
619df930be7Sderaadt 			u.ugold -= total;
620df930be7Sderaadt 			shopkeeper->mgold += total;
621df930be7Sderaadt 	pline("%s comes and takes the %ld zorkmids you owed him.",
622df930be7Sderaadt 		Monnam(shopkeeper), total);
623df930be7Sderaadt 		}
624df930be7Sderaadt 		setpaid();	/* in case we create bones */
625df930be7Sderaadt 	}
626df930be7Sderaadt }
627df930be7Sderaadt 
628df930be7Sderaadt /* find obj on one of the lists */
6294a5fbbc4Spjanzen static struct obj *
bp_to_obj(struct bill_x * bp)6304a5fbbc4Spjanzen bp_to_obj(struct bill_x *bp)
631df930be7Sderaadt {
6324a5fbbc4Spjanzen 	struct obj *obj;
6334a5fbbc4Spjanzen 	struct monst *mtmp;
6344a5fbbc4Spjanzen 	unsigned id = bp->bo_id;
635df930be7Sderaadt 
636df930be7Sderaadt 	if(bp->useup)
637df930be7Sderaadt 		obj = o_on(id, billobjs);
638df930be7Sderaadt 	else if(!(obj = o_on(id, invent)) &&
639df930be7Sderaadt 		!(obj = o_on(id, fobj)) &&
640df930be7Sderaadt 		!(obj = o_on(id, fcobj))) {
641df930be7Sderaadt 		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
6424a5fbbc4Spjanzen 			if ((obj = o_on(id, mtmp->minvent)))
643df930be7Sderaadt 			    break;
644df930be7Sderaadt 		    for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
6454a5fbbc4Spjanzen 			if ((obj = o_on(id, mtmp->minvent)))
646df930be7Sderaadt 			    break;
647df930be7Sderaadt 		}
648df930be7Sderaadt 	return(obj);
649df930be7Sderaadt }
650df930be7Sderaadt 
651df930be7Sderaadt /* called in hack.c when we pickup an object */
6524a5fbbc4Spjanzen void
addtobill(struct obj * obj)6534a5fbbc4Spjanzen addtobill(struct obj *obj)
6544a5fbbc4Spjanzen {
6554a5fbbc4Spjanzen 	struct bill_x *bp;
6564a5fbbc4Spjanzen 
657df930be7Sderaadt 	if(!inshop() ||
658df930be7Sderaadt 	(u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
659df930be7Sderaadt 	(u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) ||
660df930be7Sderaadt 		onbill(obj) /* perhaps we threw it away earlier */
661df930be7Sderaadt 	  ) return;
662df930be7Sderaadt 	if(ESHK(shopkeeper)->billct == BILLSZ){
663df930be7Sderaadt 		pline("You got that for free!");
664df930be7Sderaadt 		return;
665df930be7Sderaadt 	}
666df930be7Sderaadt 	bp = &bill[ESHK(shopkeeper)->billct];
667df930be7Sderaadt 	bp->bo_id = obj->o_id;
668df930be7Sderaadt 	bp->bquan = obj->quan;
669df930be7Sderaadt 	bp->useup = 0;
670df930be7Sderaadt 	bp->price = getprice(obj);
671df930be7Sderaadt 	ESHK(shopkeeper)->billct++;
672df930be7Sderaadt 	obj->unpaid = 1;
673df930be7Sderaadt }
674df930be7Sderaadt 
6754a5fbbc4Spjanzen void
splitbill(struct obj * obj,struct obj * otmp)6764a5fbbc4Spjanzen splitbill(struct obj *obj, struct obj *otmp)
6774a5fbbc4Spjanzen {
678df930be7Sderaadt 	/* otmp has been split off from obj */
6794a5fbbc4Spjanzen struct bill_x *bp;
6804a5fbbc4Spjanzen int tmp;
681df930be7Sderaadt 	bp = onbill(obj);
682df930be7Sderaadt 	if(!bp) {
683df930be7Sderaadt 		impossible("splitbill: not on bill?");
684df930be7Sderaadt 		return;
685df930be7Sderaadt 	}
686df930be7Sderaadt 	if(bp->bquan < otmp->quan) {
687df930be7Sderaadt 		impossible("Negative quantity on bill??");
688df930be7Sderaadt 	}
689df930be7Sderaadt 	if(bp->bquan == otmp->quan) {
690df930be7Sderaadt 		impossible("Zero quantity on bill??");
691df930be7Sderaadt 	}
692df930be7Sderaadt 	bp->bquan -= otmp->quan;
693df930be7Sderaadt 
694df930be7Sderaadt 	/* addtobill(otmp); */
695df930be7Sderaadt 	if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0;
696df930be7Sderaadt 	else {
697df930be7Sderaadt 		tmp = bp->price;
698df930be7Sderaadt 		bp = &bill[ESHK(shopkeeper)->billct];
699df930be7Sderaadt 		bp->bo_id = otmp->o_id;
700df930be7Sderaadt 		bp->bquan = otmp->quan;
701df930be7Sderaadt 		bp->useup = 0;
702df930be7Sderaadt 		bp->price = tmp;
703df930be7Sderaadt 		ESHK(shopkeeper)->billct++;
704df930be7Sderaadt 	}
705df930be7Sderaadt }
706df930be7Sderaadt 
7074a5fbbc4Spjanzen void
subfrombill(struct obj * obj)7084a5fbbc4Spjanzen subfrombill(struct obj *obj)
7094a5fbbc4Spjanzen {
710df930be7Sderaadt 	long ltmp;
7114a5fbbc4Spjanzen 	int tmp;
7124a5fbbc4Spjanzen 	struct obj *otmp;
7134a5fbbc4Spjanzen 	struct bill_x *bp;
7144a5fbbc4Spjanzen 
715df930be7Sderaadt 	if(!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
716df930be7Sderaadt 		(u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y))
717df930be7Sderaadt 		return;
718df930be7Sderaadt 	if((bp = onbill(obj)) != 0){
719df930be7Sderaadt 		obj->unpaid = 0;
720df930be7Sderaadt 		if(bp->bquan > obj->quan){
721df930be7Sderaadt 			otmp = newobj(0);
722df930be7Sderaadt 			*otmp = *obj;
723df930be7Sderaadt 			bp->bo_id = otmp->o_id = flags.ident++;
724df930be7Sderaadt 			otmp->quan = (bp->bquan -= obj->quan);
725df930be7Sderaadt 			otmp->owt = 0;	/* superfluous */
726df930be7Sderaadt 			otmp->onamelth = 0;
727df930be7Sderaadt 			bp->useup = 1;
728df930be7Sderaadt 			otmp->nobj = billobjs;
729df930be7Sderaadt 			billobjs = otmp;
730df930be7Sderaadt 			return;
731df930be7Sderaadt 		}
732df930be7Sderaadt 		ESHK(shopkeeper)->billct--;
733df930be7Sderaadt 		*bp = bill[ESHK(shopkeeper)->billct];
734df930be7Sderaadt 		return;
735df930be7Sderaadt 	}
736df930be7Sderaadt 	if(obj->unpaid){
737df930be7Sderaadt 		pline("%s didn't notice.", Monnam(shopkeeper));
738df930be7Sderaadt 		obj->unpaid = 0;
739df930be7Sderaadt 		return;		/* %% */
740df930be7Sderaadt 	}
741df930be7Sderaadt 	/* he dropped something of his own - probably wants to sell it */
742df930be7Sderaadt 	if(shopkeeper->msleep || shopkeeper->mfroz ||
743df930be7Sderaadt 		inroom(shopkeeper->mx,shopkeeper->my) != ESHK(shopkeeper)->shoproom)
744df930be7Sderaadt 		return;
745df930be7Sderaadt 	if(ESHK(shopkeeper)->billct == BILLSZ ||
746df930be7Sderaadt 	  ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype-8]) && tmp != obj->olet)
747180acc8fSmillert 	  || strchr("_0", obj->olet)) {
748df930be7Sderaadt 		pline("%s seems not interested.", Monnam(shopkeeper));
749df930be7Sderaadt 		return;
750df930be7Sderaadt 	}
751df930be7Sderaadt 	ltmp = getprice(obj) * obj->quan;
752df930be7Sderaadt 	if(ANGRY(shopkeeper)) {
753df930be7Sderaadt 		ltmp /= 3;
754df930be7Sderaadt 		NOTANGRY(shopkeeper) = 1;
755df930be7Sderaadt 	} else	ltmp /= 2;
756df930be7Sderaadt 	if(ESHK(shopkeeper)->robbed){
757df930be7Sderaadt 		if((ESHK(shopkeeper)->robbed -= ltmp) < 0)
758df930be7Sderaadt 			ESHK(shopkeeper)->robbed = 0;
759df930be7Sderaadt pline("Thank you for your contribution to restock this recently plundered shop.");
760df930be7Sderaadt 		return;
761df930be7Sderaadt 	}
762df930be7Sderaadt 	if(ltmp > shopkeeper->mgold)
763df930be7Sderaadt 		ltmp = shopkeeper->mgold;
764df930be7Sderaadt 	pay(-ltmp, shopkeeper);
765df930be7Sderaadt 	if(!ltmp)
766df930be7Sderaadt 	pline("%s gladly accepts %s but cannot pay you at present.",
767df930be7Sderaadt 		Monnam(shopkeeper), doname(obj));
768df930be7Sderaadt 	else
769df930be7Sderaadt 	pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
770df930be7Sderaadt 		plur(ltmp));
771df930be7Sderaadt }
772df930be7Sderaadt 
773*aed906e4Smestre /* int mode;		0: deliver count 1: paged */
7744a5fbbc4Spjanzen int
doinvbill(int mode)7754a5fbbc4Spjanzen doinvbill(int mode)
776df930be7Sderaadt {
7774a5fbbc4Spjanzen 	struct bill_x *bp;
7784a5fbbc4Spjanzen 	struct obj *obj;
779df930be7Sderaadt 	long totused, thisused;
780df930be7Sderaadt 	char buf[BUFSZ];
781df930be7Sderaadt 
782df930be7Sderaadt 	if(mode == 0) {
7834a5fbbc4Spjanzen 	    int cnt = 0;
784df930be7Sderaadt 
785df930be7Sderaadt 	    if(shopkeeper)
786df930be7Sderaadt 		for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
787df930be7Sderaadt 		    if(bp->useup ||
788df930be7Sderaadt 		      ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
789df930be7Sderaadt 			cnt++;
790df930be7Sderaadt 	    return(cnt);
791df930be7Sderaadt 	}
792df930be7Sderaadt 
793df930be7Sderaadt 	if(!shopkeeper) {
794df930be7Sderaadt 		impossible("doinvbill: no shopkeeper?");
795df930be7Sderaadt 		return(0);
796df930be7Sderaadt 	}
797df930be7Sderaadt 
798df930be7Sderaadt 	set_pager(0);
799df930be7Sderaadt 	if(page_line("Unpaid articles already used up:") || page_line(""))
800df930be7Sderaadt 	    goto quit;
801df930be7Sderaadt 
802df930be7Sderaadt 	totused = 0;
803df930be7Sderaadt 	for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
804df930be7Sderaadt 	    obj = bp_to_obj(bp);
805df930be7Sderaadt 	    if(!obj) {
806df930be7Sderaadt 		impossible("Bad shopkeeper administration.");
807df930be7Sderaadt 		goto quit;
808df930be7Sderaadt 	    }
809df930be7Sderaadt 	    if(bp->useup || bp->bquan > obj->quan) {
8104a5fbbc4Spjanzen 		int cnt, oquan, uquan;
811df930be7Sderaadt 
812df930be7Sderaadt 		oquan = obj->quan;
813df930be7Sderaadt 		uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
814df930be7Sderaadt 		thisused = bp->price * uquan;
815df930be7Sderaadt 		totused += thisused;
816df930be7Sderaadt 		obj->quan = uquan;		/* cheat doname */
81742ceebb3Sderaadt 		(void) snprintf(buf, sizeof buf, "x -  %s", doname(obj));
818df930be7Sderaadt 		obj->quan = oquan;		/* restore value */
819df930be7Sderaadt 		for(cnt = 0; buf[cnt]; cnt++);
820df930be7Sderaadt 		while(cnt < 50)
821df930be7Sderaadt 			buf[cnt++] = ' ';
82242ceebb3Sderaadt 		(void) snprintf(&buf[cnt], sizeof buf - cnt,
82342ceebb3Sderaadt 		    " %5ld zorkmids", thisused);
824df930be7Sderaadt 		if(page_line(buf))
825df930be7Sderaadt 			goto quit;
826df930be7Sderaadt 	    }
827df930be7Sderaadt 	}
82842ceebb3Sderaadt 	(void) snprintf(buf, sizeof buf, "Total:%50ld zorkmids", totused);
829df930be7Sderaadt 	if(page_line("") || page_line(buf))
830df930be7Sderaadt 		goto quit;
831df930be7Sderaadt 	set_pager(1);
832df930be7Sderaadt 	return(0);
833df930be7Sderaadt quit:
834df930be7Sderaadt 	set_pager(2);
835df930be7Sderaadt 	return(0);
836df930be7Sderaadt }
837df930be7Sderaadt 
8384a5fbbc4Spjanzen static int
getprice(struct obj * obj)8394a5fbbc4Spjanzen getprice(struct obj *obj)
8404a5fbbc4Spjanzen {
8414a5fbbc4Spjanzen 	int tmp, ac;
842df930be7Sderaadt 
843df930be7Sderaadt 	switch(obj->olet){
844df930be7Sderaadt 	case AMULET_SYM:
845df930be7Sderaadt 		tmp = 10*rnd(500);
846df930be7Sderaadt 		break;
847df930be7Sderaadt 	case TOOL_SYM:
848df930be7Sderaadt 		tmp = 10*rnd((obj->otyp == EXPENSIVE_CAMERA) ? 150 : 30);
849df930be7Sderaadt 		break;
850df930be7Sderaadt 	case RING_SYM:
851df930be7Sderaadt 		tmp = 10*rnd(100);
852df930be7Sderaadt 		break;
853df930be7Sderaadt 	case WAND_SYM:
854df930be7Sderaadt 		tmp = 10*rnd(100);
855df930be7Sderaadt 		break;
856df930be7Sderaadt 	case SCROLL_SYM:
857df930be7Sderaadt 		tmp = 10*rnd(50);
858df930be7Sderaadt #ifdef MAIL
859df930be7Sderaadt 		if(obj->otyp == SCR_MAIL)
860df930be7Sderaadt 			tmp = rnd(5);
86154da88e4Spjanzen #endif /* MAIL */
862df930be7Sderaadt 		break;
863df930be7Sderaadt 	case POTION_SYM:
864df930be7Sderaadt 		tmp = 10*rnd(50);
865df930be7Sderaadt 		break;
866df930be7Sderaadt 	case FOOD_SYM:
867df930be7Sderaadt 		tmp = 10*rnd(5 + (2000/realhunger()));
868df930be7Sderaadt 		break;
869df930be7Sderaadt 	case GEM_SYM:
870df930be7Sderaadt 		tmp = 10*rnd(20);
871df930be7Sderaadt 		break;
872df930be7Sderaadt 	case ARMOR_SYM:
873df930be7Sderaadt 		ac = ARM_BONUS(obj);
874df930be7Sderaadt 		if(ac <= -10)		/* probably impossible */
875df930be7Sderaadt 			ac = -9;
876df930be7Sderaadt 		tmp = 100 + ac*ac*rnd(10+ac);
877df930be7Sderaadt 		break;
878df930be7Sderaadt 	case WEAPON_SYM:
879df930be7Sderaadt 		if(obj->otyp < BOOMERANG)
880df930be7Sderaadt 			tmp = 5*rnd(10);
881df930be7Sderaadt 		else if(obj->otyp == LONG_SWORD ||
882df930be7Sderaadt 			obj->otyp == TWO_HANDED_SWORD)
883df930be7Sderaadt 			tmp = 10*rnd(150);
884df930be7Sderaadt 		else	tmp = 10*rnd(75);
885df930be7Sderaadt 		break;
886df930be7Sderaadt 	case CHAIN_SYM:
887df930be7Sderaadt 		pline("Strange ..., carrying a chain?");
888df930be7Sderaadt 	case BALL_SYM:
889df930be7Sderaadt 		tmp = 10;
890df930be7Sderaadt 		break;
891df930be7Sderaadt 	default:
892df930be7Sderaadt 		tmp = 10000;
893df930be7Sderaadt 	}
894df930be7Sderaadt 	return(tmp);
895df930be7Sderaadt }
896df930be7Sderaadt 
8974a5fbbc4Spjanzen /* not completely foolproof */
8984a5fbbc4Spjanzen static int
realhunger(void)899*aed906e4Smestre realhunger(void)
9004a5fbbc4Spjanzen {
9014a5fbbc4Spjanzen 	int tmp = u.uhunger;
9024a5fbbc4Spjanzen 	struct obj *otmp = invent;
9034a5fbbc4Spjanzen 
904df930be7Sderaadt 	while(otmp){
905df930be7Sderaadt 		if(otmp->olet == FOOD_SYM && !otmp->unpaid)
906df930be7Sderaadt 			tmp += objects[otmp->otyp].nutrition;
907df930be7Sderaadt 		otmp = otmp->nobj;
908df930be7Sderaadt 	}
909df930be7Sderaadt 	return((tmp <= 0) ? 1 : tmp);
910df930be7Sderaadt }
911df930be7Sderaadt 
9124a5fbbc4Spjanzen int
shkcatch(struct obj * obj)9134a5fbbc4Spjanzen shkcatch(struct obj *obj)
914df930be7Sderaadt {
9154a5fbbc4Spjanzen 	struct monst *shkp = shopkeeper;
916df930be7Sderaadt 
917df930be7Sderaadt 	if(u.uinshop && shkp && !shkp->mfroz && !shkp->msleep &&
918df930be7Sderaadt 	    u.dx && u.dy &&
919df930be7Sderaadt 	    inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop &&
920df930be7Sderaadt 	    shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y &&
921df930be7Sderaadt 	    u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) {
922df930be7Sderaadt 		pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj));
923df930be7Sderaadt 		obj->nobj = shkp->minvent;
924df930be7Sderaadt 		shkp->minvent = obj;
925df930be7Sderaadt 		return(1);
926df930be7Sderaadt 	}
927df930be7Sderaadt 	return(0);
928df930be7Sderaadt }
929df930be7Sderaadt 
930df930be7Sderaadt /*
931df930be7Sderaadt  * shk_move: return 1: he moved  0: he didnt  -1: let m_move do it
932df930be7Sderaadt  */
9334a5fbbc4Spjanzen int
shk_move(struct monst * shkp)9344a5fbbc4Spjanzen shk_move(struct monst *shkp)
935df930be7Sderaadt {
9364a5fbbc4Spjanzen 	struct monst *mtmp;
9374a5fbbc4Spjanzen 	struct permonst *mdat = shkp->data;
9384a5fbbc4Spjanzen 	xchar gx,gy,omx,omy,nx,ny,nix,niy;
9394a5fbbc4Spjanzen 	schar appr,i;
9404a5fbbc4Spjanzen 	int udist;
941df930be7Sderaadt 	int z;
942df930be7Sderaadt 	schar shkroom,chi,chcnt,cnt;
943df930be7Sderaadt 	boolean uondoor, satdoor, avoid, badinv;
944df930be7Sderaadt 	coord poss[9];
945df930be7Sderaadt 	int info[9];
946df930be7Sderaadt 	struct obj *ib = 0;
947df930be7Sderaadt 
948df930be7Sderaadt 	omx = shkp->mx;
949df930be7Sderaadt 	omy = shkp->my;
950df930be7Sderaadt 
951df930be7Sderaadt 	if((udist = dist(omx,omy)) < 3) {
952df930be7Sderaadt 		if(ANGRY(shkp)) {
953df930be7Sderaadt 			(void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
954df930be7Sderaadt 			return(0);
955df930be7Sderaadt 		}
956df930be7Sderaadt 		if(ESHK(shkp)->following) {
957df930be7Sderaadt 			if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)){
958df930be7Sderaadt 				pline("Hello %s! I was looking for %s.",
959df930be7Sderaadt 					plname, ESHK(shkp)->customer);
960df930be7Sderaadt 				ESHK(shkp)->following = 0;
961df930be7Sderaadt 				return(0);
962df930be7Sderaadt 			}
963df930be7Sderaadt 			if(!ESHK(shkp)->robbed) {	/* impossible? */
964df930be7Sderaadt 				ESHK(shkp)->following = 0;
965df930be7Sderaadt 				return(0);
966df930be7Sderaadt 			}
967df930be7Sderaadt 			if(moves > followmsg+4) {
968df930be7Sderaadt 				pline("Hello %s! Didn't you forget to pay?",
969df930be7Sderaadt 					plname);
970df930be7Sderaadt 				followmsg = moves;
971df930be7Sderaadt 			}
972df930be7Sderaadt 			if(udist < 2)
973df930be7Sderaadt 				return(0);
974df930be7Sderaadt 		}
975df930be7Sderaadt 	}
976df930be7Sderaadt 
977df930be7Sderaadt 	shkroom = inroom(omx,omy);
978df930be7Sderaadt 	appr = 1;
979df930be7Sderaadt 	gx = ESHK(shkp)->shk.x;
980df930be7Sderaadt 	gy = ESHK(shkp)->shk.y;
981df930be7Sderaadt 	satdoor = (gx == omx && gy == omy);
982df930be7Sderaadt 	if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
983df930be7Sderaadt 		gx = u.ux;
984df930be7Sderaadt 		gy = u.uy;
985df930be7Sderaadt 		if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
986df930be7Sderaadt 		    if(udist > 4)
987df930be7Sderaadt 			return(-1);	/* leave it to m_move */
988df930be7Sderaadt 	} else if(ANGRY(shkp)) {
989df930be7Sderaadt 		long saveBlind = Blind;
990df930be7Sderaadt 		Blind = 0;
991df930be7Sderaadt 		if(shkp->mcansee && !Invis && cansee(omx,omy)) {
992df930be7Sderaadt 			gx = u.ux;
993df930be7Sderaadt 			gy = u.uy;
994df930be7Sderaadt 		}
995df930be7Sderaadt 		Blind = saveBlind;
996df930be7Sderaadt 		avoid = FALSE;
997df930be7Sderaadt 	} else {
998df930be7Sderaadt #define	GDIST(x,y)	((x-gx)*(x-gx)+(y-gy)*(y-gy))
999df930be7Sderaadt 		if(Invis)
1000df930be7Sderaadt 		  avoid = FALSE;
1001df930be7Sderaadt 		else {
1002df930be7Sderaadt 		  uondoor = (u.ux == ESHK(shkp)->shd.x &&
1003df930be7Sderaadt 				u.uy == ESHK(shkp)->shd.y);
1004df930be7Sderaadt 		  if(uondoor) {
1005df930be7Sderaadt 		    if(ESHK(shkp)->billct)
1006df930be7Sderaadt 			pline("Hello %s! Will you please pay before leaving?",
1007df930be7Sderaadt 				plname);
1008df930be7Sderaadt 		    badinv = (carrying(PICK_AXE) || carrying(ICE_BOX));
1009df930be7Sderaadt 		    if(satdoor && badinv)
1010df930be7Sderaadt 			return(0);
1011df930be7Sderaadt 		    avoid = !badinv;
1012df930be7Sderaadt 		  } else {
1013df930be7Sderaadt 		    avoid = (u.uinshop && dist(gx,gy) > 8);
1014df930be7Sderaadt 		    badinv = FALSE;
1015df930be7Sderaadt 		  }
1016df930be7Sderaadt 
1017df930be7Sderaadt 		  if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid)
1018df930be7Sderaadt 		  	&& GDIST(omx,omy) < 3){
1019df930be7Sderaadt 		  	if(!badinv && !online(omx,omy))
1020df930be7Sderaadt 				return(0);
1021df930be7Sderaadt 		  	if(satdoor)
1022df930be7Sderaadt 		  		appr = gx = gy = 0;
1023df930be7Sderaadt 		  }
1024df930be7Sderaadt 		}
1025df930be7Sderaadt 	}
1026df930be7Sderaadt 	if(omx == gx && omy == gy)
1027df930be7Sderaadt 		return(0);
1028df930be7Sderaadt 	if(shkp->mconf) {
1029df930be7Sderaadt 		avoid = FALSE;
1030df930be7Sderaadt 		appr = 0;
1031df930be7Sderaadt 	}
1032df930be7Sderaadt 	nix = omx;
1033df930be7Sderaadt 	niy = omy;
1034df930be7Sderaadt 	cnt = mfndpos(shkp,poss,info,ALLOW_SSM);
1035df930be7Sderaadt 	if(avoid && uondoor) {		/* perhaps we cannot avoid him */
1036df930be7Sderaadt 		for(i=0; i<cnt; i++)
10374a5fbbc4Spjanzen 			if(!(info[(int)i] & NOTONL)) goto notonl_ok;
1038df930be7Sderaadt 		avoid = FALSE;
1039df930be7Sderaadt 	notonl_ok:
1040df930be7Sderaadt 		;
1041df930be7Sderaadt 	}
1042df930be7Sderaadt 	chi = -1;
1043df930be7Sderaadt 	chcnt = 0;
1044df930be7Sderaadt 	for(i=0; i<cnt; i++){
10454a5fbbc4Spjanzen 		nx = poss[(int)i].x;
10464a5fbbc4Spjanzen 		ny = poss[(int)i].y;
10474a5fbbc4Spjanzen 	   	if(levl[(int)nx][(int)ny].typ == ROOM
1048df930be7Sderaadt 		|| shkroom != ESHK(shkp)->shoproom
1049df930be7Sderaadt 		|| ESHK(shkp)->following) {
1050df930be7Sderaadt #ifdef STUPID
1051df930be7Sderaadt 		    /* cater for stupid compilers */
10524a5fbbc4Spjanzen 		    int zz;
105354da88e4Spjanzen #endif /* STUPID */
1054df930be7Sderaadt 		    if(uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) {
1055df930be7Sderaadt 			nix = nx; niy = ny; chi = i; break;
1056df930be7Sderaadt 		    }
10574a5fbbc4Spjanzen 		    if(avoid && (info[(int)i] & NOTONL))
1058df930be7Sderaadt 			continue;
1059df930be7Sderaadt 		    if((!appr && !rn2(++chcnt)) ||
1060df930be7Sderaadt #ifdef STUPID
1061df930be7Sderaadt 			(appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))
1062df930be7Sderaadt #else
1063df930be7Sderaadt 			(appr && GDIST(nx,ny) < GDIST(nix,niy))
106454da88e4Spjanzen #endif /* STUPID */
1065df930be7Sderaadt 			) {
1066df930be7Sderaadt 			    nix = nx;
1067df930be7Sderaadt 			    niy = ny;
1068df930be7Sderaadt 			    chi = i;
1069df930be7Sderaadt 		    }
1070df930be7Sderaadt 		}
1071df930be7Sderaadt 	}
1072df930be7Sderaadt 	if(nix != omx || niy != omy){
10734a5fbbc4Spjanzen 		if(info[(int)chi] & ALLOW_M){
1074df930be7Sderaadt 			mtmp = m_at(nix,niy);
1075df930be7Sderaadt 			if(hitmm(shkp,mtmp) == 1 && rn2(3) &&
1076df930be7Sderaadt 			   hitmm(mtmp,shkp) == 2) return(2);
1077df930be7Sderaadt 			return(0);
10784a5fbbc4Spjanzen 		} else if(info[(int)chi] & ALLOW_U){
1079df930be7Sderaadt 			(void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
1080df930be7Sderaadt 			return(0);
1081df930be7Sderaadt 		}
1082df930be7Sderaadt 		shkp->mx = nix;
1083df930be7Sderaadt 		shkp->my = niy;
1084df930be7Sderaadt 		pmon(shkp);
1085df930be7Sderaadt 		if(ib) {
1086df930be7Sderaadt 			freeobj(ib);
1087df930be7Sderaadt 			mpickobj(shkp, ib);
1088df930be7Sderaadt 		}
1089df930be7Sderaadt 		return(1);
1090df930be7Sderaadt 	}
1091df930be7Sderaadt 	return(0);
1092df930be7Sderaadt }
1093df930be7Sderaadt 
1094df930be7Sderaadt /* He is digging in the shop. */
10954a5fbbc4Spjanzen void
shopdig(int fall)10964a5fbbc4Spjanzen shopdig(int fall)
1097df930be7Sderaadt {
1098df930be7Sderaadt     if(!fall) {
1099df930be7Sderaadt 	if(u.utraptype == TT_PIT)
1100df930be7Sderaadt 	    pline("\"Be careful, sir, or you might fall through the floor.\"");
1101df930be7Sderaadt 	else
1102df930be7Sderaadt 	    pline("\"Please, do not damage the floor here.\"");
1103df930be7Sderaadt     } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) {
11044a5fbbc4Spjanzen 	struct obj *obj, *obj2;
1105df930be7Sderaadt 
1106df930be7Sderaadt 	pline("%s grabs your backpack!", shkname(shopkeeper));
1107df930be7Sderaadt 	for(obj = invent; obj; obj = obj2) {
1108df930be7Sderaadt 		obj2 = obj->nobj;
1109df930be7Sderaadt 		if(obj->owornmask) continue;
1110df930be7Sderaadt 		freeinv(obj);
1111df930be7Sderaadt 		obj->nobj = shopkeeper->minvent;
1112df930be7Sderaadt 		shopkeeper->minvent = obj;
1113df930be7Sderaadt 		if(obj->unpaid)
1114df930be7Sderaadt 			subfrombill(obj);
1115df930be7Sderaadt 	}
1116df930be7Sderaadt     }
1117df930be7Sderaadt }
111854da88e4Spjanzen #endif /* QUEST */
1119df930be7Sderaadt 
11204a5fbbc4Spjanzen int
online(int x,int y)11214a5fbbc4Spjanzen online(int x, int y)
11224a5fbbc4Spjanzen {
1123df930be7Sderaadt 	return(x==u.ux || y==u.uy ||
1124df930be7Sderaadt 		(x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
1125df930be7Sderaadt }
1126df930be7Sderaadt 
1127df930be7Sderaadt /* Does this monster follow me downstairs? */
11284a5fbbc4Spjanzen int
follower(struct monst * mtmp)11294a5fbbc4Spjanzen follower(struct monst *mtmp)
1130df930be7Sderaadt {
1131180acc8fSmillert 	return( mtmp->mtame || strchr("1TVWZi&, ", mtmp->data->mlet)
1132df930be7Sderaadt #ifndef QUEST
1133df930be7Sderaadt 		|| (mtmp->isshk && ESHK(mtmp)->following)
113454da88e4Spjanzen #endif /* QUEST */
1135df930be7Sderaadt 		);
1136df930be7Sderaadt }
1137