1 /* NetHack 3.6 shk.c $NHDT-Date: 1571436007 2019/10/18 22:00:07 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.171 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed. See license for details. */
5
6 #include "hack.h"
7
8 #define PAY_SOME 2
9 #define PAY_BUY 1
10 #define PAY_CANT 0 /* too poor */
11 #define PAY_SKIP (-1)
12 #define PAY_BROKE (-2)
13
14 STATIC_DCL void FDECL(makekops, (coord *));
15 STATIC_DCL void FDECL(call_kops, (struct monst *, BOOLEAN_P));
16 STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P));
17
18 #define NOTANGRY(mon) ((mon)->mpeaceful)
19 #define ANGRY(mon) (!NOTANGRY(mon))
20 #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
21
22 #define muteshk(shkp) \
23 ((shkp)->msleeping || !(shkp)->mcanmove \
24 || (shkp)->data->msound <= MS_ANIMAL)
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 STATIC_VAR const char and_its_contents[] = " and its contents";
30 STATIC_VAR const char the_contents_of[] = "the contents of ";
31
32 STATIC_DCL void FDECL(append_honorific, (char *));
33 STATIC_DCL long FDECL(addupbill, (struct monst *));
34 STATIC_DCL void FDECL(pacify_shk, (struct monst *));
35 STATIC_DCL struct bill_x *FDECL(onbill, (struct obj *, struct monst *,
36 BOOLEAN_P));
37 STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
38 STATIC_DCL long FDECL(shop_debt, (struct eshk *));
39 STATIC_DCL char *FDECL(shk_owns, (char *, struct obj *));
40 STATIC_DCL char *FDECL(mon_owns, (char *, struct obj *));
41 STATIC_DCL void FDECL(clear_unpaid_obj, (struct monst *, struct obj *));
42 STATIC_DCL void FDECL(clear_unpaid, (struct monst *, struct obj *));
43 STATIC_DCL long FDECL(check_credit, (long, struct monst *));
44 STATIC_DCL void FDECL(pay, (long, struct monst *));
45 STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *));
46 STATIC_DCL long FDECL(set_cost, (struct obj *, struct monst *));
47 STATIC_DCL const char *FDECL(shk_embellish, (struct obj *, long));
48 STATIC_DCL long FDECL(cost_per_charge, (struct monst *, struct obj *,
49 BOOLEAN_P));
50 STATIC_DCL long FDECL(cheapest_item, (struct monst *));
51 STATIC_DCL int FDECL(dopayobj, (struct monst *, struct bill_x *,
52 struct obj **, int, BOOLEAN_P));
53 STATIC_DCL long FDECL(stolen_container, (struct obj *, struct monst *,
54 long, BOOLEAN_P));
55 STATIC_DCL long FDECL(getprice, (struct obj *, BOOLEAN_P));
56 STATIC_DCL void FDECL(shk_names_obj, (struct monst *, struct obj *,
57 const char *, long, const char *));
58 STATIC_DCL boolean FDECL(inherits, (struct monst *, int, int, BOOLEAN_P));
59 STATIC_DCL void FDECL(set_repo_loc, (struct monst *));
60 STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *));
61 STATIC_DCL long FDECL(get_pricing_units, (struct obj *));
62 STATIC_DCL boolean NDECL(angry_shk_exists);
63 STATIC_DCL void FDECL(rile_shk, (struct monst *));
64 STATIC_DCL void FDECL(rouse_shk, (struct monst *, BOOLEAN_P));
65 STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P));
66 STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *));
67 STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P,
68 struct monst *));
69 STATIC_DCL void FDECL(dropped_container, (struct obj *, struct monst *,
70 BOOLEAN_P));
71 STATIC_DCL void FDECL(add_to_billobjs, (struct obj *));
72 STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
73 struct monst *));
74 STATIC_DCL boolean FDECL(rob_shop, (struct monst *));
75 STATIC_DCL void FDECL(deserted_shop, (char *));
76 STATIC_DCL boolean FDECL(special_stock, (struct obj *, struct monst *,
77 BOOLEAN_P));
78 STATIC_DCL const char *FDECL(cad, (BOOLEAN_P));
79
80 /*
81 invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
82 obj->quan <= bp->bquan
83 */
84
85 static const char *angrytexts[] = { "quite upset", "ticked off", "furious" };
86
87 /*
88 * Transfer money from inventory to monster when paying
89 * shopkeepers, priests, oracle, succubus, and other demons.
90 * Simple with only gold coins.
91 * This routine will handle money changing when multiple
92 * coin types is implemented, only appropriate
93 * monsters will pay change. (Peaceful shopkeepers, priests
94 * and the oracle try to maintain goodwill while selling
95 * their wares or services. Angry monsters and all demons
96 * will keep anything they get their hands on.
97 * Returns the amount actually paid, so we can know
98 * if the monster kept the change.
99 */
100 long
money2mon(mon,amount)101 money2mon(mon, amount)
102 struct monst *mon;
103 long amount;
104 {
105 struct obj *ygold = findgold(invent);
106
107 if (amount <= 0) {
108 impossible("%s payment in money2mon!", amount ? "negative" : "zero");
109 return 0L;
110 }
111 if (!ygold || ygold->quan < amount) {
112 impossible("Paying without %s money?", ygold ? "enough" : "");
113 return 0L;
114 }
115
116 if (ygold->quan > amount)
117 ygold = splitobj(ygold, amount);
118 else if (ygold->owornmask)
119 remove_worn_item(ygold, FALSE); /* quiver */
120 freeinv(ygold);
121 add_to_minv(mon, ygold);
122 context.botl = 1;
123 return amount;
124 }
125
126 /*
127 * Transfer money from monster to inventory.
128 * Used when the shopkeeper pay for items, and when
129 * the priest gives you money for an ale.
130 */
131 void
money2u(mon,amount)132 money2u(mon, amount)
133 struct monst *mon;
134 long amount;
135 {
136 struct obj *mongold = findgold(mon->minvent);
137
138 if (amount <= 0) {
139 impossible("%s payment in money2u!", amount ? "negative" : "zero");
140 return;
141 }
142 if (!mongold || mongold->quan < amount) {
143 impossible("%s paying without %s money?", a_monnam(mon),
144 mongold ? "enough" : "");
145 return;
146 }
147
148 if (mongold->quan > amount)
149 mongold = splitobj(mongold, amount);
150 obj_extract_self(mongold);
151
152 if (!merge_choice(invent, mongold) && inv_cnt(FALSE) >= 52) {
153 You("have no room for the money!");
154 dropy(mongold);
155 } else {
156 addinv(mongold);
157 context.botl = 1;
158 }
159 }
160
161 STATIC_OVL struct monst *
next_shkp(shkp,withbill)162 next_shkp(shkp, withbill)
163 register struct monst *shkp;
164 register boolean withbill;
165 {
166 for (; shkp; shkp = shkp->nmon) {
167 if (DEADMONSTER(shkp))
168 continue;
169 if (shkp->isshk && (ESHK(shkp)->billct || !withbill))
170 break;
171 }
172
173 if (shkp) {
174 if (NOTANGRY(shkp)) {
175 if (ESHK(shkp)->surcharge)
176 pacify_shk(shkp);
177 } else {
178 if (!ESHK(shkp)->surcharge)
179 rile_shk(shkp);
180 }
181 }
182 return shkp;
183 }
184
185 /* called in mon.c */
186 void
shkgone(mtmp)187 shkgone(mtmp)
188 struct monst *mtmp;
189 {
190 struct eshk *eshk = ESHK(mtmp);
191 struct mkroom *sroom = &rooms[eshk->shoproom - ROOMOFFSET];
192 struct obj *otmp;
193 char *p;
194 int sx, sy;
195
196 /* [BUG: some of this should be done on the shop level */
197 /* even when the shk dies on a different level.] */
198 if (on_level(&eshk->shoplevel, &u.uz)) {
199 remove_damage(mtmp, TRUE);
200 sroom->resident = (struct monst *) 0;
201 if (!search_special(ANY_SHOP))
202 level.flags.has_shop = 0;
203
204 /* items on shop floor revert to ordinary objects */
205 for (sx = sroom->lx; sx <= sroom->hx; sx++)
206 for (sy = sroom->ly; sy <= sroom->hy; sy++)
207 for (otmp = level.objects[sx][sy]; otmp;
208 otmp = otmp->nexthere)
209 otmp->no_charge = 0;
210
211 /* Make sure bill is set only when the
212 dead shk is the resident shk. */
213 if ((p = index(u.ushops, eshk->shoproom)) != 0) {
214 setpaid(mtmp);
215 eshk->bill_p = (struct bill_x *) 0;
216 /* remove eshk->shoproom from u.ushops */
217 do {
218 *p = *(p + 1);
219 } while (*++p);
220 }
221 }
222 }
223
224 void
set_residency(shkp,zero_out)225 set_residency(shkp, zero_out)
226 register struct monst *shkp;
227 register boolean zero_out;
228 {
229 if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
230 rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
231 (zero_out) ? (struct monst *) 0 : shkp;
232 }
233
234 void
replshk(mtmp,mtmp2)235 replshk(mtmp, mtmp2)
236 register struct monst *mtmp, *mtmp2;
237 {
238 rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2;
239 if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
240 ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
241 }
242 }
243
244 /* do shopkeeper specific structure munging -dlc */
245 void
restshk(shkp,ghostly)246 restshk(shkp, ghostly)
247 struct monst *shkp;
248 boolean ghostly;
249 {
250 if (u.uz.dlevel) {
251 struct eshk *eshkp = ESHK(shkp);
252
253 if (eshkp->bill_p != (struct bill_x *) -1000)
254 eshkp->bill_p = &eshkp->bill[0];
255 /* shoplevel can change as dungeons move around */
256 /* savebones guarantees that non-homed shk's will be gone */
257 if (ghostly) {
258 assign_level(&eshkp->shoplevel, &u.uz);
259 if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ))
260 pacify_shk(shkp);
261 }
262 }
263 }
264
265 /* Clear the unpaid bit on a single object and its contents. */
266 STATIC_OVL void
clear_unpaid_obj(shkp,otmp)267 clear_unpaid_obj(shkp, otmp)
268 struct monst *shkp;
269 struct obj *otmp;
270 {
271 if (Has_contents(otmp))
272 clear_unpaid(shkp, otmp->cobj);
273 if (onbill(otmp, shkp, TRUE))
274 otmp->unpaid = 0;
275 }
276
277 /* Clear the unpaid bit on all of the objects in the list. */
278 STATIC_OVL void
clear_unpaid(shkp,list)279 clear_unpaid(shkp, list)
280 struct monst *shkp;
281 struct obj *list;
282 {
283 while (list) {
284 clear_unpaid_obj(shkp, list);
285 list = list->nobj;
286 }
287 }
288
289 /* either you paid or left the shop or the shopkeeper died */
290 void
setpaid(shkp)291 setpaid(shkp)
292 register struct monst *shkp;
293 {
294 register struct obj *obj;
295 register struct monst *mtmp;
296
297 clear_unpaid(shkp, invent);
298 clear_unpaid(shkp, fobj);
299 clear_unpaid(shkp, level.buriedobjlist);
300 if (thrownobj)
301 clear_unpaid_obj(shkp, thrownobj);
302 if (kickedobj)
303 clear_unpaid_obj(shkp, kickedobj);
304 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
305 clear_unpaid(shkp, mtmp->minvent);
306 for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
307 clear_unpaid(shkp, mtmp->minvent);
308
309 while ((obj = billobjs) != 0) {
310 obj_extract_self(obj);
311 dealloc_obj(obj);
312 }
313 if (shkp) {
314 ESHK(shkp)->billct = 0;
315 ESHK(shkp)->credit = 0L;
316 ESHK(shkp)->debit = 0L;
317 ESHK(shkp)->loan = 0L;
318 }
319 }
320
321 STATIC_OVL long
addupbill(shkp)322 addupbill(shkp)
323 register struct monst *shkp;
324 {
325 register int ct = ESHK(shkp)->billct;
326 register struct bill_x *bp = ESHK(shkp)->bill_p;
327 register long total = 0L;
328
329 while (ct--) {
330 total += bp->price * bp->bquan;
331 bp++;
332 }
333 return total;
334 }
335
336 STATIC_OVL void
call_kops(shkp,nearshop)337 call_kops(shkp, nearshop)
338 register struct monst *shkp;
339 register boolean nearshop;
340 {
341 /* Keystone Kops srt@ucla */
342 register boolean nokops;
343
344 if (!shkp)
345 return;
346
347 if (!Deaf)
348 pline("An alarm sounds!");
349
350 nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE)
351 && (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE)
352 && (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE)
353 && (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE));
354
355 if (!angry_guards(!!Deaf) && nokops) {
356 if (flags.verbose && !Deaf)
357 pline("But no one seems to respond to it.");
358 return;
359 }
360
361 if (nokops)
362 return;
363
364 {
365 coord mm;
366
367 if (nearshop) {
368 /* Create swarm around you, if you merely "stepped out" */
369 if (flags.verbose)
370 pline_The("Keystone Kops appear!");
371 mm.x = u.ux;
372 mm.y = u.uy;
373 makekops(&mm);
374 return;
375 }
376 if (flags.verbose)
377 pline_The("Keystone Kops are after you!");
378 /* Create swarm near down staircase (hinders return to level) */
379 mm.x = xdnstair;
380 mm.y = ydnstair;
381 makekops(&mm);
382 /* Create swarm near shopkeeper (hinders return to shop) */
383 mm.x = shkp->mx;
384 mm.y = shkp->my;
385 makekops(&mm);
386 }
387 }
388
389 /* x,y is strictly inside shop */
390 char
inside_shop(x,y)391 inside_shop(x, y)
392 register xchar x, y;
393 {
394 register char rno;
395
396 rno = levl[x][y].roomno;
397 if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno - ROOMOFFSET))
398 rno = NO_ROOM;
399 return rno;
400 }
401
402 void
u_left_shop(leavestring,newlev)403 u_left_shop(leavestring, newlev)
404 char *leavestring;
405 boolean newlev;
406 {
407 struct monst *shkp;
408 struct eshk *eshkp;
409
410 /*
411 * IF player
412 * ((didn't leave outright) AND
413 * ((he is now strictly-inside the shop) OR
414 * (he wasn't strictly-inside last turn anyway)))
415 * THEN (there's nothing to do, so just return)
416 */
417 if (!*leavestring && (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
418 return;
419
420 shkp = shop_keeper(*u.ushops0);
421 if (!shkp || !inhishop(shkp))
422 return; /* shk died, teleported, changed levels... */
423
424 eshkp = ESHK(shkp);
425 if (!eshkp->billct && !eshkp->debit) /* bill is settled */
426 return;
427
428 if (!*leavestring && !muteshk(shkp)) {
429 /*
430 * Player just stepped onto shop-boundary (known from above logic).
431 * Try to intimidate him into paying his bill
432 */
433 if (!Deaf && !muteshk(shkp))
434 verbalize(NOTANGRY(shkp) ? "%s! Please pay before leaving."
435 : "%s! Don't you leave without paying!",
436 plname);
437 else
438 pline("%s %s that you need to pay before leaving%s",
439 Shknam(shkp),
440 NOTANGRY(shkp) ? "points out" : "makes it clear",
441 NOTANGRY(shkp) ? "." : "!");
442 return;
443 }
444
445 if (rob_shop(shkp)) {
446 call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
447 }
448 }
449
450 /* robbery from outside the shop via telekinesis or grappling hook */
451 void
remote_burglary(x,y)452 remote_burglary(x, y)
453 xchar x, y;
454 {
455 struct monst *shkp;
456 struct eshk *eshkp;
457
458 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
459 if (!shkp || !inhishop(shkp))
460 return; /* shk died, teleported, changed levels... */
461
462 eshkp = ESHK(shkp);
463 if (!eshkp->billct && !eshkp->debit) /* bill is settled */
464 return;
465
466 if (rob_shop(shkp)) {
467 /*[might want to set 2nd arg based on distance from shop doorway]*/
468 call_kops(shkp, FALSE);
469 }
470 }
471
472 /* shop merchandise has been taken; pay for it with any credit available;
473 return false if the debt is fully covered by credit, true otherwise */
474 STATIC_OVL boolean
rob_shop(shkp)475 rob_shop(shkp)
476 struct monst *shkp;
477 {
478 struct eshk *eshkp;
479 long total;
480
481 eshkp = ESHK(shkp);
482 rouse_shk(shkp, TRUE);
483 total = (addupbill(shkp) + eshkp->debit);
484 if (eshkp->credit >= total) {
485 Your("credit of %ld %s is used to cover your shopping bill.",
486 eshkp->credit, currency(eshkp->credit));
487 total = 0L; /* credit gets cleared by setpaid() */
488 } else {
489 You("escaped the shop without paying!");
490 total -= eshkp->credit;
491 }
492 setpaid(shkp);
493 if (!total)
494 return FALSE;
495
496 /* by this point, we know an actual robbery has taken place */
497 eshkp->robbed += total;
498 You("stole %ld %s worth of merchandise.", total, currency(total));
499 if (!Role_if(PM_ROGUE)) /* stealing is unlawful */
500 adjalign(-sgn(u.ualign.type));
501
502 hot_pursuit(shkp);
503 return TRUE;
504 }
505
506 /* give a message when entering an untended shop (caller has verified that) */
507 STATIC_OVL void
deserted_shop(enterstring)508 deserted_shop(enterstring)
509 /*const*/ char *enterstring;
510 {
511 struct monst *mtmp;
512 struct mkroom *r = &rooms[(int) *enterstring - ROOMOFFSET];
513 int x, y, m = 0, n = 0;
514
515 for (x = r->lx; x <= r->hx; ++x)
516 for (y = r->ly; y <= r->hy; ++y) {
517 if (x == u.ux && y == u.uy)
518 continue;
519 if ((mtmp = m_at(x, y)) != 0) {
520 ++n;
521 if (sensemon(mtmp) || ((M_AP_TYPE(mtmp) == M_AP_NOTHING
522 || M_AP_TYPE(mtmp) == M_AP_MONSTER)
523 && canseemon(mtmp)))
524 ++m;
525 }
526 }
527
528 if (Blind && !(Blind_telepat || Detect_monsters))
529 ++n; /* force feedback to be less specific */
530
531 pline("This shop %s %s.", (m < n) ? "seems to be" : "is",
532 !n ? "deserted" : "untended");
533 }
534
535 void
u_entered_shop(enterstring)536 u_entered_shop(enterstring)
537 char *enterstring;
538 {
539 register int rt;
540 register struct monst *shkp;
541 register struct eshk *eshkp;
542 static char empty_shops[5];
543
544 if (!*enterstring)
545 return;
546
547 if (!(shkp = shop_keeper(*enterstring))) {
548 if (!index(empty_shops, *enterstring)
549 && in_rooms(u.ux, u.uy, SHOPBASE)
550 != in_rooms(u.ux0, u.uy0, SHOPBASE))
551 deserted_shop(enterstring);
552 Strcpy(empty_shops, u.ushops);
553 u.ushops[0] = '\0';
554 return;
555 }
556
557 eshkp = ESHK(shkp);
558
559 if (!inhishop(shkp)) {
560 /* dump core when referenced */
561 eshkp->bill_p = (struct bill_x *) -1000;
562 if (!index(empty_shops, *enterstring))
563 deserted_shop(enterstring);
564 Strcpy(empty_shops, u.ushops);
565 u.ushops[0] = '\0';
566 return;
567 }
568
569 eshkp->bill_p = &(eshkp->bill[0]);
570
571 if ((!eshkp->visitct || *eshkp->customer)
572 && strncmpi(eshkp->customer, plname, PL_NSIZ)) {
573 /* You seem to be new here */
574 eshkp->visitct = 0;
575 eshkp->following = 0;
576 (void) strncpy(eshkp->customer, plname, PL_NSIZ);
577 pacify_shk(shkp);
578 }
579
580 if (muteshk(shkp) || eshkp->following)
581 return; /* no dialog */
582
583 if (Invis) {
584 pline("%s senses your presence.", Shknam(shkp));
585 if (!Deaf && !muteshk(shkp))
586 verbalize("Invisible customers are not welcome!");
587 else
588 pline("%s stands firm as if %s knows you are there.",
589 Shknam(shkp), noit_mhe(shkp));
590 return;
591 }
592
593 rt = rooms[*enterstring - ROOMOFFSET].rtype;
594
595 if (ANGRY(shkp)) {
596 if (!Deaf && !muteshk(shkp))
597 verbalize("So, %s, you dare return to %s %s?!", plname,
598 s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
599 else
600 pline("%s seems %s over your return to %s %s!",
601 Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
602 noit_mhis(shkp), shtypes[rt - SHOPBASE].name);
603 } else if (eshkp->robbed) {
604 if (!Deaf)
605 pline("%s mutters imprecations against shoplifters.",
606 Shknam(shkp));
607 else
608 pline("%s is combing through %s inventory list.",
609 Shknam(shkp), noit_mhis(shkp));
610 } else {
611 if (!Deaf && !muteshk(shkp))
612 verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname,
613 eshkp->visitct++ ? " again" : "",
614 s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
615 else
616 You("enter %s %s%s!",
617 s_suffix(shkname(shkp)),
618 shtypes[rt - SHOPBASE].name,
619 eshkp->visitct++ ? " again" : "");
620 }
621 /* can't do anything about blocking if teleported in */
622 if (!inside_shop(u.ux, u.uy)) {
623 boolean should_block;
624 int cnt;
625 const char *tool;
626 struct obj *pick = carrying(PICK_AXE),
627 *mattock = carrying(DWARVISH_MATTOCK);
628
629 if (pick || mattock) {
630 cnt = 1; /* so far */
631 if (pick && mattock) { /* carrying both types */
632 tool = "digging tool";
633 cnt = 2; /* `more than 1' is all that matters */
634 } else if (pick) {
635 tool = "pick-axe";
636 /* hack: `pick' already points somewhere into inventory */
637 while ((pick = pick->nobj) != 0)
638 if (pick->otyp == PICK_AXE)
639 ++cnt;
640 } else { /* assert(mattock != 0) */
641 tool = "mattock";
642 while ((mattock = mattock->nobj) != 0)
643 if (mattock->otyp == DWARVISH_MATTOCK)
644 ++cnt;
645 /* [ALI] Shopkeeper identifies mattock(s) */
646 if (!Blind)
647 makeknown(DWARVISH_MATTOCK);
648 }
649 if (!Deaf && !muteshk(shkp))
650 verbalize(NOTANGRY(shkp)
651 ? "Will you please leave your %s%s outside?"
652 : "Leave the %s%s outside.",
653 tool, plur(cnt));
654 else
655 pline("%s %s to let you in with your %s%s.",
656 Shknam(shkp),
657 NOTANGRY(shkp) ? "is hesitant" : "refuses",
658 tool, plur(cnt));
659 should_block = TRUE;
660 } else if (u.usteed) {
661 if (!Deaf && !muteshk(shkp))
662 verbalize(NOTANGRY(shkp) ? "Will you please leave %s outside?"
663 : "Leave %s outside.",
664 y_monnam(u.usteed));
665 else
666 pline("%s %s to let you in while you're riding %s.",
667 Shknam(shkp),
668 NOTANGRY(shkp) ? "doesn't want" : "refuses",
669 y_monnam(u.usteed));
670 should_block = TRUE;
671 } else {
672 should_block =
673 (Fast && (sobj_at(PICK_AXE, u.ux, u.uy)
674 || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)));
675 }
676 if (should_block)
677 (void) dochug(shkp); /* shk gets extra move */
678 }
679 return;
680 }
681
682 /* called when removing a pick-axe or mattock from a container */
683 void
pick_pick(obj)684 pick_pick(obj)
685 struct obj *obj;
686 {
687 struct monst *shkp;
688
689 if (obj->unpaid || !is_pick(obj))
690 return;
691 shkp = shop_keeper(*u.ushops);
692 if (shkp && inhishop(shkp)) {
693 static NEARDATA long pickmovetime = 0L;
694
695 /* if you bring a sack of N picks into a shop to sell,
696 don't repeat this N times when they're taken out */
697 if (moves != pickmovetime) {
698 if (!Deaf && !muteshk(shkp))
699 verbalize("You sneaky %s! Get out of here with that pick!",
700 cad(FALSE));
701 else
702 pline("%s %s your pick!",
703 Shknam(shkp),
704 haseyes(shkp->data) ? "glares at"
705 : "is dismayed because of");
706 }
707 pickmovetime = moves;
708 }
709 }
710
711 /*
712 Decide whether two unpaid items are mergable; caller is responsible for
713 making sure they're unpaid and the same type of object; we check the price
714 quoted by the shopkeeper and also that they both belong to the same shk.
715 */
716 boolean
same_price(obj1,obj2)717 same_price(obj1, obj2)
718 struct obj *obj1, *obj2;
719 {
720 register struct monst *shkp1, *shkp2;
721 struct bill_x *bp1 = 0, *bp2 = 0;
722 boolean are_mergable = FALSE;
723
724 /* look up the first object by finding shk whose bill it's on */
725 for (shkp1 = next_shkp(fmon, TRUE); shkp1;
726 shkp1 = next_shkp(shkp1->nmon, TRUE))
727 if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0)
728 break;
729 /* second object is probably owned by same shk; if not, look harder */
730 if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) {
731 shkp2 = shkp1;
732 } else {
733 for (shkp2 = next_shkp(fmon, TRUE); shkp2;
734 shkp2 = next_shkp(shkp2->nmon, TRUE))
735 if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0)
736 break;
737 }
738
739 if (!bp1 || !bp2)
740 impossible("same_price: object wasn't on any bill!");
741 else
742 are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price);
743 return are_mergable;
744 }
745
746 /*
747 * Figure out how much is owed to a given shopkeeper.
748 * At present, we ignore any amount robbed from the shop, to avoid
749 * turning the `$' command into a way to discover that the current
750 * level is bones data which has a shk on the warpath.
751 */
752 STATIC_OVL long
shop_debt(eshkp)753 shop_debt(eshkp)
754 struct eshk *eshkp;
755 {
756 struct bill_x *bp;
757 int ct;
758 long debt = eshkp->debit;
759
760 for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--)
761 debt += bp->price * bp->bquan;
762 return debt;
763 }
764
765 /* called in response to the `$' command */
766 void
shopper_financial_report()767 shopper_financial_report()
768 {
769 struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy));
770 struct eshk *eshkp;
771 long amt;
772 int pass;
773
774 eshkp = this_shkp ? ESHK(this_shkp) : 0;
775 if (eshkp && !(eshkp->credit || shop_debt(eshkp))) {
776 You("have no credit or debt in here.");
777 this_shkp = 0; /* skip first pass */
778 }
779
780 /* pass 0: report for the shop we're currently in, if any;
781 pass 1: report for all other shops on this level. */
782 for (pass = this_shkp ? 0 : 1; pass <= 1; pass++)
783 for (shkp = next_shkp(fmon, FALSE); shkp;
784 shkp = next_shkp(shkp->nmon, FALSE)) {
785 if ((shkp != this_shkp) ^ pass)
786 continue;
787 eshkp = ESHK(shkp);
788 if ((amt = eshkp->credit) != 0)
789 You("have %ld %s credit at %s %s.", amt, currency(amt),
790 s_suffix(shkname(shkp)),
791 shtypes[eshkp->shoptype - SHOPBASE].name);
792 else if (shkp == this_shkp)
793 You("have no credit in here.");
794 if ((amt = shop_debt(eshkp)) != 0)
795 You("owe %s %ld %s.", shkname(shkp), amt, currency(amt));
796 else if (shkp == this_shkp)
797 You("don't owe any money here.");
798 }
799 }
800
801 int
inhishop(mtmp)802 inhishop(mtmp)
803 register struct monst *mtmp;
804 {
805 struct eshk *eshkp = ESHK(mtmp);
806
807 return (index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE), eshkp->shoproom)
808 && on_level(&eshkp->shoplevel, &u.uz));
809 }
810
811 struct monst *
shop_keeper(rmno)812 shop_keeper(rmno)
813 char rmno;
814 {
815 struct monst *shkp;
816
817 shkp = (rmno >= ROOMOFFSET) ? rooms[rmno - ROOMOFFSET].resident : 0;
818 if (shkp) {
819 if (has_eshk(shkp)) {
820 if (NOTANGRY(shkp)) {
821 if (ESHK(shkp)->surcharge)
822 pacify_shk(shkp);
823 } else {
824 if (!ESHK(shkp)->surcharge)
825 rile_shk(shkp);
826 }
827 } else {
828 /* would have segfaulted on ESHK dereference previously */
829 impossible("%s? (rmno=%d, rtype=%d, mnum=%d, \"%s\")",
830 shkp->isshk ? "shopkeeper career change"
831 : "shop resident not shopkeeper",
832 (int) rmno,
833 (int) rooms[rmno - ROOMOFFSET].rtype,
834 shkp->mnum,
835 /* [real shopkeeper name is kept in ESHK, not MNAME] */
836 has_mname(shkp) ? MNAME(shkp) : "anonymous");
837 /* not sure if this is appropriate, because it does nothing to
838 correct the underlying rooms[].resident issue but... */
839 return (struct monst *) 0;
840 }
841 }
842 return shkp;
843 }
844
845 boolean
tended_shop(sroom)846 tended_shop(sroom)
847 struct mkroom *sroom;
848 {
849 struct monst *mtmp = sroom->resident;
850
851 return !mtmp ? FALSE : (boolean) inhishop(mtmp);
852 }
853
854 STATIC_OVL struct bill_x *
onbill(obj,shkp,silent)855 onbill(obj, shkp, silent)
856 struct obj *obj;
857 struct monst *shkp;
858 boolean silent;
859 {
860 if (shkp) {
861 register struct bill_x *bp = ESHK(shkp)->bill_p;
862 register int ct = ESHK(shkp)->billct;
863
864 while (--ct >= 0)
865 if (bp->bo_id == obj->o_id) {
866 if (!obj->unpaid)
867 pline("onbill: paid obj on bill?");
868 return bp;
869 } else
870 bp++;
871 }
872 if (obj->unpaid && !silent)
873 pline("onbill: unpaid obj not on bill?");
874 return (struct bill_x *) 0;
875 }
876
877 /* check whether an object or any of its contents belongs to a shop */
878 boolean
is_unpaid(obj)879 is_unpaid(obj)
880 struct obj *obj;
881 {
882 return (boolean) (obj->unpaid
883 || (Has_contents(obj) && count_unpaid(obj->cobj)));
884 }
885
886 /* Delete the contents of the given object. */
887 void
delete_contents(obj)888 delete_contents(obj)
889 register struct obj *obj;
890 {
891 register struct obj *curr;
892
893 while ((curr = obj->cobj) != 0) {
894 obj_extract_self(curr);
895 obfree(curr, (struct obj *) 0);
896 }
897 }
898
899 /* called with two args on merge */
900 void
obfree(obj,merge)901 obfree(obj, merge)
902 register struct obj *obj, *merge;
903 {
904 register struct bill_x *bp;
905 register struct bill_x *bpm;
906 register struct monst *shkp;
907
908 if (obj->otyp == LEASH && obj->leashmon)
909 o_unleash(obj);
910 if (obj->oclass == FOOD_CLASS)
911 food_disappears(obj);
912 if (obj->oclass == SPBOOK_CLASS)
913 book_disappears(obj);
914 if (Has_contents(obj))
915 delete_contents(obj);
916 if (Is_container(obj))
917 maybe_reset_pick(obj);
918
919 shkp = 0;
920 if (obj->unpaid) {
921 /* look for a shopkeeper who owns this object */
922 for (shkp = next_shkp(fmon, TRUE); shkp;
923 shkp = next_shkp(shkp->nmon, TRUE))
924 if (onbill(obj, shkp, TRUE))
925 break;
926 }
927 /* sanity check, in case obj is on bill but not marked 'unpaid' */
928 if (!shkp)
929 shkp = shop_keeper(*u.ushops);
930 /*
931 * Note: `shkp = shop_keeper(*u.ushops)' used to be
932 * unconditional. But obfree() is used all over
933 * the place, so making its behavior be dependent
934 * upon player location doesn't make much sense.
935 */
936
937 if ((bp = onbill(obj, shkp, FALSE)) != 0) {
938 if (!merge) {
939 bp->useup = 1;
940 obj->unpaid = 0; /* only for doinvbill */
941 add_to_billobjs(obj);
942 return;
943 }
944 bpm = onbill(merge, shkp, FALSE);
945 if (!bpm) {
946 /* this used to be a rename */
947 /* !merge already returned */
948 impossible("obfree: not on bill, %s = (%d,%d,%ld,%d) (%d,%d,%ld,%d)??",
949 "otyp,where,quan,unpaid",
950 obj->otyp, obj->where, obj->quan, obj->unpaid ? 1 : 0,
951 merge->otyp, merge->where, merge->quan,
952 merge->unpaid ? 1 : 0);
953 return;
954 } else {
955 /* this was a merger */
956 bpm->bquan += bp->bquan;
957 ESHK(shkp)->billct--;
958 #ifdef DUMB
959 {
960 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
961 int indx = ESHK(shkp)->billct;
962
963 *bp = ESHK(shkp)->bill_p[indx];
964 }
965 #else
966 *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
967 #endif
968 }
969 } else {
970 /* not on bill; if the item is being merged away rather than
971 just deleted and has a higher price adjustment than the stack
972 being merged into, give the latter the former's obj->o_id so
973 that the merged stack takes on higher price; matters if hero
974 eventually buys them from a shop, but doesn't matter if hero
975 owns them and intends to sell (unless he subsequently buys
976 them back) or if no shopping activity ever involves them */
977 if (merge && (oid_price_adjustment(obj, obj->o_id)
978 > oid_price_adjustment(merge, merge->o_id)))
979 merge->o_id = obj->o_id;
980 }
981 if (obj->owornmask) {
982 impossible("obfree: deleting worn obj (%d: %ld)", obj->otyp,
983 obj->owornmask);
984 /* unfortunately at this point we don't know whether worn mask
985 applied to hero or a monster or perhaps something bogus, so
986 can't call remove_worn_item() to get <X>_off() side-effects */
987 setnotworn(obj);
988 }
989 dealloc_obj(obj);
990 }
991
992 STATIC_OVL long
check_credit(tmp,shkp)993 check_credit(tmp, shkp)
994 long tmp;
995 register struct monst *shkp;
996 {
997 long credit = ESHK(shkp)->credit;
998
999 if (credit == 0L) {
1000 ; /* nothing to do; just 'return tmp;' */
1001 } else if (credit >= tmp) {
1002 pline_The("price is deducted from your credit.");
1003 ESHK(shkp)->credit -= tmp;
1004 tmp = 0L;
1005 } else {
1006 pline_The("price is partially covered by your credit.");
1007 ESHK(shkp)->credit = 0L;
1008 tmp -= credit;
1009 }
1010 return tmp;
1011 }
1012
1013 STATIC_OVL void
pay(tmp,shkp)1014 pay(tmp, shkp)
1015 long tmp;
1016 register struct monst *shkp;
1017 {
1018 long robbed = ESHK(shkp)->robbed;
1019 long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
1020
1021 if (balance > 0)
1022 money2mon(shkp, balance);
1023 else if (balance < 0)
1024 money2u(shkp, -balance);
1025 context.botl = 1;
1026 if (robbed) {
1027 robbed -= tmp;
1028 if (robbed < 0)
1029 robbed = 0L;
1030 ESHK(shkp)->robbed = robbed;
1031 }
1032 }
1033
1034 /* return shkp to home position */
1035 void
home_shk(shkp,killkops)1036 home_shk(shkp, killkops)
1037 register struct monst *shkp;
1038 register boolean killkops;
1039 {
1040 register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
1041
1042 (void) mnearto(shkp, x, y, TRUE);
1043 level.flags.has_shop = 1;
1044 if (killkops) {
1045 kops_gone(TRUE);
1046 pacify_guards();
1047 }
1048 after_shk_move(shkp);
1049 }
1050
1051 STATIC_OVL boolean
angry_shk_exists()1052 angry_shk_exists()
1053 {
1054 register struct monst *shkp;
1055
1056 for (shkp = next_shkp(fmon, FALSE); shkp;
1057 shkp = next_shkp(shkp->nmon, FALSE))
1058 if (ANGRY(shkp))
1059 return TRUE;
1060 return FALSE;
1061 }
1062
1063 /* remove previously applied surcharge from all billed items */
1064 STATIC_OVL void
pacify_shk(shkp)1065 pacify_shk(shkp)
1066 register struct monst *shkp;
1067 {
1068 NOTANGRY(shkp) = TRUE; /* make peaceful */
1069 if (ESHK(shkp)->surcharge) {
1070 register struct bill_x *bp = ESHK(shkp)->bill_p;
1071 register int ct = ESHK(shkp)->billct;
1072
1073 ESHK(shkp)->surcharge = FALSE;
1074 while (ct-- > 0) {
1075 register long reduction = (bp->price + 3L) / 4L;
1076 bp->price -= reduction; /* undo 33% increase */
1077 bp++;
1078 }
1079 }
1080 }
1081
1082 /* add aggravation surcharge to all billed items */
1083 STATIC_OVL void
rile_shk(shkp)1084 rile_shk(shkp)
1085 register struct monst *shkp;
1086 {
1087 NOTANGRY(shkp) = FALSE; /* make angry */
1088 if (!ESHK(shkp)->surcharge) {
1089 register struct bill_x *bp = ESHK(shkp)->bill_p;
1090 register int ct = ESHK(shkp)->billct;
1091
1092 ESHK(shkp)->surcharge = TRUE;
1093 while (ct-- > 0) {
1094 register long surcharge = (bp->price + 2L) / 3L;
1095 bp->price += surcharge;
1096 bp++;
1097 }
1098 }
1099 }
1100
1101 /* wakeup and/or unparalyze shopkeeper */
1102 STATIC_OVL void
rouse_shk(shkp,verbosely)1103 rouse_shk(shkp, verbosely)
1104 struct monst *shkp;
1105 boolean verbosely;
1106 {
1107 if (!shkp->mcanmove || shkp->msleeping) {
1108 /* greed induced recovery... */
1109 if (verbosely && canspotmon(shkp))
1110 pline("%s %s.", Shknam(shkp),
1111 shkp->msleeping ? "wakes up" : "can move again");
1112 shkp->msleeping = 0;
1113 shkp->mfrozen = 0;
1114 shkp->mcanmove = 1;
1115 }
1116 }
1117
1118 void
make_happy_shk(shkp,silentkops)1119 make_happy_shk(shkp, silentkops)
1120 register struct monst *shkp;
1121 register boolean silentkops;
1122 {
1123 boolean wasmad = ANGRY(shkp);
1124 struct eshk *eshkp = ESHK(shkp);
1125
1126 pacify_shk(shkp);
1127 eshkp->following = 0;
1128 eshkp->robbed = 0L;
1129 if (!Role_if(PM_ROGUE))
1130 adjalign(sgn(u.ualign.type));
1131 if (!inhishop(shkp)) {
1132 char shk_nam[BUFSZ];
1133 boolean vanished = canseemon(shkp);
1134
1135 Strcpy(shk_nam, shkname(shkp));
1136 if (on_level(&eshkp->shoplevel, &u.uz)) {
1137 home_shk(shkp, FALSE);
1138 /* didn't disappear if shk can still be seen */
1139 if (canseemon(shkp))
1140 vanished = FALSE;
1141 } else {
1142 /* if sensed, does disappear regardless whether seen */
1143 if (sensemon(shkp))
1144 vanished = TRUE;
1145 /* can't act as porter for the Amulet, even if shk
1146 happens to be going farther down rather than up */
1147 mdrop_special_objs(shkp);
1148 /* arrive near shop's door */
1149 migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
1150 MIGR_APPROX_XY, &eshkp->shd);
1151 /* dismiss kops on that level when shk arrives */
1152 eshkp->dismiss_kops = TRUE;
1153 }
1154 if (vanished)
1155 pline("Satisfied, %s suddenly disappears!", shk_nam);
1156 } else if (wasmad)
1157 pline("%s calms down.", Shknam(shkp));
1158
1159 make_happy_shoppers(silentkops);
1160 }
1161
1162 /* called by make_happy_shk() and also by losedogs() for migrating shk */
1163 void
make_happy_shoppers(silentkops)1164 make_happy_shoppers(silentkops)
1165 boolean silentkops;
1166 {
1167 if (!angry_shk_exists()) {
1168 kops_gone(silentkops);
1169 pacify_guards();
1170 }
1171 }
1172
1173 void
hot_pursuit(shkp)1174 hot_pursuit(shkp)
1175 register struct monst *shkp;
1176 {
1177 if (!shkp->isshk)
1178 return;
1179
1180 rile_shk(shkp);
1181 (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
1182 ESHK(shkp)->following = 1;
1183 }
1184
1185 /* Used when the shkp is teleported or falls (ox == 0) out of his shop, or
1186 when the player is not on a costly_spot and he damages something inside
1187 the shop. These conditions must be checked by the calling function. */
1188 /*ARGSUSED*/
1189 void
make_angry_shk(shkp,ox,oy)1190 make_angry_shk(shkp, ox, oy)
1191 struct monst *shkp;
1192 xchar ox UNUSED; /* <ox,oy> predate 'noit_Monnam()', let alone Shknam() */
1193 xchar oy UNUSED;
1194 {
1195 struct eshk *eshkp = ESHK(shkp);
1196
1197 /* all pending shop transactions are now "past due" */
1198 if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) {
1199 eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan);
1200 eshkp->robbed -= eshkp->credit;
1201 if (eshkp->robbed < 0L)
1202 eshkp->robbed = 0L;
1203 /* billct, debit, loan, and credit will be cleared by setpaid */
1204 setpaid(shkp);
1205 }
1206
1207 pline("%s %s!", Shknam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious");
1208 hot_pursuit(shkp);
1209 }
1210
1211 STATIC_VAR const char
1212 no_money[] = "Moreover, you%s have no money.",
1213 not_enough_money[] = "Besides, you don't have enough to interest %s.";
1214
1215 /* delivers the cheapest item on the list */
1216 STATIC_OVL long
cheapest_item(shkp)1217 cheapest_item(shkp)
1218 register struct monst *shkp;
1219 {
1220 register int ct = ESHK(shkp)->billct;
1221 register struct bill_x *bp = ESHK(shkp)->bill_p;
1222 register long gmin = (bp->price * bp->bquan);
1223
1224 while (ct--) {
1225 if (bp->price * bp->bquan < gmin)
1226 gmin = bp->price * bp->bquan;
1227 bp++;
1228 }
1229 return gmin;
1230 }
1231
1232 int
dopay()1233 dopay()
1234 {
1235 register struct eshk *eshkp;
1236 register struct monst *shkp;
1237 struct monst *nxtm, *resident;
1238 long ltmp;
1239 long umoney;
1240 int pass, tmp, sk = 0, seensk = 0;
1241 boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
1242
1243 multi = 0;
1244
1245 /* Find how many shk's there are, how many are in
1246 * sight, and are you in a shop room with one.
1247 */
1248 nxtm = resident = 0;
1249 for (shkp = next_shkp(fmon, FALSE); shkp;
1250 shkp = next_shkp(shkp->nmon, FALSE)) {
1251 sk++;
1252 if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2)
1253 nxtm = shkp;
1254 if (canspotmon(shkp))
1255 seensk++;
1256 if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
1257 resident = shkp;
1258 }
1259
1260 if (nxtm) { /* Player should always appease an */
1261 shkp = nxtm; /* irate shk standing next to them. */
1262 goto proceed;
1263 }
1264
1265 if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) {
1266 There("appears to be no shopkeeper here to receive your payment.");
1267 return 0;
1268 }
1269
1270 if (!seensk) {
1271 You_cant("see...");
1272 return 0;
1273 }
1274
1275 /* The usual case. Allow paying at a distance when
1276 * inside a tended shop. Should we change that?
1277 */
1278 if (sk == 1 && resident) {
1279 shkp = resident;
1280 goto proceed;
1281 }
1282
1283 if (seensk == 1) {
1284 for (shkp = next_shkp(fmon, FALSE); shkp;
1285 shkp = next_shkp(shkp->nmon, FALSE))
1286 if (canspotmon(shkp))
1287 break;
1288 if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
1289 pline("%s is not near enough to receive your payment.",
1290 Shknam(shkp));
1291 return 0;
1292 }
1293 } else {
1294 struct monst *mtmp;
1295 coord cc;
1296 int cx, cy;
1297
1298 pline("Pay whom?");
1299 cc.x = u.ux;
1300 cc.y = u.uy;
1301 if (getpos(&cc, TRUE, "the creature you want to pay") < 0)
1302 return 0; /* player pressed ESC */
1303 cx = cc.x;
1304 cy = cc.y;
1305 if (cx < 0) {
1306 pline("Try again...");
1307 return 0;
1308 }
1309 if (u.ux == cx && u.uy == cy) {
1310 You("are generous to yourself.");
1311 return 0;
1312 }
1313 mtmp = m_at(cx, cy);
1314 if (!cansee(cx, cy) && (!mtmp || !canspotmon(mtmp))) {
1315 You("can't %s anyone there.", !Blind ? "see" : "sense");
1316 return 0;
1317 }
1318 if (!mtmp) {
1319 There("is no one there to receive your payment.");
1320 return 0;
1321 }
1322 if (!mtmp->isshk) {
1323 pline("%s is not interested in your payment.", Monnam(mtmp));
1324 return 0;
1325 }
1326 if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
1327 pline("%s is too far to receive your payment.", Shknam(mtmp));
1328 return 0;
1329 }
1330 shkp = mtmp;
1331 }
1332
1333 if (!shkp) {
1334 debugpline0("dopay: null shkp.");
1335 return 0;
1336 }
1337 proceed:
1338 eshkp = ESHK(shkp);
1339 ltmp = eshkp->robbed;
1340
1341 /* wake sleeping shk when someone who owes money offers payment */
1342 if (ltmp || eshkp->billct || eshkp->debit)
1343 rouse_shk(shkp, TRUE);
1344
1345 if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */
1346 pline("%s %s.", Shknam(shkp),
1347 rn2(2) ? "seems to be napping" : "doesn't respond");
1348 return 0;
1349 }
1350
1351 if (shkp != resident && NOTANGRY(shkp)) {
1352 umoney = money_cnt(invent);
1353 if (!ltmp)
1354 You("do not owe %s anything.", shkname(shkp));
1355 else if (!umoney) {
1356 You("%shave no money.", stashed_gold ? "seem to " : "");
1357 if (stashed_gold)
1358 pline("But you have some gold stashed away.");
1359 } else {
1360 if (umoney > ltmp) {
1361 You("give %s the %ld gold piece%s %s asked for.",
1362 shkname(shkp), ltmp, plur(ltmp), noit_mhe(shkp));
1363 pay(ltmp, shkp);
1364 } else {
1365 You("give %s all your%s gold.", shkname(shkp),
1366 stashed_gold ? " openly kept" : "");
1367 pay(umoney, shkp);
1368 if (stashed_gold)
1369 pline("But you have hidden gold!");
1370 }
1371 if ((umoney < ltmp / 2L) || (umoney < ltmp && stashed_gold))
1372 pline("Unfortunately, %s doesn't look satisfied.",
1373 noit_mhe(shkp));
1374 else
1375 make_happy_shk(shkp, FALSE);
1376 }
1377 return 1;
1378 }
1379
1380 /* ltmp is still eshkp->robbed here */
1381 if (!eshkp->billct && !eshkp->debit) {
1382 umoney = money_cnt(invent);
1383 if (!ltmp && NOTANGRY(shkp)) {
1384 You("do not owe %s anything.", shkname(shkp));
1385 if (!umoney)
1386 pline(no_money, stashed_gold ? " seem to" : "");
1387 } else if (ltmp) {
1388 pline("%s is after blood, not money!", shkname(shkp));
1389 if (umoney < ltmp / 2L || (umoney < ltmp && stashed_gold)) {
1390 if (!umoney)
1391 pline(no_money, stashed_gold ? " seem to" : "");
1392 else
1393 pline(not_enough_money, noit_mhim(shkp));
1394 return 1;
1395 }
1396 pline("But since %s shop has been robbed recently,",
1397 noit_mhis(shkp));
1398 pline("you %scompensate %s for %s losses.",
1399 (umoney < ltmp) ? "partially " : "", shkname(shkp),
1400 noit_mhis(shkp));
1401 pay(umoney < ltmp ? umoney : ltmp, shkp);
1402 make_happy_shk(shkp, FALSE);
1403 } else {
1404 /* shopkeeper is angry, but has not been robbed --
1405 * door broken, attacked, etc. */
1406 pline("%s is after your hide, not your money!", Shknam(shkp));
1407 if (umoney < 1000L) {
1408 if (!umoney)
1409 pline(no_money, stashed_gold ? " seem to" : "");
1410 else
1411 pline(not_enough_money, noit_mhim(shkp));
1412 return 1;
1413 }
1414 You("try to appease %s by giving %s 1000 gold pieces.",
1415 canspotmon(shkp)
1416 ? x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE)
1417 : shkname(shkp),
1418 noit_mhim(shkp));
1419 pay(1000L, shkp);
1420 if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
1421 make_happy_shk(shkp, FALSE);
1422 else
1423 pline("But %s is as angry as ever.", shkname(shkp));
1424 }
1425 return 1;
1426 }
1427 if (shkp != resident) {
1428 impossible("dopay: not to shopkeeper?");
1429 if (resident)
1430 setpaid(resident);
1431 return 0;
1432 }
1433 /* pay debt, if any, first */
1434 if (eshkp->debit) {
1435 long dtmp = eshkp->debit;
1436 long loan = eshkp->loan;
1437 char sbuf[BUFSZ];
1438
1439 umoney = money_cnt(invent);
1440 Sprintf(sbuf, "You owe %s %ld %s ", shkname(shkp), dtmp,
1441 currency(dtmp));
1442 if (loan) {
1443 if (loan == dtmp)
1444 Strcat(sbuf, "you picked up in the store.");
1445 else
1446 Strcat(sbuf,
1447 "for gold picked up and the use of merchandise.");
1448 } else
1449 Strcat(sbuf, "for the use of merchandise.");
1450 pline1(sbuf);
1451 if (umoney + eshkp->credit < dtmp) {
1452 pline("But you don't%s have enough gold%s.",
1453 stashed_gold ? " seem to" : "",
1454 eshkp->credit ? " or credit" : "");
1455 return 1;
1456 } else {
1457 if (eshkp->credit >= dtmp) {
1458 eshkp->credit -= dtmp;
1459 eshkp->debit = 0L;
1460 eshkp->loan = 0L;
1461 Your("debt is covered by your credit.");
1462 } else if (!eshkp->credit) {
1463 money2mon(shkp, dtmp);
1464 eshkp->debit = 0L;
1465 eshkp->loan = 0L;
1466 You("pay that debt.");
1467 context.botl = 1;
1468 } else {
1469 dtmp -= eshkp->credit;
1470 eshkp->credit = 0L;
1471 money2mon(shkp, dtmp);
1472 eshkp->debit = 0L;
1473 eshkp->loan = 0L;
1474 pline("That debt is partially offset by your credit.");
1475 You("pay the remainder.");
1476 context.botl = 1;
1477 }
1478 paid = TRUE;
1479 }
1480 }
1481 /* now check items on bill */
1482 if (eshkp->billct) {
1483 register boolean itemize;
1484 int iprompt;
1485
1486 umoney = money_cnt(invent);
1487 if (!umoney && !eshkp->credit) {
1488 You("%shave no money or credit%s.",
1489 stashed_gold ? "seem to " : "", paid ? " left" : "");
1490 return 0;
1491 }
1492 if ((umoney + eshkp->credit) < cheapest_item(shkp)) {
1493 You("don't have enough money to buy%s the item%s you picked.",
1494 eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
1495 if (stashed_gold)
1496 pline("Maybe you have some gold stashed away?");
1497 return 0;
1498 }
1499
1500 /* this isn't quite right; it itemizes without asking if the
1501 * single item on the bill is partly used up and partly unpaid */
1502 iprompt = (eshkp->billct > 1 ? ynq("Itemized billing?") : 'y');
1503 itemize = (iprompt == 'y');
1504 if (iprompt == 'q')
1505 goto thanks;
1506
1507 for (pass = 0; pass <= 1; pass++) {
1508 tmp = 0;
1509 while (tmp < eshkp->billct) {
1510 struct obj *otmp;
1511 register struct bill_x *bp = &(eshkp->bill_p[tmp]);
1512
1513 /* find the object on one of the lists */
1514 if ((otmp = bp_to_obj(bp)) != 0) {
1515 /* if completely used up, object quantity is stale;
1516 restoring it to its original value here avoids
1517 making the partly-used-up code more complicated */
1518 if (bp->useup)
1519 otmp->quan = bp->bquan;
1520 } else {
1521 impossible("Shopkeeper administration out of order.");
1522 setpaid(shkp); /* be nice to the player */
1523 return 1;
1524 }
1525 if (pass == bp->useup && otmp->quan == bp->bquan) {
1526 /* pay for used-up items on first pass and others
1527 * on second, so player will be stuck in the store
1528 * less often; things which are partly used up
1529 * are processed on both passes */
1530 tmp++;
1531 } else {
1532 switch (dopayobj(shkp, bp, &otmp, pass, itemize)) {
1533 case PAY_CANT:
1534 return 1; /*break*/
1535 case PAY_BROKE:
1536 paid = TRUE;
1537 goto thanks; /*break*/
1538 case PAY_SKIP:
1539 tmp++;
1540 continue; /*break*/
1541 case PAY_SOME:
1542 paid = TRUE;
1543 if (itemize)
1544 bot();
1545 continue; /*break*/
1546 case PAY_BUY:
1547 paid = TRUE;
1548 break;
1549 }
1550 if (itemize)
1551 bot();
1552 *bp = eshkp->bill_p[--eshkp->billct];
1553 }
1554 }
1555 }
1556 thanks:
1557 if (!itemize)
1558 update_inventory(); /* Done in dopayobj() if itemize. */
1559 }
1560 if (!ANGRY(shkp) && paid) {
1561 if (!Deaf && !muteshk(shkp))
1562 verbalize("Thank you for shopping in %s %s!",
1563 s_suffix(shkname(shkp)),
1564 shtypes[eshkp->shoptype - SHOPBASE].name);
1565 else
1566 pline("%s nods appreciatively at you for shopping in %s %s!",
1567 Shknam(shkp), noit_mhis(shkp),
1568 shtypes[eshkp->shoptype - SHOPBASE].name);
1569 }
1570 return 1;
1571 }
1572
1573 /* return 2 if used-up portion paid
1574 * 1 if paid successfully
1575 * 0 if not enough money
1576 * -1 if skip this object
1577 * -2 if no money/credit left
1578 */
1579 STATIC_OVL int
dopayobj(shkp,bp,obj_p,which,itemize)1580 dopayobj(shkp, bp, obj_p, which, itemize)
1581 register struct monst *shkp;
1582 register struct bill_x *bp;
1583 struct obj **obj_p;
1584 int which; /* 0 => used-up item, 1 => other (unpaid or lost) */
1585 boolean itemize;
1586 {
1587 register struct obj *obj = *obj_p;
1588 long ltmp, quan, save_quan;
1589 long umoney = money_cnt(invent);
1590 int buy;
1591 boolean stashed_gold = (hidden_gold() > 0L), consumed = (which == 0);
1592
1593 if (!obj->unpaid && !bp->useup) {
1594 impossible("Paid object on bill??");
1595 return PAY_BUY;
1596 }
1597 if (itemize && umoney + ESHK(shkp)->credit == 0L) {
1598 You("%shave no money or credit left.",
1599 stashed_gold ? "seem to " : "");
1600 return PAY_BROKE;
1601 }
1602 /* we may need to temporarily adjust the object, if part of the
1603 original quantity has been used up but part remains unpaid */
1604 save_quan = obj->quan;
1605 if (consumed) {
1606 /* either completely used up (simple), or split needed */
1607 quan = bp->bquan;
1608 if (quan > obj->quan) /* difference is amount used up */
1609 quan -= obj->quan;
1610 } else {
1611 /* dealing with ordinary unpaid item */
1612 quan = obj->quan;
1613 }
1614 obj->quan = quan; /* to be used by doname() */
1615 obj->unpaid = 0; /* ditto */
1616 iflags.suppress_price++; /* affects containers */
1617 ltmp = bp->price * quan;
1618 buy = PAY_BUY; /* flag; if changed then return early */
1619
1620 if (itemize) {
1621 char qbuf[BUFSZ], qsfx[BUFSZ];
1622
1623 Sprintf(qsfx, " for %ld %s. Pay?", ltmp, currency(ltmp));
1624 (void) safe_qbuf(qbuf, (char *) 0, qsfx, obj,
1625 (quan == 1L) ? Doname2 : doname, ansimpleoname,
1626 (quan == 1L) ? "that" : "those");
1627 if (yn(qbuf) == 'n') {
1628 buy = PAY_SKIP; /* don't want to buy */
1629 } else if (quan < bp->bquan && !consumed) { /* partly used goods */
1630 obj->quan = bp->bquan - save_quan; /* used up amount */
1631 if (!Deaf && !muteshk(shkp)) {
1632 verbalize("%s for the other %s before buying %s.",
1633 ANGRY(shkp) ? "Pay" : "Please pay",
1634 simpleonames(obj), /* short name suffices */
1635 save_quan > 1L ? "these" : "this one");
1636 } else {
1637 pline("%s %s%s your bill for the other %s first.",
1638 Shknam(shkp),
1639 ANGRY(shkp) ? "angrily " : "",
1640 nolimbs(shkp->data) ? "motions to" : "points out",
1641 simpleonames(obj));
1642 }
1643 buy = PAY_SKIP; /* shk won't sell */
1644 }
1645 }
1646 if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) {
1647 You("don't%s have gold%s enough to pay for %s.",
1648 stashed_gold ? " seem to" : "",
1649 (ESHK(shkp)->credit > 0L) ? " or credit" : "",
1650 thesimpleoname(obj));
1651 buy = itemize ? PAY_SKIP : PAY_CANT;
1652 }
1653
1654 if (buy != PAY_BUY) {
1655 /* restore unpaid object to original state */
1656 obj->quan = save_quan;
1657 obj->unpaid = 1;
1658 iflags.suppress_price--;
1659 return buy;
1660 }
1661
1662 pay(ltmp, shkp);
1663 shk_names_obj(shkp, obj,
1664 consumed ? "paid for %s at a cost of %ld gold piece%s.%s"
1665 : "bought %s for %ld gold piece%s.%s",
1666 ltmp, "");
1667 obj->quan = save_quan; /* restore original count */
1668 /* quan => amount just bought, save_quan => remaining unpaid count */
1669 if (consumed) {
1670 if (quan != bp->bquan) {
1671 /* eliminate used-up portion; remainder is still unpaid */
1672 bp->bquan = obj->quan;
1673 obj->unpaid = 1;
1674 bp->useup = 0;
1675 buy = PAY_SOME;
1676 } else { /* completely used-up, so get rid of it */
1677 obj_extract_self(obj);
1678 /* assert( obj == *obj_p ); */
1679 dealloc_obj(obj);
1680 *obj_p = 0; /* destroy pointer to freed object */
1681 }
1682 } else if (itemize)
1683 update_inventory(); /* Done just once in dopay() if !itemize. */
1684 iflags.suppress_price--;
1685 return buy;
1686 }
1687
1688 static struct repo { /* repossession context */
1689 struct monst *shopkeeper;
1690 coord location;
1691 } repo;
1692
1693 /* routine called after dying (or quitting) */
1694 boolean
paybill(croaked,silently)1695 paybill(croaked, silently)
1696 int croaked; /* -1: escaped dungeon; 0: quit; 1: died */
1697 boolean silently; /* maybe avoid messages */
1698 {
1699 struct monst *mtmp, *mtmp2, *firstshk, *resident, *creditor, *hostile,
1700 *localshk;
1701 struct eshk *eshkp;
1702 boolean taken = FALSE, local;
1703 int numsk = 0;
1704
1705 /* if we escaped from the dungeon, shopkeepers can't reach us;
1706 shops don't occur on level 1, but this could happen if hero
1707 level teleports out of the dungeon and manages not to die */
1708 if (croaked < 0)
1709 return FALSE;
1710 /* [should probably also return false when dead hero has been
1711 petrified since shk shouldn't be able to grab inventory
1712 which has been shut inside a statue] */
1713
1714 /* this is where inventory will end up if any shk takes it */
1715 repo.location.x = repo.location.y = 0;
1716 repo.shopkeeper = 0;
1717
1718 /*
1719 * Scan all shopkeepers on the level, to prioritize them:
1720 * 1) keeper of shop hero is inside and who is owed money,
1721 * 2) keeper of shop hero is inside who isn't owed any money,
1722 * 3) other shk who is owed money, 4) other shk who is angry,
1723 * 5) any shk local to this level, and if none is found,
1724 * 6) first shk on monster list (last resort; unlikely, since
1725 * any nonlocal shk will probably be in the owed category
1726 * and almost certainly be in the angry category).
1727 */
1728 resident = creditor = hostile = localshk = (struct monst *) 0;
1729 for (mtmp = next_shkp(fmon, FALSE); mtmp;
1730 mtmp = next_shkp(mtmp2, FALSE)) {
1731 mtmp2 = mtmp->nmon;
1732 eshkp = ESHK(mtmp);
1733 local = on_level(&eshkp->shoplevel, &u.uz);
1734 if (local && index(u.ushops, eshkp->shoproom)) {
1735 /* inside this shk's shop [there might be more than one
1736 resident shk if hero is standing in a breech of a shared
1737 wall, so give priority to one who's also owed money] */
1738 if (!resident || eshkp->billct || eshkp->debit || eshkp->robbed)
1739 resident = mtmp;
1740 } else if (eshkp->billct || eshkp->debit || eshkp->robbed) {
1741 /* owe this shopkeeper money (might also owe others) */
1742 if (!creditor)
1743 creditor = mtmp;
1744 } else if (eshkp->following || ANGRY(mtmp)) {
1745 /* this shopkeeper is antagonistic (others might be too) */
1746 if (!hostile)
1747 hostile = mtmp;
1748 } else if (local) {
1749 /* this shopkeeper's shop is on current level */
1750 if (!localshk)
1751 localshk = mtmp;
1752 }
1753 }
1754
1755 /* give highest priority shopkeeper first crack */
1756 firstshk = resident ? resident
1757 : creditor ? creditor
1758 : hostile ? hostile
1759 : localshk;
1760 if (firstshk) {
1761 numsk++;
1762 taken = inherits(firstshk, numsk, croaked, silently);
1763 }
1764
1765 /* now handle the rest */
1766 for (mtmp = next_shkp(fmon, FALSE); mtmp;
1767 mtmp = next_shkp(mtmp2, FALSE)) {
1768 mtmp2 = mtmp->nmon;
1769 eshkp = ESHK(mtmp);
1770 local = on_level(&eshkp->shoplevel, &u.uz);
1771 if (mtmp != firstshk) {
1772 numsk++;
1773 taken |= inherits(mtmp, numsk, croaked, silently);
1774 }
1775 /* for bones: we don't want a shopless shk around */
1776 if (!local)
1777 mongone(mtmp);
1778 }
1779 return taken;
1780 }
1781
1782 STATIC_OVL boolean
inherits(shkp,numsk,croaked,silently)1783 inherits(shkp, numsk, croaked, silently)
1784 struct monst *shkp;
1785 int numsk;
1786 int croaked;
1787 boolean silently;
1788 {
1789 long loss = 0L;
1790 long umoney;
1791 struct eshk *eshkp = ESHK(shkp);
1792 boolean take = FALSE, taken = FALSE;
1793 unsigned save_minvis = shkp->minvis;
1794 int roomno = *u.ushops;
1795 char takes[BUFSZ];
1796
1797 /* not strictly consistent; affects messages and prevents next player
1798 (if bones are saved) from blundering into or being ambused by an
1799 invisible shopkeeper */
1800 shkp->minvis = 0;
1801 /* The simplifying principle is that first-come
1802 already took everything you had. */
1803 if (numsk > 1) {
1804 if (cansee(shkp->mx, shkp->my) && croaked && !silently) {
1805 takes[0] = '\0';
1806 if (has_head(shkp->data) && !rn2(2))
1807 Sprintf(takes, ", shakes %s %s,", noit_mhis(shkp),
1808 mbodypart(shkp, HEAD));
1809 pline("%s %slooks at your corpse%s and %s.", Shknam(shkp),
1810 (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "",
1811 takes, !inhishop(shkp) ? "disappears" : "sighs");
1812 }
1813 rouse_shk(shkp, FALSE); /* wake shk for bones */
1814 taken = (roomno == eshkp->shoproom);
1815 goto skip;
1816 }
1817
1818 /* get one case out of the way: you die in the shop, the */
1819 /* shopkeeper is peaceful, nothing stolen, nothing owed. */
1820 if (roomno == eshkp->shoproom && inhishop(shkp) && !eshkp->billct
1821 && !eshkp->robbed && !eshkp->debit && NOTANGRY(shkp)
1822 && !eshkp->following && u.ugrave_arise < LOW_PM) {
1823 taken = (invent != 0);
1824 if (taken && !silently)
1825 pline("%s gratefully inherits all your possessions.",
1826 Shknam(shkp));
1827 set_repo_loc(shkp);
1828 goto clear;
1829 }
1830
1831 if (eshkp->billct || eshkp->debit || eshkp->robbed) {
1832 if (roomno == eshkp->shoproom && inhishop(shkp))
1833 loss = addupbill(shkp) + eshkp->debit;
1834 if (loss < eshkp->robbed)
1835 loss = eshkp->robbed;
1836 take = TRUE;
1837 }
1838
1839 if (eshkp->following || ANGRY(shkp) || take) {
1840 if (!invent)
1841 goto skip;
1842 umoney = money_cnt(invent);
1843 takes[0] = '\0';
1844 if (!shkp->mcanmove || shkp->msleeping)
1845 Strcat(takes, "wakes up and ");
1846 if (distu(shkp->mx, shkp->my) > 2)
1847 Strcat(takes, "comes and ");
1848 Strcat(takes, "takes");
1849
1850 if (loss > umoney || !loss || roomno == eshkp->shoproom) {
1851 eshkp->robbed -= umoney;
1852 if (eshkp->robbed < 0L)
1853 eshkp->robbed = 0L;
1854 if (umoney > 0L) {
1855 money2mon(shkp, umoney);
1856 context.botl = 1;
1857 }
1858 if (!silently)
1859 pline("%s %s all your possessions.", Shknam(shkp), takes);
1860 taken = TRUE;
1861 /* where to put player's invent (after disclosure) */
1862 set_repo_loc(shkp);
1863 } else {
1864 money2mon(shkp, loss);
1865 context.botl = 1;
1866 if (!silently)
1867 pline("%s %s the %ld %s %sowed %s.", Shknam(shkp),
1868 takes, loss, currency(loss),
1869 strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ",
1870 noit_mhim(shkp));
1871 /* shopkeeper has now been paid in full */
1872 pacify_shk(shkp);
1873 eshkp->following = 0;
1874 eshkp->robbed = 0L;
1875 }
1876 skip:
1877 /* in case we create bones */
1878 rouse_shk(shkp, FALSE); /* wake up */
1879 if (!inhishop(shkp))
1880 home_shk(shkp, FALSE);
1881 }
1882 clear:
1883 shkp->minvis = save_minvis;
1884 setpaid(shkp);
1885 return taken;
1886 }
1887
1888 STATIC_OVL void
set_repo_loc(shkp)1889 set_repo_loc(shkp)
1890 struct monst *shkp;
1891 {
1892 register xchar ox, oy;
1893 struct eshk *eshkp = ESHK(shkp);
1894
1895 /* if you're not in this shk's shop room, or if you're in its doorway
1896 or entry spot, then your gear gets dumped all the way inside */
1897 if (*u.ushops != eshkp->shoproom || IS_DOOR(levl[u.ux][u.uy].typ)
1898 || (u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) {
1899 /* shk.x,shk.y is the position immediately in
1900 * front of the door -- move in one more space
1901 */
1902 ox = eshkp->shk.x;
1903 oy = eshkp->shk.y;
1904 ox += sgn(ox - eshkp->shd.x);
1905 oy += sgn(oy - eshkp->shd.y);
1906 } else { /* already inside this shk's shop */
1907 ox = u.ux;
1908 oy = u.uy;
1909 }
1910 /* finish_paybill will deposit invent here */
1911 repo.location.x = ox;
1912 repo.location.y = oy;
1913 repo.shopkeeper = shkp;
1914 }
1915
1916 /* called at game exit, after inventory disclosure but before making bones;
1917 shouldn't issue any messages */
1918 void
finish_paybill()1919 finish_paybill()
1920 {
1921 struct monst *shkp = repo.shopkeeper;
1922 int ox = repo.location.x, oy = repo.location.y;
1923
1924 #if 0 /* don't bother */
1925 if (ox == 0 && oy == 0)
1926 impossible("finish_paybill: no location");
1927 #endif
1928 /* normally done by savebones(), but that's too late in this case */
1929 unleash_all();
1930 /* if hero has any gold left, take it into shopkeeper's possession */
1931 if (shkp) {
1932 long umoney = money_cnt(invent);
1933
1934 if (umoney)
1935 money2mon(shkp, umoney);
1936 }
1937 /* transfer rest of the character's inventory to the shop floor */
1938 drop_upon_death((struct monst *) 0, (struct obj *) 0, ox, oy);
1939 }
1940
1941 /* find obj on one of the lists */
1942 STATIC_OVL struct obj *
bp_to_obj(bp)1943 bp_to_obj(bp)
1944 register struct bill_x *bp;
1945 {
1946 register struct obj *obj;
1947 register unsigned int id = bp->bo_id;
1948
1949 if (bp->useup)
1950 obj = o_on(id, billobjs);
1951 else
1952 obj = find_oid(id);
1953 return obj;
1954 }
1955
1956 /*
1957 * Look for o_id on all lists but billobj. Return obj or NULL if not found.
1958 * Its OK for restore_timers() to call this function, there should not
1959 * be any timeouts on the billobjs chain.
1960 */
1961 struct obj *
find_oid(id)1962 find_oid(id)
1963 unsigned id;
1964 {
1965 struct obj *obj;
1966 struct monst *mon, *mmtmp[3];
1967 int i;
1968
1969 /* first check various obj lists directly */
1970 if ((obj = o_on(id, invent)) != 0)
1971 return obj;
1972 if ((obj = o_on(id, fobj)) != 0)
1973 return obj;
1974 if ((obj = o_on(id, level.buriedobjlist)) != 0)
1975 return obj;
1976 if ((obj = o_on(id, migrating_objs)) != 0)
1977 return obj;
1978
1979 /* not found yet; check inventory for members of various monst lists */
1980 mmtmp[0] = fmon;
1981 mmtmp[1] = migrating_mons;
1982 mmtmp[2] = mydogs; /* for use during level changes */
1983 for (i = 0; i < 3; i++)
1984 for (mon = mmtmp[i]; mon; mon = mon->nmon)
1985 if ((obj = o_on(id, mon->minvent)) != 0)
1986 return obj;
1987
1988 /* not found at all */
1989 return (struct obj *) 0;
1990 }
1991
1992 /* Returns the price of an arbitrary item in the shop,
1993 0 if the item doesn't belong to a shopkeeper or hero is not in the shop. */
1994 long
get_cost_of_shop_item(obj,nochrg)1995 get_cost_of_shop_item(obj, nochrg)
1996 register struct obj *obj;
1997 int *nochrg; /* alternate return value: 1: no charge, 0: shop owned, */
1998 { /* -1: not in a shop (so should't be formatted as "no charge") */
1999 struct monst *shkp;
2000 struct obj *top;
2001 xchar x, y;
2002 boolean freespot;
2003 long cost = 0L;
2004
2005 *nochrg = -1; /* assume 'not applicable' */
2006 if (*u.ushops && obj->oclass != COIN_CLASS
2007 && obj != uball && obj != uchain
2008 && get_obj_location(obj, &x, &y, CONTAINED_TOO)
2009 && *in_rooms(x, y, SHOPBASE) == *u.ushops
2010 && (shkp = shop_keeper(inside_shop(x, y))) != 0 && inhishop(shkp)) {
2011 for (top = obj; top->where == OBJ_CONTAINED; top = top->ocontainer)
2012 continue;
2013 freespot = (top->where == OBJ_FLOOR
2014 && x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y);
2015 /* no_charge is only set for floor items inside shop proper;
2016 items on freespot are implicitly 'no charge' */
2017 *nochrg = (top->where == OBJ_FLOOR && (obj->no_charge || freespot));
2018
2019 if (carried(top) ? (int) obj->unpaid : !*nochrg) {
2020 long per_unit_cost = get_cost(obj, shkp);
2021
2022 cost = get_pricing_units(obj) * per_unit_cost;
2023 }
2024 if (Has_contents(obj) && !freespot)
2025 cost += contained_cost(obj, shkp, 0L, FALSE, TRUE);
2026 }
2027 return cost;
2028 }
2029
2030 STATIC_OVL long
get_pricing_units(obj)2031 get_pricing_units(obj)
2032 struct obj *obj;
2033 {
2034 long units = obj->quan;
2035
2036 if (obj->globby) {
2037 /* globs must be sold by weight not by volume */
2038 long unit_weight = (long) objects[obj->otyp].oc_weight,
2039 wt = (obj->owt > 0) ? (long) obj->owt : (long) weight(obj);
2040
2041 if (unit_weight)
2042 units = (wt + unit_weight - 1L) / unit_weight;
2043 }
2044 return units;
2045 }
2046
2047 /* decide whether to apply a surcharge (or hypothetically, a discount) to obj
2048 if it had ID number 'oid'; returns 1: increase, 0: normal, -1: decrease */
2049 int
oid_price_adjustment(obj,oid)2050 oid_price_adjustment(obj, oid)
2051 struct obj *obj;
2052 unsigned oid;
2053 {
2054 int res = 0, otyp = obj->otyp;
2055
2056 if (!(obj->dknown && objects[otyp].oc_name_known)
2057 && (obj->oclass != GEM_CLASS || objects[otyp].oc_material != GLASS)) {
2058 res = ((oid % 4) == 0); /* id%4 ==0 -> +1, ==1..3 -> 0 */
2059 }
2060 return res;
2061 }
2062
2063 /* calculate the value that the shk will charge for [one of] an object */
2064 STATIC_OVL long
get_cost(obj,shkp)2065 get_cost(obj, shkp)
2066 register struct obj *obj;
2067 register struct monst *shkp; /* if angry, impose a surcharge */
2068 {
2069 long tmp = getprice(obj, FALSE),
2070 /* used to perform a single calculation even when multiple
2071 adjustments (unID'd, dunce/tourist, charisma) are made */
2072 multiplier = 1L, divisor = 1L;
2073
2074 if (!tmp)
2075 tmp = 5L;
2076 /* shopkeeper may notice if the player isn't very knowledgeable -
2077 especially when gem prices are concerned */
2078 if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
2079 if (obj->oclass == GEM_CLASS
2080 && objects[obj->otyp].oc_material == GLASS) {
2081 int i;
2082 /* get a value that's 'random' from game to game, but the
2083 same within the same game */
2084 boolean pseudorand =
2085 (((int) ubirthday % obj->otyp) >= obj->otyp / 2);
2086
2087 /* all gems are priced high - real or not */
2088 switch (obj->otyp - LAST_GEM) {
2089 case 1: /* white */
2090 i = pseudorand ? DIAMOND : OPAL;
2091 break;
2092 case 2: /* blue */
2093 i = pseudorand ? SAPPHIRE : AQUAMARINE;
2094 break;
2095 case 3: /* red */
2096 i = pseudorand ? RUBY : JASPER;
2097 break;
2098 case 4: /* yellowish brown */
2099 i = pseudorand ? AMBER : TOPAZ;
2100 break;
2101 case 5: /* orange */
2102 i = pseudorand ? JACINTH : AGATE;
2103 break;
2104 case 6: /* yellow */
2105 i = pseudorand ? CITRINE : CHRYSOBERYL;
2106 break;
2107 case 7: /* black */
2108 i = pseudorand ? BLACK_OPAL : JET;
2109 break;
2110 case 8: /* green */
2111 i = pseudorand ? EMERALD : JADE;
2112 break;
2113 case 9: /* violet */
2114 i = pseudorand ? AMETHYST : FLUORITE;
2115 break;
2116 default:
2117 impossible("bad glass gem %d?", obj->otyp);
2118 i = STRANGE_OBJECT;
2119 break;
2120 }
2121 tmp = (long) objects[i].oc_cost;
2122 } else if (oid_price_adjustment(obj, obj->o_id) > 0) {
2123 /* unid'd, arbitrarily impose surcharge: tmp *= 4/3 */
2124 multiplier *= 4L;
2125 divisor *= 3L;
2126 }
2127 }
2128 if (uarmh && uarmh->otyp == DUNCE_CAP)
2129 multiplier *= 4L, divisor *= 3L;
2130 else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV / 2))
2131 || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */
2132 multiplier *= 4L, divisor *= 3L;
2133
2134 if (ACURR(A_CHA) > 18)
2135 divisor *= 2L;
2136 else if (ACURR(A_CHA) == 18)
2137 multiplier *= 2L, divisor *= 3L;
2138 else if (ACURR(A_CHA) >= 16)
2139 multiplier *= 3L, divisor *= 4L;
2140 else if (ACURR(A_CHA) <= 5)
2141 multiplier *= 2L;
2142 else if (ACURR(A_CHA) <= 7)
2143 multiplier *= 3L, divisor *= 2L;
2144 else if (ACURR(A_CHA) <= 10)
2145 multiplier *= 4L, divisor *= 3L;
2146
2147 /* tmp = (tmp * multiplier) / divisor [with roundoff tweak] */
2148 tmp *= multiplier;
2149 if (divisor > 1L) {
2150 /* tmp = (((tmp * 10) / divisor) + 5) / 10 */
2151 tmp *= 10L;
2152 tmp /= divisor;
2153 tmp += 5L;
2154 tmp /= 10L;
2155 }
2156
2157 if (tmp <= 0L)
2158 tmp = 1L;
2159 /* the artifact prices in artilist[] are also used as a score bonus;
2160 inflate their shop price here without affecting score calculation */
2161 if (obj->oartifact)
2162 tmp *= 4L;
2163
2164 /* anger surcharge should match rile_shk's, so we do it separately
2165 from the multiplier/divisor calculation */
2166 if (shkp && ESHK(shkp)->surcharge)
2167 tmp += (tmp + 2L) / 3L;
2168 return tmp;
2169 }
2170
2171 /* returns the price of a container's content. the price
2172 * of the "top" container is added in the calling functions.
2173 * a different price quoted for selling as vs. buying.
2174 */
2175 long
contained_cost(obj,shkp,price,usell,unpaid_only)2176 contained_cost(obj, shkp, price, usell, unpaid_only)
2177 struct obj *obj;
2178 struct monst *shkp;
2179 long price;
2180 boolean usell;
2181 boolean unpaid_only;
2182 {
2183 register struct obj *otmp, *top;
2184 xchar x, y;
2185 boolean on_floor, freespot;
2186
2187 for (top = obj; top->where == OBJ_CONTAINED; top = top->ocontainer)
2188 continue;
2189 /* pick_obj() removes item from floor, adds it to shop bill, then
2190 puts it in inventory; behave as if it is still on the floor
2191 during the add-to-bill portion of that situation */
2192 on_floor = (top->where == OBJ_FLOOR || top->where == OBJ_FREE);
2193 if (top->where == OBJ_FREE || !get_obj_location(top, &x, &y, 0))
2194 x = u.ux, y = u.uy;
2195 freespot = (on_floor && x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y);
2196
2197 /* price of contained objects; "top" container handled by caller */
2198 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2199 if (otmp->oclass == COIN_CLASS)
2200 continue;
2201
2202 if (usell) {
2203 if (saleable(shkp, otmp) && !otmp->unpaid
2204 && otmp->oclass != BALL_CLASS
2205 && !(otmp->oclass == FOOD_CLASS && otmp->oeaten)
2206 && !(Is_candle(otmp)
2207 && otmp->age < 20L * (long) objects[otmp->otyp].oc_cost))
2208 price += set_cost(otmp, shkp);
2209 } else {
2210 /* no_charge is only set for floor items (including
2211 contents of floor containers) inside shop proper;
2212 items on freespot are implicitly 'no charge' */
2213 if (on_floor ? (!otmp->no_charge && !freespot)
2214 : (otmp->unpaid || !unpaid_only))
2215 price += get_cost(otmp, shkp) * get_pricing_units(otmp);
2216 }
2217
2218 if (Has_contents(otmp))
2219 price = contained_cost(otmp, shkp, price, usell, unpaid_only);
2220 }
2221
2222 return price;
2223 }
2224
2225 /* count amount of gold inside container 'obj' and any nested containers */
2226 long
contained_gold(obj)2227 contained_gold(obj)
2228 struct obj *obj;
2229 {
2230 register struct obj *otmp;
2231 register long value = 0L;
2232
2233 /* accumulate contained gold */
2234 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
2235 if (otmp->oclass == COIN_CLASS)
2236 value += otmp->quan;
2237 else if (Has_contents(otmp))
2238 value += contained_gold(otmp);
2239
2240 return value;
2241 }
2242
2243 STATIC_OVL void
dropped_container(obj,shkp,sale)2244 dropped_container(obj, shkp, sale)
2245 register struct obj *obj;
2246 register struct monst *shkp;
2247 register boolean sale;
2248 {
2249 register struct obj *otmp;
2250
2251 /* the "top" container is treated in the calling fn */
2252 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2253 if (otmp->oclass == COIN_CLASS)
2254 continue;
2255
2256 if (!otmp->unpaid && !(sale && saleable(shkp, otmp)))
2257 otmp->no_charge = 1;
2258
2259 if (Has_contents(otmp))
2260 dropped_container(otmp, shkp, sale);
2261 }
2262 }
2263
2264 void
picked_container(obj)2265 picked_container(obj)
2266 register struct obj *obj;
2267 {
2268 register struct obj *otmp;
2269
2270 /* the "top" container is treated in the calling fn */
2271 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2272 if (otmp->oclass == COIN_CLASS)
2273 continue;
2274
2275 if (otmp->no_charge)
2276 otmp->no_charge = 0;
2277
2278 if (Has_contents(otmp))
2279 picked_container(otmp);
2280 }
2281 }
2282
2283 STATIC_OVL boolean
special_stock(obj,shkp,quietly)2284 special_stock(obj, shkp, quietly)
2285 struct obj *obj;
2286 struct monst *shkp;
2287 boolean quietly;
2288 {
2289 /* for unique situations */
2290 if (ESHK(shkp)->shoptype == CANDLESHOP
2291 && obj->otyp == CANDELABRUM_OF_INVOCATION) {
2292 if (!quietly) {
2293 if (is_izchak(shkp, TRUE) && !u.uevent.invoked) {
2294 if (Deaf || muteshk(shkp)) {
2295 pline("%s seems %s that you want to sell that.",
2296 Shknam(shkp),
2297 (obj->spe < 7) ? "horrified" : "concerned");
2298 } else {
2299 verbalize("No thanks, I'd hang onto that if I were you.");
2300 if (obj->spe < 7)
2301 verbalize(
2302 "You'll need %d%s candle%s to go along with it.",
2303 (7 - obj->spe), (obj->spe > 0) ? " more" : "",
2304 plur(7 - obj->spe));
2305 /* [what if hero is already carrying enough candles?
2306 should Izchak explain how to attach them instead?] */
2307 }
2308 } else {
2309 if (!Deaf && !muteshk(shkp))
2310 verbalize("I won't stock that. Take it out of here!");
2311 else
2312 pline("%s shakes %s %s in refusal.",
2313 Shknam(shkp), noit_mhis(shkp),
2314 mbodypart(shkp, HEAD));
2315 }
2316 }
2317 return TRUE;
2318 }
2319 return FALSE;
2320 }
2321
2322 /* calculate how much the shk will pay when buying [all of] an object */
2323 STATIC_OVL long
set_cost(obj,shkp)2324 set_cost(obj, shkp)
2325 register struct obj *obj;
2326 register struct monst *shkp;
2327 {
2328 long tmp, unit_price = getprice(obj, TRUE), multiplier = 1L, divisor = 1L;
2329
2330 tmp = get_pricing_units(obj) * unit_price;
2331
2332 if (uarmh && uarmh->otyp == DUNCE_CAP)
2333 divisor *= 3L;
2334 else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV / 2))
2335 || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */
2336 divisor *= 3L;
2337 else
2338 divisor *= 2L;
2339
2340 /* shopkeeper may notice if the player isn't very knowledgeable -
2341 especially when gem prices are concerned */
2342 if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
2343 if (obj->oclass == GEM_CLASS) {
2344 /* different shop keepers give different prices */
2345 if (objects[obj->otyp].oc_material == GEMSTONE
2346 || objects[obj->otyp].oc_material == GLASS) {
2347 tmp = (obj->otyp % (6 - shkp->m_id % 3));
2348 tmp = (tmp + 3) * obj->quan;
2349 }
2350 } else if (tmp > 1L && !(shkp->m_id % 4))
2351 multiplier *= 3L, divisor *= 4L;
2352 }
2353
2354 if (tmp >= 1L) {
2355 /* [see get_cost()] */
2356 tmp *= multiplier;
2357 if (divisor > 1L) {
2358 tmp *= 10L;
2359 tmp /= divisor;
2360 tmp += 5L;
2361 tmp /= 10L;
2362 }
2363 /* avoid adjusting nonzero to zero */
2364 if (tmp < 1L)
2365 tmp = 1L;
2366 }
2367
2368 /* (no adjustment for angry shk here) */
2369 return tmp;
2370 }
2371
2372 /* unlike alter_cost() which operates on a specific item, identifying or
2373 forgetting a gem causes all unpaid gems of its type to change value */
2374 void
gem_learned(oindx)2375 gem_learned(oindx)
2376 int oindx;
2377 {
2378 struct obj *obj;
2379 struct monst *shkp;
2380 struct bill_x *bp;
2381 int ct;
2382
2383 /*
2384 * Unfortunately, shop bill doesn't have object type included,
2385 * just obj->oid for each unpaid stack, so we have to go through
2386 * every bill and every item on that bill and match up against
2387 * every unpaid stack on the level....
2388 *
2389 * Fortunately, there's no need to catch up when changing dungeon
2390 * levels even if we ID'd or forget some gems while gone from a
2391 * level. There won't be any shop bills when arriving; they were
2392 * either paid before leaving or got treated as robbery and it's
2393 * too late to adjust pricing.
2394 */
2395 for (shkp = next_shkp(fmon, TRUE); shkp;
2396 shkp = next_shkp(shkp->nmon, TRUE)) {
2397 ct = ESHK(shkp)->billct;
2398 bp = ESHK(shkp)->bill;
2399 while (--ct >= 0) {
2400 obj = find_oid(bp->bo_id);
2401 if (!obj) /* shouldn't happen */
2402 continue;
2403 if ((oindx != STRANGE_OBJECT) ? (obj->otyp == oindx)
2404 : (obj->oclass == GEM_CLASS))
2405 bp->price = get_cost(obj, shkp);
2406 ++bp;
2407 }
2408 }
2409 }
2410
2411 /* called when an item's value has been enhanced; if it happens to be
2412 on any shop bill, update that bill to reflect the new higher price
2413 [if the new price drops for some reason, keep the old one in place] */
2414 void
alter_cost(obj,amt)2415 alter_cost(obj, amt)
2416 struct obj *obj;
2417 long amt; /* if 0, use regular shop pricing, otherwise force amount;
2418 if negative, use abs(amt) even if it's less than old cost */
2419 {
2420 struct bill_x *bp = 0;
2421 struct monst *shkp;
2422 long new_price;
2423
2424 for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp, TRUE))
2425 if ((bp = onbill(obj, shkp, TRUE)) != 0) {
2426 new_price = !amt ? get_cost(obj, shkp) : (amt < 0L) ? -amt : amt;
2427 if (new_price > bp->price || amt < 0L) {
2428 bp->price = new_price;
2429 update_inventory();
2430 }
2431 break; /* done */
2432 }
2433 return;
2434 }
2435
2436 /* called from doinv(invent.c) for inventory of unpaid objects */
2437 long
unpaid_cost(unp_obj,include_contents)2438 unpaid_cost(unp_obj, include_contents)
2439 struct obj *unp_obj; /* known to be unpaid or contain unpaid */
2440 boolean include_contents;
2441 {
2442 struct bill_x *bp = (struct bill_x *) 0;
2443 struct monst *shkp;
2444 long amt = 0L;
2445 xchar ox, oy;
2446
2447 if (!get_obj_location(unp_obj, &ox, &oy, BURIED_TOO | CONTAINED_TOO))
2448 ox = u.ux, oy = u.uy; /* (shouldn't happen) */
2449 if ((shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))) != 0) {
2450 bp = onbill(unp_obj, shkp, TRUE);
2451 } else {
2452 /* didn't find shk? try searching bills */
2453 for (shkp = next_shkp(fmon, TRUE); shkp;
2454 shkp = next_shkp(shkp->nmon, TRUE))
2455 if ((bp = onbill(unp_obj, shkp, TRUE)) != 0)
2456 break;
2457 }
2458
2459 /* onbill() gave no message if unexpected problem occurred */
2460 if (!shkp || (unp_obj->unpaid && !bp)) {
2461 impossible("unpaid_cost: object wasn't on any bill.");
2462 } else {
2463 if (bp)
2464 amt = unp_obj->quan * bp->price;
2465 if (include_contents && Has_contents(unp_obj))
2466 amt = contained_cost(unp_obj, shkp, amt, FALSE, TRUE);
2467 }
2468 return amt;
2469 }
2470
2471 STATIC_OVL void
add_one_tobill(obj,dummy,shkp)2472 add_one_tobill(obj, dummy, shkp)
2473 struct obj *obj;
2474 boolean dummy;
2475 struct monst *shkp;
2476 {
2477 struct eshk *eshkp;
2478 struct bill_x *bp;
2479 int bct;
2480
2481 if (!billable(&shkp, obj, *u.ushops, TRUE))
2482 return;
2483 eshkp = ESHK(shkp);
2484
2485 if (eshkp->billct == BILLSZ) {
2486 You("got that for free!");
2487 return;
2488 }
2489
2490 /* normally bill_p gets set up whenever you enter the shop, but obj
2491 might be going onto the bill because hero just snagged it with
2492 a grappling hook from outside without ever having been inside */
2493 if (!eshkp->bill_p)
2494 eshkp->bill_p = &(eshkp->bill[0]);
2495
2496 bct = eshkp->billct;
2497 bp = &(eshkp->bill_p[bct]);
2498 bp->bo_id = obj->o_id;
2499 bp->bquan = obj->quan;
2500 if (dummy) { /* a dummy object must be inserted into */
2501 bp->useup = 1; /* the billobjs chain here. crucial for */
2502 add_to_billobjs(obj); /* eating floorfood in shop. see eat.c */
2503 } else
2504 bp->useup = 0;
2505 bp->price = get_cost(obj, shkp);
2506 if (obj->globby)
2507 /* for globs, the amt charged for quan 1 depends on owt */
2508 bp->price *= get_pricing_units(obj);
2509 eshkp->billct++;
2510 obj->unpaid = 1;
2511 }
2512
2513 STATIC_OVL void
add_to_billobjs(obj)2514 add_to_billobjs(obj)
2515 struct obj *obj;
2516 {
2517 if (obj->where != OBJ_FREE)
2518 panic("add_to_billobjs: obj not free");
2519 if (obj->timed)
2520 obj_stop_timers(obj);
2521
2522 obj->nobj = billobjs;
2523 billobjs = obj;
2524 obj->where = OBJ_ONBILL;
2525 }
2526
2527 /* recursive billing of objects within containers. */
2528 STATIC_OVL void
bill_box_content(obj,ininv,dummy,shkp)2529 bill_box_content(obj, ininv, dummy, shkp)
2530 register struct obj *obj;
2531 register boolean ininv, dummy;
2532 register struct monst *shkp;
2533 {
2534 register struct obj *otmp;
2535
2536 if (SchroedingersBox(obj))
2537 return;
2538 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2539 if (otmp->oclass == COIN_CLASS)
2540 continue;
2541
2542 /* the "top" box is added in addtobill() */
2543 if (!otmp->no_charge)
2544 add_one_tobill(otmp, dummy, shkp);
2545 if (Has_contents(otmp))
2546 bill_box_content(otmp, ininv, dummy, shkp);
2547 }
2548 }
2549
2550 /* shopkeeper tells you what you bought or sold, sometimes partly IDing it */
2551 STATIC_OVL void
shk_names_obj(shkp,obj,fmt,amt,arg)2552 shk_names_obj(shkp, obj, fmt, amt, arg)
2553 struct monst *shkp;
2554 struct obj *obj;
2555 const char *fmt; /* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */
2556 long amt;
2557 const char *arg;
2558 {
2559 char *obj_name, fmtbuf[BUFSZ];
2560 boolean was_unknown = !obj->dknown;
2561
2562 obj->dknown = TRUE;
2563 /* Use real name for ordinary weapons/armor, and spell-less
2564 * scrolls/books (that is, blank and mail), but only if the
2565 * object is within the shk's area of interest/expertise.
2566 */
2567 if (!objects[obj->otyp].oc_magic && saleable(shkp, obj)
2568 && (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS
2569 || obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS
2570 || obj->otyp == MIRROR)) {
2571 was_unknown |= !objects[obj->otyp].oc_name_known;
2572 makeknown(obj->otyp);
2573 }
2574 obj_name = doname(obj);
2575 /* Use an alternate message when extra information is being provided */
2576 if (was_unknown) {
2577 Sprintf(fmtbuf, "%%s; you %s", fmt);
2578 obj_name[0] = highc(obj_name[0]);
2579 pline(fmtbuf, obj_name, (obj->quan > 1L) ? "them" : "it", amt,
2580 plur(amt), arg);
2581 } else {
2582 You(fmt, obj_name, amt, plur(amt), arg);
2583 }
2584 }
2585
2586 /* decide whether a shopkeeper thinks an item belongs to her */
2587 boolean
billable(shkpp,obj,roomno,reset_nocharge)2588 billable(shkpp, obj, roomno, reset_nocharge)
2589 struct monst **shkpp; /* in: non-null if shk has been validated; out: shk */
2590 struct obj *obj;
2591 char roomno;
2592 boolean reset_nocharge;
2593 {
2594 struct monst *shkp = *shkpp;
2595
2596 /* if caller hasn't supplied a shopkeeper, look one up now */
2597 if (!shkp) {
2598 if (!roomno)
2599 return FALSE;
2600 shkp = shop_keeper(roomno);
2601 if (!shkp || !inhishop(shkp))
2602 return FALSE;
2603 *shkpp = shkp;
2604 }
2605 /* perhaps we threw it away earlier */
2606 if (onbill(obj, shkp, FALSE)
2607 || (obj->oclass == FOOD_CLASS && obj->oeaten))
2608 return FALSE;
2609 /* outer container might be marked no_charge but still have contents
2610 which should be charged for; clear no_charge when picking things up */
2611 if (obj->no_charge) {
2612 if (!Has_contents(obj) || (contained_gold(obj) == 0L
2613 && contained_cost(obj, shkp, 0L, FALSE,
2614 !reset_nocharge) == 0L))
2615 shkp = 0; /* not billable */
2616 if (reset_nocharge && !shkp && obj->oclass != COIN_CLASS) {
2617 obj->no_charge = 0;
2618 if (Has_contents(obj))
2619 picked_container(obj); /* clear no_charge */
2620 }
2621 }
2622 return shkp ? TRUE : FALSE;
2623 }
2624
2625 void
addtobill(obj,ininv,dummy,silent)2626 addtobill(obj, ininv, dummy, silent)
2627 struct obj *obj;
2628 boolean ininv, dummy, silent;
2629 {
2630 struct monst *shkp = 0;
2631 long ltmp, cltmp, gltmp;
2632 int contentscount;
2633 boolean container;
2634
2635 if (!billable(&shkp, obj, *u.ushops, TRUE))
2636 return;
2637
2638 if (obj->oclass == COIN_CLASS) {
2639 costly_gold(obj->ox, obj->oy, obj->quan);
2640 return;
2641 } else if (ESHK(shkp)->billct == BILLSZ) {
2642 if (!silent)
2643 You("got that for free!");
2644 return;
2645 }
2646
2647 ltmp = cltmp = gltmp = 0L;
2648 container = Has_contents(obj);
2649
2650 if (!obj->no_charge) {
2651 ltmp = get_cost(obj, shkp);
2652 if (obj->globby)
2653 ltmp *= get_pricing_units(obj);
2654 }
2655 if (obj->no_charge && !container) {
2656 obj->no_charge = 0;
2657 return;
2658 }
2659
2660 if (container) {
2661 cltmp = contained_cost(obj, shkp, cltmp, FALSE, FALSE);
2662 gltmp = contained_gold(obj);
2663
2664 if (ltmp)
2665 add_one_tobill(obj, dummy, shkp);
2666 if (cltmp)
2667 bill_box_content(obj, ininv, dummy, shkp);
2668 picked_container(obj); /* reset contained obj->no_charge */
2669
2670 ltmp += cltmp;
2671
2672 if (gltmp) {
2673 costly_gold(obj->ox, obj->oy, gltmp);
2674 if (!ltmp)
2675 return;
2676 }
2677
2678 if (obj->no_charge)
2679 obj->no_charge = 0;
2680 contentscount = count_unpaid(obj->cobj);
2681 } else { /* !container */
2682 add_one_tobill(obj, dummy, shkp);
2683 contentscount = 0;
2684 }
2685
2686 if (!Deaf && !muteshk(shkp) && !silent) {
2687 char buf[BUFSZ];
2688
2689 if (!ltmp) {
2690 pline("%s has no interest in %s.", Shknam(shkp), the(xname(obj)));
2691 return;
2692 }
2693 if (!ininv) {
2694 pline("%s will cost you %ld %s%s.", The(xname(obj)), ltmp,
2695 currency(ltmp), (obj->quan > 1L) ? " each" : "");
2696 } else {
2697 long save_quan = obj->quan;
2698
2699 Strcpy(buf, "\"For you, ");
2700 if (ANGRY(shkp)) {
2701 Strcat(buf, "scum;");
2702 } else {
2703 append_honorific(buf);
2704 Strcat(buf, "; only");
2705 }
2706 obj->quan = 1L; /* fool xname() into giving singular */
2707 pline("%s %ld %s %s %s%s.\"", buf, ltmp, currency(ltmp),
2708 (save_quan > 1L) ? "per"
2709 : (contentscount && !obj->unpaid)
2710 ? "for the contents of this"
2711 : "for this",
2712 xname(obj),
2713 (contentscount && obj->unpaid) ? and_its_contents : "");
2714 obj->quan = save_quan;
2715 }
2716 } else if (!silent) {
2717 if (ltmp)
2718 pline_The("list price of %s%s%s is %ld %s%s.",
2719 (contentscount && !obj->unpaid) ? the_contents_of : "",
2720 the(xname(obj)),
2721 (contentscount && obj->unpaid) ? and_its_contents : "",
2722 ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : "");
2723 else
2724 pline("%s does not notice.", Shknam(shkp));
2725 }
2726 }
2727
2728 STATIC_OVL void
append_honorific(buf)2729 append_honorific(buf)
2730 char *buf;
2731 {
2732 /* (chooses among [0]..[3] normally; [1]..[4] after the
2733 Wizard has been killed or invocation ritual performed) */
2734 static const char *const honored[] = { "good", "honored", "most gracious",
2735 "esteemed",
2736 "most renowned and sacred" };
2737
2738 Strcat(buf, honored[rn2(SIZE(honored) - 1) + u.uevent.udemigod]);
2739 if (is_vampire(youmonst.data))
2740 Strcat(buf, (flags.female) ? " dark lady" : " dark lord");
2741 else if (is_elf(youmonst.data))
2742 Strcat(buf, (flags.female) ? " hiril" : " hir");
2743 else
2744 Strcat(buf, !is_human(youmonst.data) ? " creature"
2745 : (flags.female) ? " lady"
2746 : " sir");
2747 }
2748
2749 void
splitbill(obj,otmp)2750 splitbill(obj, otmp)
2751 register struct obj *obj, *otmp;
2752 {
2753 /* otmp has been split off from obj */
2754 register struct bill_x *bp;
2755 register long tmp;
2756 register struct monst *shkp = shop_keeper(*u.ushops);
2757
2758 if (!shkp || !inhishop(shkp)) {
2759 impossible("splitbill: no resident shopkeeper??");
2760 return;
2761 }
2762 bp = onbill(obj, shkp, FALSE);
2763 if (!bp) {
2764 impossible("splitbill: not on bill?");
2765 return;
2766 }
2767 if (bp->bquan < otmp->quan) {
2768 impossible("Negative quantity on bill??");
2769 }
2770 if (bp->bquan == otmp->quan) {
2771 impossible("Zero quantity on bill??");
2772 }
2773 bp->bquan -= otmp->quan;
2774
2775 if (ESHK(shkp)->billct == BILLSZ)
2776 otmp->unpaid = 0;
2777 else {
2778 tmp = bp->price;
2779 bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]);
2780 bp->bo_id = otmp->o_id;
2781 bp->bquan = otmp->quan;
2782 bp->useup = 0;
2783 bp->price = tmp;
2784 ESHK(shkp)->billct++;
2785 }
2786 }
2787
2788 STATIC_OVL void
sub_one_frombill(obj,shkp)2789 sub_one_frombill(obj, shkp)
2790 register struct obj *obj;
2791 register struct monst *shkp;
2792 {
2793 register struct bill_x *bp;
2794
2795 if ((bp = onbill(obj, shkp, FALSE)) != 0) {
2796 register struct obj *otmp;
2797
2798 obj->unpaid = 0;
2799 if (bp->bquan > obj->quan) {
2800 otmp = newobj();
2801 *otmp = *obj;
2802 otmp->oextra = (struct oextra *) 0;
2803 bp->bo_id = otmp->o_id = context.ident++;
2804 otmp->where = OBJ_FREE;
2805 otmp->quan = (bp->bquan -= obj->quan);
2806 otmp->owt = 0; /* superfluous */
2807 bp->useup = 1;
2808 add_to_billobjs(otmp);
2809 return;
2810 }
2811 ESHK(shkp)->billct--;
2812 #ifdef DUMB
2813 {
2814 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
2815 int indx = ESHK(shkp)->billct;
2816
2817 *bp = ESHK(shkp)->bill_p[indx];
2818 }
2819 #else
2820 *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
2821 #endif
2822 return;
2823 } else if (obj->unpaid) {
2824 impossible("sub_one_frombill: unpaid object not on bill");
2825 obj->unpaid = 0;
2826 }
2827 }
2828
2829 /* recursive check of unpaid objects within nested containers. */
2830 void
subfrombill(obj,shkp)2831 subfrombill(obj, shkp)
2832 register struct obj *obj;
2833 register struct monst *shkp;
2834 {
2835 register struct obj *otmp;
2836
2837 sub_one_frombill(obj, shkp);
2838
2839 if (Has_contents(obj))
2840 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2841 if (otmp->oclass == COIN_CLASS)
2842 continue;
2843
2844 if (Has_contents(otmp))
2845 subfrombill(otmp, shkp);
2846 else
2847 sub_one_frombill(otmp, shkp);
2848 }
2849 }
2850
2851 STATIC_OVL long
stolen_container(obj,shkp,price,ininv)2852 stolen_container(obj, shkp, price, ininv)
2853 struct obj *obj;
2854 struct monst *shkp;
2855 long price;
2856 boolean ininv;
2857 {
2858 struct obj *otmp;
2859 struct bill_x *bp;
2860 long billamt;
2861
2862 /* the price of contained objects; caller handles top container */
2863 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2864 if (otmp->oclass == COIN_CLASS)
2865 continue;
2866 billamt = 0L;
2867 if (!billable(&shkp, otmp, ESHK(shkp)->shoproom, TRUE)) {
2868 /* billable() returns false for objects already on bill */
2869 if ((bp = onbill(otmp, shkp, FALSE)) == 0)
2870 continue;
2871 /* this assumes that we're being called by stolen_value()
2872 (or by a recursive call to self on behalf of it) where
2873 the cost of this object is about to be added to shop
2874 debt in place of having it remain on the current bill */
2875 billamt = bp->bquan * bp->price;
2876 sub_one_frombill(otmp, shkp); /* avoid double billing */
2877 }
2878
2879 if (billamt)
2880 price += billamt;
2881 else if (ininv ? otmp->unpaid : !otmp->no_charge)
2882 price += get_pricing_units(otmp) * get_cost(otmp, shkp);
2883
2884 if (Has_contents(otmp))
2885 price = stolen_container(otmp, shkp, price, ininv);
2886 }
2887
2888 return price;
2889 }
2890
2891 long
stolen_value(obj,x,y,peaceful,silent)2892 stolen_value(obj, x, y, peaceful, silent)
2893 struct obj *obj;
2894 xchar x, y;
2895 boolean peaceful, silent;
2896 {
2897 long value = 0L, gvalue = 0L, billamt = 0L;
2898 char roomno = *in_rooms(x, y, SHOPBASE);
2899 struct bill_x *bp;
2900 struct monst *shkp = 0;
2901 boolean was_unpaid;
2902 long c_count = 0L, u_count = 0L;
2903
2904 /* gather information for message(s) prior to manipulating bill */
2905 was_unpaid = obj->unpaid ? TRUE : FALSE;
2906 if (Has_contents(obj)) {
2907 c_count = count_contents(obj, TRUE, FALSE, TRUE, FALSE);
2908 u_count = count_contents(obj, TRUE, FALSE, FALSE, FALSE);
2909 }
2910
2911 if (!billable(&shkp, obj, roomno, FALSE)) {
2912 /* things already on the bill yield a not-billable result, so
2913 we need to check bill before deciding that shk doesn't care */
2914 if ((bp = onbill(obj, shkp, FALSE)) != 0) {
2915 /* shk does care; take obj off bill to avoid double billing */
2916 billamt = bp->bquan * bp->price;
2917 sub_one_frombill(obj, shkp);
2918 }
2919 if (!bp && !u_count)
2920 return 0L;
2921 }
2922
2923 if (obj->oclass == COIN_CLASS) {
2924 gvalue += obj->quan;
2925 } else {
2926 if (billamt)
2927 value += billamt;
2928 else if (!obj->no_charge)
2929 value += get_pricing_units(obj) * get_cost(obj, shkp);
2930
2931 if (Has_contents(obj)) {
2932 boolean ininv =
2933 (obj->where == OBJ_INVENT || obj->where == OBJ_FREE);
2934
2935 value += stolen_container(obj, shkp, 0L, ininv);
2936 if (!ininv)
2937 gvalue += contained_gold(obj);
2938 }
2939 }
2940
2941 if (gvalue + value == 0L)
2942 return 0L;
2943
2944 value += gvalue;
2945
2946 if (peaceful) {
2947 boolean credit_use = !!ESHK(shkp)->credit;
2948
2949 value = check_credit(value, shkp);
2950 /* 'peaceful' affects general treatment, but doesn't affect
2951 * the fact that other code expects that all charges after the
2952 * shopkeeper is angry are included in robbed, not debit */
2953 if (ANGRY(shkp))
2954 ESHK(shkp)->robbed += value;
2955 else
2956 ESHK(shkp)->debit += value;
2957
2958 if (!silent) {
2959 char buf[BUFSZ];
2960 const char *still = "";
2961
2962 if (credit_use) {
2963 if (ESHK(shkp)->credit) {
2964 You("have %ld %s credit remaining.", ESHK(shkp)->credit,
2965 currency(ESHK(shkp)->credit));
2966 return value;
2967 } else if (!value) {
2968 You("have no credit remaining.");
2969 return 0;
2970 }
2971 still = "still ";
2972 }
2973 Sprintf(buf, "%sowe %s %ld %s", still, shkname(shkp),
2974 value, currency(value));
2975 if (u_count) /* u_count > 0 implies Has_contents(obj) */
2976 Sprintf(eos(buf), " for %s%sits contents",
2977 was_unpaid ? "it and " : "",
2978 (c_count > u_count) ? "some of " : "");
2979 else if (obj->oclass != COIN_CLASS)
2980 Sprintf(eos(buf), " for %s",
2981 (obj->quan > 1L) ? "them" : "it");
2982
2983 You("%s!", buf); /* "You owe <shk> N zorkmids for it!" */
2984 }
2985 } else {
2986 ESHK(shkp)->robbed += value;
2987
2988 if (!silent) {
2989 if (canseemon(shkp)) {
2990 Norep("%s booms: \"%s, you are a thief!\"",
2991 Shknam(shkp), plname);
2992 } else if (!Deaf) {
2993 Norep("You hear a scream, \"Thief!\""); /* Deaf-aware */
2994 }
2995 }
2996 hot_pursuit(shkp);
2997 (void) angry_guards(FALSE);
2998 }
2999 return value;
3000 }
3001
3002 /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
3003 static char sell_response = 'a';
3004 static int sell_how = SELL_NORMAL;
3005 /* can't just use sell_response='y' for auto_credit because the 'a' response
3006 shouldn't carry over from ordinary selling to credit selling */
3007 static boolean auto_credit = FALSE;
3008
3009 void
sellobj_state(deliberate)3010 sellobj_state(deliberate)
3011 int deliberate;
3012 {
3013 /* If we're deliberately dropping something, there's no automatic
3014 response to the shopkeeper's "want to sell" query; however, if we
3015 accidentally drop anything, the shk will buy it/them without asking.
3016 This retains the old pre-query risk that slippery fingers while in
3017 shops entailed: you drop it, you've lost it.
3018 */
3019 sell_response = (deliberate != SELL_NORMAL) ? '\0' : 'a';
3020 sell_how = deliberate;
3021 auto_credit = FALSE;
3022 }
3023
3024 void
sellobj(obj,x,y)3025 sellobj(obj, x, y)
3026 register struct obj *obj;
3027 xchar x, y;
3028 {
3029 register struct monst *shkp;
3030 register struct eshk *eshkp;
3031 long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer, shkmoney;
3032 boolean saleitem, cgold = FALSE, container = Has_contents(obj);
3033 boolean isgold = (obj->oclass == COIN_CLASS);
3034 boolean only_partially_your_contents = FALSE;
3035
3036 if (!*u.ushops) /* do cheapest exclusion test first */
3037 return;
3038 if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
3039 return;
3040 if (!costly_spot(x, y))
3041 return;
3042
3043 if (obj->unpaid && !container && !isgold) {
3044 sub_one_frombill(obj, shkp);
3045 return;
3046 }
3047 if (container) {
3048 /* find the price of content before subfrombill */
3049 cltmp = contained_cost(obj, shkp, cltmp, TRUE, FALSE);
3050 /* find the value of contained gold */
3051 gltmp += contained_gold(obj);
3052 cgold = (gltmp > 0L);
3053 }
3054
3055 saleitem = saleable(shkp, obj);
3056 if (!isgold && !obj->unpaid && saleitem)
3057 ltmp = set_cost(obj, shkp);
3058
3059 offer = ltmp + cltmp;
3060
3061 /* get one case out of the way: nothing to sell, and no gold */
3062 if (!(isgold || cgold)
3063 && ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) {
3064 boolean unpaid = is_unpaid(obj);
3065
3066 if (container) {
3067 dropped_container(obj, shkp, FALSE);
3068 if (!obj->unpaid)
3069 obj->no_charge = 1;
3070 if (unpaid)
3071 subfrombill(obj, shkp);
3072 } else
3073 obj->no_charge = 1;
3074
3075 if (!unpaid && (sell_how != SELL_DONTSELL)
3076 && !special_stock(obj, shkp, FALSE))
3077 pline("%s seems uninterested.", Shknam(shkp));
3078 return;
3079 }
3080
3081 /* you dropped something of your own - probably want to sell it */
3082 rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */
3083 eshkp = ESHK(shkp);
3084
3085 if (ANGRY(shkp)) { /* they become shop-objects, no pay */
3086 if (!Deaf && !muteshk(shkp))
3087 verbalize("Thank you, scum!");
3088 else
3089 pline("%s smirks with satisfaction.", Shknam(shkp));
3090 subfrombill(obj, shkp);
3091 return;
3092 }
3093
3094 if (eshkp->robbed) { /* shkp is not angry? */
3095 if (isgold)
3096 offer = obj->quan;
3097 else if (cgold)
3098 offer += cgold;
3099 if ((eshkp->robbed -= offer < 0L))
3100 eshkp->robbed = 0L;
3101 if (offer && !Deaf && !muteshk(shkp))
3102 verbalize(
3103 "Thank you for your contribution to restock this recently plundered shop.");
3104 subfrombill(obj, shkp);
3105 return;
3106 }
3107
3108 if (isgold || cgold) {
3109 if (!cgold)
3110 gltmp = obj->quan;
3111
3112 if (eshkp->debit >= gltmp) {
3113 if (eshkp->loan) { /* you carry shop's gold */
3114 if (eshkp->loan >= gltmp)
3115 eshkp->loan -= gltmp;
3116 else
3117 eshkp->loan = 0L;
3118 }
3119 eshkp->debit -= gltmp;
3120 Your("debt is %spaid off.", eshkp->debit ? "partially " : "");
3121 } else {
3122 long delta = gltmp - eshkp->debit;
3123
3124 eshkp->credit += delta;
3125 if (eshkp->debit) {
3126 eshkp->debit = 0L;
3127 eshkp->loan = 0L;
3128 Your("debt is paid off.");
3129 }
3130 if (eshkp->credit == delta)
3131 You("have established %ld %s credit.", delta,
3132 currency(delta));
3133 else
3134 pline("%ld %s added to your credit; total is now %ld %s.",
3135 delta, currency(delta), eshkp->credit,
3136 currency(eshkp->credit));
3137 }
3138
3139 if (!offer || sell_how == SELL_DONTSELL) {
3140 if (!isgold) {
3141 if (container)
3142 dropped_container(obj, shkp, FALSE);
3143 if (!obj->unpaid)
3144 obj->no_charge = 1;
3145 subfrombill(obj, shkp);
3146 }
3147 return;
3148 }
3149 }
3150
3151 if ((!saleitem && !(container && cltmp > 0L)) || eshkp->billct == BILLSZ
3152 || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS
3153 || offer == 0L || (obj->oclass == FOOD_CLASS && obj->oeaten)
3154 || (Is_candle(obj)
3155 && obj->age < 20L * (long) objects[obj->otyp].oc_cost)) {
3156 pline("%s seems uninterested%s.", Shknam(shkp),
3157 cgold ? " in the rest" : "");
3158 if (container)
3159 dropped_container(obj, shkp, FALSE);
3160 obj->no_charge = 1;
3161 return;
3162 }
3163
3164 shkmoney = money_cnt(shkp->minvent);
3165 if (!shkmoney) {
3166 char c, qbuf[BUFSZ];
3167 long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L);
3168
3169 if (sell_how == SELL_NORMAL || auto_credit) {
3170 c = sell_response = 'y';
3171 } else if (sell_response != 'n') {
3172 pline("%s cannot pay you at present.", Shknam(shkp));
3173 Sprintf(qbuf, "Will you accept %ld %s in credit for ", tmpcr,
3174 currency(tmpcr));
3175 c = ynaq(safe_qbuf(qbuf, qbuf, "?", obj, doname, thesimpleoname,
3176 (obj->quan == 1L) ? "that" : "those"));
3177 if (c == 'a') {
3178 c = 'y';
3179 auto_credit = TRUE;
3180 }
3181 } else /* previously specified "quit" */
3182 c = 'n';
3183
3184 if (c == 'y') {
3185 shk_names_obj(
3186 shkp, obj,
3187 (sell_how != SELL_NORMAL)
3188 ? "traded %s for %ld zorkmid%s in %scredit."
3189 : "relinquish %s and acquire %ld zorkmid%s in %scredit.",
3190 tmpcr, (eshkp->credit > 0L) ? "additional " : "");
3191 eshkp->credit += tmpcr;
3192 subfrombill(obj, shkp);
3193 } else {
3194 if (c == 'q')
3195 sell_response = 'n';
3196 if (container)
3197 dropped_container(obj, shkp, FALSE);
3198 if (!obj->unpaid)
3199 obj->no_charge = 1;
3200 subfrombill(obj, shkp);
3201 }
3202 } else {
3203 char qbuf[BUFSZ], qsfx[BUFSZ];
3204 boolean short_funds = (offer > shkmoney), one;
3205
3206 if (short_funds)
3207 offer = shkmoney;
3208 if (!sell_response) {
3209 long yourc = 0L, shksc;
3210
3211 if (container) {
3212 /* number of items owned by shk */
3213 shksc = count_contents(obj, TRUE, TRUE, FALSE, TRUE);
3214 /* number of items owned by you (total - shksc) */
3215 yourc = count_contents(obj, TRUE, TRUE, TRUE, TRUE) - shksc;
3216 only_partially_your_contents = shksc && yourc;
3217 }
3218 /*
3219 "<shk> offers * for ..." query formatting.
3220 Normal item(s):
3221 "... your <object>. Sell it?"
3222 "... your <objects>. Sell them?"
3223 A container is either owned by the hero, or already
3224 owned by the shk (!ltmp), or the shk isn't interested
3225 in buying it (also !ltmp). It's either empty (!cltmp)
3226 or it has contents owned by the hero or it has some
3227 contents owned by the hero and others by the shk.
3228 (The case where it has contents already entirely owned
3229 by the shk is treated the same was if it were empty
3230 since the hero isn't selling any of those contents.)
3231 Your container and shk is willing to buy it:
3232 "... your <empty bag>. Sell it?"
3233 "... your <bag> and its contents. Sell them?"
3234 "... your <bag> and item inside. Sell them?"
3235 "... your <bag> and items inside. Sell them?"
3236 Your container but shk only cares about the contents:
3237 "... your item in your <bag>. Sell it?"
3238 "... your items in your <bag>. Sell them?"
3239 Shk's container:
3240 "... your item in the <bag>. Sell it?"
3241 "... your items in the <bag>. Sell them?"
3242 FIXME:
3243 "your items" should sometimes be "some of your items"
3244 (when container has some stuff the shk is willing to buy
3245 and other stuff he or she doesn't care about); likewise,
3246 "your item" should sometimes be "one of your items".
3247 That would make the prompting even more verbose so
3248 living without it might be a good thing.
3249 FIXME too:
3250 when container's contents are unknown, plural "items"
3251 should be used to not give away information.
3252 */
3253 Sprintf(qbuf, "%s offers%s %ld gold piece%s for %s%s ",
3254 Shknam(shkp), short_funds ? " only" : "", offer,
3255 plur(offer),
3256 (cltmp && !ltmp)
3257 ? ((yourc == 1L) ? "your item in " : "your items in ")
3258 : "",
3259 obj->unpaid ? "the" : "your");
3260 one = !ltmp ? (yourc == 1L) : (obj->quan == 1L && !cltmp);
3261 Sprintf(qsfx, "%s. Sell %s?",
3262 (cltmp && ltmp)
3263 ? (only_partially_your_contents
3264 ? ((yourc == 1L) ? " and item inside"
3265 : " and items inside")
3266 : and_its_contents)
3267 : "",
3268 one ? "it" : "them");
3269 (void) safe_qbuf(qbuf, qbuf, qsfx, obj, xname, simpleonames,
3270 one ? "that" : "those");
3271 } else
3272 qbuf[0] = '\0'; /* just to pacify lint */
3273
3274 switch (sell_response ? sell_response : ynaq(qbuf)) {
3275 case 'q':
3276 sell_response = 'n';
3277 /*FALLTHRU*/
3278 case 'n':
3279 if (container)
3280 dropped_container(obj, shkp, FALSE);
3281 if (!obj->unpaid)
3282 obj->no_charge = 1;
3283 subfrombill(obj, shkp);
3284 break;
3285 case 'a':
3286 sell_response = 'y';
3287 /*FALLTHRU*/
3288 case 'y':
3289 if (container)
3290 dropped_container(obj, shkp, TRUE);
3291 if (!obj->unpaid && !saleitem)
3292 obj->no_charge = 1;
3293 subfrombill(obj, shkp);
3294 pay(-offer, shkp);
3295 shk_names_obj(shkp, obj,
3296 (sell_how != SELL_NORMAL)
3297 ? ((!ltmp && cltmp && only_partially_your_contents)
3298 ? "sold some items inside %s for %ld gold piece%s.%s"
3299 : "sold %s for %ld gold piece%s.%s")
3300 : "relinquish %s and receive %ld gold piece%s in compensation.%s",
3301 offer, "");
3302 break;
3303 default:
3304 impossible("invalid sell response");
3305 }
3306 }
3307 }
3308
3309 int
doinvbill(mode)3310 doinvbill(mode)
3311 int mode; /* 0: deliver count 1: paged */
3312 {
3313 #ifdef __SASC
3314 void sasc_bug(struct obj *, unsigned);
3315 #endif
3316 struct monst *shkp;
3317 struct eshk *eshkp;
3318 struct bill_x *bp, *end_bp;
3319 struct obj *obj;
3320 long totused;
3321 char *buf_p;
3322 winid datawin;
3323
3324 shkp = shop_keeper(*u.ushops);
3325 if (!shkp || !inhishop(shkp)) {
3326 if (mode != 0)
3327 impossible("doinvbill: no shopkeeper?");
3328 return 0;
3329 }
3330 eshkp = ESHK(shkp);
3331
3332 if (mode == 0) {
3333 /* count expended items, so that the `I' command can decide
3334 whether to include 'x' in its prompt string */
3335 int cnt = !eshkp->debit ? 0 : 1;
3336
3337 for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
3338 bp < end_bp; bp++)
3339 if (bp->useup
3340 || ((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan))
3341 cnt++;
3342 return cnt;
3343 }
3344
3345 datawin = create_nhwindow(NHW_MENU);
3346 putstr(datawin, 0, "Unpaid articles already used up:");
3347 putstr(datawin, 0, "");
3348
3349 totused = 0L;
3350 for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
3351 bp < end_bp; bp++) {
3352 obj = bp_to_obj(bp);
3353 if (!obj) {
3354 impossible("Bad shopkeeper administration.");
3355 goto quit;
3356 }
3357 if (bp->useup || bp->bquan > obj->quan) {
3358 long oquan, uquan, thisused;
3359
3360 oquan = obj->quan;
3361 uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
3362 thisused = bp->price * uquan;
3363 totused += thisused;
3364 iflags.suppress_price++; /* suppress "(unpaid)" suffix */
3365 /* Why 'x'? To match `I x', more or less. */
3366 buf_p = xprname(obj, (char *) 0, 'x', FALSE, thisused, uquan);
3367 iflags.suppress_price--;
3368 putstr(datawin, 0, buf_p);
3369 }
3370 }
3371 if (eshkp->debit) {
3372 /* additional shop debt which has no itemization available */
3373 if (totused)
3374 putstr(datawin, 0, "");
3375 totused += eshkp->debit;
3376 buf_p = xprname((struct obj *) 0, "usage charges and/or other fees",
3377 GOLD_SYM, FALSE, eshkp->debit, 0L);
3378 putstr(datawin, 0, buf_p);
3379 }
3380 buf_p = xprname((struct obj *) 0, "Total:", '*', FALSE, totused, 0L);
3381 putstr(datawin, 0, "");
3382 putstr(datawin, 0, buf_p);
3383 display_nhwindow(datawin, FALSE);
3384 quit:
3385 destroy_nhwindow(datawin);
3386 return 0;
3387 }
3388
3389 STATIC_OVL long
getprice(obj,shk_buying)3390 getprice(obj, shk_buying)
3391 register struct obj *obj;
3392 boolean shk_buying;
3393 {
3394 register long tmp = (long) objects[obj->otyp].oc_cost;
3395
3396 if (obj->oartifact) {
3397 tmp = arti_cost(obj);
3398 if (shk_buying)
3399 tmp /= 4;
3400 }
3401 switch (obj->oclass) {
3402 case FOOD_CLASS:
3403 /* simpler hunger check, (2-4)*cost */
3404 if (u.uhs >= HUNGRY && !shk_buying)
3405 tmp *= (long) u.uhs;
3406 if (obj->oeaten)
3407 tmp = 0L;
3408 break;
3409 case WAND_CLASS:
3410 if (obj->spe == -1)
3411 tmp = 0L;
3412 break;
3413 case POTION_CLASS:
3414 if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
3415 tmp = 0L;
3416 break;
3417 case ARMOR_CLASS:
3418 case WEAPON_CLASS:
3419 if (obj->spe > 0)
3420 tmp += 10L * (long) obj->spe;
3421 break;
3422 case TOOL_CLASS:
3423 if (Is_candle(obj)
3424 && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
3425 tmp /= 2L;
3426 break;
3427 }
3428 return tmp;
3429 }
3430
3431 /* shk catches thrown pick-axe */
3432 struct monst *
shkcatch(obj,x,y)3433 shkcatch(obj, x, y)
3434 register struct obj *obj;
3435 register xchar x, y;
3436 {
3437 register struct monst *shkp;
3438
3439 if (!(shkp = shop_keeper(inside_shop(x, y))) || !inhishop(shkp))
3440 return 0;
3441
3442 if (shkp->mcanmove && !shkp->msleeping
3443 && (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy))
3444 && dist2(shkp->mx, shkp->my, x, y) < 3
3445 /* if it is the shk's pos, you hit and anger him */
3446 && (shkp->mx != x || shkp->my != y)) {
3447 if (mnearto(shkp, x, y, TRUE) == 2 && !Deaf && !muteshk(shkp))
3448 verbalize("Out of my way, scum!");
3449 if (cansee(x, y)) {
3450 pline("%s nimbly%s catches %s.", Shknam(shkp),
3451 (x == shkp->mx && y == shkp->my) ? "" : " reaches over and",
3452 the(xname(obj)));
3453 if (!canspotmon(shkp))
3454 map_invisible(x, y);
3455 delay_output();
3456 mark_synch();
3457 }
3458 subfrombill(obj, shkp);
3459 (void) mpickobj(shkp, obj);
3460 return shkp;
3461 }
3462 return (struct monst *) 0;
3463 }
3464
3465 void
add_damage(x,y,cost)3466 add_damage(x, y, cost)
3467 register xchar x, y;
3468 long cost;
3469 {
3470 struct damage *tmp_dam;
3471 char *shops;
3472
3473 if (IS_DOOR(levl[x][y].typ)) {
3474 struct monst *mtmp;
3475
3476 /* Don't schedule for repair unless it's a real shop entrance */
3477 for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++)
3478 if ((mtmp = shop_keeper(*shops)) != 0
3479 && x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y)
3480 break;
3481 if (!*shops)
3482 return;
3483 }
3484 for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next)
3485 if (tmp_dam->place.x == x && tmp_dam->place.y == y) {
3486 tmp_dam->cost += cost;
3487 tmp_dam->when = monstermoves; /* needed by pay_for_damage() */
3488 return;
3489 }
3490 tmp_dam = (struct damage *) alloc((unsigned) sizeof *tmp_dam);
3491 (void) memset((genericptr_t) tmp_dam, 0, sizeof *tmp_dam);
3492 tmp_dam->when = monstermoves;
3493 tmp_dam->place.x = x;
3494 tmp_dam->place.y = y;
3495 tmp_dam->cost = cost;
3496 tmp_dam->typ = levl[x][y].typ;
3497 tmp_dam->next = level.damagelist;
3498 level.damagelist = tmp_dam;
3499 /* If player saw damage, display as a wall forever */
3500 if (cansee(x, y))
3501 levl[x][y].seenv = SVALL;
3502 }
3503
3504 /*
3505 * Do something about damage. Either (!croaked) try to repair it, or
3506 * (croaked) just discard damage structs for non-shared locations, since
3507 * they'll never get repaired. Assume that shared locations will get
3508 * repaired eventually by the other shopkeeper(s). This might be an erroneous
3509 * assumption (they might all be dead too), but we have no reasonable way of
3510 * telling that.
3511 */
3512 STATIC_OVL
3513 void
remove_damage(shkp,croaked)3514 remove_damage(shkp, croaked)
3515 struct monst *shkp;
3516 boolean croaked;
3517 {
3518 struct damage *tmp_dam, *tmp2_dam;
3519 struct obj *shk_inv = shkp->minvent;
3520 boolean did_repair = FALSE, saw_door = FALSE, saw_floor = FALSE,
3521 stop_picking = FALSE, doorway_trap = FALSE, skip_msg = FALSE;
3522 int saw_walls = 0, saw_untrap = 0, feedback;
3523 char trapmsg[BUFSZ];
3524
3525 feedback = !croaked; /* 1 => give feedback, 0 => don't or already did */
3526 tmp_dam = level.damagelist;
3527 tmp2_dam = 0;
3528 while (tmp_dam) {
3529 register xchar x = tmp_dam->place.x, y = tmp_dam->place.y;
3530 char shops[5];
3531 int disposition;
3532 unsigned old_doormask = 0;
3533
3534 disposition = 0;
3535 Strcpy(shops, in_rooms(x, y, SHOPBASE));
3536 if (index(shops, ESHK(shkp)->shoproom)) {
3537 if (IS_DOOR(levl[x][y].typ))
3538 old_doormask = levl[x][y].doormask;
3539
3540 if (croaked) {
3541 disposition = (shops[1]) ? 0 : 1;
3542 } else if (stop_picking) {
3543 disposition = repair_damage(shkp, tmp_dam, &feedback, FALSE);
3544 } else {
3545 /* Defer the stop_occupation() until after repair msgs */
3546 if (closed_door(x, y))
3547 stop_picking = picking_at(x, y);
3548 disposition = repair_damage(shkp, tmp_dam, &feedback, FALSE);
3549 if (!disposition)
3550 stop_picking = FALSE;
3551 }
3552 }
3553
3554 if (!disposition) {
3555 tmp2_dam = tmp_dam;
3556 tmp_dam = tmp_dam->next;
3557 continue;
3558 }
3559
3560 if (disposition > 1) {
3561 did_repair = TRUE;
3562 if (cansee(x, y)) {
3563 if (IS_WALL(levl[x][y].typ)) {
3564 saw_walls++;
3565 } else if (IS_DOOR(levl[x][y].typ)
3566 /* an existing door here implies trap removal */
3567 && !(old_doormask & (D_ISOPEN | D_CLOSED))) {
3568 saw_door = TRUE;
3569 } else if (disposition == 3) { /* untrapped */
3570 saw_untrap++;
3571 if (IS_DOOR(levl[x][y].typ))
3572 doorway_trap = TRUE;
3573 } else {
3574 saw_floor = TRUE;
3575 }
3576 }
3577 }
3578
3579 tmp_dam = tmp_dam->next;
3580 if (!tmp2_dam) {
3581 free((genericptr_t) level.damagelist);
3582 level.damagelist = tmp_dam;
3583 } else {
3584 free((genericptr_t) tmp2_dam->next);
3585 tmp2_dam->next = tmp_dam;
3586 }
3587 }
3588 if (!did_repair)
3589 return;
3590
3591 trapmsg[0] = '\0'; /* not just lint suppression... */
3592 shk_inv = (shkp->minvent != shk_inv) ? shkp->minvent : 0;
3593 if (saw_untrap == 1 && shk_inv
3594 && (shk_inv->otyp == BEARTRAP || shk_inv->otyp == LAND_MINE)
3595 && canseemon(shkp)) {
3596 pline("%s untraps %s.", Shknam(shkp), ansimpleoname(shk_inv));
3597 /* we've already reported this trap (and know it's the only one) */
3598 saw_untrap = 0;
3599 skip_msg = !(saw_walls || saw_door || saw_floor);
3600 } else if (saw_untrap) {
3601 Sprintf(trapmsg, "%s trap%s",
3602 (saw_untrap > 3) ? "several" : (saw_untrap > 1) ? "some"
3603 : "a",
3604 plur(saw_untrap));
3605 Sprintf(eos(trapmsg), " %s", vtense(trapmsg, "are"));
3606 Sprintf(eos(trapmsg), " removed from the %s",
3607 (doorway_trap && saw_untrap == 1) ? "doorway" : "floor");
3608 }
3609
3610 if (skip_msg) {
3611 ; /* already gave an untrap message which covered the only repair */
3612 } else if (saw_walls) {
3613 char wallbuf[BUFSZ];
3614
3615 Sprintf(wallbuf, "section%s", plur(saw_walls));
3616 pline("Suddenly, %s %s of wall %s up!",
3617 (saw_walls == 1) ? "a" : (saw_walls <= 3) ? "some" : "several",
3618 wallbuf, vtense(wallbuf, "close"));
3619
3620 if (saw_door)
3621 pline_The("shop door reappears!");
3622 if (saw_floor)
3623 pline_The("floor is repaired!");
3624 if (saw_untrap)
3625 pline("%s!", upstart(trapmsg));
3626 } else {
3627 if (saw_door || saw_floor || saw_untrap)
3628 pline("Suddenly, %s%s%s%s%s!",
3629 saw_door ? "the shop door reappears" : "",
3630 (saw_door && saw_floor) ? " and " : "",
3631 saw_floor ? "the floor damage is gone" : "",
3632 ((saw_door || saw_floor) && *trapmsg) ? " and " : "",
3633 trapmsg);
3634 /* FIXME:
3635 * these messages aren't right if the unseen repairs were only
3636 * for trap removal (except for hole and possibly trap door).
3637 */
3638 else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom)
3639 You_feel("more claustrophobic than before.");
3640 else if (!Deaf && !rn2(10))
3641 Norep("The dungeon acoustics noticeably change.");
3642 }
3643 if (stop_picking)
3644 stop_occupation();
3645 }
3646
3647 /*
3648 * 0: repair postponed, 1: silent repair (no messages), 2: normal repair
3649 * 3: untrap
3650 */
3651 int
repair_damage(shkp,tmp_dam,once,catchup)3652 repair_damage(shkp, tmp_dam, once, catchup)
3653 struct monst *shkp;
3654 struct damage *tmp_dam;
3655 int *once;
3656 boolean catchup; /* restoring a level */
3657 {
3658 xchar x, y;
3659 xchar litter[9];
3660 struct monst *mtmp;
3661 struct obj *otmp;
3662 struct trap *ttmp;
3663 int i, k, ix, iy, disposition = 1;
3664
3665 if ((monstermoves - tmp_dam->when) < REPAIR_DELAY)
3666 return 0;
3667 if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following)
3668 return 0;
3669 x = tmp_dam->place.x;
3670 y = tmp_dam->place.y;
3671 if (!IS_ROOM(tmp_dam->typ)) {
3672 if ((x == u.ux && y == u.uy && !Passes_walls)
3673 || (x == shkp->mx && y == shkp->my)
3674 || ((mtmp = m_at(x, y)) != 0 && !passes_walls(mtmp->data)))
3675 return 0;
3676 }
3677 ttmp = t_at(x, y);
3678 if (ttmp && x == u.ux && y == u.uy && !Passes_walls)
3679 return 0;
3680
3681 if (once && *once) {
3682 boolean shk_closeby = (distu(shkp->mx, shkp->my)
3683 <= (BOLT_LIM / 2) * (BOLT_LIM / 2));
3684
3685 /* this is suboptimal if we eventually give a "shk untraps"
3686 message for the only repair, but perhaps the shop repair
3687 incantation means that shk's untrap attempt will never fail */
3688 if (canseemon(shkp))
3689 pline("%s whispers %s.", Shknam(shkp),
3690 shk_closeby ? "an incantation" : "something");
3691 else if (!Deaf && shk_closeby)
3692 You_hear("someone muttering an incantation.");
3693 *once = 0;
3694 }
3695 if (ttmp) {
3696 if ((ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP)
3697 && dist2(x, y, shkp->mx, shkp->my) <= 2) {
3698 /* convert to an object */
3699 otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP,
3700 TRUE, FALSE);
3701 otmp->quan = 1L;
3702 otmp->owt = weight(otmp);
3703 (void) mpickobj(shkp, otmp);
3704 }
3705 deltrap(ttmp);
3706 if (cansee(x, y))
3707 newsym(x, y);
3708 if (!catchup)
3709 disposition = 3;
3710 }
3711 if (IS_ROOM(tmp_dam->typ)
3712 || (tmp_dam->typ == levl[x][y].typ
3713 && (!IS_DOOR(tmp_dam->typ) || levl[x][y].doormask > D_BROKEN)))
3714 /* no terrain fix necessary (trap removal or manually repaired) */
3715 return disposition;
3716
3717 /* door or wall repair; trap, if any, is now gone;
3718 restore original terrain type and move any items away */
3719 levl[x][y].typ = tmp_dam->typ;
3720 if (IS_DOOR(tmp_dam->typ))
3721 levl[x][y].doormask = D_CLOSED; /* arbitrary */
3722
3723 (void) memset((genericptr_t) litter, 0, sizeof litter);
3724 #define NEED_UPDATE 1
3725 #define OPEN 2
3726 #define INSHOP 4
3727 #define horiz(i) ((i % 3) - 1)
3728 #define vert(i) ((i / 3) - 1)
3729 k = 0; /* number of adjacent shop spots */
3730 if (level.objects[x][y] && !IS_ROOM(levl[x][y].typ)) {
3731 for (i = 0; i < 9; i++) {
3732 ix = x + horiz(i);
3733 iy = y + vert(i);
3734 if (i == 4 || !isok(ix, iy) || !ZAP_POS(levl[ix][iy].typ))
3735 continue;
3736 litter[i] = OPEN;
3737 if (inside_shop(ix, iy) == ESHK(shkp)->shoproom) {
3738 litter[i] |= INSHOP;
3739 ++k;
3740 }
3741 }
3742 }
3743 /* placement below assumes there is always at least one adjacent
3744 spot; the 'k' check guards against getting stuck in an infinite
3745 loop if some irregularly shaped room breaks that assumption */
3746 if (k > 0) {
3747 /* Scatter objects haphazardly into the shop */
3748 if (Punished && !u.uswallow
3749 && ((uchain->ox == x && uchain->oy == y)
3750 || (uball->ox == x && uball->oy == y))) {
3751 /*
3752 * Either the ball or chain is in the repair location.
3753 * Take the easy way out and put ball&chain under hero.
3754 *
3755 * FIXME: message should be reworded; this might be the
3756 * shop's doorway rather than a wall, there might be some
3757 * other stuff here which isn't junk, and "your junk" has
3758 * a slang connotation which could be applicable if hero
3759 * has Passes_walls ability.
3760 */
3761 if (!Deaf && !muteshk(shkp))
3762 verbalize("Get your junk out of my wall!");
3763 unplacebc(); /* pick 'em up */
3764 placebc(); /* put 'em down */
3765 }
3766 while ((otmp = level.objects[x][y]) != 0)
3767 /* Don't mess w/ boulders -- just merge into wall */
3768 if (otmp->otyp == BOULDER || otmp->otyp == ROCK) {
3769 obj_extract_self(otmp);
3770 obfree(otmp, (struct obj *) 0);
3771 } else {
3772 int trylimit = 50;
3773
3774 /* otmp must be moved otherwise level.objects[x][y] will
3775 never become Null and while-loop won't terminate */
3776 do {
3777 i = rn2(9);
3778 } while (--trylimit && !(litter[i] & INSHOP));
3779 if ((litter[i] & (OPEN | INSHOP)) != 0) {
3780 ix = x + horiz(i);
3781 iy = y + vert(i);
3782 } else {
3783 /* we know shk isn't at <x,y> because repair
3784 is deferred in that situation */
3785 ix = shkp->mx;
3786 iy = shkp->my;
3787 }
3788 remove_object(otmp);
3789 place_object(otmp, ix, iy);
3790 litter[i] |= NEED_UPDATE;
3791 }
3792 }
3793 if (catchup)
3794 return 1; /* repair occurred while off level so no messages */
3795
3796 block_point(x, y);
3797 if (cansee(x, y)) {
3798 if (IS_WALL(tmp_dam->typ))
3799 /* player sees actual repair process, so KNOWS it's a wall */
3800 levl[x][y].seenv = SVALL;
3801 newsym(x, y);
3802 }
3803 for (i = 0; i < 9; i++)
3804 if (litter[i] & NEED_UPDATE)
3805 newsym(x + horiz(i), y + vert(i));
3806
3807 if (disposition < 3)
3808 disposition = 2;
3809 return disposition;
3810 #undef NEED_UPDATE
3811 #undef OPEN
3812 #undef INSHOP
3813 #undef vert
3814 #undef horiz
3815 }
3816
3817 /*
3818 * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died
3819 */
3820 int
shk_move(shkp)3821 shk_move(shkp)
3822 struct monst *shkp;
3823 {
3824 xchar gx, gy, omx, omy;
3825 int udist;
3826 schar appr;
3827 struct eshk *eshkp = ESHK(shkp);
3828 int z;
3829 boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv;
3830
3831 omx = shkp->mx;
3832 omy = shkp->my;
3833
3834 if (inhishop(shkp))
3835 remove_damage(shkp, FALSE);
3836
3837 if ((udist = distu(omx, omy)) < 3 && (shkp->data != &mons[PM_GRID_BUG]
3838 || (omx == u.ux || omy == u.uy))) {
3839 if (ANGRY(shkp) || (Conflict && !resist(shkp, RING_CLASS, 0, 0))) {
3840 if (Displaced)
3841 Your("displaced image doesn't fool %s!", shkname(shkp));
3842 (void) mattacku(shkp);
3843 return 0;
3844 }
3845 if (eshkp->following) {
3846 if (strncmp(eshkp->customer, plname, PL_NSIZ)) {
3847 if (!Deaf && !muteshk(shkp))
3848 verbalize("%s, %s! I was looking for %s.", Hello(shkp),
3849 plname, eshkp->customer);
3850 eshkp->following = 0;
3851 return 0;
3852 }
3853 if (moves > followmsg + 4) {
3854 if (!Deaf && !muteshk(shkp))
3855 verbalize("%s, %s! Didn't you forget to pay?",
3856 Hello(shkp), plname);
3857 else
3858 pline("%s holds out %s upturned %s.",
3859 Shknam(shkp), noit_mhis(shkp),
3860 mbodypart(shkp, HAND));
3861 followmsg = moves;
3862 if (!rn2(9)) {
3863 pline("%s doesn't like customers who don't pay.",
3864 Shknam(shkp));
3865 rile_shk(shkp);
3866 }
3867 }
3868 if (udist < 2)
3869 return 0;
3870 }
3871 }
3872
3873 appr = 1;
3874 gx = eshkp->shk.x;
3875 gy = eshkp->shk.y;
3876 satdoor = (gx == omx && gy == omy);
3877 if (eshkp->following || ((z = holetime()) >= 0 && z * z <= udist)) {
3878 /* [This distance check used to apply regardless of
3879 whether the shk was following, but that resulted in
3880 m_move() sometimes taking the shk out of the shop if
3881 the player had fenced him in with boulders or traps.
3882 Such voluntary abandonment left unpaid objects in
3883 invent, triggering billing impossibilities on the
3884 next level once the character fell through the hole.] */
3885 if (udist > 4 && eshkp->following && !eshkp->billct)
3886 return -1; /* leave it to m_move */
3887 gx = u.ux;
3888 gy = u.uy;
3889 } else if (ANGRY(shkp)) {
3890 /* Move towards the hero if the shopkeeper can see him. */
3891 if (shkp->mcansee && m_canseeu(shkp)) {
3892 gx = u.ux;
3893 gy = u.uy;
3894 }
3895 avoid = FALSE;
3896 } else {
3897 #define GDIST(x, y) (dist2(x, y, gx, gy))
3898 if (Invis || u.usteed) {
3899 avoid = FALSE;
3900 } else {
3901 uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y);
3902 if (uondoor) {
3903 badinv =
3904 (carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK)
3905 || (Fast && (sobj_at(PICK_AXE, u.ux, u.uy)
3906 || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))));
3907 if (satdoor && badinv)
3908 return 0;
3909 avoid = !badinv;
3910 } else {
3911 avoid = (*u.ushops && distu(gx, gy) > 8);
3912 badinv = FALSE;
3913 }
3914
3915 if (((!eshkp->robbed && !eshkp->billct && !eshkp->debit) || avoid)
3916 && GDIST(omx, omy) < 3) {
3917 if (!badinv && !onlineu(omx, omy))
3918 return 0;
3919 if (satdoor)
3920 appr = gx = gy = 0;
3921 }
3922 }
3923 }
3924
3925 z = move_special(shkp, inhishop(shkp), appr, uondoor, avoid, omx, omy, gx,
3926 gy);
3927 if (z > 0)
3928 after_shk_move(shkp);
3929
3930 return z;
3931 }
3932
3933 /* called after shopkeeper moves, in case themove causes re-entry into shop */
3934 void
after_shk_move(shkp)3935 after_shk_move(shkp)
3936 struct monst *shkp;
3937 {
3938 struct eshk *eshkp = ESHK(shkp);
3939
3940 if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) {
3941 /* reset bill_p, need to re-calc player's occupancy too */
3942 eshkp->bill_p = &eshkp->bill[0];
3943 check_special_room(FALSE);
3944 }
3945 }
3946
3947 /* for use in levl_follower (mondata.c) */
3948 boolean
is_fshk(mtmp)3949 is_fshk(mtmp)
3950 register struct monst *mtmp;
3951 {
3952 return (boolean) (mtmp->isshk && ESHK(mtmp)->following);
3953 }
3954
3955 /* You are digging in the shop. */
3956 void
shopdig(fall)3957 shopdig(fall)
3958 register int fall;
3959 {
3960 register struct monst *shkp = shop_keeper(*u.ushops);
3961 int lang;
3962 const char *grabs = "grabs";
3963
3964 if (!shkp)
3965 return;
3966
3967 /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */
3968 lang = 0;
3969 if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data))
3970 ; /* lang stays 0 */
3971 else if (shkp->data->msound <= MS_ANIMAL)
3972 lang = 1;
3973 else if (shkp->data->msound >= MS_HUMANOID)
3974 lang = 2;
3975
3976 if (!inhishop(shkp)) {
3977 if (Role_if(PM_KNIGHT)) {
3978 You_feel("like a common thief.");
3979 adjalign(-sgn(u.ualign.type));
3980 }
3981 return;
3982 }
3983
3984 if (!fall) {
3985 if (lang == 2) {
3986 if (!Deaf && !muteshk(shkp)) {
3987 if (u.utraptype == TT_PIT)
3988 verbalize(
3989 "Be careful, %s, or you might fall through the floor.",
3990 flags.female ? "madam" : "sir");
3991 else
3992 verbalize("%s, do not damage the floor here!",
3993 flags.female ? "Madam" : "Sir");
3994 }
3995 }
3996 if (Role_if(PM_KNIGHT)) {
3997 You_feel("like a common thief.");
3998 adjalign(-sgn(u.ualign.type));
3999 }
4000 } else if (!um_dist(shkp->mx, shkp->my, 5)
4001 && !shkp->msleeping && shkp->mcanmove
4002 && (ESHK(shkp)->billct || ESHK(shkp)->debit)) {
4003 register struct obj *obj, *obj2;
4004
4005 if (nolimbs(shkp->data)) {
4006 grabs = "knocks off";
4007 #if 0
4008 /* This is what should happen, but for balance
4009 * reasons, it isn't currently.
4010 */
4011 if (lang == 2)
4012 pline("%s curses %s inability to grab your backpack!",
4013 Shknam(shkp), noit_mhim(shkp));
4014 rile_shk(shkp);
4015 return;
4016 #endif
4017 }
4018 if (distu(shkp->mx, shkp->my) > 2) {
4019 mnexto(shkp);
4020 /* for some reason the shopkeeper can't come next to you */
4021 if (distu(shkp->mx, shkp->my) > 2) {
4022 if (lang == 2)
4023 pline("%s curses you in anger and frustration!",
4024 Shknam(shkp));
4025 else if (lang == 1)
4026 growl(shkp);
4027 rile_shk(shkp);
4028 return;
4029 } else
4030 pline("%s %s, and %s your backpack!", Shknam(shkp),
4031 makeplural(locomotion(shkp->data, "leap")), grabs);
4032 } else
4033 pline("%s %s your backpack!", Shknam(shkp), grabs);
4034
4035 for (obj = invent; obj; obj = obj2) {
4036 obj2 = obj->nobj;
4037 if ((obj->owornmask & ~(W_SWAPWEP | W_QUIVER)) != 0
4038 || (obj == uswapwep && u.twoweap)
4039 || (obj->otyp == LEASH && obj->leashmon))
4040 continue;
4041 if (obj == current_wand)
4042 continue;
4043 setnotworn(obj);
4044 freeinv(obj);
4045 subfrombill(obj, shkp);
4046 (void) add_to_minv(shkp, obj); /* may free obj */
4047 }
4048 }
4049 }
4050
4051 STATIC_OVL void
makekops(mm)4052 makekops(mm)
4053 coord *mm;
4054 {
4055 static const short k_mndx[4] = { PM_KEYSTONE_KOP, PM_KOP_SERGEANT,
4056 PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN };
4057 int k_cnt[4], cnt, mndx, k;
4058
4059 k_cnt[0] = cnt = abs(depth(&u.uz)) + rnd(5);
4060 k_cnt[1] = (cnt / 3) + 1; /* at least one sarge */
4061 k_cnt[2] = (cnt / 6); /* maybe a lieutenant */
4062 k_cnt[3] = (cnt / 9); /* and maybe a kaptain */
4063
4064 for (k = 0; k < 4; k++) {
4065 if ((cnt = k_cnt[k]) == 0)
4066 break;
4067 mndx = k_mndx[k];
4068 if (mvitals[mndx].mvflags & G_GONE)
4069 continue;
4070
4071 while (cnt--)
4072 if (enexto(mm, mm->x, mm->y, &mons[mndx]))
4073 (void) makemon(&mons[mndx], mm->x, mm->y, NO_MM_FLAGS);
4074 }
4075 }
4076
4077 void
pay_for_damage(dmgstr,cant_mollify)4078 pay_for_damage(dmgstr, cant_mollify)
4079 const char *dmgstr;
4080 boolean cant_mollify;
4081 {
4082 register struct monst *shkp = (struct monst *) 0;
4083 char shops_affected[5];
4084 boolean uinshp = (*u.ushops != '\0');
4085 char qbuf[80];
4086 xchar x, y;
4087 boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */
4088 || !strcmp(dmgstr, "damage")); /* pick-axe */
4089 boolean animal, pursue;
4090 struct damage *tmp_dam, *appear_here = 0;
4091 long cost_of_damage = 0L;
4092 unsigned int nearest_shk = (ROWNO * ROWNO) + (COLNO * COLNO),
4093 nearest_damage = nearest_shk;
4094 int picks = 0;
4095
4096 for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) {
4097 char *shp;
4098
4099 if (tmp_dam->when != monstermoves || !tmp_dam->cost)
4100 continue;
4101 cost_of_damage += tmp_dam->cost;
4102 Strcpy(shops_affected,
4103 in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
4104 for (shp = shops_affected; *shp; shp++) {
4105 struct monst *tmp_shk;
4106 unsigned int shk_distance;
4107
4108 if (!(tmp_shk = shop_keeper(*shp)))
4109 continue;
4110 if (tmp_shk == shkp) {
4111 unsigned int damage_distance =
4112 distu(tmp_dam->place.x, tmp_dam->place.y);
4113
4114 if (damage_distance < nearest_damage) {
4115 nearest_damage = damage_distance;
4116 appear_here = tmp_dam;
4117 }
4118 continue;
4119 }
4120 if (!inhishop(tmp_shk))
4121 continue;
4122 shk_distance = distu(tmp_shk->mx, tmp_shk->my);
4123 if (shk_distance > nearest_shk)
4124 continue;
4125 if ((shk_distance == nearest_shk) && picks) {
4126 if (rn2(++picks))
4127 continue;
4128 } else
4129 picks = 1;
4130 shkp = tmp_shk;
4131 nearest_shk = shk_distance;
4132 appear_here = tmp_dam;
4133 nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y);
4134 }
4135 }
4136
4137 if (!cost_of_damage || !shkp)
4138 return;
4139
4140 animal = (shkp->data->msound <= MS_ANIMAL);
4141 pursue = FALSE;
4142 x = appear_here->place.x;
4143 y = appear_here->place.y;
4144
4145 /* not the best introduction to the shk... */
4146 (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
4147
4148 /* if the shk is already on the war path, be sure it's all out */
4149 if (ANGRY(shkp) || ESHK(shkp)->following) {
4150 hot_pursuit(shkp);
4151 return;
4152 }
4153
4154 /* if the shk is not in their shop.. */
4155 if (!*in_rooms(shkp->mx, shkp->my, SHOPBASE)) {
4156 if (!cansee(shkp->mx, shkp->my))
4157 return;
4158 pursue = TRUE;
4159 goto getcad;
4160 }
4161
4162 if (uinshp) {
4163 if (um_dist(shkp->mx, shkp->my, 1)
4164 && !um_dist(shkp->mx, shkp->my, 3)) {
4165 pline("%s leaps towards you!", Shknam(shkp));
4166 mnexto(shkp);
4167 }
4168 pursue = um_dist(shkp->mx, shkp->my, 1);
4169 if (pursue)
4170 goto getcad;
4171 } else {
4172 /*
4173 * Make shkp show up at the door. Effect: If there is a monster
4174 * in the doorway, have the hero hear the shopkeeper yell a bit,
4175 * pause, then have the shopkeeper appear at the door, having
4176 * yanked the hapless critter out of the way.
4177 */
4178 if (MON_AT(x, y)) {
4179 if (!animal) {
4180 if (!Deaf && !muteshk(shkp)) {
4181 You_hear("an angry voice:");
4182 verbalize("Out of my way, scum!");
4183 }
4184 wait_synch();
4185 #if defined(UNIX) || defined(VMS)
4186 #if defined(SYSV) || defined(ULTRIX) || defined(VMS)
4187 (void)
4188 #endif
4189 sleep(1);
4190 #endif
4191 } else {
4192 growl(shkp);
4193 }
4194 }
4195 (void) mnearto(shkp, x, y, TRUE);
4196 }
4197
4198 if ((um_dist(x, y, 1) && !uinshp) || cant_mollify
4199 || (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage
4200 || !rn2(50)) {
4201 getcad:
4202 if (muteshk(shkp)) {
4203 if (animal && shkp->mcanmove && !shkp->msleeping)
4204 yelp(shkp);
4205 } else if (pursue || uinshp || !um_dist(x, y, 1)) {
4206 if (!Deaf)
4207 verbalize("How dare you %s my %s?", dmgstr,
4208 dugwall ? "shop" : "door");
4209 else
4210 pline("%s is %s that you decided to %s %s %s!",
4211 Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
4212 dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door");
4213 } else {
4214 if (!Deaf) {
4215 pline("%s shouts:", Shknam(shkp));
4216 verbalize("Who dared %s my %s?", dmgstr,
4217 dugwall ? "shop" : "door");
4218 } else {
4219 pline("%s is %s that someone decided to %s %s %s!",
4220 Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
4221 dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door");
4222 }
4223 }
4224 hot_pursuit(shkp);
4225 return;
4226 }
4227
4228 if (Invis)
4229 Your("invisibility does not fool %s!", shkname(shkp));
4230 Sprintf(qbuf, "%sYou did %ld %s worth of damage!%s Pay?",
4231 !animal ? cad(TRUE) : "", cost_of_damage,
4232 currency(cost_of_damage), !animal ? "\"" : "");
4233 if (yn(qbuf) != 'n') {
4234 cost_of_damage = check_credit(cost_of_damage, shkp);
4235 if (cost_of_damage > 0L) {
4236 money2mon(shkp, cost_of_damage);
4237 context.botl = 1;
4238 }
4239 pline("Mollified, %s accepts your restitution.", shkname(shkp));
4240 /* move shk back to his home loc */
4241 home_shk(shkp, FALSE);
4242 pacify_shk(shkp);
4243 } else {
4244 if (!animal) {
4245 if (!Deaf && !muteshk(shkp))
4246 verbalize("Oh, yes! You'll pay!");
4247 else
4248 pline("%s lunges %s %s toward your %s!",
4249 Shknam(shkp), noit_mhis(shkp),
4250 mbodypart(shkp, HAND), body_part(NECK));
4251 } else
4252 growl(shkp);
4253 hot_pursuit(shkp);
4254 adjalign(-sgn(u.ualign.type));
4255 }
4256 }
4257
4258 /* called in dokick.c when we kick an object that might be in a store */
4259 boolean
costly_spot(x,y)4260 costly_spot(x, y)
4261 register xchar x, y;
4262 {
4263 struct monst *shkp;
4264 struct eshk *eshkp;
4265
4266 if (!level.flags.has_shop)
4267 return FALSE;
4268 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
4269 if (!shkp || !inhishop(shkp))
4270 return FALSE;
4271 eshkp = ESHK(shkp);
4272 return (boolean) (inside_shop(x, y)
4273 && !(x == eshkp->shk.x && y == eshkp->shk.y));
4274 }
4275
4276 /* called by dotalk(sounds.c) when #chatting; returns obj if location
4277 contains shop goods and shopkeeper is willing & able to speak */
4278 struct obj *
shop_object(x,y)4279 shop_object(x, y)
4280 register xchar x, y;
4281 {
4282 register struct obj *otmp;
4283 register struct monst *shkp;
4284
4285 if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
4286 return (struct obj *) 0;
4287
4288 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
4289 if (otmp->oclass != COIN_CLASS)
4290 break;
4291 /* note: otmp might have ->no_charge set, but that's ok */
4292 return (otmp && costly_spot(x, y)
4293 && NOTANGRY(shkp) && shkp->mcanmove && !shkp->msleeping)
4294 ? otmp
4295 : (struct obj *) 0;
4296 }
4297
4298 /* give price quotes for all objects linked to this one (ie, on this spot) */
4299 void
price_quote(first_obj)4300 price_quote(first_obj)
4301 register struct obj *first_obj;
4302 {
4303 register struct obj *otmp;
4304 char buf[BUFSZ], price[40];
4305 long cost = 0L;
4306 int cnt = 0;
4307 boolean contentsonly = FALSE;
4308 winid tmpwin;
4309 struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy));
4310
4311 tmpwin = create_nhwindow(NHW_MENU);
4312 putstr(tmpwin, 0, "Fine goods for sale:");
4313 putstr(tmpwin, 0, "");
4314 for (otmp = first_obj; otmp; otmp = otmp->nexthere) {
4315 if (otmp->oclass == COIN_CLASS)
4316 continue;
4317 cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L
4318 : get_cost(otmp, shkp);
4319 contentsonly = !cost;
4320 if (Has_contents(otmp))
4321 cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
4322 if (otmp->globby)
4323 cost *= get_pricing_units(otmp); /* always quan 1, vary by wt */
4324 if (!cost) {
4325 Strcpy(price, "no charge");
4326 contentsonly = FALSE;
4327 } else {
4328 Sprintf(price, "%ld %s%s", cost, currency(cost),
4329 (otmp->quan) > 1L ? " each" : "");
4330 }
4331 Sprintf(buf, "%s%s, %s", contentsonly ? the_contents_of : "",
4332 doname(otmp), price);
4333 putstr(tmpwin, 0, buf), cnt++;
4334 }
4335 if (cnt > 1) {
4336 display_nhwindow(tmpwin, TRUE);
4337 } else if (cnt == 1) {
4338 if (!cost) {
4339 /* "<doname(obj)>, no charge" */
4340 pline("%s!", upstart(buf)); /* buf still contains the string */
4341 } else {
4342 /* print cost in slightly different format, so can't reuse buf;
4343 cost and contentsonly are already set up */
4344 Sprintf(buf, "%s%s", contentsonly ? the_contents_of : "",
4345 doname(first_obj));
4346 pline("%s, price %ld %s%s%s", upstart(buf), cost, currency(cost),
4347 (first_obj->quan > 1L) ? " each" : "",
4348 contentsonly ? "." : shk_embellish(first_obj, cost));
4349 }
4350 }
4351 destroy_nhwindow(tmpwin);
4352 }
4353
4354 STATIC_OVL const char *
shk_embellish(itm,cost)4355 shk_embellish(itm, cost)
4356 register struct obj *itm;
4357 long cost;
4358 {
4359 if (!rn2(3)) {
4360 register int o, choice = rn2(5);
4361
4362 if (choice == 0)
4363 choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3);
4364 switch (choice) {
4365 case 4:
4366 if (cost < 10L)
4367 break;
4368 else
4369 o = itm->oclass;
4370 if (o == FOOD_CLASS)
4371 return ", gourmets' delight!";
4372 if (objects[itm->otyp].oc_name_known
4373 ? objects[itm->otyp].oc_magic
4374 : (o == AMULET_CLASS || o == RING_CLASS || o == WAND_CLASS
4375 || o == POTION_CLASS || o == SCROLL_CLASS
4376 || o == SPBOOK_CLASS))
4377 return ", painstakingly developed!";
4378 return ", superb craftsmanship!";
4379 case 3:
4380 return ", finest quality.";
4381 case 2:
4382 return ", an excellent choice.";
4383 case 1:
4384 return ", a real bargain.";
4385 default:
4386 break;
4387 }
4388 } else if (itm->oartifact) {
4389 return ", one of a kind!";
4390 }
4391 return ".";
4392 }
4393
4394 /* First 4 supplied by Ronen and Tamar, remainder by development team */
4395 const char *Izchak_speaks[] = {
4396 "%s says: 'These shopping malls give me a headache.'",
4397 "%s says: 'Slow down. Think clearly.'",
4398 "%s says: 'You need to take things one at a time.'",
4399 "%s says: 'I don't like poofy coffee... give me Colombian Supremo.'",
4400 "%s says that getting the devteam's agreement on anything is difficult.",
4401 "%s says that he has noticed those who serve their deity will prosper.",
4402 "%s says: 'Don't try to steal from me - I have friends in high places!'",
4403 "%s says: 'You may well need something from this shop in the future.'",
4404 "%s comments about the Valley of the Dead as being a gateway."
4405 };
4406
4407 void
shk_chat(shkp)4408 shk_chat(shkp)
4409 struct monst *shkp;
4410 {
4411 struct eshk *eshk;
4412 long shkmoney;
4413
4414 if (!shkp->isshk) {
4415 /* The monster type is shopkeeper, but this monster is
4416 not actually a shk, which could happen if someone
4417 wishes for a shopkeeper statue and then animates it.
4418 (Note: shkname() would be "" in a case like this.) */
4419 pline("%s asks whether you've seen any untended shops recently.",
4420 Monnam(shkp));
4421 /* [Perhaps we ought to check whether this conversation
4422 is taking place inside an untended shop, but a shopless
4423 shk can probably be expected to be rather disoriented.] */
4424 return;
4425 }
4426
4427 eshk = ESHK(shkp);
4428 if (ANGRY(shkp)) {
4429 pline("%s %s how much %s dislikes %s customers.",
4430 Shknam(shkp),
4431 (!Deaf && !muteshk(shkp)) ? "mentions" : "indicates",
4432 noit_mhe(shkp), eshk->robbed ? "non-paying" : "rude");
4433 } else if (eshk->following) {
4434 if (strncmp(eshk->customer, plname, PL_NSIZ)) {
4435 if (!Deaf && !muteshk(shkp))
4436 verbalize("%s %s! I was looking for %s.",
4437 Hello(shkp), plname, eshk->customer);
4438 eshk->following = 0;
4439 } else {
4440 if (!Deaf && !muteshk(shkp))
4441 verbalize("%s %s! Didn't you forget to pay?",
4442 Hello(shkp), plname);
4443 else
4444 pline("%s taps you on the %s.",
4445 Shknam(shkp), body_part(ARM));
4446 }
4447 } else if (eshk->billct) {
4448 register long total = addupbill(shkp) + eshk->debit;
4449
4450 pline("%s %s that your bill comes to %ld %s.",
4451 Shknam(shkp),
4452 (!Deaf && !muteshk(shkp)) ? "says" : "indicates",
4453 total, currency(total));
4454 } else if (eshk->debit) {
4455 pline("%s %s that you owe %s %ld %s.",
4456 Shknam(shkp),
4457 (!Deaf && !muteshk(shkp)) ? "reminds you" : "indicates",
4458 noit_mhim(shkp), eshk->debit, currency(eshk->debit));
4459 } else if (eshk->credit) {
4460 pline("%s encourages you to use your %ld %s of credit.",
4461 Shknam(shkp), eshk->credit, currency(eshk->credit));
4462 } else if (eshk->robbed) {
4463 pline("%s %s about a recent robbery.",
4464 Shknam(shkp),
4465 (!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern");
4466 } else if ((shkmoney = money_cnt(shkp->minvent)) < 50L) {
4467 pline("%s %s that business is bad.",
4468 Shknam(shkp),
4469 (!Deaf && !muteshk(shkp)) ? "complains" : "indicates");
4470 } else if (shkmoney > 4000) {
4471 pline("%s %s that business is good.",
4472 Shknam(shkp),
4473 (!Deaf && !muteshk(shkp)) ? "says" : "indicates");
4474 } else if (is_izchak(shkp, FALSE)) {
4475 if (!Deaf && !muteshk(shkp))
4476 pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp));
4477 } else {
4478 if (!Deaf && !muteshk(shkp))
4479 pline("%s talks about the problem of shoplifters.", Shknam(shkp));
4480 }
4481 }
4482
4483 STATIC_OVL void
kops_gone(silent)4484 kops_gone(silent)
4485 boolean silent;
4486 {
4487 register int cnt = 0;
4488 register struct monst *mtmp, *mtmp2;
4489
4490 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
4491 mtmp2 = mtmp->nmon;
4492 if (mtmp->data->mlet == S_KOP) {
4493 if (canspotmon(mtmp))
4494 cnt++;
4495 mongone(mtmp);
4496 }
4497 }
4498 if (cnt && !silent)
4499 pline_The("Kop%s (disappointed) vanish%s into thin air.",
4500 plur(cnt), (cnt == 1) ? "es" : "");
4501 }
4502
4503 STATIC_OVL long
cost_per_charge(shkp,otmp,altusage)4504 cost_per_charge(shkp, otmp, altusage)
4505 struct monst *shkp;
4506 struct obj *otmp;
4507 boolean altusage; /* some items have an "alternate" use with different cost */
4508 {
4509 long tmp = 0L;
4510
4511 if (!shkp || !inhishop(shkp))
4512 return 0L; /* insurance */
4513 tmp = get_cost(otmp, shkp);
4514
4515 /* The idea is to make the exhaustive use of an unpaid item
4516 * more expensive than buying it outright.
4517 */
4518 if (otmp->otyp == MAGIC_LAMP) { /* 1 */
4519 /* normal use (ie, as light source) of a magic lamp never
4520 degrades its value, but not charging anything would make
4521 identification too easy; charge an amount comparable to
4522 what is charged for an ordinary lamp (don't bother with
4523 angry shk surcharge) */
4524 if (!altusage)
4525 tmp = (long) objects[OIL_LAMP].oc_cost;
4526 else
4527 tmp += tmp / 3L; /* djinni is being released */
4528 } else if (otmp->otyp == MAGIC_MARKER) { /* 70 - 100 */
4529 /* No way to determine in advance how many charges will be
4530 * wasted. So, arbitrarily, one half of the price per use.
4531 */
4532 tmp /= 2L;
4533 } else if (otmp->otyp == BAG_OF_TRICKS /* 1 - 20 */
4534 || otmp->otyp == HORN_OF_PLENTY) {
4535 /* altusage: emptying of all the contents at once */
4536 if (!altusage)
4537 tmp /= 5L;
4538 } else if (otmp->otyp == CRYSTAL_BALL /* 1 - 5 */
4539 || otmp->otyp == OIL_LAMP /* 1 - 10 */
4540 || otmp->otyp == BRASS_LANTERN
4541 || (otmp->otyp >= MAGIC_FLUTE
4542 && otmp->otyp <= DRUM_OF_EARTHQUAKE) /* 5 - 9 */
4543 || otmp->oclass == WAND_CLASS) { /* 3 - 11 */
4544 if (otmp->spe > 1)
4545 tmp /= 4L;
4546 } else if (otmp->oclass == SPBOOK_CLASS) {
4547 tmp -= tmp / 5L;
4548 } else if (otmp->otyp == CAN_OF_GREASE || otmp->otyp == TINNING_KIT
4549 || otmp->otyp == EXPENSIVE_CAMERA) {
4550 tmp /= 10L;
4551 } else if (otmp->otyp == POT_OIL) {
4552 tmp /= 5L;
4553 }
4554 return tmp;
4555 }
4556
4557 /* Charge the player for partial use of an unpaid object.
4558 *
4559 * Note that bill_dummy_object() should be used instead
4560 * when an object is completely used.
4561 */
4562 void
check_unpaid_usage(otmp,altusage)4563 check_unpaid_usage(otmp, altusage)
4564 struct obj *otmp;
4565 boolean altusage;
4566 {
4567 struct monst *shkp;
4568 const char *fmt, *arg1, *arg2;
4569 char buf[BUFSZ];
4570 long tmp;
4571
4572 if (!otmp->unpaid || !*u.ushops
4573 || (otmp->spe <= 0 && objects[otmp->otyp].oc_charged))
4574 return;
4575 if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp))
4576 return;
4577 if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L)
4578 return;
4579
4580 arg1 = arg2 = "";
4581 if (otmp->oclass == SPBOOK_CLASS) {
4582 fmt = "%sYou owe%s %ld %s.";
4583 Sprintf(buf, "This is no free library, %s! ", cad(FALSE));
4584 arg1 = rn2(2) ? buf : "";
4585 arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
4586 } else if (otmp->otyp == POT_OIL) {
4587 fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax).";
4588 } else if (altusage && (otmp->otyp == BAG_OF_TRICKS
4589 || otmp->otyp == HORN_OF_PLENTY)) {
4590 fmt = "%s%sEmptying that will cost you %ld %s.";
4591 if (!rn2(3))
4592 arg1 = "Whoa! ";
4593 if (!rn2(3))
4594 arg1 = "Watch it! ";
4595 } else {
4596 fmt = "%s%sUsage fee, %ld %s.";
4597 if (!rn2(3))
4598 arg1 = "Hey! ";
4599 if (!rn2(3))
4600 arg2 = "Ahem. ";
4601 }
4602
4603 if (!Deaf && !muteshk(shkp)) {
4604 verbalize(fmt, arg1, arg2, tmp, currency(tmp));
4605 exercise(A_WIS, TRUE); /* you just got info */
4606 }
4607 ESHK(shkp)->debit += tmp;
4608 }
4609
4610 /* for using charges of unpaid objects "used in the normal manner" */
4611 void
check_unpaid(otmp)4612 check_unpaid(otmp)
4613 struct obj *otmp;
4614 {
4615 check_unpaid_usage(otmp, FALSE); /* normal item use */
4616 }
4617
4618 void
costly_gold(x,y,amount)4619 costly_gold(x, y, amount)
4620 register xchar x, y;
4621 register long amount;
4622 {
4623 register long delta;
4624 register struct monst *shkp;
4625 register struct eshk *eshkp;
4626
4627 if (!costly_spot(x, y))
4628 return;
4629 /* shkp now guaranteed to exist by costly_spot() */
4630 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
4631
4632 eshkp = ESHK(shkp);
4633 if (eshkp->credit >= amount) {
4634 if (eshkp->credit > amount)
4635 Your("credit is reduced by %ld %s.", amount, currency(amount));
4636 else
4637 Your("credit is erased.");
4638 eshkp->credit -= amount;
4639 } else {
4640 delta = amount - eshkp->credit;
4641 if (eshkp->credit)
4642 Your("credit is erased.");
4643 if (eshkp->debit)
4644 Your("debt increases by %ld %s.", delta, currency(delta));
4645 else
4646 You("owe %s %ld %s.", shkname(shkp), delta, currency(delta));
4647 eshkp->debit += delta;
4648 eshkp->loan += delta;
4649 eshkp->credit = 0L;
4650 }
4651 }
4652
4653 /* used in domove to block diagonal shop-exit */
4654 /* x,y should always be a door */
4655 boolean
block_door(x,y)4656 block_door(x, y)
4657 register xchar x, y;
4658 {
4659 register int roomno = *in_rooms(x, y, SHOPBASE);
4660 register struct monst *shkp;
4661
4662 if (roomno < 0 || !IS_SHOP(roomno))
4663 return FALSE;
4664 if (!IS_DOOR(levl[x][y].typ))
4665 return FALSE;
4666 if (roomno != *u.ushops)
4667 return FALSE;
4668
4669 if (!(shkp = shop_keeper((char) roomno)) || !inhishop(shkp))
4670 return FALSE;
4671
4672 if (shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y
4673 /* Actually, the shk should be made to block _any_
4674 * door, including a door the player digs, if the
4675 * shk is within a 'jumping' distance.
4676 */
4677 && ESHK(shkp)->shd.x == x
4678 && ESHK(shkp)->shd.y == y
4679 && shkp->mcanmove && !shkp->msleeping
4680 && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) {
4681 pline("%s%s blocks your way!", Shknam(shkp),
4682 Invis ? " senses your motion and" : "");
4683 return TRUE;
4684 }
4685 return FALSE;
4686 }
4687
4688 /* used in domove to block diagonal shop-entry;
4689 u.ux, u.uy should always be a door */
4690 boolean
block_entry(x,y)4691 block_entry(x, y)
4692 register xchar x, y;
4693 {
4694 register xchar sx, sy;
4695 register int roomno;
4696 register struct monst *shkp;
4697
4698 if (!(IS_DOOR(levl[u.ux][u.uy].typ)
4699 && levl[u.ux][u.uy].doormask == D_BROKEN))
4700 return FALSE;
4701
4702 roomno = *in_rooms(x, y, SHOPBASE);
4703 if (roomno < 0 || !IS_SHOP(roomno))
4704 return FALSE;
4705 if (!(shkp = shop_keeper((char) roomno)) || !inhishop(shkp))
4706 return FALSE;
4707
4708 if (ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy)
4709 return FALSE;
4710
4711 sx = ESHK(shkp)->shk.x;
4712 sy = ESHK(shkp)->shk.y;
4713
4714 if (shkp->mx == sx && shkp->my == sy && shkp->mcanmove && !shkp->msleeping
4715 && (x == sx - 1 || x == sx + 1 || y == sy - 1 || y == sy + 1)
4716 && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK)
4717 || u.usteed)) {
4718 pline("%s%s blocks your way!", Shknam(shkp),
4719 Invis ? " senses your motion and" : "");
4720 return TRUE;
4721 }
4722 return FALSE;
4723 }
4724
4725 /* "your " or "Foobar's " (note the trailing space) */
4726 char *
shk_your(buf,obj)4727 shk_your(buf, obj)
4728 char *buf;
4729 struct obj *obj;
4730 {
4731 if (!shk_owns(buf, obj) && !mon_owns(buf, obj))
4732 Strcpy(buf, the_your[carried(obj) ? 1 : 0]);
4733 return strcat(buf, " ");
4734 }
4735
4736 char *
Shk_Your(buf,obj)4737 Shk_Your(buf, obj)
4738 char *buf;
4739 struct obj *obj;
4740 {
4741 (void) shk_your(buf, obj);
4742 *buf = highc(*buf);
4743 return buf;
4744 }
4745
4746 STATIC_OVL char *
shk_owns(buf,obj)4747 shk_owns(buf, obj)
4748 char *buf;
4749 struct obj *obj;
4750 {
4751 struct monst *shkp;
4752 xchar x, y;
4753
4754 if (get_obj_location(obj, &x, &y, 0)
4755 && (obj->unpaid || (obj->where == OBJ_FLOOR && !obj->no_charge
4756 && costly_spot(x, y)))) {
4757 shkp = shop_keeper(inside_shop(x, y));
4758 return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : the_your[0]);
4759 }
4760 return (char *) 0;
4761 }
4762
4763 STATIC_OVL char *
mon_owns(buf,obj)4764 mon_owns(buf, obj)
4765 char *buf;
4766 struct obj *obj;
4767 {
4768 if (obj->where == OBJ_MINVENT)
4769 return strcpy(buf, s_suffix(y_monnam(obj->ocarry)));
4770 return (char *) 0;
4771 }
4772
4773 STATIC_OVL const char *
cad(altusage)4774 cad(altusage)
4775 boolean altusage; /* used as a verbalized exclamation: \"Cad! ...\" */
4776 {
4777 const char *res = 0;
4778
4779 switch (is_demon(youmonst.data) ? 3 : poly_gender()) {
4780 case 0:
4781 res = "cad";
4782 break;
4783 case 1:
4784 res = "minx";
4785 break;
4786 case 2:
4787 res = "beast";
4788 break;
4789 case 3:
4790 res = "fiend";
4791 break;
4792 default:
4793 impossible("cad: unknown gender");
4794 res = "thing";
4795 break;
4796 }
4797 if (altusage) {
4798 char *cadbuf = mon_nam(&youmonst); /* snag an output buffer */
4799
4800 /* alternate usage adds a leading double quote and trailing
4801 exclamation point plus sentence separating spaces */
4802 Sprintf(cadbuf, "\"%s! ", res);
4803 cadbuf[1] = highc(cadbuf[1]);
4804 res = cadbuf;
4805 }
4806 return res;
4807 }
4808
4809 #ifdef __SASC
4810 void
sasc_bug(struct obj * op,unsigned x)4811 sasc_bug(struct obj *op, unsigned x)
4812 {
4813 op->unpaid = x;
4814 }
4815 #endif
4816
4817 /*
4818 * The caller is about to make obj_absorbed go away.
4819 *
4820 * There's no way for you (or a shopkeeper) to prevent globs
4821 * from merging with each other on the floor due to the
4822 * inherent nature of globs so it irretrievably becomes part
4823 * of the floor glob mass. When one glob is absorbed by another
4824 * glob, the two become indistinguishable and the remaining
4825 * glob object grows in mass, the product of both.
4826 *
4827 * billing admin, player compensation, shopkeeper compensation
4828 * all need to be considered.
4829 *
4830 * Any original billed item is lost to the absorption so the
4831 * original billed amount for the object being absorbed must
4832 * get added to the cost owing for the absorber, and the
4833 * separate cost for the object being absorbed goes away.
4834 *
4835 * There are four scenarios to deal with:
4836 * 1. shop_owned glob merging into shop_owned glob
4837 * 2. player_owned glob merging into shop_owned glob
4838 * 3. shop_owned glob merging into player_owned glob
4839 * 4. player_owned glob merging into player_owned glob
4840 */
4841 void
globby_bill_fixup(obj_absorber,obj_absorbed)4842 globby_bill_fixup(obj_absorber, obj_absorbed)
4843 struct obj *obj_absorber, *obj_absorbed;
4844 {
4845 int x = 0, y = 0;
4846 struct bill_x *bp, *bp_absorber = (struct bill_x *) 0;
4847 struct monst *shkp = 0;
4848 struct eshk *eshkp;
4849 long amount, per_unit_cost = set_cost(obj_absorbed, shkp);
4850 boolean floor_absorber = (obj_absorber->where == OBJ_FLOOR);
4851
4852 if (!obj_absorber->globby)
4853 impossible("globby_bill_fixup called for non-globby object");
4854
4855 if (floor_absorber) {
4856 x = obj_absorber->ox, y = obj_absorber->oy;
4857 }
4858 if (obj_absorber->unpaid) {
4859 /* look for a shopkeeper who owns this object */
4860 for (shkp = next_shkp(fmon, TRUE); shkp;
4861 shkp = next_shkp(shkp->nmon, TRUE))
4862 if (onbill(obj_absorber, shkp, TRUE))
4863 break;
4864 } else if (obj_absorbed->unpaid) {
4865 if (obj_absorbed->where == OBJ_FREE
4866 && floor_absorber && costly_spot(x, y)) {
4867 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
4868 }
4869 }
4870 /* sanity check, in case obj is on bill but not marked 'unpaid' */
4871 if (!shkp)
4872 shkp = shop_keeper(*u.ushops);
4873 if (!shkp)
4874 return;
4875 bp_absorber = onbill(obj_absorber, shkp, FALSE);
4876 bp = onbill(obj_absorbed, shkp, FALSE);
4877 eshkp = ESHK(shkp);
4878
4879 /**************************************************************
4880 * Scenario 1. Shop-owned glob absorbing into shop-owned glob
4881 **************************************************************/
4882 if (bp && (!obj_absorber->no_charge
4883 || billable(&shkp, obj_absorber, eshkp->shoproom, FALSE))) {
4884 /* the glob being absorbed has a billing record */
4885 amount = bp->price;
4886 eshkp->billct--;
4887 #ifdef DUMB
4888 {
4889 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
4890 int indx = eshkp->billct;
4891
4892 *bp = eshkp->bill_p[indx];
4893 }
4894 #else
4895 *bp = eshkp->bill_p[eshkp->billct];
4896 #endif
4897 clear_unpaid_obj(shkp, obj_absorbed);
4898
4899 if (bp_absorber) {
4900 /* the absorber has a billing record */
4901 bp_absorber->price += amount;
4902 } else {
4903 /* the absorber has no billing record */
4904 ;
4905 }
4906 return;
4907 }
4908 /**************************************************************
4909 * Scenario 2. Player-owned glob absorbing into shop-owned glob
4910 **************************************************************/
4911 if (!bp_absorber && !bp && !obj_absorber->no_charge) {
4912 /* there are no billing records */
4913 amount = get_pricing_units(obj_absorbed) * per_unit_cost;
4914 if (saleable(shkp, obj_absorbed)) {
4915 if (eshkp->debit >= amount) {
4916 if (eshkp->loan) { /* you carry shop's gold */
4917 if (eshkp->loan >= amount)
4918 eshkp->loan -= amount;
4919 else
4920 eshkp->loan = 0L;
4921 }
4922 eshkp->debit -= amount;
4923 pline_The("donated %s %spays off your debt.",
4924 obj_typename(obj_absorbed->otyp),
4925 eshkp->debit ? "partially " : "");
4926 } else {
4927 long delta = amount - eshkp->debit;
4928
4929 eshkp->credit += delta;
4930 if (eshkp->debit) {
4931 eshkp->debit = 0L;
4932 eshkp->loan = 0L;
4933 Your("debt is paid off.");
4934 }
4935 if (eshkp->credit == delta)
4936 pline_The("%s established %ld %s credit.",
4937 obj_typename(obj_absorbed->otyp),
4938 delta, currency(delta));
4939 else
4940 pline_The("%s added %ld %s %s %ld %s.",
4941 obj_typename(obj_absorbed->otyp),
4942 delta, currency(delta),
4943 "to your credit; total is now",
4944 eshkp->credit, currency(eshkp->credit));
4945 }
4946 }
4947 return;
4948 } else if (bp_absorber) {
4949 /* absorber has a billing record */
4950 bp_absorber->price += per_unit_cost * get_pricing_units(obj_absorbed);
4951 return;
4952 }
4953 /**************************************************************
4954 * Scenario 3. shop_owned glob merging into player_owned glob
4955 **************************************************************/
4956 if (bp && (obj_absorber->no_charge
4957 || (floor_absorber && !costly_spot(x, y)))) {
4958 amount = bp->price;
4959 bill_dummy_object(obj_absorbed);
4960 verbalize("You owe me %ld %s for my %s that you %s with your%s",
4961 amount, currency(amount), obj_typename(obj_absorbed->otyp),
4962 ANGRY(shkp) ? "had the audacity to mix" : "just mixed",
4963 ANGRY(shkp) ? " stinking batch!" : "s.");
4964 return;
4965 }
4966 /**************************************************************
4967 * Scenario 4. player_owned glob merging into player_owned glob
4968 **************************************************************/
4969
4970 return;
4971 }
4972
4973 /*shk.c*/
4974