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