1    | /*	SCCS Id: @(#)shk.c	3.3	2000/03/28	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | #include "eshk.h"
7    | 
8    | /*#define DEBUG*/
9    | 
10   | #define PAY_SOME    2
11   | #define PAY_BUY     1
12   | #define PAY_CANT    0	/* too poor */
13   | #define PAY_SKIP  (-1)
14   | #define PAY_BROKE (-2)
15   | 
16   | #ifdef KOPS
17   | STATIC_DCL void FDECL(makekops, (coord *));
18   | STATIC_DCL void FDECL(call_kops, (struct monst *,BOOLEAN_P));
19   | # ifdef OVLB
20   | STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P));
21   | # endif /* OVLB */
22   | #endif /* KOPS */
23   | 
24   | #define IS_SHOP(x)	(rooms[x].rtype >= SHOPBASE)
25   | 
26   | extern const struct shclass shtypes[];	/* defined in shknam.c */
27   | 
28   | STATIC_VAR NEARDATA long int followmsg;	/* last time of follow message */
29   | 
30   | STATIC_DCL void FDECL(setpaid, (struct monst *));
31   | STATIC_DCL long FDECL(addupbill, (struct monst *));
32   | STATIC_DCL void FDECL(pacify_shk, (struct monst *));
33   | STATIC_DCL struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P));
34   | STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
35   | STATIC_DCL long FDECL(shop_debt, (struct eshk *));
36   | STATIC_DCL char *FDECL(shk_owns, (char *,struct obj *));
37   | STATIC_DCL char *FDECL(mon_owns, (char *,struct obj *));
38   | STATIC_DCL void FDECL(clear_unpaid,(struct obj *));
39   | STATIC_DCL long FDECL(check_credit, (long, struct monst *));
40   | STATIC_DCL void FDECL(pay, (long, struct monst *));
41   | STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *));
42   | STATIC_DCL long FDECL(set_cost, (struct obj *, struct monst *));
43   | STATIC_DCL const char *FDECL(shk_embellish, (struct obj *, long));
44   | STATIC_DCL long FDECL(cost_per_charge, (struct monst *,struct obj *,BOOLEAN_P));
45   | STATIC_DCL long FDECL(cheapest_item, (struct monst *));
46   | STATIC_DCL int FDECL(dopayobj, (struct monst *, struct bill_x *,
47   | 			    struct obj **, int, BOOLEAN_P));
48   | STATIC_DCL long FDECL(stolen_container, (struct obj *, struct monst *, long,
49   | 				     BOOLEAN_P));
50   | STATIC_DCL long FDECL(getprice, (struct obj *,BOOLEAN_P));
51   | STATIC_DCL void FDECL(shk_names_obj,
52   | 		 (struct monst *,struct obj *,const char *,long,const char *));
53   | STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *));
54   | STATIC_DCL boolean FDECL(inherits, (struct monst *, int, BOOLEAN_P));
55   | STATIC_DCL void FDECL(set_repo_loc, (struct eshk *));
56   | STATIC_DCL boolean NDECL(angry_shk_exists);
57   | STATIC_DCL void FDECL(rile_shk, (struct monst *));
58   | STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P));
59   | STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *));
60   | STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P));
61   | STATIC_DCL void FDECL(dropped_container, (struct obj *, struct monst *,
62   | 				      BOOLEAN_P));
63   | STATIC_DCL void FDECL(add_to_billobjs, (struct obj *));
64   | STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
65   | 				     struct monst *));
66   | 
67   | #ifdef OVLB
68   | /*
69   | 	invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
70   | 		obj->quan <= bp->bquan
71   |  */
72   | 
73   | STATIC_OVL struct monst *
74   | next_shkp(shkp, withbill)
75   | register struct monst *shkp;
76   | register boolean withbill;
77   | {
78   | 	for (; shkp; shkp = shkp->nmon) {
79   | 	    if (DEADMONSTER(shkp)) continue;
80   | 	    if (shkp->isshk && (ESHK(shkp)->billct || !withbill)) break;
81   | 	}
82   | 
83   | 	if (shkp) {
84   | 	    if (NOTANGRY(shkp)) {
85   | 		if (ESHK(shkp)->surcharge) pacify_shk(shkp);
86   | 	    } else {
87   | 		if (!ESHK(shkp)->surcharge) rile_shk(shkp);
88   | 	    }
89   | 	}
90   | 	return(shkp);
91   | }
92   | 
93   | char *
94   | shkname(mtmp)				/* called in do_name.c */
95   | register struct monst *mtmp;
96   | {
97   | 	return(ESHK(mtmp)->shknam);
98   | }
99   | 
100  | void
101  | shkgone(mtmp)				/* called in mon.c */
102  | register struct monst *mtmp;
103  | {
104  | 	register struct eshk *eshk = ESHK(mtmp);
105  | 
106  | 	if(on_level(&(eshk->shoplevel), &u.uz)) {
107  | 		remove_damage(mtmp, TRUE);
108  | 		rooms[eshk->shoproom - ROOMOFFSET].resident
109  | 						  = (struct monst *)0;
110  | 		if(!search_special(ANY_SHOP))
111  | 		    level.flags.has_shop = 0;
112  | 	}
113  | 	/* make sure bill is set only when the
114  | 	 * dead shk is the resident shk.	*/
115  | 	if(*u.ushops == eshk->shoproom) {
116  | 	    setpaid(mtmp);
117  | 	    /* dump core when referenced */
118  | 	    ESHK(mtmp)->bill_p = (struct bill_x *) -1000;
119  | 	    u.ushops[0] = '\0';
120  | 	}
121  | }
122  | 
123  | void
124  | set_residency(shkp, zero_out)
125  | register struct monst *shkp;
126  | register boolean zero_out;
127  | {
128  | 	if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
129  | 	    rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
130  | 		(zero_out)? (struct monst *)0 : shkp;
131  | }
132  | 
133  | void
134  | replshk(mtmp,mtmp2)
135  | register struct monst *mtmp, *mtmp2;
136  | {
137  | 	rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2;
138  | 	if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
139  | 		ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
140  | 	}
141  | }
142  | 
143  | /* do shopkeeper specific structure munging -dlc */
144  | void
145  | restshk(shkp, ghostly)
146  | struct monst *shkp;
147  | boolean ghostly;
148  | {
149  |     if (u.uz.dlevel) {
150  | 	struct eshk *eshkp = ESHK(shkp);
151  | 
152  | 	if (eshkp->bill_p != (struct bill_x *) -1000)
153  | 	    eshkp->bill_p = &eshkp->bill[0];
154  | 	/* shoplevel can change as dungeons move around */
155  | 	/* savebones guarantees that non-homed shk's will be gone */
156  | 	if (ghostly) {
157  | 	    assign_level(&eshkp->shoplevel, &u.uz);
158  | 	    if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ))
159  | 		pacify_shk(shkp);
160  | 	}
161  |     }
162  | }
163  | 
164  | #endif /* OVLB */
165  | #ifdef OVL3
166  | 
167  | /* Clear the unpaid bit on all of the objects in the list. */
168  | STATIC_OVL void
169  | clear_unpaid(list)
170  | register struct obj *list;
171  | {
172  |     while (list) {
173  | 	if (Has_contents(list)) clear_unpaid(list->cobj);
174  | 	list->unpaid = 0;
175  | 	list = list->nobj;
176  |     }
177  | }
178  | #endif /*OVL3*/
179  | #ifdef OVLB
180  | 
181  | STATIC_OVL void
182  | setpaid(shkp)	/* either you paid or left the shop or the shopkeeper died */
183  | register struct monst *shkp;
184  | {
185  | 	register struct obj *obj;
186  | 	register struct monst *mtmp;
187  | 
188  | 	clear_unpaid(invent);
189  | 	clear_unpaid(fobj);
190  | 	clear_unpaid(level.buriedobjlist);
191  | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
192  | 		clear_unpaid(mtmp->minvent);
193  | 	for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
194  | 		clear_unpaid(mtmp->minvent);
195  | 
196  | 	while ((obj = billobjs) != 0) {
197  | 		obj_extract_self(obj);
198  | 		dealloc_obj(obj);
199  | 	}
200  | 	if(shkp) {
201  | 		ESHK(shkp)->billct = 0;
202  | 		ESHK(shkp)->credit = 0L;
203  | 		ESHK(shkp)->debit = 0L;
204  | 		ESHK(shkp)->loan = 0L;
205  | 	}
206  | }
207  | 
208  | STATIC_OVL long
209  | addupbill(shkp)
210  | register struct monst *shkp;
211  | {
212  | 	register int ct = ESHK(shkp)->billct;
213  | 	register struct bill_x *bp = ESHK(shkp)->bill_p;
214  | 	register long total = 0L;
215  | 
216  | 	while(ct--){
217  | 		total += bp->price * bp->bquan;
218  | 		bp++;
219  | 	}
220  | 	return(total);
221  | }
222  | 
223  | #endif /* OVLB */
224  | #ifdef OVL1
225  | 
226  | #ifdef KOPS
227  | STATIC_OVL void
228  | call_kops(shkp, nearshop)
229  | register struct monst *shkp;
230  | register boolean nearshop;
231  | {
232  | 	/* Keystone Kops srt@ucla */
233  | 	register boolean nokops;
234  | 
235  | 	if(!shkp) return;
236  | 
237  | 	if (flags.soundok)
238  | 	    pline("An alarm sounds!");
239  | 
240  | 	nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) &&
241  | 		  (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) &&
242  | 		  (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) &&
243  | 		  (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE));
244  | 
245  | 	if(!angry_guards(!flags.soundok) && nokops) {
246  | 	    if(flags.verbose && flags.soundok)
247  | 		pline("But no one seems to respond to it.");
248  | 	    return;
249  | 	}
250  | 
251  | 	if(nokops) return;
252  | 
253  | 	{
254  | 	    coord mm;
255  | 
256  | 	    if (nearshop) {
257  | 		/* Create swarm around you, if you merely "stepped out" */
258  | 		if (flags.verbose)
259  | 		    pline_The("Keystone Kops appear!");
260  | 		mm.x = u.ux;
261  | 		mm.y = u.uy;
262  | 		makekops(&mm);
263  | 		return;
264  | 	    }
265  | 	    if (flags.verbose)
266  | 		 pline_The("Keystone Kops are after you!");
267  | 	    /* Create swarm near down staircase (hinders return to level) */
268  | 	    mm.x = xdnstair;
269  | 	    mm.y = ydnstair;
270  | 	    makekops(&mm);
271  | 	    /* Create swarm near shopkeeper (hinders return to shop) */
272  | 	    mm.x = shkp->mx;
273  | 	    mm.y = shkp->my;
274  | 	    makekops(&mm);
275  | 	}
276  | }
277  | #endif	/* KOPS */
278  | 
279  | /* x,y is strictly inside shop */
280  | char
281  | inside_shop(x, y)
282  | register xchar x, y;
283  | {
284  | 	register char rno;
285  | 
286  | 	rno = levl[x][y].roomno;
287  | 	if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET))
288  | 	    return(NO_ROOM);
289  | 	else
290  | 	    return(rno);
291  | }
292  | 
293  | void
294  | u_left_shop(leavestring, newlev)
295  | register char *leavestring;
296  | register boolean newlev;
297  | {
298  | 	register struct monst *shkp;
299  | 	register struct eshk *eshkp;
300  | 	register long total;
301  | 
302  | 	/*
303  | 	 * IF player
304  | 	 * ((didn't leave outright) AND
305  | 	 *  ((he is now strictly-inside the shop) OR
306  | 	 *   (he wasn't strictly-inside last turn anyway)))
307  | 	 * THEN (there's nothing to do, so just return)
308  | 	 */
309  | 	if(!*leavestring &&
310  | 	   (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
311  | 	    return;
312  | 
313  | 	shkp = shop_keeper(*u.ushops0);
314  | 
315  | 	if(!shkp || !inhishop(shkp))
316  | 				/* shk died, teleported, changed levels... */
317  | 	    return;
318  | 
319  | 	eshkp = ESHK(shkp);
320  | 
321  | 	if(!eshkp->billct && !eshkp->debit)	/* bill is settled */
322  | 	    return;
323  | 
324  | 	if (!*leavestring && shkp->mcanmove && !shkp->msleeping) {
325  | 	    /*
326  | 	     * Player just stepped onto shop-boundary (known from above logic).
327  | 	     * Try to intimidate him into paying his bill
328  | 	     */
329  | 	    verbalize(NOTANGRY(shkp) ?
330  | 		      "%s!  Please pay before leaving." :
331  | 		      "%s!  Don't you leave without paying!",
332  | 		      plname);
333  | 	    return;
334  | 	}
335  | 	total = (addupbill(shkp) + eshkp->debit);
336  | 	if (eshkp->credit >= total) {
337  | 	    Your("credit of %ld zorkmid%s is used to cover your shopping bill.",
338  | 		 eshkp->credit, plur(eshkp->credit));
339  | 	    total = 0L;		/* credit gets cleared by setpaid() */
340  | 	} else {
341  | 	    You("escaped the shop without paying!");
342  | 	    total -= eshkp->credit;
343  | 	}
344  | 	setpaid(shkp);
345  | 	if (!total) return;
346  | 
347  | 	/* by this point, we know an actual robbery has taken place */
348  | 	eshkp->robbed += total;
349  | 	You("stole %ld zorkmid%s worth of merchandise.",
350  | 	    total, plur(total));
351  | 	if (!Role_if(PM_ROGUE))	/* stealing is unlawful */
352  | 	    adjalign(-sgn(u.ualign.type));
353  | 
354  | 	hot_pursuit(shkp);
355  | #ifdef KOPS
356  | 	call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
357  | #else
358  | 	(void) angry_guards(FALSE);
359  | #endif
360  | }
361  | 
362  | void
363  | u_entered_shop(enterstring)
364  | register char *enterstring;
365  | {
366  | 
367  | 	register int rt;
368  | 	register struct monst *shkp;
369  | 	register struct eshk *eshkp;
370  | 	static const char no_shk[] = "This shop appears to be deserted.";
371  | 	static char empty_shops[5];
372  | 
373  | 	if(!*enterstring)
374  | 		return;
375  | 
376  | 	if(!(shkp = shop_keeper(*enterstring))) {
377  | 	    if (!index(empty_shops, *enterstring) &&
378  | 		in_rooms(u.ux, u.uy, SHOPBASE) !=
379  | 				  in_rooms(u.ux0, u.uy0, SHOPBASE))
380  | 		pline(no_shk);
381  | 	    Strcpy(empty_shops, u.ushops);
382  | 	    u.ushops[0] = '\0';
383  | 	    return;
384  | 	}
385  | 
386  | 	eshkp = ESHK(shkp);
387  | 
388  | 	if (!inhishop(shkp)) {
389  | 	    /* dump core when referenced */
390  | 	    eshkp->bill_p = (struct bill_x *) -1000;
391  | 	    if (!index(empty_shops, *enterstring))
392  | 		pline(no_shk);
393  | 	    Strcpy(empty_shops, u.ushops);
394  | 	    u.ushops[0] = '\0';
395  | 	    return;
396  | 	}
397  | 
398  | 	eshkp->bill_p = &(eshkp->bill[0]);
399  | 
400  | 	if (!eshkp->visitct || strncmpi(eshkp->customer, plname, PL_NSIZ)) {
401  | 	    /* You seem to be new here */
402  | 	    eshkp->visitct = 0;
403  | 	    eshkp->following = 0;
404  | 	    (void) strncpy(eshkp->customer,plname,PL_NSIZ);
405  | 	    pacify_shk(shkp);
406  | 	}
407  | 
408  | 	if (shkp->msleeping || !shkp->mcanmove || eshkp->following)
409  | 	    return;	/* no dialog */
410  | 
411  | 	if (Invis) {
412  | 	    pline("%s senses your presence.", shkname(shkp));
413  | 	    verbalize("Invisible customers are not welcome!");
414  | 	    return;
415  | 	}
416  | 
417  | 	rt = rooms[*enterstring - ROOMOFFSET].rtype;
418  | 
419  | 	if (ANGRY(shkp)) {
420  | 	    verbalize("So, %s, you dare return to %s %s?!",
421  | 		      plname,
422  | 		      s_suffix(shkname(shkp)),
423  | 		      shtypes[rt - SHOPBASE].name);
424  | 	} else if (eshkp->robbed) {
425  | 	    pline("%s mutters imprecations against shoplifters.", shkname(shkp));
426  | 	} else {
427  | 	    verbalize("%s, %s!  Welcome%s to %s %s!",
428  | 		      Hello(shkp), plname,
429  | 		      eshkp->visitct++ ? " again" : "",
430  | 		      s_suffix(shkname(shkp)),
431  | 		      shtypes[rt - SHOPBASE].name);
432  | 	}
433  | 	/* can't do anything about blocking if teleported in */
434  | 	if (!inside_shop(u.ux, u.uy)) {
435  | 	    boolean should_block;
436  | 	    int cnt;
437  | 	    const char *tool;
438  | 	    struct obj *pick = carrying(PICK_AXE),
439  | 		       *mattock = carrying(DWARVISH_MATTOCK);
440  | 
441  | 	    if (pick || mattock) {
442  | 		cnt = 1;	/* so far */
443  | 		if (pick && mattock) {	/* carrying both types */
444  | 		    tool = "digging tool";
445  | 		    cnt = 2;	/* `more than 1' is all that matters */
446  | 		} else if (pick) {
447  | 		    tool = "pick-axe";
448  | 		    /* hack: `pick' already points somewhere into inventory */
449  | 		    while ((pick = pick->nobj) != 0)
450  | 			if (pick->otyp == PICK_AXE) ++cnt;
451  | 		} else {	/* assert(mattock != 0) */
452  | 		    tool = "mattock";
453  | 		    while ((mattock = mattock->nobj) != 0)
454  | 			if (mattock->otyp == DWARVISH_MATTOCK) ++cnt;
455  | 		}
456  | 		verbalize(NOTANGRY(shkp) ?
457  | 			  "Will you please leave your %s%s outside?" :
458  | 			  "Leave the %s%s outside.",
459  | 			  tool, plur(cnt));
460  | 		should_block = TRUE;
461  | #ifdef STEED
462  | 	    } else if (u.usteed) {
463  | 		verbalize(NOTANGRY(shkp) ?
464  | 			  "Will you please leave %s outside?" :
465  | 			  "Leave %s outside.", y_monnam(u.usteed));
466  | 		should_block = TRUE;
467  | #endif
468  | 	    } else {
469  | 		should_block = (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) ||
470  | 				      sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)));
471  | 	    }
472  | 	    if (should_block) (void) dochug(shkp);  /* shk gets extra move */
473  | 	}
474  | 	return;
475  | }
476  | 
477  | /*
478  |    Decide whether two unpaid items are mergable; caller is responsible for
479  |    making sure they're unpaid and the same type of object; we check the price
480  |    quoted by the shopkeeper and also that they both belong to the same shk.
481  |  */
482  | boolean same_price(obj1, obj2)
483  | struct obj *obj1, *obj2;
484  | {
485  | 	register struct monst *shkp1, *shkp2;
486  | 	register struct bill_x *bp1 = 0, *bp2 = 0;
487  | 	register boolean are_mergable = FALSE;
488  | 
489  | 	/* look up the first object by finding shk whose bill it's on */
490  | 	for (shkp1 = next_shkp(fmon, TRUE); shkp1;
491  | 		shkp1 = next_shkp(shkp1, TRUE))
492  | 	    if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0) break;
493  | 	/* second object is probably owned by same shk; if not, look harder */
494  | 	if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) {
495  | 	    shkp2 = shkp1;
496  | 	} else {
497  | 	    for (shkp2 = next_shkp(fmon, TRUE); shkp2;
498  | 		    shkp2 = next_shkp(shkp2, TRUE))
499  | 		if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0) break;
500  | 	}
501  | 
502  | 	if (!bp1 || !bp2) impossible("same_price: object wasn't on any bill!");
503  | 	else are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price);
504  | 	return are_mergable;
505  | }
506  | 
507  | /*
508  |  * Figure out how much is owed to a given shopkeeper.
509  |  * At present, we ignore any amount robbed from the shop, to avoid
510  |  * turning the `$' command into a way to discover that the current
511  |  * level is bones data which has a shk on the warpath.
512  |  */
513  | STATIC_OVL long
514  | shop_debt(eshkp)
515  | struct eshk *eshkp;
516  | {
517  | 	struct bill_x *bp;
518  | 	int ct;
519  | 	long debt = eshkp->debit;
520  | 
521  | 	for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--)
522  | 	    debt += bp->price * bp->bquan;
523  | 	return debt;
524  | }
525  | 
526  | /* called in response to the `$' command */
527  | void
528  | shopper_financial_report()
529  | {
530  | 	struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy));
531  | 	struct eshk *eshkp;
532  | 	long amt;
533  | 	int pass;
534  | 
535  | 	if (this_shkp &&
536  | 	    !(ESHK(this_shkp)->credit || shop_debt(ESHK(this_shkp)))) {
537  | 	    You("have no credit or debt in here.");
538  | 	    this_shkp = 0;	/* skip first pass */
539  | 	}
540  | 
541  | 	/* pass 0: report for the shop we're currently in, if any;
542  | 	   pass 1: report for all other shops on this level. */
543  | 	for (pass = this_shkp ? 0 : 1; pass <= 1; pass++)
544  | 	    for (shkp = next_shkp(fmon, FALSE);
545  | 		    shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
546  | 		if ((shkp != this_shkp) ^ pass) continue;
547  | 		eshkp = ESHK(shkp);
548  | 		if ((amt = eshkp->credit) != 0)
549  | 		    You("have %ld zorkmid%s credit at %s %s.",
550  | 			amt, plur(amt), s_suffix(shkname(shkp)),
551  | 			shtypes[eshkp->shoptype - SHOPBASE].name);
552  | 		else if (shkp == this_shkp)
553  | 		    You("have no credit in here.");
554  | 		if ((amt = shop_debt(eshkp)) != 0)
555  | 		    You("owe %s %ld zorkmid%s.",
556  | 			shkname(shkp), amt, plur(amt));
557  | 		else if (shkp == this_shkp)
558  | 		    You("don't owe any money here.");
559  | 	    }
560  | }
561  | 
562  | #endif /* OVL1 */
563  | #ifdef OVLB
564  | 
565  | int
566  | inhishop(mtmp)
567  | register struct monst *mtmp;
568  | {
569  | 	return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE),
570  | 		     ESHK(mtmp)->shoproom) &&
571  | 		on_level(&(ESHK(mtmp)->shoplevel), &u.uz));
572  | }
573  | 
574  | struct monst *
575  | shop_keeper(rmno)
576  | register char rmno;
577  | {
578  | 	struct monst *shkp = rmno >= ROOMOFFSET ?
579  | 				rooms[rmno - ROOMOFFSET].resident : 0;
580  | 
581  | 	if (shkp) {
582  | 	    if (NOTANGRY(shkp)) {
583  | 		if (ESHK(shkp)->surcharge) pacify_shk(shkp);
584  | 	    } else {
585  | 		if (!ESHK(shkp)->surcharge) rile_shk(shkp);
586  | 	    }
587  | 	}
588  | 	return shkp;
589  | }
590  | 
591  | boolean
592  | tended_shop(sroom)
593  | register struct mkroom *sroom;
594  | {
595  | 	register struct monst *mtmp = sroom->resident;
596  | 
597  | 	if (!mtmp)
598  | 		return(FALSE);
599  | 	else
600  | 		return((boolean)(inhishop(mtmp)));
601  | }
602  | 
603  | STATIC_OVL struct bill_x *
604  | onbill(obj, shkp, silent)
605  | register struct obj *obj;
606  | register struct monst *shkp;
607  | register boolean silent;
608  | {
609  | 	if (shkp) {
610  | 		register struct bill_x *bp = ESHK(shkp)->bill_p;
611  | 		register int ct = ESHK(shkp)->billct;
612  | 
613  | 		while (--ct >= 0)
614  | 		    if (bp->bo_id == obj->o_id) {
615  | 			if (!obj->unpaid) pline("onbill: paid obj on bill?");
616  | 			return bp;
617  | 		    } else bp++;
618  | 	}
619  | 	if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?");
620  | 	return (struct bill_x *)0;
621  | }
622  | 
623  | /* Delete the contents of the given object. */
624  | void
625  | delete_contents(obj)
626  | register struct obj *obj;
627  | {
628  | 	register struct obj *curr;
629  | 
630  | 	while ((curr = obj->cobj) != 0) {
631  | 	    obj_extract_self(curr);
632  | 	    obfree(curr, (struct obj *)0);
633  | 	}
634  | }
635  | 
636  | /* called with two args on merge */
637  | void
638  | obfree(obj, merge)
639  | register struct obj *obj, *merge;
640  | {
641  | 	register struct bill_x *bp;
642  | 	register struct bill_x *bpm;
643  | 	register struct monst *shkp;
644  | 
645  | 
646  | 	if (obj->otyp == LEASH && obj->leashmon) o_unleash(obj);
647  | 	if (obj->oclass == FOOD_CLASS) food_disappears(obj);
648  | 	if (Has_contents(obj)) delete_contents(obj);
649  | 
650  | 	shkp = 0;
651  | 	if (obj->unpaid) {
652  | 	    /* look for a shopkeeper who owns this object */
653  | 	    for (shkp = next_shkp(fmon, TRUE); shkp;
654  | 		    shkp = next_shkp(shkp, TRUE))
655  | 		if (onbill(obj, shkp, TRUE)) break;
656  | 	}
657  | 	/* sanity check, more or less */
658  | 	if (!shkp) shkp = shop_keeper(*u.ushops);
659  | 		/*
660  | 		 * Note:  `shkp = shop_keeper(*u.ushops)' used to be
661  | 		 *	  unconditional.  But obfree() is used all over
662  | 		 *	  the place, so making its behavior be dependent
663  | 		 *	  upon player location doesn't make much sense.
664  | 		 */
665  | 
666  | 	if ((bp = onbill(obj, shkp, FALSE)) != 0) {
667  | 		if(!merge){
668  | 			bp->useup = 1;
669  | 			obj->unpaid = 0;	/* only for doinvbill */
670  | 			add_to_billobjs(obj);
671  | 			return;
672  | 		}
673  | 		bpm = onbill(merge, shkp, FALSE);
674  | 		if(!bpm){
675  | 			/* this used to be a rename */
676  | 			impossible("obfree: not on bill??");
677  | 			return;
678  | 		} else {
679  | 			/* this was a merger */
680  | 			bpm->bquan += bp->bquan;
681  | 			ESHK(shkp)->billct--;
682  | #ifdef DUMB
683  | 			{
684  | 			/* DRS/NS 2.2.6 messes up -- Peter Kendell */
685  | 				int indx = ESHK(shkp)->billct;
686  | 				*bp = ESHK(shkp)->bill_p[indx];
687  | 			}
688  | #else
689  | 			*bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
690  | #endif
691  | 		}
692  | 	}
693  | 	dealloc_obj(obj);
694  | }
695  | #endif /* OVLB */
696  | #ifdef OVL3
697  | 
698  | STATIC_OVL long
699  | check_credit(tmp, shkp)
700  | long tmp;
701  | register struct monst *shkp;
702  | {
703  | 	long credit = ESHK(shkp)->credit;
704  | 
705  | 	if(credit == 0L) return(tmp);
706  | 	if(credit >= tmp) {
707  | 		pline_The("price is deducted from your credit.");
708  | 		ESHK(shkp)->credit -=tmp;
709  | 		tmp = 0L;
710  | 	} else {
711  | 		pline_The("price is partially covered by your credit.");
712  | 		ESHK(shkp)->credit = 0L;
713  | 		tmp -= credit;
714  | 	}
715  | 	return(tmp);
716  | }
717  | 
718  | STATIC_OVL void
719  | pay(tmp,shkp)
720  | long tmp;
721  | register struct monst *shkp;
722  | {
723  | 	long robbed = ESHK(shkp)->robbed;
724  | 	long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
725  | 
726  | 	u.ugold -= balance;
727  | 	shkp->mgold += balance;
728  | 	flags.botl = 1;
729  | 	if(robbed) {
730  | 		robbed -= tmp;
731  | 		if(robbed < 0) robbed = 0L;
732  | 		ESHK(shkp)->robbed = robbed;
733  | 	}
734  | }
735  | #endif /*OVL3*/
736  | #ifdef OVLB
737  | 
738  | /* return shkp to home position */
739  | void
740  | home_shk(shkp, killkops)
741  | register struct monst *shkp;
742  | register boolean killkops;
743  | {
744  | 	register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
745  | 
746  | 	(void) mnearto(shkp, x, y, TRUE);
747  | 	level.flags.has_shop = 1;
748  | 	if (killkops) {
749  | #ifdef KOPS
750  | 		kops_gone(TRUE);
751  | #else
752  | 		You_feel("vaguely apprehensive.");
753  | #endif
754  | 		pacify_guards();
755  | 	}
756  | }
757  | 
758  | STATIC_OVL boolean
759  | angry_shk_exists()
760  | {
761  | 	register struct monst *shkp;
762  | 
763  | 	for (shkp = next_shkp(fmon, FALSE);
764  | 		shkp; shkp = next_shkp(shkp->nmon, FALSE))
765  | 	    if (ANGRY(shkp)) return(TRUE);
766  | 	return(FALSE);
767  | }
768  | 
769  | /* remove previously applied surcharge from all billed items */
770  | STATIC_OVL void
771  | pacify_shk(shkp)
772  | register struct monst *shkp;
773  | {
774  | 	NOTANGRY(shkp) = TRUE;	/* make peaceful */
775  | 	if (ESHK(shkp)->surcharge) {
776  | 		register struct bill_x *bp = ESHK(shkp)->bill_p;
777  | 		register int ct = ESHK(shkp)->billct;
778  | 
779  | 		ESHK(shkp)->surcharge = FALSE;
780  | 		while (ct-- > 0) {
781  | 			register long reduction = (bp->price + 3L) / 4L;
782  | 			bp->price -= reduction;		/* undo 33% increase */
783  | 			bp++;
784  | 		}
785  | 	}
786  | }
787  | 
788  | /* add aggravation surcharge to all billed items */
789  | STATIC_OVL void
790  | rile_shk(shkp)
791  | register struct monst *shkp;
792  | {
793  | 	NOTANGRY(shkp) = FALSE;	/* make angry */
794  | 	if (!ESHK(shkp)->surcharge) {
795  | 		register struct bill_x *bp = ESHK(shkp)->bill_p;
796  | 		register int ct = ESHK(shkp)->billct;
797  | 
798  | 		ESHK(shkp)->surcharge = TRUE;
799  | 		while (ct-- > 0) {
800  | 			register long surcharge = (bp->price + 2L) / 3L;
801  | 			bp->price += surcharge;
802  | 			bp++;
803  | 		}
804  | 	}
805  | }
806  | 
807  | void
808  | make_happy_shk(shkp, silentkops)
809  | register struct monst *shkp;
810  | register boolean silentkops;
811  | {
812  | 	boolean wasmad = ANGRY(shkp);
813  | 	struct eshk *eshkp = ESHK(shkp);
814  | 
815  | 	pacify_shk(shkp);
816  | 	eshkp->following = 0;
817  | 	eshkp->robbed = 0L;
818  | 	if (!Role_if(PM_ROGUE))
819  | 		adjalign(sgn(u.ualign.type));
820  | 	if(!inhishop(shkp)) {
821  | 		char shk_nam[BUFSZ];
822  | 		boolean vanished = canseemon(shkp);
823  | 
824  | 		Strcpy(shk_nam, mon_nam(shkp));
825  | 		if (on_level(&eshkp->shoplevel, &u.uz)) {
826  | 			home_shk(shkp, FALSE);
827  | 			/* didn't disappear if shk can still be seen */
828  | 			if (canseemon(shkp)) vanished = FALSE;
829  | 		} else {
830  | 			/* if sensed, does disappear regardless whether seen */
831  | 			if (sensemon(shkp)) vanished = TRUE;
832  | 			/* arrive near shop's door */
833  | 			migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
834  | 					 MIGR_APPROX_XY, &eshkp->shd);
835  | 		}
836  | 		if (vanished)
837  | 		    pline("Satisfied, %s suddenly disappears!", shk_nam);
838  | 	} else if(wasmad)
839  | 		pline("%s calms down.", Monnam(shkp));
840  | 
841  | 	if(!angry_shk_exists()) {
842  | #ifdef KOPS
843  | 		kops_gone(silentkops);
844  | #endif
845  | 		pacify_guards();
846  | 	}
847  | }
848  | 
849  | void
850  | hot_pursuit(shkp)
851  | register struct monst *shkp;
852  | {
853  | 	if(!shkp->isshk) return;
854  | 
855  | 	rile_shk(shkp);
856  | 	ESHK(shkp)->following = 1;
857  | }
858  | 
859  | /* used when the shkp is teleported out of his shop,
860  |  * or when the player is not on a costly_spot and he
861  |  * damages something inside the shop.  these conditions
862  |  * must be checked by the calling function.
863  |  */
864  | void
865  | make_angry_shk(shkp, ox, oy)
866  | register struct monst *shkp;
867  | register xchar ox,oy;
868  | {
869  | 	xchar sx, sy;
870  | 	struct eshk *eshkp = ESHK(shkp);
871  | 
872  | 	/* all pending shop transactions are now "past due" */
873  | 	if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) {
874  | 	    eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan);
875  | 	    eshkp->robbed -= eshkp->credit;
876  | 	    if (eshkp->robbed < 0L) eshkp->robbed = 0L;
877  | 	    /* billct, debit, loan, and credit will be cleared by setpaid */
878  | 	    setpaid(shkp);
879  | 	}
880  | 
881  | 	/* If you just used a wand of teleportation to send the shk away, you
882  | 	   might not be able to see her any more.  Monnam would yield "it",
883  | 	   which makes this message look pretty silly, so temporarily restore
884  | 	   her original location during the call to Monnam. */
885  | 	sx = shkp->mx,  sy = shkp->my;
886  | 	if (cansee(ox, oy) && !cansee(sx, sy))
887  | 		shkp->mx = ox,  shkp->my = oy;
888  | 	pline("%s %s!", Monnam(shkp),
889  | 	      !ANGRY(shkp) ? "gets angry" : "is furious");
890  | 	shkp->mx = sx,  shkp->my = sy;
891  | 	hot_pursuit(shkp);
892  | }
893  | 
894  | STATIC_VAR const char no_money[] = "Moreover, you%s have no money.";
895  | STATIC_VAR const char not_enough_money[] =
896  | 			    "Besides, you don't have enough to interest %s.";
897  | 
898  | #else
899  | STATIC_VAR const char no_money[];
900  | STATIC_VAR const char not_enough_money[];
901  | #endif /*OVLB*/
902  | 
903  | #ifdef OVL3
904  | 
905  | STATIC_OVL long
906  | cheapest_item(shkp)   /* delivers the cheapest item on the list */
907  | register struct monst *shkp;
908  | {
909  | 	register int ct = ESHK(shkp)->billct;
910  | 	register struct bill_x *bp = ESHK(shkp)->bill_p;
911  | 	register long gmin = (bp->price * bp->bquan);
912  | 
913  | 	while(ct--){
914  | 		if(bp->price * bp->bquan < gmin)
915  | 			gmin = bp->price * bp->bquan;
916  | 		bp++;
917  | 	}
918  | 	return(gmin);
919  | }
920  | #endif /*OVL3*/
921  | #ifdef OVL0
922  | 
923  | int
924  | dopay()
925  | {
926  | 	register struct eshk *eshkp;
927  | 	register struct monst *shkp;
928  | 	struct monst *nxtm, *resident;
929  | 	long ltmp;
930  | 	int pass, tmp, shk_pronoun, sk = 0, seensk = 0;
931  | 	boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
932  | 
933  | 	multi = 0;
934  | 
935  | 	/* find how many shk's there are, how many are in */
936  | 	/* sight, and are you in a shop room with one.    */
937  | 	nxtm = resident = 0;
938  | 	for (shkp = next_shkp(fmon, FALSE);
939  | 		shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
940  | 	    sk++;
941  | 	    if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp;
942  | 	    if (canspotmon(shkp)) seensk++;
943  | 	    if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
944  | 		resident = shkp;
945  | 	}
946  | 
947  | 	if (nxtm) {			/* Player should always appease an */
948  | 	     shkp = nxtm;		/* irate shk standing next to them. */
949  | 	     goto proceed;
950  | 	}
951  | 
952  | 	if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) {
953  |       There("appears to be no shopkeeper here to receive your payment.");
954  | 		return(0);
955  | 	}
956  | 
957  | 	if(!seensk) {
958  | 		You_cant("see...");
959  | 		return(0);
960  | 	}
961  | 
962  | 	/* the usual case.  allow paying at a distance when */
963  | 	/* inside a tended shop.  should we change that?    */
964  | 	if(sk == 1 && resident) {
965  | 		shkp = resident;
966  | 		goto proceed;
967  | 	}
968  | 
969  | 	if (seensk == 1) {
970  | 		for (shkp = next_shkp(fmon, FALSE);
971  | 			shkp; shkp = next_shkp(shkp->nmon, FALSE))
972  | 		    if (canspotmon(shkp)) break;
973  | 		if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
974  | 		    pline("%s is not near enough to receive your payment.",
975  | 					     Monnam(shkp));
976  | 		    return(0);
977  | 		}
978  | 	} else {
979  | 		struct monst *mtmp;
980  | 		coord cc;
981  | 		int cx, cy;
982  | 
983  | 		pline("Pay whom?");
984  | 		cc.x = u.ux;
985  | 		cc.y = u.uy;
986  | 		if (getpos(&cc, TRUE, "the creature you want to pay") < 0)
987  | 		    return 0;	/* player pressed ESC */
988  | 		cx = cc.x;
989  | 		cy = cc.y;
990  | 		if(cx < 0) {
991  | 		     pline("Try again...");
992  | 		     return(0);
993  | 		}
994  | 		if(u.ux == cx && u.uy == cy) {
995  | 		     You("are generous to yourself.");
996  | 		     return(0);
997  | 		}
998  | 		mtmp = m_at(cx, cy);
999  | 		if(!mtmp) {
1000 | 		     There("is no one there to receive your payment.");
1001 | 		     return(0);
1002 | 		}
1003 | 		if(!mtmp->isshk) {
1004 | 		     pline("%s is not interested in your payment.",
1005 | 				    Monnam(mtmp));
1006 | 		     return(0);
1007 | 		}
1008 | 		if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
1009 | 		     pline("%s is too far to receive your payment.",
1010 | 				    Monnam(mtmp));
1011 | 		     return(0);
1012 | 		}
1013 | 		shkp = mtmp;
1014 | 	}
1015 | 
1016 | 	if(!shkp) {
1017 | #ifdef DEBUG
1018 | 		pline("dopay: null shkp.");
1019 | #endif
1020 | 		return(0);
1021 | 	}
1022 | proceed:
1023 | 
1024 | 	if (shkp->msleeping || !shkp->mcanmove) {
1025 | 		pline("%s %s.", Monnam(shkp),
1026 | 		      rn2(2) ? "seems to be napping" : "doesn't respond");
1027 | 		return 0;
1028 | 	}
1029 | 	eshkp = ESHK(shkp);
1030 | 	shk_pronoun = pronoun_gender(shkp);
1031 | 
1032 | 	ltmp = eshkp->robbed;
1033 | 	if(shkp != resident && NOTANGRY(shkp)) {
1034 | 		if(!ltmp)
1035 | 		    You("do not owe %s anything.", mon_nam(shkp));
1036 | 		else if(!u.ugold) {
1037 | 		    You("%shave no money.", stashed_gold ? "seem to " : "");
1038 | 		    if(stashed_gold)
1039 | 			pline("But you have some gold stashed away.");
1040 | 		} else {
1041 | 		    long ugold = u.ugold;
1042 | 
1043 | 		    if(ugold > ltmp) {
1044 | 			You("give %s the %ld gold piece%s %s asked for.",
1045 | 			    mon_nam(shkp), ltmp, plur(ltmp), he[shk_pronoun]);
1046 | 			pay(ltmp, shkp);
1047 | 		    } else {
1048 | 			You("give %s all your%s gold.", mon_nam(shkp),
1049 | 					stashed_gold ? " openly kept" : "");
1050 | 			pay(u.ugold, shkp);
1051 | 			if (stashed_gold) pline("But you have hidden gold!");
1052 | 		    }
1053 | 		    if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold))
1054 | 			pline("Unfortunately, %s doesn't look satisfied.",
1055 | 			      he[shk_pronoun]);
1056 | 		    else
1057 | 			make_happy_shk(shkp, FALSE);
1058 | 		}
1059 | 		return(1);
1060 | 	}
1061 | 
1062 | 	/* ltmp is still eshkp->robbed here */
1063 | 	if (!eshkp->billct && !eshkp->debit) {
1064 | 		if(!ltmp && NOTANGRY(shkp)) {
1065 | 		    You("do not owe %s anything.", mon_nam(shkp));
1066 | 		    if (!u.ugold)
1067 | 			pline(no_money, stashed_gold ? " seem to" : "");
1068 | 		} else if(ltmp) {
1069 | 		    pline("%s is after blood, not money!", Monnam(shkp));
1070 | 		    if(u.ugold < ltmp/2L ||
1071 | 				(u.ugold < ltmp && stashed_gold)) {
1072 | 			if (!u.ugold)
1073 | 			    pline(no_money, stashed_gold ? " seem to" : "");
1074 | 			else pline(not_enough_money, him[shk_pronoun]);
1075 | 			return(1);
1076 | 		    }
1077 | 		    pline("But since %s shop has been robbed recently,",
1078 | 			  his[shk_pronoun]);
1079 | 		    pline("you %scompensate %s for %s losses.",
1080 | 			  (u.ugold < ltmp) ? "partially " : "",
1081 | 			  mon_nam(shkp), his[shk_pronoun]);
1082 | 		    pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
1083 | 		    make_happy_shk(shkp, FALSE);
1084 | 		} else {
1085 | 		    /* shopkeeper is angry, but has not been robbed --
1086 | 		     * door broken, attacked, etc. */
1087 | 		    pline("%s is after your hide, not your money!",
1088 | 			  Monnam(shkp));
1089 | 		    if(u.ugold < 1000L) {
1090 | 			if (!u.ugold)
1091 | 			    pline(no_money, stashed_gold ? " seem to" : "");
1092 | 			else pline(not_enough_money, him[shk_pronoun]);
1093 | 			return(1);
1094 | 		    }
1095 | 		    You("try to appease %s by giving %s 1000 gold pieces.",
1096 | 			x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE),
1097 | 			him[shk_pronoun]);
1098 | 		    pay(1000L,shkp);
1099 | 		    if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
1100 | 			make_happy_shk(shkp, FALSE);
1101 | 		    else
1102 | 			pline("But %s is as angry as ever.", mon_nam(shkp));
1103 | 		}
1104 | 		return(1);
1105 | 	}
1106 | 	if(shkp != resident) {
1107 | 		impossible("dopay: not to shopkeeper?");
1108 | 		if(resident) setpaid(resident);
1109 | 		return(0);
1110 | 	}
1111 | 	/* pay debt, if any, first */
1112 | 	if(eshkp->debit) {
1113 | 		long dtmp = eshkp->debit;
1114 | 		long loan = eshkp->loan;
1115 | 		char sbuf[BUFSZ];
1116 | 
1117 | 		Sprintf(sbuf, "You owe %s %ld zorkmid%s ",
1118 | 					   shkname(shkp), dtmp, plur(dtmp));
1119 | 		if(loan) {
1120 | 		    if(loan == dtmp)
1121 | 			Strcat(sbuf, "you picked up in the store.");
1122 | 		    else Strcat(sbuf,
1123 | 			   "for gold picked up and the use of merchandise.");
1124 | 		} else Strcat(sbuf, "for the use of merchandise.");
1125 | 		pline(sbuf);
1126 | 		if (u.ugold + eshkp->credit < dtmp) {
1127 | 		    pline("But you don't%s have enough gold%s.",
1128 | 			stashed_gold ? " seem to" : "",
1129 | 			eshkp->credit ? " or credit" : "");
1130 | 		    return(1);
1131 | 		} else {
1132 | 		    if (eshkp->credit >= dtmp) {
1133 | 			eshkp->credit -= dtmp;
1134 | 			eshkp->debit = 0L;
1135 | 			eshkp->loan = 0L;
1136 | 			Your("debt is covered by your credit.");
1137 | 		    } else if (!eshkp->credit) {
1138 | 			u.ugold -= dtmp;
1139 | 			shkp->mgold += dtmp;
1140 | 			eshkp->debit = 0L;
1141 | 			eshkp->loan = 0L;
1142 | 			You("pay that debt.");
1143 | 			flags.botl = 1;
1144 | 		    } else {
1145 | 			dtmp -= eshkp->credit;
1146 | 			eshkp->credit = 0L;
1147 | 			u.ugold -= dtmp;
1148 | 			shkp->mgold += dtmp;
1149 | 			eshkp->debit = 0L;
1150 | 			eshkp->loan = 0L;
1151 | 			pline("That debt is partially offset by your credit.");
1152 | 			You("pay the remainder.");
1153 | 			flags.botl = 1;
1154 | 		    }
1155 | 		    paid = TRUE;
1156 | 		}
1157 | 	}
1158 | 	/* now check items on bill */
1159 | 	if (eshkp->billct) {
1160 | 	    register boolean itemize;
1161 | 
1162 | 	    if (!u.ugold && !eshkp->credit) {
1163 | 		You("%shave no money or credit%s.",
1164 | 				    stashed_gold ? "seem to " : "",
1165 | 				    paid ? " left" : "");
1166 | 		return(0);
1167 | 	    }
1168 | 	    if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) {
1169 | 		You("don't have enough money to buy%s the item%s you picked.",
1170 | 		    eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
1171 | 		if(stashed_gold)
1172 | 		    pline("Maybe you have some gold stashed away?");
1173 | 		return(0);
1174 | 	    }
1175 | 
1176 | 	    /* this isn't quite right; it itemizes without asking if the
1177 | 	     * single item on the bill is partly used up and partly unpaid */
1178 | 	    itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1);
1179 | 
1180 | 	    for (pass = 0; pass <= 1; pass++) {
1181 | 		tmp = 0;
1182 | 		while (tmp < eshkp->billct) {
1183 | 		    struct obj *otmp;
1184 | 		    register struct bill_x *bp = &(eshkp->bill_p[tmp]);
1185 | 
1186 | 		    /* find the object on one of the lists */
1187 | 		    if ((otmp = bp_to_obj(bp)) != 0) {
1188 | 			/* if completely used up, object quantity is stale;
1189 | 			   restoring it to its original value here avoids
1190 | 			   making the partly-used-up code more complicated */
1191 | 			if (bp->useup) otmp->quan = bp->bquan;
1192 | 		    } else {
1193 | 			impossible("Shopkeeper administration out of order.");
1194 | 			setpaid(shkp);	/* be nice to the player */
1195 | 			return 1;
1196 | 		    }
1197 | 		    if (pass == bp->useup && otmp->quan == bp->bquan) {
1198 | 			/* pay for used-up items on first pass and others
1199 | 			 * on second, so player will be stuck in the store
1200 | 			 * less often; things which are partly used up
1201 | 			 * are processed on both passes */
1202 | 			tmp++;
1203 | 		    } else {
1204 | 			switch (dopayobj(shkp, bp, &otmp, pass, itemize)) {
1205 | 			  case PAY_CANT:
1206 | 				return 1;	/*break*/
1207 | 			  case PAY_BROKE:
1208 | 				paid = TRUE;
1209 | 				goto thanks;	/*break*/
1210 | 			  case PAY_SKIP:
1211 | 				tmp++;
1212 | 				continue;	/*break*/
1213 | 			  case PAY_SOME:
1214 | 				paid = TRUE;
1215 | 				if (itemize) bot();
1216 | 				continue;	/*break*/
1217 | 			  case PAY_BUY:
1218 | 				paid = TRUE;
1219 | 				break;
1220 | 			}
1221 | 			if (itemize) bot();
1222 | 			*bp = eshkp->bill_p[--eshkp->billct];
1223 | 		    }
1224 | 		}
1225 | 	    }
1226 | 	thanks:
1227 | 	    if (!itemize)
1228 | 	        update_inventory(); /* Done in dopayobj() if itemize. */
1229 | 	}
1230 | 	if(!ANGRY(shkp) && paid)
1231 | 	    verbalize("Thank you for shopping in %s %s!",
1232 | 		s_suffix(shkname(shkp)),
1233 | 		shtypes[eshkp->shoptype - SHOPBASE].name);
1234 | 	return(1);
1235 | }
1236 | #endif /*OVL0*/
1237 | #ifdef OVL3
1238 | 
1239 | /* return 2 if used-up portion paid */
1240 | /*	  1 if paid successfully    */
1241 | /*	  0 if not enough money     */
1242 | /*	 -1 if skip this object     */
1243 | /*	 -2 if no money/credit left */
1244 | STATIC_OVL int
1245 | dopayobj(shkp, bp, obj_p, which, itemize)
1246 | register struct monst *shkp;
1247 | register struct bill_x *bp;
1248 | struct obj **obj_p;
1249 | int	which;		/* 0 => used-up item, 1 => other (unpaid or lost) */
1250 | boolean itemize;
1251 | {
1252 | 	register struct obj *obj = *obj_p;
1253 | 	long ltmp, quan, save_quan;
1254 | 	int buy;
1255 | 	boolean stashed_gold = (hidden_gold() > 0L),
1256 | 		consumed = (which == 0);
1257 | 
1258 | 	if(!obj->unpaid && !bp->useup){
1259 | 		impossible("Paid object on bill??");
1260 | 		return PAY_BUY;
1261 | 	}
1262 | 	if(itemize && u.ugold + ESHK(shkp)->credit == 0L){
1263 | 		You("%shave no money or credit left.",
1264 | 			     stashed_gold ? "seem to " : "");
1265 | 		return PAY_BROKE;
1266 | 	}
1267 | 	/* we may need to temporarily adjust the object, if part of the
1268 | 	   original quantity has been used up but part remains unpaid  */
1269 | 	save_quan = obj->quan;
1270 | 	if (consumed) {
1271 | 	    /* either completely used up (simple), or split needed */
1272 | 	    quan = bp->bquan;
1273 | 	    if (quan > obj->quan)	/* difference is amount used up */
1274 | 		quan -= obj->quan;
1275 | 	} else {
1276 | 	    /* dealing with ordinary unpaid item */
1277 | 	    quan = obj->quan;
1278 | 	}
1279 | 	obj->quan = quan;	/* to be used by doname() */
1280 | 	obj->unpaid = 0;	/* ditto */
1281 | 	ltmp = bp->price * quan;
1282 | 	buy = PAY_BUY;		/* flag; if changed then return early */
1283 | 
1284 | 	if (itemize) {
1285 | 	    char qbuf[BUFSZ];
1286 | 	    Sprintf(qbuf,"%s for %ld zorkmid%s.  Pay?", quan == 1L ?
1287 | 		    Doname2(obj) : doname(obj), ltmp, plur(ltmp));
1288 | 	    if (yn(qbuf) == 'n') {
1289 | 		buy = PAY_SKIP;		/* don't want to buy */
1290 | 	    } else if (quan < bp->bquan && !consumed) { /* partly used goods */
1291 | 		obj->quan = bp->bquan - save_quan;	/* used up amount */
1292 | 		verbalize("%s for the other %s before buying %s.",
1293 | 			  ANGRY(shkp) ? "Pay" : "Please pay", xname(obj),
1294 | 			  save_quan > 1L ? "these" : "this one");
1295 | 		buy = PAY_SKIP;		/* shk won't sell */
1296 | 	    }
1297 | 	}
1298 | 	if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) {
1299 | 	    You("don't%s have gold%s enough to pay for %s.",
1300 | 		stashed_gold ? " seem to" : "",
1301 | 		(ESHK(shkp)->credit > 0L) ? " or credit" : "",
1302 | 		doname(obj));
1303 | 	    buy = itemize ? PAY_SKIP : PAY_CANT;
1304 | 	}
1305 | 
1306 | 	if (buy != PAY_BUY) {
1307 | 	    /* restore unpaid object to original state */
1308 | 	    obj->quan = save_quan;
1309 | 	    obj->unpaid = 1;
1310 | 	    return buy;
1311 | 	}
1312 | 
1313 | 	pay(ltmp, shkp);
1314 | 	shk_names_obj(shkp, obj, "bought %s for %ld gold piece%s.%s", ltmp, "");
1315 | 	obj->quan = save_quan;		/* restore original count */
1316 | 	/* quan => amount just bought, save_quan => remaining unpaid count */
1317 | 	if (consumed) {
1318 | 	    if (quan != bp->bquan) {
1319 | 		/* eliminate used-up portion; remainder is still unpaid */
1320 | 		bp->bquan = obj->quan;
1321 | 		obj->unpaid = 1;
1322 | 		bp->useup = 0;
1323 | 		buy = PAY_SOME;
1324 | 	    } else {	/* completely used-up, so get rid of it */
1325 | 		obj_extract_self(obj);
1326 | 	     /* assert( obj == *obj_p ); */
1327 | 		dealloc_obj(obj);
1328 | 		*obj_p = 0;	/* destroy pointer to freed object */
1329 | 	    }
1330 | 	} else if (itemize)
1331 | 	    update_inventory();	/* Done just once in dopay() if !itemize. */
1332 | 	return buy;
1333 | }
1334 | #endif /*OVL3*/
1335 | #ifdef OVLB
1336 | 
1337 | static coord repo_location;	/* repossession context */
1338 | 
1339 | /* routine called after dying (or quitting) */
1340 | boolean
1341 | paybill(croaked)
1342 | boolean croaked;
1343 | {
1344 | 	register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
1345 | 	register boolean taken = FALSE;
1346 | 	register int numsk = 0;
1347 | 
1348 | 	/* this is where inventory will end up if any shk takes it */
1349 | 	repo_location.x = repo_location.y = 0;
1350 | 
1351 | 	/* give shopkeeper first crack */
1352 | 	if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) {
1353 | 	    numsk++;
1354 | 	    resident = mtmp;
1355 | 	    taken = inherits(resident, numsk, croaked);
1356 | 	}
1357 | 	for (mtmp = next_shkp(fmon, FALSE);
1358 | 		mtmp; mtmp = next_shkp(mtmp2, FALSE)) {
1359 | 	    mtmp2 = mtmp->nmon;
1360 | 	    if (mtmp != resident) {
1361 | 		/* for bones: we don't want a shopless shk around */
1362 | 		if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz))
1363 | 			mongone(mtmp);
1364 | 		else {
1365 | 		    numsk++;
1366 | 		    taken |= inherits(mtmp, numsk, croaked);
1367 | 		}
1368 | 	    }
1369 | 	}
1370 | 	if(numsk == 0) return(FALSE);
1371 | 	return(taken);
1372 | }
1373 | 
1374 | STATIC_OVL boolean
1375 | inherits(shkp, numsk, croaked)
1376 | struct monst *shkp;
1377 | int numsk;
1378 | boolean croaked;
1379 | {
1380 | 	long loss = 0L;
1381 | 	struct eshk *eshkp = ESHK(shkp);
1382 | 	boolean take = FALSE, taken = FALSE;
1383 | 	int roomno = *u.ushops;
1384 | 
1385 | 	/* the simplifying principle is that first-come */
1386 | 	/* already took everything you had.		*/
1387 | 	if(numsk > 1) {
1388 | 	    if(cansee(shkp->mx, shkp->my) && croaked)
1389 | 		pline("%s %slooks at your corpse%s%s", Monnam(shkp),
1390 | 		     (shkp->msleeping || !shkp->mcanmove) ?
1391 | 				   "wakes up, " : "",
1392 | 		     !rn2(2) ? (shkp->female ? ", shakes her head," :
1393 | 				 ", shakes his head,") : "",
1394 | 		     !inhishop(shkp) ? " and disappears. " : " and sighs.");
1395 | 	    taken = (roomno == eshkp->shoproom);
1396 | 	    goto skip;
1397 | 	}
1398 | 
1399 | 	/* get one case out of the way: you die in the shop, the */
1400 | 	/* shopkeeper is peaceful, nothing stolen, nothing owed. */
1401 | 	if(roomno == eshkp->shoproom && inhishop(shkp) &&
1402 | 	    !eshkp->billct && !eshkp->robbed && !eshkp->debit &&
1403 | 	     NOTANGRY(shkp) && !eshkp->following) {
1404 | 		if (invent)
1405 | 			pline("%s gratefully inherits all your possessions.",
1406 | 				shkname(shkp));
1407 | 		set_repo_loc(eshkp);
1408 | 		goto clear;
1409 | 	}
1410 | 
1411 | 	if (eshkp->billct || eshkp->debit || eshkp->robbed) {
1412 | 		if (roomno == eshkp->shoproom && inhishop(shkp))
1413 | 		    loss = addupbill(shkp) + eshkp->debit;
1414 | 		if (loss < eshkp->robbed) loss = eshkp->robbed;
1415 | 		take = TRUE;
1416 | 	}
1417 | 
1418 | 	if (eshkp->following || ANGRY(shkp) || take) {
1419 | 		if (!invent && !u.ugold) goto skip;
1420 | 
1421 | 		if (loss > u.ugold || !loss || roomno == eshkp->shoproom) {
1422 | 			eshkp->robbed -= u.ugold;
1423 | 			if (eshkp->robbed < 0L) eshkp->robbed = 0L;
1424 | 			shkp->mgold += u.ugold;
1425 | 			u.ugold = 0L;
1426 | 			flags.botl = 1;
1427 | 			pline("%s %s%stakes all your possessions.",
1428 | 			      shkname(shkp),
1429 | 			      (shkp->msleeping || !shkp->mcanmove) ?
1430 | 					"wakes up and " : "",
1431 | 			      (distu(shkp->mx, shkp->my) > 2) ?
1432 | 					"comes and " : "");
1433 | 			taken = TRUE;
1434 | 			/* where to put player's invent (after disclosure) */
1435 | 			set_repo_loc(eshkp);
1436 | 		} else {
1437 | 			shkp->mgold += loss;
1438 | 			u.ugold -= loss;
1439 | 			flags.botl = 1;
1440 | 			pline("%s %sand takes %ld zorkmid%s %sowed %s.",
1441 | 			      Monnam(shkp),
1442 | 			      (shkp->msleeping || !shkp->mcanmove) ?
1443 | 					"wakes up " : "comes ",
1444 | 			      loss, plur(loss),
1445 | 			      strncmp(eshkp->customer, plname, PL_NSIZ) ?
1446 | 					"" : "you ",
1447 | 			      shkp->female ? "her" : "him");
1448 | 			/* shopkeeper has now been paid in full */
1449 | 			pacify_shk(shkp);
1450 | 			eshkp->following = 0;
1451 | 			eshkp->robbed = 0L;
1452 | 		}
1453 | skip:
1454 | 		/* in case we create bones */
1455 | 		shkp->msleeping = 0;
1456 | 		if (!inhishop(shkp))
1457 | 			home_shk(shkp, FALSE);
1458 | 	}
1459 | clear:
1460 | 	setpaid(shkp);
1461 | 	return(taken);
1462 | }
1463 | 
1464 | STATIC_OVL void
1465 | set_repo_loc(eshkp)
1466 | struct eshk *eshkp;
1467 | {
1468 | 	register xchar ox, oy;
1469 | 
1470 | 	/* if you're not in this shk's shop room, or if you're in its doorway
1471 | 	    or entry spot, then your gear gets dumped all the way inside */
1472 | 	if (*u.ushops != eshkp->shoproom ||
1473 | 		IS_DOOR(levl[u.ux][u.uy].typ) ||
1474 | 		(u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) {
1475 | 	    /* shk.x,shk.y is the position immediately in
1476 | 	     * front of the door -- move in one more space
1477 | 	     */
1478 | 	    ox = eshkp->shk.x;
1479 | 	    oy = eshkp->shk.y;
1480 | 	    ox += sgn(ox - eshkp->shd.x);
1481 | 	    oy += sgn(oy - eshkp->shd.y);
1482 | 	} else {		/* already inside this shk's shop */
1483 | 	    ox = u.ux;
1484 | 	    oy = u.uy;
1485 | 	}
1486 | 	/* finish_paybill will deposit invent here */
1487 | 	repo_location.x = ox;
1488 | 	repo_location.y = oy;
1489 | }
1490 | 
1491 | /* called at game exit, after inventory disclosure but before making bones */
1492 | void finish_paybill()
1493 | {
1494 | 	register struct obj *otmp;
1495 | 	int ox = repo_location.x,
1496 | 	    oy = repo_location.y;
1497 | 
1498 | #if 0		/* don't bother */
1499 | 	if (ox == 0 && oy == 0) impossible("finish_paybill: no location");
1500 | #endif
1501 | 	/* transfer all of the character's inventory to the shop floor */
1502 | 	while ((otmp = invent) != 0) {
1503 | 	    otmp->owornmask = 0L;	/* perhaps we should call setnotworn? */
1504 | 	    otmp->lamplit = 0;		/* avoid "goes out" msg from freeinv */
1505 | 	    if (rn2(5)) curse(otmp);	/* normal bones treatment for invent */
1506 | 	    obj_extract_self(otmp);
1507 | 	    place_object(otmp, ox, oy);
1508 | 	}
1509 | }
1510 | 
1511 | /* find obj on one of the lists */
1512 | STATIC_OVL struct obj *
1513 | bp_to_obj(bp)
1514 | register struct bill_x *bp;
1515 | {
1516 | 	register struct obj *obj;
1517 | 	register unsigned int id = bp->bo_id;
1518 | 
1519 | 	if(bp->useup)
1520 | 		obj = o_on(id, billobjs);
1521 | 	else
1522 | 		obj = find_oid(id);
1523 | 	return obj;
1524 | }
1525 | 
1526 | /*
1527 |  * Look for o_id on all lists but billobj.  Return obj or NULL if not found.
1528 |  * Its OK for restore_timers() to call this function, there should not
1529 |  * be any timeouts on the billobjs chain.
1530 |  */
1531 | struct obj *
1532 | find_oid(id)
1533 | unsigned id;
1534 | {
1535 | 	struct obj *obj;
1536 | 	struct monst *mon, *mmtmp[3];
1537 | 	int i;
1538 | 
1539 | 	/* first check various obj lists directly */
1540 | 	if ((obj = o_on(id, invent)) != 0) return obj;
1541 | 	if ((obj = o_on(id, fobj)) != 0) return obj;
1542 | 	if ((obj = o_on(id, level.buriedobjlist)) != 0) return obj;
1543 | 	if ((obj = o_on(id, migrating_objs)) != 0) return obj;
1544 | 
1545 | 	/* not found yet; check inventory for members of various monst lists */
1546 | 	mmtmp[0] = fmon;
1547 | 	mmtmp[1] = migrating_mons;
1548 | 	mmtmp[2] = mydogs;		/* for use during level changes */
1549 | 	for (i = 0; i < 3; i++)
1550 | 	    for (mon = mmtmp[i]; mon; mon = mon->nmon)
1551 | 		if ((obj = o_on(id, mon->minvent)) != 0) return obj;
1552 | 
1553 | 	/* not found at all */
1554 | 	return (struct obj *)0;
1555 | }
1556 | #endif /*OVLB*/
1557 | #ifdef OVL3
1558 | 
1559 | /* calculate the value that the shk will charge for [one of] an object */
1560 | STATIC_OVL long
1561 | get_cost(obj, shkp)
1562 | register struct obj *obj;
1563 | register struct monst *shkp;	/* if angry, impose a surcharge */
1564 | {
1565 | 	register long tmp = getprice(obj, FALSE);
1566 | 
1567 | 	if (!tmp) tmp = 5L;
1568 | 	/* shopkeeper may notice if the player isn't very knowledgeable -
1569 | 	   especially when gem prices are concerned */
1570 | 	if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
1571 | 		if (obj->oclass == GEM_CLASS) {
1572 | 			/* all gems are priced high - real or not */
1573 | 			if (objects[obj->otyp].oc_material == GLASS) {
1574 | 			    int i = obj->otyp - LUCKSTONE + JADE + 1;
1575 | 			    /* real gem's cost (worthless gems come
1576 | 			       after jade but before luckstone) */
1577 | 			    tmp = (long) objects[i].oc_cost;
1578 | 			}
1579 | 		} else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
1580 | 			tmp += tmp / 3L;
1581 | 	}
1582 | #ifdef TOURIST
1583 | 	if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
1584 | 	    || (uarmu && !uarm && !uarmc))	/* touristy shirt visible */
1585 | 		tmp += tmp / 3L;
1586 | 	else
1587 | #endif
1588 | 	if (uarmh && uarmh->otyp == DUNCE_CAP)
1589 | 		tmp += tmp / 3L;
1590 | 
1591 | 	if (ACURR(A_CHA) > 18)		tmp /= 2L;
1592 | 	else if (ACURR(A_CHA) > 17)	tmp -= tmp / 3L;
1593 | 	else if (ACURR(A_CHA) > 15)	tmp -= tmp / 4L;
1594 | 	else if (ACURR(A_CHA) < 6)	tmp *= 2L;
1595 | 	else if (ACURR(A_CHA) < 8)	tmp += tmp / 2L;
1596 | 	else if (ACURR(A_CHA) < 11)	tmp += tmp / 3L;
1597 | 	if (tmp <= 0L) tmp = 1L;
1598 | 	else if (obj->oartifact) tmp *= 4L;
1599 | 	/* anger surcharge should match rile_shk's */
1600 | 	if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
1601 | 	return tmp;
1602 | }
1603 | #endif /*OVL3*/
1604 | #ifdef OVLB
1605 | 
1606 | /* returns the price of a container's content.  the price
1607 |  * of the "top" container is added in the calling functions.
1608 |  * a different price quoted for selling as vs. buying.
1609 |  */
1610 | long
1611 | contained_cost(obj, shkp, price, usell)
1612 | register struct obj *obj;
1613 | register struct monst *shkp;
1614 | long price;
1615 | register boolean usell;
1616 | {
1617 | 	register struct obj *otmp;
1618 | 
1619 | 	/* the price of contained objects */
1620 | 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
1621 | 	    if (otmp->oclass == GOLD_CLASS) continue;
1622 | 	    /* the "top" container is evaluated by caller */
1623 | 	    if (usell) {
1624 | 		if (saleable(shkp, otmp) &&
1625 | 			!otmp->unpaid && otmp->oclass != BALL_CLASS &&
1626 | 			!(otmp->oclass == FOOD_CLASS && otmp->oeaten) &&
1627 | 			!(Is_candle(otmp) && otmp->age <
1628 | 				20L * (long)objects[otmp->otyp].oc_cost))
1629 | 		    price += set_cost(otmp, shkp);
1630 | 	    } else if (!otmp->no_charge) {
1631 | 		    price += get_cost(otmp, shkp) * otmp->quan;
1632 | 	    }
1633 | 
1634 | 	    if (Has_contents(otmp))
1635 | 		    price += contained_cost(otmp, shkp, price, usell);
1636 | 	}
1637 | 
1638 | 	return(price);
1639 | }
1640 | 
1641 | long
1642 | contained_gold(obj)
1643 | register struct obj *obj;
1644 | {
1645 | 	register struct obj *otmp;
1646 | 	register long value = 0L;
1647 | 
1648 | 	/* accumulate contained gold */
1649 | 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
1650 | 	    if (otmp->oclass == GOLD_CLASS)
1651 | 		value += otmp->quan;
1652 | 	    else if (Has_contents(otmp))
1653 | 		value += contained_gold(otmp);
1654 | 
1655 | 	return(value);
1656 | }
1657 | 
1658 | STATIC_OVL void
1659 | dropped_container(obj, shkp, sale)
1660 | register struct obj *obj;
1661 | register struct monst *shkp;
1662 | register boolean sale;
1663 | {
1664 | 	register struct obj *otmp;
1665 | 
1666 | 	/* the "top" container is treated in the calling fn */
1667 | 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
1668 | 	    if (otmp->oclass == GOLD_CLASS) continue;
1669 | 
1670 | 	    if (!otmp->unpaid && !(sale && saleable(shkp, otmp)))
1671 | 		otmp->no_charge = 1;
1672 | 
1673 | 	    if (Has_contents(otmp))
1674 | 		dropped_container(otmp, shkp, sale);
1675 | 	}
1676 | }
1677 | 
1678 | void
1679 | picked_container(obj)
1680 | register struct obj *obj;
1681 | {
1682 | 	register struct obj *otmp;
1683 | 
1684 | 	/* the "top" container is treated in the calling fn */
1685 | 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
1686 | 	    if (otmp->oclass == GOLD_CLASS) continue;
1687 | 
1688 | 	    if (otmp->no_charge)
1689 | 		otmp->no_charge = 0;
1690 | 
1691 | 	    if (Has_contents(otmp))
1692 | 		picked_container(otmp);
1693 | 	}
1694 | }
1695 | #endif /*OVLB*/
1696 | #ifdef OVL3
1697 | 
1698 | /* calculate how much the shk will pay when buying [all of] an object */
1699 | STATIC_OVL long
1700 | set_cost(obj, shkp)
1701 | register struct obj *obj;
1702 | register struct monst *shkp;
1703 | {
1704 | 	long tmp = getprice(obj, TRUE) * obj->quan;
1705 | 
1706 | #ifdef TOURIST
1707 | 	if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
1708 | 	    || (uarmu && !uarm && !uarmc))	/* touristy shirt visible */
1709 | 		tmp /= 3L;
1710 | 	else
1711 | #endif
1712 | 	if (uarmh && uarmh->otyp == DUNCE_CAP)
1713 | 		tmp /= 3L;
1714 | 	else
1715 | 		tmp /= 2L;
1716 | 
1717 | 	/* shopkeeper may notice if the player isn't very knowledgeable -
1718 | 	   especially when gem prices are concerned */
1719 | 	if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
1720 | 		if (obj->oclass == GEM_CLASS) {
1721 | 			/* different shop keepers give different prices */
1722 | 			if (objects[obj->otyp].oc_material == GEMSTONE ||
1723 | 			    objects[obj->otyp].oc_material == GLASS) {
1724 | 				tmp = (obj->otyp % (6 - shkp->m_id % 3));
1725 | 				tmp = (tmp + 3) * obj->quan;
1726 | 			}
1727 | 		} else if (tmp > 1L && !rn2(4))
1728 | 			tmp -= tmp / 4L;
1729 | 	}
1730 | 	return tmp;
1731 | }
1732 | 
1733 | #endif /*OVL3*/
1734 | #ifdef OVLB
1735 | 
1736 | /* called from doinv(invent.c) for inventory of unpaid objects */
1737 | long
1738 | unpaid_cost(unp_obj)
1739 | register struct obj *unp_obj;	/* known to be unpaid */
1740 | {
1741 | 	register struct bill_x *bp = (struct bill_x *)0;
1742 | 	register struct monst *shkp;
1743 | 
1744 | 	for(shkp = next_shkp(fmon, TRUE); shkp;
1745 | 					shkp = next_shkp(shkp->nmon, TRUE))
1746 | 	    if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break;
1747 | 
1748 | 	/* onbill() gave no message if unexpected problem occurred */
1749 | 	if(!bp) impossible("unpaid_cost: object wasn't on any bill!");
1750 | 
1751 | 	return bp ? unp_obj->quan * bp->price : 0L;
1752 | }
1753 | 
1754 | STATIC_OVL void
1755 | add_one_tobill(obj, dummy)
1756 | register struct obj *obj;
1757 | register boolean dummy;
1758 | {
1759 | 	register struct monst *shkp;
1760 | 	register struct bill_x *bp;
1761 | 	register int bct;
1762 | 	register char roomno = *u.ushops;
1763 | 
1764 | 	if (!roomno) return;
1765 | 	if (!(shkp = shop_keeper(roomno))) return;
1766 | 	if (!inhishop(shkp)) return;
1767 | 
1768 | 	if (onbill(obj, shkp, FALSE) || /* perhaps thrown away earlier */
1769 | 		    (obj->oclass == FOOD_CLASS && obj->oeaten))
1770 | 		return;
1771 | 
1772 | 	if (ESHK(shkp)->billct == BILLSZ) {
1773 | 		You("got that for free!");
1774 | 		return;
1775 | 	}
1776 | 
1777 | 	/* To recognize objects the shopkeeper is not interested in. -dgk
1778 | 	 */
1779 | 	if (obj->no_charge) {
1780 | 		obj->no_charge = 0;
1781 | 		return;
1782 | 	}
1783 | 
1784 | 	bct = ESHK(shkp)->billct;
1785 | 	bp = &(ESHK(shkp)->bill_p[bct]);
1786 | 	bp->bo_id = obj->o_id;
1787 | 	bp->bquan = obj->quan;
1788 | 	if(dummy) {		  /* a dummy object must be inserted into  */
1789 | 	    bp->useup = 1;	  /* the billobjs chain here.  crucial for */
1790 | 	    add_to_billobjs(obj); /* eating floorfood in shop.  see eat.c  */
1791 | 	} else	bp->useup = 0;
1792 | 	bp->price = get_cost(obj, shkp);
1793 | 	ESHK(shkp)->billct++;
1794 | 	obj->unpaid = 1;
1795 | }
1796 | 
1797 | STATIC_OVL void
1798 | add_to_billobjs(obj)
1799 |     struct obj *obj;
1800 | {
1801 |     if (obj->where != OBJ_FREE)
1802 | 	panic("add_to_billobjs: obj not free");
1803 |     if (obj->timed)
1804 | 	panic("add_to_billobjs: obj is timed");
1805 | 
1806 |     obj->nobj = billobjs;
1807 |     billobjs = obj;
1808 |     obj->where = OBJ_ONBILL;
1809 | }
1810 | 
1811 | /* recursive billing of objects within containers. */
1812 | STATIC_OVL void
1813 | bill_box_content(obj, ininv, dummy, shkp)
1814 | register struct obj *obj;
1815 | register boolean ininv, dummy;
1816 | register struct monst *shkp;
1817 | {
1818 | 	register struct obj *otmp;
1819 | 
1820 | 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
1821 | 		if (otmp->oclass == GOLD_CLASS) continue;
1822 | 
1823 | 		/* the "top" box is added in addtobill() */
1824 | 		if (!otmp->no_charge)
1825 | 		    add_one_tobill(otmp, dummy);
1826 | 		if (Has_contents(otmp))
1827 | 		    bill_box_content(otmp, ininv, dummy, shkp);
1828 | 	}
1829 | 
1830 | }
1831 | 
1832 | /* shopkeeper tells you what you bought or sold, sometimes partly IDing it */
1833 | STATIC_OVL void
1834 | shk_names_obj(shkp, obj, fmt, amt, arg)
1835 | struct monst *shkp;
1836 | struct obj *obj;
1837 | const char *fmt;	/* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */
1838 | long amt;
1839 | const char *arg;
1840 | {
1841 | 	char *obj_name, fmtbuf[BUFSZ];
1842 | 	boolean was_unknown = !obj->dknown;
1843 | 
1844 | 	obj->dknown = TRUE;
1845 | 	/* Use real name for ordinary weapons/armor, and spell-less
1846 | 	 * scrolls/books (that is, blank and mail), but only if the
1847 | 	 * object is within the shk's area of interest/expertise.
1848 | 	 */
1849 | 	if (!objects[obj->otyp].oc_magic && saleable(shkp, obj) &&
1850 | 	    (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS ||
1851 | 	     obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS ||
1852 | 	     obj->otyp == MIRROR)) {
1853 | 	    was_unknown |= !objects[obj->otyp].oc_name_known;
1854 | 	    makeknown(obj->otyp);
1855 | 	}
1856 | 	obj_name = doname(obj);
1857 | 	/* Use an alternate message when extra information is being provided */
1858 | 	if (was_unknown) {
1859 | 	    Sprintf(fmtbuf, "%%s; you %s", fmt);
1860 | 	    obj_name[0] = highc(obj_name[0]);
1861 | 	    pline(fmtbuf, obj_name, (obj->quan > 1) ? "them" : "it",
1862 | 		  amt, plur(amt), arg);
1863 | 	} else {
1864 | 	    You(fmt, obj_name, amt, plur(amt), arg);
1865 | 	}
1866 | }
1867 | 
1868 | void
1869 | addtobill(obj, ininv, dummy, silent)
1870 | register struct obj *obj;
1871 | register boolean ininv, dummy, silent;
1872 | {
1873 | 	register struct monst *shkp;
1874 | 	register char roomno = *u.ushops;
1875 | 	long ltmp = 0L, cltmp = 0L, gltmp = 0L;
1876 | 	register boolean container = Has_contents(obj);
1877 | 
1878 | 	if(!*u.ushops) return;
1879 | 
1880 | 	if(!(shkp = shop_keeper(roomno))) return;
1881 | 
1882 | 	if(!inhishop(shkp)) return;
1883 | 
1884 | 	if(/* perhaps we threw it away earlier */
1885 | 		 onbill(obj, shkp, FALSE) ||
1886 | 		 (obj->oclass == FOOD_CLASS && obj->oeaten)
1887 | 	      ) return;
1888 | 
1889 | 	if(ESHK(shkp)->billct == BILLSZ) {
1890 | 		You("got that for free!");
1891 | 		return;
1892 | 	}
1893 | 
1894 | 	if(obj->oclass == GOLD_CLASS) {
1895 | 		costly_gold(obj->ox, obj->oy, obj->quan);
1896 | 		return;
1897 | 	}
1898 | 
1899 | 	if(!obj->no_charge)
1900 | 	    ltmp = get_cost(obj, shkp);
1901 | 
1902 | 	if (obj->no_charge && !container) {
1903 | 		obj->no_charge = 0;
1904 | 		return;
1905 | 	}
1906 | 
1907 | 	if(container) {
1908 | 	    if(obj->cobj == (struct obj *)0) {
1909 | 		if(obj->no_charge) {
1910 | 		    obj->no_charge = 0;
1911 | 		    return;
1912 | 		} else {
1913 | 		    add_one_tobill(obj, dummy);
1914 | 		    goto speak;
1915 | 		}
1916 | 	    } else {
1917 | 		cltmp += contained_cost(obj, shkp, cltmp, FALSE);
1918 | 		gltmp += contained_gold(obj);
1919 | 	    }
1920 | 
1921 | 	    if(ltmp) add_one_tobill(obj, dummy);
1922 | 	    if(cltmp) bill_box_content(obj, ininv, dummy, shkp);
1923 | 	    picked_container(obj); /* reset contained obj->no_charge */
1924 | 
1925 | 	    ltmp += cltmp;
1926 | 
1927 | 	    if(gltmp) {
1928 | 		costly_gold(obj->ox, obj->oy, gltmp);
1929 | 		if(!ltmp) return;
1930 | 	    }
1931 | 
1932 | 	    if(obj->no_charge)
1933 | 		obj->no_charge = 0;
1934 | 
1935 | 	} else /* i.e., !container */
1936 | 	    add_one_tobill(obj, dummy);
1937 | speak:
1938 | 	if (shkp->mcanmove && !shkp->msleeping && !silent) {
1939 | 	    char buf[BUFSZ];
1940 | 
1941 | 	    if(!ltmp) {
1942 | 		pline("%s has no interest in %s.", Monnam(shkp),
1943 | 					     the(xname(obj)));
1944 | 		return;
1945 | 	    }
1946 | 	    Strcpy(buf, "\"For you, ");
1947 | 	    if (ANGRY(shkp)) Strcat(buf, "scum ");
1948 | 	    else {
1949 | 		static const char *honored[5] = {
1950 | 		  "good", "honored", "most gracious", "esteemed",
1951 | 		  "most renowned and sacred"
1952 | 		};
1953 | 		Strcat(buf, honored[rn2(4) + u.uevent.udemigod]);
1954 | 		if (!is_human(youmonst.data)) Strcat(buf, " creature");
1955 | 		else
1956 | 		    Strcat(buf, (flags.female) ? " lady" : " sir");
1957 | 	    }
1958 | 	    if(ininv) {
1959 | 		long quan = obj->quan;
1960 | 		obj->quan = 1L; /* fool xname() into giving singular */
1961 | 		pline("%s; only %ld %s %s.\"", buf, ltmp,
1962 | 			(quan > 1L) ? "per" : "for this", xname(obj));
1963 | 		obj->quan = quan;
1964 | 	    } else
1965 | 		pline("%s will cost you %ld zorkmid%s%s.",
1966 | 			The(xname(obj)), ltmp, plur(ltmp),
1967 | 			(obj->quan > 1L) ? " each" : "");
1968 | 	} else if(!silent) {
1969 | 	    if(ltmp) pline_The("list price of %s is %ld zorkmid%s%s.",
1970 | 				   the(xname(obj)), ltmp, plur(ltmp),
1971 | 				   (obj->quan > 1L) ? " each" : "");
1972 | 	    else pline("%s does not notice.", Monnam(shkp));
1973 | 	}
1974 | }
1975 | 
1976 | void
1977 | splitbill(obj, otmp)
1978 | register struct obj *obj, *otmp;
1979 | {
1980 | 	/* otmp has been split off from obj */
1981 | 	register struct bill_x *bp;
1982 | 	register long tmp;
1983 | 	register struct monst *shkp = shop_keeper(*u.ushops);
1984 | 
1985 | 	if(!shkp || !inhishop(shkp)) {
1986 | 		impossible("splitbill: no resident shopkeeper??");
1987 | 		return;
1988 | 	}
1989 | 	bp = onbill(obj, shkp, FALSE);
1990 | 	if(!bp) {
1991 | 		impossible("splitbill: not on bill?");
1992 | 		return;
1993 | 	}
1994 | 	if(bp->bquan < otmp->quan) {
1995 | 		impossible("Negative quantity on bill??");
1996 | 	}
1997 | 	if(bp->bquan == otmp->quan) {
1998 | 		impossible("Zero quantity on bill??");
1999 | 	}
2000 | 	bp->bquan -= otmp->quan;
2001 | 
2002 | 	if(ESHK(shkp)->billct == BILLSZ) otmp->unpaid = 0;
2003 | 	else {
2004 | 		tmp = bp->price;
2005 | 		bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]);
2006 | 		bp->bo_id = otmp->o_id;
2007 | 		bp->bquan = otmp->quan;
2008 | 		bp->useup = 0;
2009 | 		bp->price = tmp;
2010 | 		ESHK(shkp)->billct++;
2011 | 	}
2012 | }
2013 | 
2014 | STATIC_OVL void
2015 | sub_one_frombill(obj, shkp)
2016 | register struct obj *obj;
2017 | register struct monst *shkp;
2018 | {
2019 | 	register struct bill_x *bp;
2020 | 
2021 | 	if((bp = onbill(obj, shkp, FALSE)) != 0) {
2022 | 		register struct obj *otmp;
2023 | 
2024 | 		obj->unpaid = 0;
2025 | 		if(bp->bquan > obj->quan){
2026 | 			otmp = newobj(0);
2027 | 			*otmp = *obj;
2028 | 			bp->bo_id = otmp->o_id = flags.ident++;
2029 | 			otmp->where = OBJ_FREE;
2030 | 			otmp->quan = (bp->bquan -= obj->quan);
2031 | 			otmp->owt = 0;	/* superfluous */
2032 | 			otmp->onamelth = 0;
2033 | 			otmp->oxlth = 0;
2034 | 			otmp->oattached = OATTACHED_NOTHING;
2035 | 			bp->useup = 1;
2036 | 			add_to_billobjs(otmp);
2037 | 			return;
2038 | 		}
2039 | 		ESHK(shkp)->billct--;
2040 | #ifdef DUMB
2041 | 		{
2042 | 		/* DRS/NS 2.2.6 messes up -- Peter Kendell */
2043 | 			int indx = ESHK(shkp)->billct;
2044 | 			*bp = ESHK(shkp)->bill_p[indx];
2045 | 		}
2046 | #else
2047 | 		*bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
2048 | #endif
2049 | 		return;
2050 | 	} else if (obj->unpaid) {
2051 | 		impossible("sub_one_frombill: unpaid object not on bill");
2052 | 		obj->unpaid = 0;
2053 | 	}
2054 | }
2055 | 
2056 | /* recursive check of unpaid objects within nested containers. */
2057 | void
2058 | subfrombill(obj, shkp)
2059 | register struct obj *obj;
2060 | register struct monst *shkp;
2061 | {
2062 | 	register struct obj *otmp;
2063 | 
2064 | 	sub_one_frombill(obj, shkp);
2065 | 
2066 | 	if (Has_contents(obj))
2067 | 	    for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2068 | 		if(otmp->oclass == GOLD_CLASS) continue;
2069 | 
2070 | 		if (Has_contents(otmp))
2071 | 		    subfrombill(otmp, shkp);
2072 | 		else
2073 | 		    sub_one_frombill(otmp, shkp);
2074 | 	    }
2075 | }
2076 | 
2077 | #endif /*OVLB*/
2078 | #ifdef OVL3
2079 | 
2080 | STATIC_OVL long
2081 | stolen_container(obj, shkp, price, ininv)
2082 | register struct obj *obj;
2083 | register struct monst *shkp;
2084 | long price;
2085 | register boolean ininv;
2086 | {
2087 | 	register struct obj *otmp;
2088 | 
2089 | 	if(ininv && obj->unpaid)
2090 | 	    price += get_cost(obj, shkp);
2091 | 	else {
2092 | 	    if(!obj->no_charge)
2093 | 		price += get_cost(obj, shkp);
2094 | 	    obj->no_charge = 0;
2095 | 	}
2096 | 
2097 | 	/* the price of contained objects, if any */
2098 | 	for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2099 | 
2100 | 	    if(otmp->oclass == GOLD_CLASS) continue;
2101 | 
2102 | 	    if (!Has_contents(otmp)) {
2103 | 		if(ininv) {
2104 | 		    if(otmp->unpaid)
2105 | 			price += get_cost(otmp, shkp);
2106 | 		} else {
2107 | 		    if(!otmp->no_charge) {
2108 | 			if(!(otmp->oclass == BALL_CLASS ||
2109 | 			    (otmp->oclass == FOOD_CLASS && otmp->oeaten) ||
2110 | 			    (Is_candle(otmp) && otmp->age <
2111 | 				  20L * (long)objects[otmp->otyp].oc_cost))
2112 | 			  ) price += get_cost(otmp, shkp);
2113 | 		    }
2114 | 		    otmp->no_charge = 0;
2115 | 		}
2116 | 	    } else
2117 | 		price += stolen_container(otmp, shkp, price, ininv);
2118 | 	}
2119 | 
2120 | 	return(price);
2121 | }
2122 | #endif /*OVL3*/
2123 | #ifdef OVLB
2124 | 
2125 | long
2126 | stolen_value(obj, x, y, peaceful, silent)
2127 | register struct obj *obj;
2128 | register xchar x, y;
2129 | register boolean peaceful, silent;
2130 | {
2131 | 	register long value = 0L, gvalue = 0L;
2132 | 	register struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
2133 | 
2134 | 	if (!shkp || !inhishop(shkp))
2135 | 	    return (0L);
2136 | 
2137 | 	if(obj->oclass == GOLD_CLASS) {
2138 | 	    gvalue += obj->quan;
2139 | 	} else if (Has_contents(obj)) {
2140 | 	    register boolean ininv = !!count_unpaid(obj->cobj);
2141 | 
2142 | 	    value += stolen_container(obj, shkp, value, ininv);
2143 | 	    if(!ininv) gvalue += contained_gold(obj);
2144 | 	} else if (!obj->no_charge && saleable(shkp, obj)) {
2145 | 	    value += get_cost(obj, shkp);
2146 | 	}
2147 | 
2148 | 	if(gvalue + value == 0L) return(0L);
2149 | 
2150 | 	value += gvalue;
2151 | 
2152 | 	if(peaceful) {
2153 | 	    value = check_credit(value, shkp);
2154 | 	    ESHK(shkp)->debit += value;
2155 | 
2156 | 	    if(!silent) {
2157 | 		if(obj->oclass == GOLD_CLASS)
2158 | 		    You("owe %s %ld zorkmids!", mon_nam(shkp), value);
2159 | 		else You("owe %s %ld zorkmids for %s!",
2160 | 			mon_nam(shkp),
2161 | 			value,
2162 | 			obj->quan > 1L ? "them" : "it");
2163 | 	    }
2164 | 	} else {
2165 | 	    ESHK(shkp)->robbed += value;
2166 | 
2167 | 	    if(!silent) {
2168 | 		if(cansee(shkp->mx, shkp->my)) {
2169 | 		    if(ESHK(shkp)->customer[0] == 0)
2170 | 			(void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ);
2171 | 		    Norep("%s booms: \"%s, you are a thief!\"",
2172 | 				Monnam(shkp), plname);
2173 | 		} else  Norep("You hear a scream, \"Thief!\"");
2174 | 	    }
2175 | 	    hot_pursuit(shkp);
2176 | 	    (void) angry_guards(FALSE);
2177 | 	}
2178 | 	return(value);
2179 | }
2180 | 
2181 | /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
2182 | static char sell_response = 'a';
2183 | static boolean sell_voluntarily = FALSE;
2184 | 
2185 | void
2186 | sellobj_state(deliberate)	/* called from dodrop(do.c) and doddrop() */
2187 | boolean deliberate;
2188 | {
2189 | 	/* If we're deliberately dropping something, there's no automatic
2190 | 	response to the shopkeeper's "want to sell" query; however, if we
2191 | 	accidentally drop anything, the shk will buy it/them without asking.
2192 | 	This retains the old pre-query risk that slippery fingers while in
2193 | 	shops entailed:  you drop it, you've lost it.
2194 | 	 */
2195 | 	sell_response = deliberate ? '\0' : 'a';
2196 | 	sell_voluntarily = deliberate;
2197 | }
2198 | 
2199 | void
2200 | sellobj(obj, x, y)
2201 | register struct obj *obj;
2202 | xchar x, y;
2203 | {
2204 | 	register struct monst *shkp;
2205 | 	register struct eshk *eshkp;
2206 | 	long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer;
2207 | 	boolean saleitem, cgold = FALSE, container = Has_contents(obj);
2208 | 	boolean isgold = (obj->oclass == GOLD_CLASS);
2209 | 
2210 | 	if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) ||
2211 | 	   !inhishop(shkp)) return;
2212 | 	if(!costly_spot(x, y))	return;
2213 | 	if(!*u.ushops) return;
2214 | 
2215 | 	if(obj->unpaid && !container && !isgold) {
2216 | 	    sub_one_frombill(obj, shkp);
2217 | 	    return;
2218 | 	}
2219 | 	if(container) {
2220 | 		/* find the price of content before subfrombill */
2221 | 		cltmp += contained_cost(obj, shkp, cltmp, TRUE);
2222 | 		/* find the value of contained gold */
2223 | 		gltmp += contained_gold(obj);
2224 | 		cgold = (gltmp > 0L);
2225 | 	}
2226 | 
2227 | 	saleitem = saleable(shkp, obj);
2228 | 	if(!isgold && !obj->unpaid && saleitem)
2229 | 	    ltmp = set_cost(obj, shkp);
2230 | 
2231 | 	offer = ltmp + cltmp;
2232 | 
2233 | 	/* get one case out of the way: nothing to sell, and no gold */
2234 | 	if(!isgold && (offer + gltmp) == 0L) {
2235 | 		register boolean unpaid = (obj->unpaid ||
2236 | 				  (container && count_unpaid(obj->cobj)));
2237 | 
2238 | 		if(container) {
2239 | 			dropped_container(obj, shkp, FALSE);
2240 | 			if(!obj->unpaid && !saleitem)
2241 | 			    obj->no_charge = 1;
2242 | 			if(obj->unpaid || count_unpaid(obj->cobj))
2243 | 			    subfrombill(obj, shkp);
2244 | 		} else obj->no_charge = 1;
2245 | 
2246 | 		if(!unpaid)
2247 | 		    pline("%s seems uninterested.", Monnam(shkp));
2248 | 		return;
2249 | 	}
2250 | 
2251 | 	/* you dropped something of your own - probably want to sell it */
2252 | 	if (shkp->msleeping || !shkp->mcanmove) {
2253 | 		if (container)
2254 | 		    dropped_container(obj, shkp, TRUE);
2255 | 		if (!obj->unpaid)
2256 | 		    obj->no_charge = 1;
2257 | 		if (!shkp->mcanmove) {
2258 | 		    if(ANGRY(shkp) && !rn2(4))
2259 | 			pline("%s utters a curse.", Monnam(shkp));
2260 | 		    else pline("%s is indisposed.", Monnam(shkp));
2261 | 		} else if(!rn2(3)) {
2262 | 		    pline("%s snores indifferently.", Monnam(shkp));
2263 | 		}
2264 | 		subfrombill(obj, shkp);
2265 | 		return;
2266 | 	}
2267 | 
2268 | 	eshkp = ESHK(shkp);
2269 | 
2270 | 	if (ANGRY(shkp)) { /* they become shop-objects, no pay */
2271 | 		pline("Thank you, scum!");
2272 | 		subfrombill(obj, shkp);
2273 | 		return;
2274 | 	}
2275 | 
2276 | 	if(eshkp->robbed) {  /* shkp is not angry? */
2277 | 		if(isgold) offer = obj->quan;
2278 | 		else if(cgold) offer += cgold;
2279 | 		if((eshkp->robbed -= offer < 0L))
2280 | 			eshkp->robbed = 0L;
2281 | 		if(offer) verbalize(
2282 |   "Thank you for your contribution to restock this recently plundered shop.");
2283 | 		subfrombill(obj, shkp);
2284 | 		return;
2285 | 	}
2286 | 
2287 | 	if(isgold || cgold) {
2288 | 		if(!cgold) gltmp = obj->quan;
2289 | 
2290 | 		if(eshkp->debit >= gltmp) {
2291 | 		    if(eshkp->loan) { /* you carry shop's gold */
2292 | 			 if(eshkp->loan >= gltmp)
2293 | 			     eshkp->loan -= gltmp;
2294 | 			 else eshkp->loan = 0L;
2295 | 		    }
2296 | 		    eshkp->debit -= gltmp;
2297 | 		    Your("debt is %spaid off.",
2298 | 				eshkp->debit ? "partially " : "");
2299 | 		} else {
2300 | 		    long delta = gltmp - eshkp->debit;
2301 | 
2302 | 		    eshkp->credit += delta;
2303 | 		    if(eshkp->debit) {
2304 | 			eshkp->debit = 0L;
2305 | 			eshkp->loan = 0L;
2306 | 			Your("debt is paid off.");
2307 | 		    }
2308 | 		    pline("%ld zorkmid%s added to your credit.",
2309 | 				delta, delta > 1L ? "s are" : " is");
2310 | 		}
2311 | 		if(offer) goto move_on;
2312 | 		else {
2313 | 		    if(!isgold) {
2314 | 			if (container)
2315 | 			    dropped_container(obj, shkp, FALSE);
2316 | 			if (!obj->unpaid && !saleitem) obj->no_charge = 1;
2317 | 			subfrombill(obj, shkp);
2318 | 		    }
2319 | 		    return;
2320 | 		}
2321 | 	}
2322 | move_on:
2323 | 	if((!saleitem && !(container && cltmp > 0L))
2324 | 	   || eshkp->billct == BILLSZ
2325 | 	   || obj->oclass == BALL_CLASS
2326 | 	   || obj->oclass == CHAIN_CLASS || offer == 0L
2327 | 	   || (obj->oclass == FOOD_CLASS && obj->oeaten)
2328 | 	   || (Is_candle(obj) &&
2329 | 		   obj->age < 20L * (long)objects[obj->otyp].oc_cost)) {
2330 | 		pline("%s seems not interested%s.", Monnam(shkp),
2331 | 			cgold ? " in the rest" : "");
2332 | 		if (container)
2333 | 		    dropped_container(obj, shkp, FALSE);
2334 | 		obj->no_charge = 1;
2335 | 		return;
2336 | 	}
2337 | 
2338 | 	if(!shkp->mgold) {
2339 | 		char c, qbuf[BUFSZ];
2340 | 		long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L);
2341 | 
2342 | 		if (!sell_voluntarily) {
2343 | 		    c = sell_response = 'y';
2344 | 		} else if (sell_response != 'n') {
2345 | 		    pline("%s cannot pay you at present.", Monnam(shkp));
2346 | 		    Sprintf(qbuf,
2347 | 			    "Will you accept %ld zorkmid%s in credit for %s?",
2348 | 			    tmpcr, plur(tmpcr), doname(obj));
2349 | 		    /* won't accept 'a' response here */
2350 | 		    c = ynq(qbuf);
2351 | 		} else		/* previously specified "quit" */
2352 | 		    c = 'n';
2353 | 
2354 | 		if (c == 'y') {
2355 | 		    shk_names_obj(shkp, obj, sell_voluntarily ?
2356 | 			    "traded %s for %ld zorkmid%s in %scredit." :
2357 | 			"relinquish %s and acquire %ld zorkmid%s in %scredit.",
2358 | 			    tmpcr,
2359 | 			    (eshkp->credit > 0L) ? "additional " : "");
2360 | 		    eshkp->credit += tmpcr;
2361 | 		    subfrombill(obj, shkp);
2362 | 		} else {
2363 | 		    if (c == 'q') sell_response = 'n';
2364 | 		    if (container)
2365 | 			dropped_container(obj, shkp, FALSE);
2366 | 		    if (!obj->unpaid) obj->no_charge = 1;
2367 | 		    subfrombill(obj, shkp);
2368 | 		}
2369 | 	} else {
2370 | 		char qbuf[BUFSZ];
2371 | 		boolean short_funds = (offer > shkp->mgold);
2372 | 
2373 | 		if (short_funds) offer = shkp->mgold;
2374 | 
2375 | 		if (!sell_response) {
2376 | 		    Sprintf(qbuf,
2377 | 			 "%s offers%s %ld gold piece%s for%s %s %s.  Sell %s?",
2378 | 			    Monnam(shkp), short_funds ? " only" : "",
2379 | 			    offer, plur(offer),
2380 | 			    (!ltmp && cltmp) ? " the contents of" : "",
2381 | 			    obj->unpaid ? "the" : "your", xname(obj),
2382 | 			    (obj->quan == 1L) ? "it" : "them");
2383 | 		} else  qbuf[0] = '\0';		/* just to pacify lint */
2384 | 
2385 | 		switch (sell_response ? sell_response : ynaq(qbuf)) {
2386 | 		 case 'q':  sell_response = 'n';
2387 | 		 case 'n':  if (container)
2388 | 				dropped_container(obj, shkp, FALSE);
2389 | 			    if (!obj->unpaid) obj->no_charge = 1;
2390 | 			    subfrombill(obj, shkp);
2391 | 			    break;
2392 | 		 case 'a':  sell_response = 'y';
2393 | 		 case 'y':  if (container)
2394 | 				dropped_container(obj, shkp, TRUE);
2395 | 			    if (!obj->unpaid && !saleitem) obj->no_charge = 1;
2396 | 			    subfrombill(obj, shkp);
2397 | 			    pay(-offer, shkp);
2398 | 			    shk_names_obj(shkp, obj, sell_voluntarily ?
2399 | 				    "sold %s for %ld gold piece%s.%s" :
2400 | 	       "relinquish %s and receive %ld gold piece%s in compensation.%s",
2401 | 				    offer, "");
2402 | 			    break;
2403 | 		 default:   impossible("invalid sell response");
2404 | 		}
2405 | 	}
2406 | }
2407 | 
2408 | int
2409 | doinvbill(mode)
2410 | int mode;		/* 0: deliver count 1: paged */
2411 | {
2412 | #ifdef	__SASC
2413 | 	void sasc_bug(struct obj *, unsigned);
2414 | #endif
2415 | 	struct monst *shkp;
2416 | 	struct eshk *eshkp;
2417 | 	struct bill_x *bp, *end_bp;
2418 | 	struct obj *obj;
2419 | 	long totused;
2420 | 	char *buf_p;
2421 | 	winid datawin;
2422 | 
2423 | 	shkp = shop_keeper(*u.ushops);
2424 | 	if (!shkp || !inhishop(shkp)) {
2425 | 	    if (mode != 0) impossible("doinvbill: no shopkeeper?");
2426 | 	    return 0;
2427 | 	}
2428 | 	eshkp = ESHK(shkp);
2429 | 
2430 | 	if (mode == 0) {
2431 | 	    /* count expended items, so that the `I' command can decide
2432 | 	       whether to include 'x' in its prompt string */
2433 | 	    int cnt = !eshkp->debit ? 0 : 1;
2434 | 
2435 | 	    for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
2436 | 		    bp < end_bp; bp++)
2437 | 		if (bp->useup ||
2438 | 			((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan))
2439 | 		    cnt++;
2440 | 	    return cnt;
2441 | 	}
2442 | 
2443 | 	datawin = create_nhwindow(NHW_MENU);
2444 | 	putstr(datawin, 0, "Unpaid articles already used up:");
2445 | 	putstr(datawin, 0, "");
2446 | 
2447 | 	totused = 0L;
2448 | 	for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
2449 | 		bp < end_bp; bp++) {
2450 | 	    obj = bp_to_obj(bp);
2451 | 	    if(!obj) {
2452 | 		impossible("Bad shopkeeper administration.");
2453 | 		goto quit;
2454 | 	    }
2455 | 	    if(bp->useup || bp->bquan > obj->quan) {
2456 | 		long oquan, uquan, thisused;
2457 | 		unsigned save_unpaid;
2458 | 
2459 | 		save_unpaid = obj->unpaid;
2460 | 		oquan = obj->quan;
2461 | 		uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
2462 | 		thisused = bp->price * uquan;
2463 | 		totused += thisused;
2464 | 		obj->quan = uquan;		/* cheat doname */
2465 | 		obj->unpaid = 0;		/* ditto */
2466 | 		/* Why 'x'?  To match `I x', more or less. */
2467 | 		buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused);
2468 | 		obj->quan = oquan;		/* restore value */
2469 | #ifdef __SASC
2470 | 				/* SAS/C 6.2 can't cope for some reason */
2471 | 		sasc_bug(obj,save_unpaid);
2472 | #else
2473 | 		obj->unpaid = save_unpaid;
2474 | #endif
2475 | 		putstr(datawin, 0, buf_p);
2476 | 	    }
2477 | 	}
2478 | 	if (eshkp->debit) {
2479 | 	    /* additional shop debt which has no itemization available */
2480 | 	    if (totused) putstr(datawin, 0, "");
2481 | 	    totused += eshkp->debit;
2482 | 	    buf_p = xprname((struct obj *)0,
2483 | 			    "usage charges and/or other fees",
2484 | 			    GOLD_SYM, FALSE, eshkp->debit);
2485 | 	    putstr(datawin, 0, buf_p);
2486 | 	}
2487 | 	buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused);
2488 | 	putstr(datawin, 0, "");
2489 | 	putstr(datawin, 0, buf_p);
2490 | 	display_nhwindow(datawin, FALSE);
2491 |     quit:
2492 | 	destroy_nhwindow(datawin);
2493 | 	return(0);
2494 | }
2495 | 
2496 | #define HUNGRY	2
2497 | 
2498 | STATIC_OVL long
2499 | getprice(obj, shk_buying)
2500 | register struct obj *obj;
2501 | boolean shk_buying;
2502 | {
2503 | 	register long tmp = (long) objects[obj->otyp].oc_cost;
2504 | 
2505 | 	switch(obj->oclass) {
2506 | 	case FOOD_CLASS:
2507 | 		/* simpler hunger check, (2-4)*cost */
2508 | 		if (u.uhs >= HUNGRY && !shk_buying) tmp *= (long) u.uhs;
2509 | 		if (obj->oeaten) tmp = 0L;
2510 | 		break;
2511 | 	case WAND_CLASS:
2512 | 		if (obj->spe == -1) tmp = 0L;
2513 | 		break;
2514 | 	case POTION_CLASS:
2515 | 		if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
2516 | 			tmp = 0L;
2517 | 		break;
2518 | 	case ARMOR_CLASS:
2519 | 	case WEAPON_CLASS:
2520 | 		if (obj->spe > 0) tmp += 10L * (long) obj->spe;
2521 | 		break;
2522 | 	case TOOL_CLASS:
2523 | 		if (Is_candle(obj) &&
2524 | 			obj->age < 20L * (long)objects[obj->otyp].oc_cost)
2525 | 		    tmp /= 2L;
2526 | 		break;
2527 | 	}
2528 | 	if (obj->oartifact) tmp *= 25L;
2529 | 	return tmp;
2530 | }
2531 | 
2532 | /* shk catches thrown pick-axe */
2533 | int
2534 | shkcatch(obj, x, y)
2535 | register struct obj *obj;
2536 | register xchar x, y;
2537 | {
2538 | 	register struct monst *shkp;
2539 | 
2540 | 	if (!(shkp = shop_keeper(inside_shop(x, y))) ||
2541 | 	    !inhishop(shkp)) return(0);
2542 | 
2543 | 	if (shkp->mcanmove && !shkp->msleeping &&
2544 | 	    (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy)) &&
2545 | 	    dist2(shkp->mx, shkp->my, x, y) < 3 &&
2546 | 	    /* if it is the shk's pos, you hit and anger him */
2547 | 	    (shkp->mx != x || shkp->my != y)) {
2548 | 		if (mnearto(shkp, x, y, TRUE))
2549 | 		    verbalize("Out of my way, scum!");
2550 | 		if (cansee(x, y)) {
2551 | 		    pline("%s nimbly catches %s.",
2552 | 			  Monnam(shkp), the(xname(obj)));
2553 | 		    if (!canspotmon(shkp))
2554 | 			map_invisible(x, y);
2555 | 		    delay_output();
2556 | 		    mark_synch();
2557 | 		}
2558 | 		subfrombill(obj, shkp);
2559 | 		(void) mpickobj(shkp, obj);
2560 | 		return(1);
2561 | 	}
2562 | 	return(0);
2563 | }
2564 | 
2565 | void
2566 | add_damage(x, y, cost)
2567 | register xchar x, y;
2568 | long cost;
2569 | {
2570 | 	struct damage *tmp_dam;
2571 | 	char *shops;
2572 | 
2573 | 	if (IS_DOOR(levl[x][y].typ)) {
2574 | 	    struct monst *mtmp;
2575 | 
2576 | 	    /* Don't schedule for repair unless it's a real shop entrance */
2577 | 	    for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++)
2578 | 		if ((mtmp = shop_keeper(*shops)) != 0 &&
2579 | 			x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y)
2580 | 		    break;
2581 | 	    if (!*shops) return;
2582 | 	}
2583 | 	for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next)
2584 | 	    if (tmp_dam->place.x == x && tmp_dam->place.y == y) {
2585 | 		tmp_dam->cost += cost;
2586 | 		return;
2587 | 	    }
2588 | 	tmp_dam = (struct damage *)alloc((unsigned)sizeof(struct damage));
2589 | 	tmp_dam->when = monstermoves;
2590 | 	tmp_dam->place.x = x;
2591 | 	tmp_dam->place.y = y;
2592 | 	tmp_dam->cost = cost;
2593 | 	tmp_dam->typ = levl[x][y].typ;
2594 | 	tmp_dam->next = level.damagelist;
2595 | 	level.damagelist = tmp_dam;
2596 | 	/* If player saw damage, display as a wall forever */
2597 | 	if (cansee(x, y))
2598 | 	    levl[x][y].seenv = SVALL;
2599 | }
2600 | 
2601 | #endif /*OVLB*/
2602 | #ifdef OVL0
2603 | 
2604 | /*
2605 |  * Do something about damage. Either (!croaked) try to repair it, or
2606 |  * (croaked) just discard damage structs for non-shared locations, since
2607 |  * they'll never get repaired. Assume that shared locations will get
2608 |  * repaired eventually by the other shopkeeper(s). This might be an erroneous
2609 |  * assumption (they might all be dead too), but we have no reasonable way of
2610 |  * telling that.
2611 |  */
2612 | STATIC_OVL
2613 | void
2614 | remove_damage(shkp, croaked)
2615 | register struct monst *shkp;
2616 | register boolean croaked;
2617 | {
2618 | 	register struct damage *tmp_dam, *tmp2_dam;
2619 | 	register boolean did_repair = FALSE, saw_door = FALSE;
2620 | 	register boolean saw_floor = FALSE, stop_picking = FALSE;
2621 | 	register boolean saw_untrap = FALSE;
2622 | 	uchar saw_walls = 0;
2623 | 
2624 | 	tmp_dam = level.damagelist;
2625 | 	tmp2_dam = 0;
2626 | 	while (tmp_dam) {
2627 | 	    register xchar x = tmp_dam->place.x, y = tmp_dam->place.y;
2628 | 	    char shops[5];
2629 | 	    int disposition;
2630 | 
2631 | 	    disposition = 0;
2632 | 	    Strcpy(shops, in_rooms(x, y, SHOPBASE));
2633 | 	    if (index(shops, ESHK(shkp)->shoproom)) {
2634 | 		if (croaked)
2635 | 		    disposition = (shops[1])? 0 : 1;
2636 | 		else if (stop_picking)
2637 | 		    disposition = repair_damage(shkp, tmp_dam, FALSE);
2638 | 		else {
2639 | 		    /* Defer the stop_occupation() until after repair msgs */
2640 | 		    if (closed_door(x, y))
2641 | 			stop_picking = picking_at(x, y);
2642 | 		    disposition = repair_damage(shkp, tmp_dam, FALSE);
2643 | 		    if (!disposition)
2644 | 			stop_picking = FALSE;
2645 | 		}
2646 | 	    }
2647 | 
2648 | 	    if (!disposition) {
2649 | 		tmp2_dam = tmp_dam;
2650 | 		tmp_dam = tmp_dam->next;
2651 | 		continue;
2652 | 	    }
2653 | 
2654 | 	    if (disposition > 1) {
2655 | 		did_repair = TRUE;
2656 | 		if (cansee(x, y)) {
2657 | 		    if (IS_WALL(levl[x][y].typ))
2658 | 			saw_walls++;
2659 | 		    else if (IS_DOOR(levl[x][y].typ))
2660 | 			saw_door = TRUE;
2661 | 		    else if (disposition == 3)		/* untrapped */
2662 | 			saw_untrap = TRUE;
2663 | 		    else
2664 | 			saw_floor = TRUE;
2665 | 		}
2666 | 	    }
2667 | 
2668 | 	    tmp_dam = tmp_dam->next;
2669 | 	    if (!tmp2_dam) {
2670 | 		free((genericptr_t)level.damagelist);
2671 | 		level.damagelist = tmp_dam;
2672 | 	    } else {
2673 | 		free((genericptr_t)tmp2_dam->next);
2674 | 		tmp2_dam->next = tmp_dam;
2675 | 	    }
2676 | 	}
2677 | 	if (!did_repair)
2678 | 	    return;
2679 | 	if (saw_walls) {
2680 | 	    pline("Suddenly, %s section%s of wall close%s up!",
2681 | 		  (saw_walls == 1) ? "a" : (saw_walls <= 3) ?
2682 | 						  "some" : "several",
2683 | 		  (saw_walls == 1) ? "" : "s", (saw_walls == 1) ? "s" : "");
2684 | 	    if (saw_door)
2685 | 		pline_The("shop door reappears!");
2686 | 	    if (saw_floor)
2687 | 		pline_The("floor is repaired!");
2688 | 	} else {
2689 | 	    if (saw_door)
2690 | 		pline("Suddenly, the shop door reappears!");
2691 | 	    else if (saw_floor)
2692 | 		pline("Suddenly, the floor damage is gone!");
2693 | 	    else if (saw_untrap)
2694 | 	        pline("Suddenly, the trap is removed from the floor!");
2695 | 	    else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom)
2696 | 		You_feel("more claustrophobic than before.");
2697 | 	    else if (flags.soundok && !rn2(10))
2698 | 		Norep("The dungeon acoustics noticeably change.");
2699 | 	}
2700 | 	if (stop_picking)
2701 | 		stop_occupation();
2702 | }
2703 | 
2704 | /*
2705 |  * 0: repair postponed, 1: silent repair (no messages), 2: normal repair
2706 |  * 3: untrap
2707 |  */
2708 | int
2709 | repair_damage(shkp, tmp_dam, catchup)
2710 | register struct monst *shkp;
2711 | register struct damage *tmp_dam;
2712 | boolean catchup;	/* restoring a level */
2713 | {
2714 | 	register xchar x, y, i;
2715 | 	xchar litter[9];
2716 | 	register struct monst *mtmp;
2717 | 	register struct obj *otmp;
2718 | 	register struct trap *ttmp;
2719 | 
2720 | 	if ((monstermoves - tmp_dam->when) < REPAIR_DELAY)
2721 | 	    return(0);
2722 | 	if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following)
2723 | 	    return(0);
2724 | 	x = tmp_dam->place.x;
2725 | 	y = tmp_dam->place.y;
2726 | 	if (!IS_ROOM(tmp_dam->typ)) {
2727 | 	    if (x == u.ux && y == u.uy)
2728 | 		if (!Passes_walls)
2729 | 		    return(0);
2730 | 	    if (x == shkp->mx && y == shkp->my)
2731 | 		return(0);
2732 | 	    if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data)))
2733 | 		return(0);
2734 | 	}
2735 | 	if ((ttmp = t_at(x, y)) != 0) {
2736 | 	    if (x == u.ux && y == u.uy)
2737 | 		if (!Passes_walls)
2738 | 		    return(0);
2739 | 	    if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) {
2740 | 		/* convert to an object */
2741 | 		otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE :
2742 | 				BEARTRAP, TRUE, FALSE);
2743 | 		otmp->quan= 1;
2744 | 		otmp->owt = weight(otmp);
2745 | 		(void) mpickobj(shkp, otmp);
2746 | 	    }
2747 | 	    deltrap(ttmp);
2748 | 	    newsym(x, y);
2749 | 	    return(3);
2750 | 	}
2751 | 	if (IS_ROOM(tmp_dam->typ)) {
2752 | 	    /* No messages if player already filled trap door */
2753 | 	    if (catchup || !ttmp)
2754 | 		return(1);
2755 | 	    newsym(x, y);
2756 | 	    return(2);
2757 | 	}
2758 | 	if (!ttmp && (tmp_dam->typ == levl[x][y].typ) &&
2759 | 	    (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN)))
2760 | 	    /* No messages if player already replaced shop door */
2761 | 	    return(1);
2762 | 	levl[x][y].typ = tmp_dam->typ;
2763 | 	(void) memset((genericptr_t)litter, 0, sizeof(litter));
2764 | 	if ((otmp = level.objects[x][y]) != 0) {
2765 | 	    /* Scatter objects haphazardly into the shop */
2766 | #define NEED_UPDATE 1
2767 | #define OPEN	    2
2768 | #define INSHOP	    4
2769 | #define horiz(i) ((i%3)-1)
2770 | #define vert(i)  ((i/3)-1)
2771 | 	    for (i = 0; i < 9; i++) {
2772 | 		if ((i == 4) || (!ZAP_POS(levl[x+horiz(i)][y+vert(i)].typ)))
2773 | 		    continue;
2774 | 		litter[i] = OPEN;
2775 | 		if (inside_shop(x+horiz(i),
2776 | 				y+vert(i)) == ESHK(shkp)->shoproom)
2777 | 		    litter[i] |= INSHOP;
2778 | 	    }
2779 | 	    if (Punished && !u.uswallow &&
2780 | 				((uchain->ox == x && uchain->oy == y) ||
2781 | 				 (uball->ox == x && uball->oy == y))) {
2782 | 		/*
2783 | 		 * Either the ball or chain is in the repair location.
2784 | 		 *
2785 | 		 * Take the easy way out and put ball&chain under hero.
2786 | 		 */
2787 | 		verbalize("Get your junk out of my wall!");
2788 | 		unplacebc();	/* pick 'em up */
2789 | 		placebc();	/* put 'em down */
2790 | 	    }
2791 | 	    while ((otmp = level.objects[x][y]) != 0)
2792 | 		/* Don't mess w/ boulders -- just merge into wall */
2793 | 		if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) {
2794 | 		    obj_extract_self(otmp);
2795 | 		    obfree(otmp, (struct obj *)0);
2796 | 		} else {
2797 | 		    while (!(litter[i = rn2(9)] & INSHOP));
2798 | 			remove_object(otmp);
2799 | 			place_object(otmp, x+horiz(i), y+vert(i));
2800 | 			litter[i] |= NEED_UPDATE;
2801 | 		}
2802 | 	}
2803 | 	if (catchup) return 1;	/* repair occurred while off level */
2804 | 
2805 | 	block_point(x, y);
2806 | 	if(IS_DOOR(tmp_dam->typ)) {
2807 | 	    levl[x][y].doormask = D_CLOSED; /* arbitrary */
2808 | 	    newsym(x, y);
2809 | 	} else {
2810 | 	    /* don't set doormask  - it is (hopefully) the same as it was */
2811 | 	    /* if not, perhaps save it with the damage array...  */
2812 | 
2813 | 	    if (IS_WALL(tmp_dam->typ) && cansee(x, y)) {
2814 | 	    /* Player sees actual repair process, so they KNOW it's a wall */
2815 | 		levl[x][y].seenv = SVALL;
2816 | 		newsym(x, y);
2817 | 	    }
2818 | 	    /* Mark this wall as "repaired".  There currently is no code */
2819 | 	    /* to do anything about repaired walls, so don't do it.	 */
2820 | 	}
2821 | 	for (i = 0; i < 9; i++)
2822 | 	    if (litter[i] & NEED_UPDATE)
2823 | 		newsym(x+horiz(i), y+vert(i));
2824 | 	return(2);
2825 | #undef NEED_UPDATE
2826 | #undef OPEN
2827 | #undef INSHOP
2828 | #undef vert
2829 | #undef horiz
2830 | }
2831 | #endif /*OVL0*/
2832 | #ifdef OVL3
2833 | /*
2834 |  * shk_move: return 1: moved  0: didn't  -1: let m_move do it  -2: died
2835 |  */
2836 | int
2837 | shk_move(shkp)
2838 | register struct monst *shkp;
2839 | {
2840 | 	register xchar gx,gy,omx,omy;
2841 | 	register int udist;
2842 | 	register schar appr;
2843 | 	register struct eshk *eshkp = ESHK(shkp);
2844 | 	int z;
2845 | 	boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv;
2846 | 
2847 | 	omx = shkp->mx;
2848 | 	omy = shkp->my;
2849 | 
2850 | 	if (inhishop(shkp))
2851 | 	    remove_damage(shkp, FALSE);
2852 | 
2853 | 	if((udist = distu(omx,omy)) < 3 &&
2854 | 	   (shkp->data != &mons[PM_GRID_BUG] || (omx==u.ux || omy==u.uy))) {
2855 | 		if(ANGRY(shkp) ||
2856 | 		   (Conflict && !resist(shkp, RING_CLASS, 0, 0))) {
2857 | 			if(Displaced)
2858 | 			  Your("displaced image doesn't fool %s!",
2859 | 				mon_nam(shkp));
2860 | 			(void) mattacku(shkp);
2861 | 			return(0);
2862 | 		}
2863 | 		if(eshkp->following) {
2864 | 			if(strncmp(eshkp->customer, plname, PL_NSIZ)) {
2865 | 			    verbalize("%s, %s!  I was looking for %s.",
2866 | 				    Hello(shkp), plname, eshkp->customer);
2867 | 				    eshkp->following = 0;
2868 | 			    return(0);
2869 | 			}
2870 | 			if(moves > followmsg+4) {
2871 | 			    verbalize("%s, %s!  Didn't you forget to pay?",
2872 | 				    Hello(shkp), plname);
2873 | 			    followmsg = moves;
2874 | 			    if (!rn2(9)) {
2875 | 			      pline("%s doesn't like customers who don't pay.",
2876 | 				    Monnam(shkp));
2877 | 				rile_shk(shkp);
2878 | 			    }
2879 | 			}
2880 | 			if(udist < 2)
2881 | 			    return(0);
2882 | 		}
2883 | 	}
2884 | 
2885 | 	appr = 1;
2886 | 	gx = eshkp->shk.x;
2887 | 	gy = eshkp->shk.y;
2888 | 	satdoor = (gx == omx && gy == omy);
2889 | 	if(eshkp->following || ((z = holetime()) >= 0 && z*z <= udist)){
2890 | 		if(udist > 4)
2891 | 		    return(-1);	/* leave it to m_move */
2892 | 		gx = u.ux;
2893 | 		gy = u.uy;
2894 | 	} else if(ANGRY(shkp)) {
2895 | 		/* Move towards the hero if the shopkeeper can see him. */
2896 | 		if(shkp->mcansee && m_canseeu(shkp)) {
2897 | 			gx = u.ux;
2898 | 			gy = u.uy;
2899 | 		}
2900 | 		avoid = FALSE;
2901 | 	} else {
2902 | #define	GDIST(x,y)	(dist2(x,y,gx,gy))
2903 | 		if (Invis
2904 | #ifdef STEED
2905 | 			|| u.usteed
2906 | #endif
2907 | 			) {
2908 | 		    avoid = FALSE;
2909 | 		} else {
2910 | 		    uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y);
2911 | 		    if(uondoor) {
2912 | 			badinv = (carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) ||
2913 | 				  (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) ||
2914 | 				  sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))));
2915 | 			if(satdoor && badinv)
2916 | 			    return(0);
2917 | 			avoid = !badinv;
2918 | 		    } else {
2919 | 			avoid = (*u.ushops && distu(gx,gy) > 8);
2920 | 			badinv = FALSE;
2921 | 		    }
2922 | 
2923 | 		    if(((!eshkp->robbed && !eshkp->billct && !eshkp->debit)
2924 | 			|| avoid) && GDIST(omx,omy) < 3) {
2925 | 			if (!badinv && !onlineu(omx,omy))
2926 | 			    return(0);
2927 | 			if(satdoor)
2928 | 			    appr = gx = gy = 0;
2929 | 		    }
2930 | 		}
2931 | 	}
2932 | 
2933 | 	return(move_special(shkp,inhishop(shkp),
2934 | 			    appr,uondoor,avoid,omx,omy,gx,gy));
2935 | }
2936 | 
2937 | #endif /*OVL3*/
2938 | #ifdef OVLB
2939 | 
2940 | /* for use in levl_follower (mondata.c) */
2941 | boolean
2942 | is_fshk(mtmp)
2943 | register struct monst *mtmp;
2944 | {
2945 | 	return((boolean)(mtmp->isshk && ESHK(mtmp)->following));
2946 | }
2947 | 
2948 | /* You are digging in the shop. */
2949 | void
2950 | shopdig(fall)
2951 | register int fall;
2952 | {
2953 |     register struct monst *shkp = shop_keeper(*u.ushops);
2954 | 
2955 |     if(!shkp) return;
2956 | 
2957 |     if(!inhishop(shkp)) {
2958 | 	if (Role_if(PM_KNIGHT)) {
2959 | 	    You_feel("like a common thief.");
2960 | 	    adjalign(-sgn(u.ualign.type));
2961 | 	}
2962 | 	return;
2963 |     }
2964 | 
2965 |     if(!fall) {
2966 | 	if(u.utraptype == TT_PIT)
2967 | 	    verbalize("Be careful, %s, or you might fall through the floor.",
2968 | 		flags.female ? "madam" : "sir");
2969 | 	else
2970 | 	    verbalize("%s, do not damage the floor here!",
2971 | 			flags.female ? "Madam" : "Sir");
2972 | 	if (Role_if(PM_KNIGHT)) {
2973 | 	    You_feel("like a common thief.");
2974 | 	    adjalign(-sgn(u.ualign.type));
2975 | 	}
2976 |     } else if(!um_dist(shkp->mx, shkp->my, 5) &&
2977 | 		!shkp->msleeping && shkp->mcanmove &&
2978 | 		(ESHK(shkp)->billct || ESHK(shkp)->debit)) {
2979 | 	    register struct obj *obj, *obj2;
2980 | 
2981 | 	    if (distu(shkp->mx, shkp->my) > 2) {
2982 | 		mnexto(shkp);
2983 | 		/* for some reason the shopkeeper can't come next to you */
2984 | 		if (distu(shkp->mx, shkp->my) > 2) {
2985 | 		    pline("%s curses you in anger and frustration!",
2986 | 					shkname(shkp));
2987 | 		    rile_shk(shkp);
2988 | 		    return;
2989 | 		} else pline("%s leaps, and grabs your backpack!",
2990 | 					shkname(shkp));
2991 | 	    } else pline("%s grabs your backpack!", shkname(shkp));
2992 | 
2993 | 	    for(obj = invent; obj; obj = obj2) {
2994 | 		obj2 = obj->nobj;
2995 | 		if(obj->owornmask) continue;
2996 | 		if(obj->otyp == LEASH && obj->leashmon) continue;
2997 | 		freeinv(obj);
2998 | 		subfrombill(obj, shkp);
2999 | 		(void) add_to_minv(shkp, obj);	/* may free obj */
3000 | 	    }
3001 |     }
3002 | }
3003 | 
3004 | #ifdef KOPS
3005 | STATIC_OVL void
3006 | makekops(mm)
3007 | coord *mm;
3008 | {
3009 | 	static const short k_mndx[4] = {
3010 | 	    PM_KEYSTONE_KOP, PM_KOP_SERGEANT, PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN
3011 | 	};
3012 | 	int k_cnt[4], cnt, mndx, k;
3013 | 
3014 | 	k_cnt[0] = cnt = abs(depth(&u.uz)) + rnd(5);
3015 | 	k_cnt[1] = (cnt / 3) + 1;	/* at least one sarge */
3016 | 	k_cnt[2] = (cnt / 6);		/* maybe a lieutenant */
3017 | 	k_cnt[3] = (cnt / 9);		/* and maybe a kaptain */
3018 | 
3019 | 	for (k = 0; k < 4; k++) {
3020 | 	    if ((cnt = k_cnt[k]) == 0) break;
3021 | 	    mndx = k_mndx[k];
3022 | 	    if (mvitals[mndx].mvflags & G_GONE) continue;
3023 | 
3024 | 	    while (cnt--)
3025 | 		if (enexto(mm, mm->x, mm->y, &mons[mndx]))
3026 | 		    (void) makemon(&mons[mndx], mm->x, mm->y, NO_MM_FLAGS);
3027 | 	}
3028 | }
3029 | #endif	/* KOPS */
3030 | 
3031 | void
3032 | pay_for_damage(dmgstr)
3033 | const char *dmgstr;
3034 | {
3035 | 	register struct monst *shkp = (struct monst *)0;
3036 | 	char shops_affected[5];
3037 | 	register boolean uinshp = (*u.ushops != '\0');
3038 | 	char qbuf[80];
3039 | 	register xchar x, y;
3040 | 	boolean dugwall = !strcmp(dmgstr, "dig into") ||	/* wand */
3041 | 			  !strcmp(dmgstr, "damage");		/* pick-axe */
3042 | 	struct damage *tmp_dam, *appear_here = 0;
3043 | 	/* any number >= (80*80)+(24*24) would do, actually */
3044 | 	long cost_of_damage = 0L;
3045 | 	unsigned int nearest_shk = 7000, nearest_damage = 7000;
3046 | 	int picks = 0;
3047 | 
3048 | 	for (tmp_dam = level.damagelist;
3049 | 	     (tmp_dam && (tmp_dam->when == monstermoves));
3050 | 	     tmp_dam = tmp_dam->next) {
3051 | 	    char *shp;
3052 | 
3053 | 	    if (!tmp_dam->cost)
3054 | 		continue;
3055 | 	    cost_of_damage += tmp_dam->cost;
3056 | 	    Strcpy(shops_affected,
3057 | 		   in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
3058 | 	    for (shp = shops_affected; *shp; shp++) {
3059 | 		struct monst *tmp_shk;
3060 | 		unsigned int shk_distance;
3061 | 
3062 | 		if (!(tmp_shk = shop_keeper(*shp)))
3063 | 		    continue;
3064 | 		if (tmp_shk == shkp) {
3065 | 		    unsigned int damage_distance =
3066 | 				   distu(tmp_dam->place.x, tmp_dam->place.y);
3067 | 
3068 | 		    if (damage_distance < nearest_damage) {
3069 | 			nearest_damage = damage_distance;
3070 | 			appear_here = tmp_dam;
3071 | 		    }
3072 | 		    continue;
3073 | 		}
3074 | 		if (!inhishop(tmp_shk))
3075 | 		    continue;
3076 | 		shk_distance = distu(tmp_shk->mx, tmp_shk->my);
3077 | 		if (shk_distance > nearest_shk)
3078 | 		    continue;
3079 | 		if ((shk_distance == nearest_shk) && picks) {
3080 | 		    if (rn2(++picks))
3081 | 			continue;
3082 | 		} else
3083 | 		    picks = 1;
3084 | 		shkp = tmp_shk;
3085 | 		nearest_shk = shk_distance;
3086 | 		appear_here = tmp_dam;
3087 | 		nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y);
3088 | 	    }
3089 | 	}
3090 | 
3091 | 	if (!cost_of_damage || !shkp)
3092 | 	    return;
3093 | 
3094 | 	x = appear_here->place.x;
3095 | 	y = appear_here->place.y;
3096 | 
3097 | 	/* not the best introduction to the shk... */
3098 | 	(void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ);
3099 | 
3100 | 	/* if the shk is already on the war path, be sure it's all out */
3101 | 	if(ANGRY(shkp) || ESHK(shkp)->following) {
3102 | 		hot_pursuit(shkp);
3103 | 		return;
3104 | 	}
3105 | 
3106 | 	/* if the shk is not in their shop.. */
3107 | 	if(!*in_rooms(shkp->mx,shkp->my,SHOPBASE)) {
3108 | 		if(!cansee(shkp->mx, shkp->my))
3109 | 			return;
3110 | 		goto getcad;
3111 | 	}
3112 | 
3113 | 	if(uinshp) {
3114 | 		if(um_dist(shkp->mx, shkp->my, 1) &&
3115 | 			!um_dist(shkp->mx, shkp->my, 3)) {
3116 | 		    pline("%s leaps towards you!", shkname(shkp));
3117 | 		    mnexto(shkp);
3118 | 		}
3119 | 		if(um_dist(shkp->mx, shkp->my, 1)) goto getcad;
3120 | 	} else {
3121 | 	    /*
3122 | 	     * Make shkp show up at the door.  Effect:  If there is a monster
3123 | 	     * in the doorway, have the hero hear the shopkeeper yell a bit,
3124 | 	     * pause, then have the shopkeeper appear at the door, having
3125 | 	     * yanked the hapless critter out of the way.
3126 | 	     */
3127 | 	    if (MON_AT(x, y)) {
3128 | 		if(flags.soundok) {
3129 | 		    You_hear("an angry voice:");
3130 | 		    verbalize("Out of my way, scum!");
3131 | 		    wait_synch();
3132 | #if defined(UNIX) || defined(VMS)
3133 | # if defined(SYSV) || defined(ULTRIX) || defined(VMS)
3134 | 		    (void)
3135 | # endif
3136 | 			sleep(1);
3137 | #endif
3138 | 		}
3139 | 	    }
3140 | 	    (void) mnearto(shkp, x, y, TRUE);
3141 | 	}
3142 | 
3143 | 	if((um_dist(x, y, 1) && !uinshp) ||
3144 | 			(u.ugold + ESHK(shkp)->credit) < cost_of_damage
3145 | 				|| !rn2(50)) {
3146 | 		if(um_dist(x, y, 1) && !uinshp) {
3147 | 		    pline("%s shouts:", shkname(shkp));
3148 | 		    verbalize("Who dared %s my %s?", dmgstr,
3149 | 					 dugwall ? "shop" : "door");
3150 | 		} else {
3151 | getcad:
3152 | 		    verbalize("How dare you %s my %s?", dmgstr,
3153 | 					 dugwall ? "shop" : "door");
3154 | 		}
3155 | 		hot_pursuit(shkp);
3156 | 		return;
3157 | 	}
3158 | 
3159 | 	if(Invis) Your("invisibility does not fool %s!", shkname(shkp));
3160 | 	Sprintf(qbuf,"\"Cad!  You did %ld zorkmids worth of damage!\"  Pay? ",
3161 | 		 cost_of_damage);
3162 | 	if(yn(qbuf) != 'n') {
3163 | 		cost_of_damage = check_credit(cost_of_damage, shkp);
3164 | 		u.ugold -= cost_of_damage;
3165 | 		shkp->mgold += cost_of_damage;
3166 | 		flags.botl = 1;
3167 | 		pline("Mollified, %s accepts your restitution.",
3168 | 			shkname(shkp));
3169 | 		/* move shk back to his home loc */
3170 | 		home_shk(shkp, FALSE);
3171 | 		pacify_shk(shkp);
3172 | 	} else {
3173 | 		verbalize("Oh, yes!  You'll pay!");
3174 | 		hot_pursuit(shkp);
3175 | 		adjalign(-sgn(u.ualign.type));
3176 | 	}
3177 | }
3178 | #endif /*OVLB*/
3179 | #ifdef OVL0
3180 | /* called in dokick.c when we kick an object that might be in a store */
3181 | boolean
3182 | costly_spot(x, y)
3183 | register xchar x, y;
3184 | {
3185 | 	register struct monst *shkp;
3186 | 
3187 | 	if (!level.flags.has_shop) return FALSE;
3188 | 	shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
3189 | 	if(!shkp || !inhishop(shkp)) return(FALSE);
3190 | 
3191 | 	return((boolean)(inside_shop(x, y) &&
3192 | 		!(x == ESHK(shkp)->shk.x &&
3193 | 			y == ESHK(shkp)->shk.y)));
3194 | }
3195 | #endif /*OVL0*/
3196 | #ifdef OVLB
3197 | 
3198 | /* called by dotalk(sounds.c) when #chatting; returns obj if location
3199 |    contains shop goods and shopkeeper is willing & able to speak */
3200 | struct obj *
3201 | shop_object(x, y)
3202 | register xchar x, y;
3203 | {
3204 |     register struct obj *otmp;
3205 |     register struct monst *shkp;
3206 | 
3207 |     if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
3208 | 	return(struct obj *)0;
3209 | 
3210 |     for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
3211 | 	if (otmp->oclass != GOLD_CLASS)
3212 | 	    break;
3213 |     /* note: otmp might have ->no_charge set, but that's ok */
3214 |     return (otmp && costly_spot(x, y) && NOTANGRY(shkp)
3215 | 	    && shkp->mcanmove && !shkp->msleeping)
3216 | 		? otmp : (struct obj *)0;
3217 | }
3218 | 
3219 | /* give price quotes for all objects linked to this one (ie, on this spot) */
3220 | void
3221 | price_quote(first_obj)
3222 | register struct obj *first_obj;
3223 | {
3224 |     register struct obj *otmp;
3225 |     char buf[BUFSZ], price[40];
3226 |     long cost;
3227 |     int cnt = 0;
3228 |     winid tmpwin;
3229 |     struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy));
3230 | 
3231 |     tmpwin = create_nhwindow(NHW_MENU);
3232 |     putstr(tmpwin, 0, "Fine goods for sale:");
3233 |     putstr(tmpwin, 0, "");
3234 |     for (otmp = first_obj; otmp; otmp = otmp->nexthere) {
3235 | 	if (otmp->oclass == GOLD_CLASS) continue;
3236 | 	cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L :
3237 | 		get_cost(otmp, (struct monst *)0);
3238 | 	if (Has_contents(otmp))
3239 | 	    cost += contained_cost(otmp, shkp, 0L, FALSE);
3240 | 	if (!cost) {
3241 | 	    Strcpy(price, "no charge");
3242 | 	} else {
3243 | 	    Sprintf(price, "%ld zorkmid%s%s", cost, plur(cost),
3244 | 		    otmp->quan > 1L ? " each" : "");
3245 | 	}
3246 | 	Sprintf(buf, "%s, %s", doname(otmp), price);
3247 | 	putstr(tmpwin, 0, buf),  cnt++;
3248 |     }
3249 |     if (cnt > 1) {
3250 | 	display_nhwindow(tmpwin, TRUE);
3251 |     } else if (cnt == 1) {
3252 | 	if (first_obj->no_charge || first_obj == uball || first_obj == uchain){
3253 | 	    pline("%s!", buf);	/* buf still contains the string */
3254 | 	} else {
3255 | 	    /* print cost in slightly different format, so can't reuse buf */
3256 | 	    cost = get_cost(first_obj, (struct monst *)0);
3257 | 	    if (Has_contents(first_obj))
3258 | 		cost += contained_cost(first_obj, shkp, 0L, FALSE);
3259 | 	    pline("%s, price %ld zorkmid%s%s%s", doname(first_obj),
3260 | 		cost, plur(cost), first_obj->quan > 1L ? " each" : "",
3261 | 		shk_embellish(first_obj, cost));
3262 | 	}
3263 |     }
3264 |     destroy_nhwindow(tmpwin);
3265 | }
3266 | #endif /*OVLB*/
3267 | #ifdef OVL3
3268 | 
3269 | STATIC_OVL const char *
3270 | shk_embellish(itm, cost)
3271 | register struct obj *itm;
3272 | long cost;
3273 | {
3274 |     if (!rn2(3)) {
3275 | 	register int o, choice = rn2(5);
3276 | 	if (choice == 0) choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3);
3277 | 	switch (choice) {
3278 | 	    case 4:
3279 | 		if (cost < 10L) break; else o = itm->oclass;
3280 | 		if (o == FOOD_CLASS) return ", gourmets' delight!";
3281 | 		if (objects[itm->otyp].oc_name_known
3282 | 		    ? objects[itm->otyp].oc_magic
3283 | 		    : (o == AMULET_CLASS || o == RING_CLASS   ||
3284 | 		       o == WAND_CLASS   || o == POTION_CLASS ||
3285 | 		       o == SCROLL_CLASS || o == SPBOOK_CLASS))
3286 | 		    return ", painstakingly developed!";
3287 | 		return ", superb craftsmanship!";
3288 | 	    case 3: return ", finest quality.";
3289 | 	    case 2: return ", an excellent choice.";
3290 | 	    case 1: return ", a real bargain.";
3291 | 	   default: break;
3292 | 	}
3293 |     } else if (itm->oartifact) {
3294 | 	return ", one of a kind!";
3295 |     }
3296 |     return ".";
3297 | }
3298 | #endif /*OVL3*/
3299 | #ifdef OVLB
3300 | 
3301 | /* First 4 supplied by Ronen and Tamar, remainder by development team */
3302 | const char *Izchak_speaks[]={
3303 |     "%s says: 'These shopping malls give me a headache.'",
3304 |     "%s says: 'Slow down.  Think clearly.'",
3305 |     "%s says: 'You need to take things one at a time.'",
3306 |     "%s says: 'I don't like poofy coffee... give me Columbian Supremo.'",
3307 |     "%s says that getting the devteam's agreement on anything is difficult.",
3308 |     "%s says that he has noticed those who serve their deity will prosper.",
3309 |     "%s says: 'Don't try to steal from me - I have friends in high places!'",
3310 |     "%s says: 'You may well need something from this shop in the future.'",
3311 |     "%s comments about the Valley of the Dead as being a gateway."
3312 | };
3313 | 
3314 | void
3315 | shk_chat(shkp)
3316 | register struct monst *shkp;
3317 | {
3318 | 	register struct eshk *eshk = ESHK(shkp);
3319 | 
3320 | 	if (ANGRY(shkp))
3321 | 		pline("%s mentions how much %s dislikes %s customers.",
3322 | 			shkname(shkp), he[shkp->female],
3323 | 			eshk->robbed ? "non-paying" : "rude");
3324 | 	else if (eshk->following) {
3325 | 		if (strncmp(eshk->customer, plname, PL_NSIZ)) {
3326 | 		    verbalize("%s %s!  I was looking for %s.",
3327 | 			    Hello(shkp), plname, eshk->customer);
3328 | 		    eshk->following = 0;
3329 | 		} else {
3330 | 		    verbalize("%s %s!  Didn't you forget to pay?", Hello(shkp), plname);
3331 | 		}
3332 | 	} else if (eshk->billct) {
3333 | 		register long total = addupbill(shkp) + eshk->debit;
3334 | 		pline("%s says that your bill comes to %ld zorkmid%s.",
3335 | 		      shkname(shkp), total, plur(total));
3336 | 	} else if (eshk->debit)
3337 | 		pline("%s reminds you that you owe %s %ld zorkmid%s.",
3338 | 		      shkname(shkp), him[shkp->female],
3339 | 		      eshk->debit, plur(eshk->debit));
3340 | 	else if (eshk->credit)
3341 | 		pline("%s encourages you to use your %ld zorkmid%s of credit.",
3342 | 		      shkname(shkp), eshk->credit, plur(eshk->credit));
3343 | 	else if (eshk->robbed)
3344 | 		pline("%s complains about a recent robbery.", shkname(shkp));
3345 | 	else if (shkp->mgold < 50)
3346 | 		pline("%s complains that business is bad.", shkname(shkp));
3347 | 	else if (shkp->mgold > 4000)
3348 | 		pline("%s says that business is good.", shkname(shkp));
3349 | 	else if (strcmp(shkname(shkp), "Izchak") == 0)
3350 | 		pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))],shkname(shkp));
3351 | 	else
3352 | 		pline("%s talks about the problem of shoplifters.",shkname(shkp));
3353 | }
3354 | 
3355 | #ifdef KOPS
3356 | STATIC_OVL void
3357 | kops_gone(silent)
3358 | register boolean silent;
3359 | {
3360 | 	register int cnt = 0;
3361 | 	register struct monst *mtmp, *mtmp2;
3362 | 
3363 | 	for (mtmp = fmon; mtmp; mtmp = mtmp2) {
3364 | 	    mtmp2 = mtmp->nmon;
3365 | 	    if (mtmp->data->mlet == S_KOP) {
3366 | 		if (canspotmon(mtmp)) cnt++;
3367 | 		mongone(mtmp);
3368 | 	    }
3369 | 	}
3370 | 	if (cnt && !silent)
3371 | 	    pline_The("Kop%s (disappointed) vanish%s into thin air.",
3372 | 		      plur(cnt), cnt == 1 ? "es" : "");
3373 | }
3374 | #endif	/* KOPS */
3375 | 
3376 | #endif /*OVLB*/
3377 | #ifdef OVL3
3378 | 
3379 | STATIC_OVL long
3380 | cost_per_charge(shkp, otmp, altusage)
3381 | struct monst *shkp;
3382 | struct obj *otmp;
3383 | boolean altusage; /* some items have an "alternate" use with different cost */
3384 | {
3385 | 	long tmp = 0L;
3386 | 
3387 | 	if(!shkp || !inhishop(shkp)) return(0L); /* insurance */
3388 | 	tmp = get_cost(otmp, shkp);
3389 | 
3390 | 	/* The idea is to make the exhaustive use of */
3391 | 	/* an unpaid item more expensive than buying */
3392 | 	/* it outright.				     */
3393 | 	if(otmp->otyp == MAGIC_LAMP) {			 /* 1 */
3394 | 		/* normal use (ie, as light source) of a magic lamp never
3395 | 		   degrades its value, but not charging anything would make
3396 | 		   identifcation too easy; charge an amount comparable to
3397 | 		   what is charged for an ordinary lamp (don't bother with
3398 | 		   angry shk surchage) */
3399 | 		if (!altusage) tmp = (long) objects[OIL_LAMP].oc_cost;
3400 | 		else tmp += tmp / 3L;	/* djinni is being released */
3401 | 	} else if(otmp->otyp == MAGIC_MARKER) {		 /* 70 - 100 */
3402 | 		/* no way to determine in advance   */
3403 | 		/* how many charges will be wasted. */
3404 | 		/* so, arbitrarily, one half of the */
3405 | 		/* price per use.		    */
3406 | 		tmp /= 2L;
3407 | 	} else if(otmp->otyp == BAG_OF_TRICKS ||	 /* 1 - 20 */
3408 | 		  otmp->otyp == HORN_OF_PLENTY) {
3409 | 		tmp /= 5L;
3410 | 	} else if(otmp->otyp == CRYSTAL_BALL ||		 /* 1 - 5 */
3411 | 		  otmp->otyp == OIL_LAMP ||		 /* 1 - 10 */
3412 | 		  otmp->otyp == BRASS_LANTERN ||
3413 | 		 (otmp->otyp >= MAGIC_FLUTE &&
3414 | 		  otmp->otyp <= DRUM_OF_EARTHQUAKE) ||	 /* 5 - 9 */
3415 | 		  otmp->oclass == WAND_CLASS) {		 /* 3 - 11 */
3416 | 		    if (otmp->spe > 1) tmp /= 4L;
3417 | 	} else if (otmp->oclass == SPBOOK_CLASS) {
3418 | 		    tmp -= tmp / 5L;
3419 | 	} else if (otmp->otyp == CAN_OF_GREASE) {
3420 | 		    tmp /= 10L;
3421 | 	} else if (otmp->otyp == POT_OIL) {
3422 | 		    tmp /= 5L;
3423 | 	}
3424 | 	return(tmp);
3425 | }
3426 | #endif /*OVL3*/
3427 | #ifdef OVLB
3428 | 
3429 | /* Charge the player for partial use of an unpaid object.
3430 |  *
3431 |  * Note that bill_dummy_object() should be used instead
3432 |  * when an object is completely used.
3433 |  */
3434 | void
3435 | check_unpaid_usage(otmp, altusage)
3436 | struct obj *otmp;
3437 | boolean altusage;
3438 | {
3439 | 	struct monst *shkp;
3440 | 	const char *fmt, *arg1, *arg2;
3441 | 	long tmp;
3442 | 
3443 | 	if (!otmp->unpaid || !*u.ushops ||
3444 | 		(otmp->spe <= 0 && objects[otmp->otyp].oc_charged))
3445 | 	    return;
3446 | 	if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp))
3447 | 	    return;
3448 | 	if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L)
3449 | 	    return;
3450 | 
3451 | 	arg1 = arg2 = "";
3452 | 	if (otmp->oclass == SPBOOK_CLASS) {
3453 | 	    fmt = "%sYou owe%s %ld zorkmids.";
3454 | 	    arg1 = rn2(2) ? "This is no free library, cad!  " : "";
3455 | 	    arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
3456 | 	} else if (otmp->otyp == POT_OIL) {
3457 | 	    fmt = "%s%sThat will cost you %ld zorkmids (Yendorian Fuel Tax).";
3458 | 	} else {
3459 | 	    fmt = "%s%sUsage fee, %ld zorkmids.";
3460 | 	    if (!rn2(3)) arg1 = "Hey!  ";
3461 | 	    if (!rn2(3)) arg2 = "Ahem.  ";
3462 | 	}
3463 | 
3464 | 	if (shkp->mcanmove || !shkp->msleeping)
3465 | 	    verbalize(fmt, arg1, arg2, tmp);
3466 | 	ESHK(shkp)->debit += tmp;
3467 | 	exercise(A_WIS, TRUE);		/* you just got info */
3468 | }
3469 | 
3470 | /* for using charges of unpaid objects "used in the normal manner" */
3471 | void
3472 | check_unpaid(otmp)
3473 | struct obj *otmp;
3474 | {
3475 | 	check_unpaid_usage(otmp, FALSE);		/* normal item use */
3476 | }
3477 | 
3478 | void
3479 | costly_gold(x, y, amount)
3480 | register xchar x, y;
3481 | register long amount;
3482 | {
3483 | 	register long delta;
3484 | 	register struct monst *shkp;
3485 | 	register struct eshk *eshkp;
3486 | 
3487 | 	if(!costly_spot(x, y)) return;
3488 | 	/* shkp now guaranteed to exist by costly_spot() */
3489 | 	shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
3490 | 
3491 | 	eshkp = ESHK(shkp);
3492 | 	if(eshkp->credit >= amount) {
3493 | 	    if(eshkp->credit > amount)
3494 | 		Your("credit is reduced by %ld zorkmid%s.",
3495 | 					amount, plur(amount));
3496 | 	    else Your("credit is erased.");
3497 | 	    eshkp->credit -= amount;
3498 | 	} else {
3499 | 	    delta = amount - eshkp->credit;
3500 | 	    if(eshkp->credit)
3501 | 		Your("credit is erased.");
3502 | 	    if(eshkp->debit)
3503 | 		Your("debt increases by %ld zorkmid%s.",
3504 | 					delta, plur(delta));
3505 | 	    else You("owe %s %ld zorkmid%s.",
3506 | 				shkname(shkp), delta, plur(delta));
3507 | 	    eshkp->debit += delta;
3508 | 	    eshkp->loan += delta;
3509 | 	    eshkp->credit = 0L;
3510 | 	}
3511 | }
3512 | 
3513 | /* used in domove to block diagonal shop-exit */
3514 | /* x,y should always be a door */
3515 | boolean
3516 | block_door(x,y)
3517 | register xchar x, y;
3518 | {
3519 | 	register int roomno = *in_rooms(x, y, SHOPBASE);
3520 | 	register struct monst *shkp;
3521 | 
3522 | 	if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
3523 | 	if(!IS_DOOR(levl[x][y].typ)) return(FALSE);
3524 | 	if(roomno != *u.ushops) return(FALSE);
3525 | 
3526 | 	if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
3527 | 		return(FALSE);
3528 | 
3529 | 	if(shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y
3530 | 	    /* Actually, the shk should be made to block _any_
3531 | 	     * door, including a door the player digs, if the
3532 | 	     * shk is within a 'jumping' distance.
3533 | 	     */
3534 | 	    && ESHK(shkp)->shd.x == x && ESHK(shkp)->shd.y == y
3535 | 	    && shkp->mcanmove && !shkp->msleeping
3536 | 	    && (ESHK(shkp)->debit || ESHK(shkp)->billct ||
3537 | 		ESHK(shkp)->robbed)) {
3538 | 		pline("%s%s blocks your way!", shkname(shkp),
3539 | 				Invis ? " senses your motion and" : "");
3540 | 		return(TRUE);
3541 | 	}
3542 | 	return(FALSE);
3543 | }
3544 | 
3545 | /* used in domove to block diagonal shop-entry */
3546 | /* u.ux, u.uy should always be a door */
3547 | boolean
3548 | block_entry(x,y)
3549 | register xchar x, y;
3550 | {
3551 | 	register xchar sx, sy;
3552 | 	register int roomno;
3553 | 	register struct monst *shkp;
3554 | 
3555 | 	if(!(IS_DOOR(levl[u.ux][u.uy].typ) &&
3556 | 		levl[u.ux][u.uy].doormask == D_BROKEN)) return(FALSE);
3557 | 
3558 | 	roomno = *in_rooms(x, y, SHOPBASE);
3559 | 	if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
3560 | 	if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
3561 | 		return(FALSE);
3562 | 
3563 | 	if(ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy)
3564 | 		return(FALSE);
3565 | 
3566 | 	sx = ESHK(shkp)->shk.x;
3567 | 	sy = ESHK(shkp)->shk.y;
3568 | 
3569 | 	if(shkp->mx == sx && shkp->my == sy
3570 | 		&& shkp->mcanmove && !shkp->msleeping
3571 | 		&& (x == sx-1 || x == sx+1 || y == sy-1 || y == sy+1)
3572 | 		&& (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK)
3573 | #ifdef STEED
3574 | 			|| u.usteed
3575 | #endif
3576 | 	  )) {
3577 | 		pline("%s%s blocks your way!", shkname(shkp),
3578 | 				Invis ? " senses your motion and" : "");
3579 | 		return(TRUE);
3580 | 	}
3581 | 	return(FALSE);
3582 | }
3583 | 
3584 | #endif /* OVLB */
3585 | #ifdef OVL2
3586 | 
3587 | char *
3588 | shk_your(buf, obj)
3589 | char *buf;
3590 | struct obj *obj;
3591 | {
3592 | 	if (!shk_owns(buf, obj) && !mon_owns(buf, obj))
3593 | 	    Strcpy(buf, carried(obj) ? "your" : "the");
3594 | 	return buf;
3595 | }
3596 | 
3597 | char *
3598 | Shk_Your(buf, obj)
3599 | char *buf;
3600 | struct obj *obj;
3601 | {
3602 | 	(void) shk_your(buf, obj);
3603 | 	*buf = highc(*buf);
3604 | 	return buf;
3605 | }
3606 | 
3607 | STATIC_OVL char *
3608 | shk_owns(buf, obj)
3609 | char *buf;
3610 | struct obj *obj;
3611 | {
3612 | 	struct monst *shkp;
3613 | 	xchar x, y;
3614 | 
3615 | 	if (get_obj_location(obj, &x, &y, 0) &&
3616 | 	    (obj->unpaid ||
3617 | 	     (obj->where==OBJ_FLOOR && !obj->no_charge && costly_spot(x,y)))) {
3618 | 	    shkp = shop_keeper(inside_shop(x, y));
3619 | 	    return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : "the");
3620 | 	}
3621 | 	return (char *)0;
3622 | }
3623 | 
3624 | STATIC_OVL char *
3625 | mon_owns(buf, obj)
3626 | char *buf;
3627 | struct obj *obj;
3628 | {
3629 | 	if (obj->where == OBJ_MINVENT)
3630 | 	    return strcpy(buf, s_suffix(mon_nam(obj->ocarry)));
3631 | 	return (char *)0;
3632 | }
3633 | 
3634 | #endif /* OVL2 */
3635 | #ifdef OVLB
3636 | 
3637 | #ifdef __SASC
3638 | void
3639 | sasc_bug(struct obj *op, unsigned x){
3640 | 	op->unpaid=x;
3641 | }
3642 | #endif
3643 | 
3644 | #endif /* OVLB */
3645 | 
3646 | /*shk.c*/