Blindfold removal fix
[slashemextended.git] / src / shk.c
blob3a0bd7d358cc115e6c424a5daa012da1795bbf4f
1 /* SCCS Id: @(#)shk.c 3.4 2003/12/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Note by Amy: All "shkp->mgold + (value)" routines have a chance to fail to make credit cloning harder. */
6 /* The same applies to all actions that give credit (see also dokick.c). */
8 #include "hack.h"
9 #include "eshk.h"
11 /*#define DEBUG*/
13 #define PAY_SOME 2
14 #define PAY_BUY 1
15 #define PAY_CANT 0 /* too poor */
16 #define PAY_SKIP (-1)
17 #define PAY_BROKE (-2)
19 STATIC_DCL void makekops(coord *);
20 STATIC_DCL void call_kops(struct monst *,BOOLEAN_P);
21 # ifdef OVLB
22 STATIC_DCL void kops_gone(BOOLEAN_P);
23 # endif /* OVLB */
25 #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
26 #define no_cheat ((ACURR(A_CHA) - rnl(3)) > 7)
28 extern const struct shclass shtypes[]; /* defined in shknam.c */
29 extern struct obj *thrownobj; /* defined in dothrow.c */
31 STATIC_VAR NEARDATA long int followmsg; /* last time of follow message */
33 STATIC_DCL void setpaid(struct monst *);
34 STATIC_DCL long addupbill(struct monst *);
35 STATIC_DCL void pacify_shk(struct monst *);
36 STATIC_DCL struct bill_x *onbill(struct obj *, struct monst *, BOOLEAN_P);
37 STATIC_DCL struct monst *next_shkp(struct monst *, BOOLEAN_P);
38 STATIC_DCL long shop_debt(struct eshk *);
39 STATIC_DCL char *shk_owns(char *,struct obj *);
40 STATIC_DCL char *mon_owns(char *,struct obj *);
41 STATIC_DCL void clear_unpaid(struct obj *);
42 STATIC_DCL long check_credit(long, struct monst *);
43 STATIC_DCL void pay(long, struct monst *);
44 STATIC_DCL long get_cost(struct obj *, struct monst *);
45 STATIC_DCL long set_cost(struct obj *, struct monst *);
46 STATIC_DCL const char *shk_embellish(struct obj *, long);
47 STATIC_DCL long cost_per_charge(struct monst *,struct obj *,BOOLEAN_P);
48 STATIC_DCL long cheapest_item(struct monst *);
49 STATIC_DCL int dopayobj(struct monst *, struct bill_x *, struct obj **, int, BOOLEAN_P);
50 STATIC_DCL long stolen_container(struct obj *, struct monst *, long, BOOLEAN_P, BOOLEAN_P);
51 STATIC_DCL long getprice(struct obj *,BOOLEAN_P);
52 STATIC_DCL void shk_names_obj(struct monst *,struct obj *,const char *,long,const char *);
53 STATIC_DCL struct obj *bp_to_obj(struct bill_x *);
54 STATIC_DCL boolean inherits(struct monst *,int,int);
55 STATIC_DCL void set_repo_loc(struct eshk *);
56 STATIC_DCL boolean angry_shk_exists(void);
57 STATIC_DCL void rile_shk(struct monst *);
58 STATIC_DCL void rouse_shk(struct monst *,BOOLEAN_P);
59 STATIC_DCL void remove_damage(struct monst *, BOOLEAN_P);
60 STATIC_DCL void sub_one_frombill(struct obj *, struct monst *);
61 STATIC_DCL void add_one_tobill(struct obj *, BOOLEAN_P);
62 STATIC_DCL void dropped_container(struct obj *, struct monst *, BOOLEAN_P);
63 STATIC_DCL void add_to_billobjs(struct obj *);
64 STATIC_DCL void bill_box_content(struct obj *, BOOLEAN_P, BOOLEAN_P, struct monst *);
65 #ifdef OVL1
66 static boolean rob_shop(struct monst *);
67 #endif
69 #define NOBOUND (-1) /* No lower/upper limit to charge */
70 static void shk_other_services(void);
71 static void shk_identify(char *, struct monst *);
72 static void shk_uncurse(char *, struct monst *);
73 static void shk_bless(char *, struct monst *);
74 static void shk_appraisal(char *, struct monst *);
75 static void shk_weapon_works(char *, struct monst *);
76 static void shk_armor_works(char *, struct monst *);
77 static void shk_charge(char *, struct monst *);
78 static void shk_estcredit(char *, struct monst *);
79 static boolean shk_obj_match(struct obj *, struct monst *);
80 /*static int shk_class_match(long class, struct monst *shkp);*/
81 static boolean shk_offer_price(char *, long, struct monst *);
82 static void shk_smooth_charge(int *, int, int);
84 #ifdef OVLB
86 invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
87 obj->quan <= bp->bquan
91 #ifdef GOLDOBJ
93 Transfer money from inventory to monster when paying
94 shopkeepers, priests, oracle, succubus, & other demons.
95 Simple with only gold coins.
96 This routine will handle money changing when multiple
97 coin types is implemented, only appropriate
98 monsters will pay change. (Peaceful shopkeepers, priests
99 & the oracle try to maintain goodwill while selling
100 their wares or services. Angry monsters and all demons
101 will keep anything they get their hands on.
102 Returns the amount actually paid, so we can know
103 if the monster kept the change.
105 long
106 money2mon(mon, amount)
107 struct monst *mon;
108 long amount;
110 struct obj *ygold = findgold(invent);
112 if (amount <= 0) {
113 impossible("%s payment in money2mon!", amount ? "negative" : "zero");
114 return 0L;
116 if (!ygold || ygold->quan < amount) {
117 impossible("Paying without %s money?", ygold ? "enough" : "");
118 return 0L;
121 if (ygold->quan > amount)
122 ygold = splitobj(ygold, amount);
123 else if (ygold->owornmask)
124 remove_worn_item(ygold, FALSE); /* quiver */
125 freeinv(ygold);
126 add_to_minv(mon, ygold);
127 flags.botl = 1;
128 return amount;
133 Transfer money from monster to inventory.
134 Used when the shopkeeper pay for items, and when
135 the priest gives you money for an ale.
137 void
138 money2u(mon, amount)
139 struct monst *mon;
140 long amount;
142 struct obj *mongold = findgold(mon->minvent);
144 if (amount <= 0) {
145 impossible("%s payment in money2u!", amount ? "negative" : "zero");
146 return;
148 if (!mongold || mongold->quan < amount) {
149 impossible("%s paying without %s money?", a_monnam(mon),
150 mongold ? "enough" : "");
151 return;
154 if (mongold->quan > amount) mongold = splitobj(mongold, amount);
155 obj_extract_self(mongold);
157 if (!merge_choice(invent, mongold) && inv_cnt() >= 52) {
158 You("have no room for the money!");
159 dropy(mongold);
160 } else {
161 addinv(mongold);
162 flags.botl = 1;
166 #endif /* GOLDOBJ */
168 STATIC_OVL struct monst *
169 next_shkp(shkp, withbill)
170 register struct monst *shkp;
171 register boolean withbill;
173 for (; shkp; shkp = shkp->nmon) {
174 if (DEADMONSTER(shkp)) continue;
175 if (shkp->isshk && (ESHK(shkp)->billct || !withbill)) break;
178 if (shkp) {
179 if (NOTANGRY(shkp)) {
180 if (ESHK(shkp)->surcharge) pacify_shk(shkp);
181 } else {
182 if (!ESHK(shkp)->surcharge) rile_shk(shkp);
185 return(shkp);
188 char *
189 shkname(mtmp) /* called in do_name.c */
190 register struct monst *mtmp;
192 return(ESHK(mtmp)->shknam);
195 void
196 shkgone(mtmp) /* called in mon.c */
197 struct monst *mtmp;
199 struct eshk *eshk = ESHK(mtmp);
200 struct mkroom *sroom = &rooms[eshk->shoproom - ROOMOFFSET];
201 struct obj *otmp;
202 char *p;
203 int sx, sy;
205 /* [BUG: some of this should be done on the shop level */
206 /* even when the shk dies on a different level.] */
207 if (on_level(&eshk->shoplevel, &u.uz)) {
208 remove_damage(mtmp, TRUE);
209 sroom->resident = (struct monst *)0;
210 if (!search_special(ANY_SHOP))
211 level.flags.has_shop = 0;
213 /* items on shop floor revert to ordinary objects */
214 for (sx = sroom->lx; sx <= sroom->hx; sx++)
215 for (sy = sroom->ly; sy <= sroom->hy; sy++)
216 for (otmp = level.objects[sx][sy]; otmp; otmp = otmp->nexthere)
217 otmp->no_charge = 0;
219 /* Make sure bill is set only when the
220 dead shk is the resident shk. */
221 if ((p = index(u.ushops, eshk->shoproom)) != 0) {
222 setpaid(mtmp);
223 eshk->bill_p = (struct bill_x *)0;
224 /* remove eshk->shoproom from u.ushops */
225 do { *p = *(p + 1); } while (*++p);
230 void
231 set_residency(shkp, zero_out)
232 register struct monst *shkp;
233 register boolean zero_out;
235 if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
236 rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
237 (zero_out)? (struct monst *)0 : shkp;
240 void
241 replshk(mtmp,mtmp2)
242 register struct monst *mtmp, *mtmp2;
244 rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2;
245 if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
246 ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
250 /* do shopkeeper specific structure munging -dlc */
251 void
252 restshk(shkp, ghostly)
253 struct monst *shkp;
254 boolean ghostly;
256 if (u.uz.dlevel) {
257 struct eshk *eshkp = ESHK(shkp);
259 if (eshkp->bill_p != (struct bill_x *) -1000)
260 eshkp->bill_p = &eshkp->bill[0];
261 /* shoplevel can change as dungeons move around */
262 /* savebones guarantees that non-homed shk's will be gone */
263 if (ghostly) {
264 assign_level(&eshkp->shoplevel, &u.uz);
265 if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ))
266 pacify_shk(shkp);
271 #endif /* OVLB */
272 #ifdef OVL3
274 /* Clear the unpaid bit on all of the objects in the list. */
275 STATIC_OVL void
276 clear_unpaid(list)
277 register struct obj *list;
279 while (list) {
280 if (Has_contents(list)) clear_unpaid(list->cobj);
281 list->unpaid = 0;
282 list = list->nobj;
285 #endif /*OVL3*/
286 #ifdef OVLB
288 /* either you paid or left the shop or the shopkeeper died */
289 STATIC_OVL void
290 setpaid(shkp)
291 register struct monst *shkp;
293 register struct obj *obj;
294 register struct monst *mtmp;
296 /* FIXME: object handling should be limited to
297 items which are on this particular shk's bill */
299 clear_unpaid(invent);
300 clear_unpaid(fobj);
301 clear_unpaid(level.buriedobjlist);
302 if (thrownobj) thrownobj->unpaid = 0;
303 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
304 clear_unpaid(mtmp->minvent);
305 for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
306 clear_unpaid(mtmp->minvent);
308 while ((obj = billobjs) != 0) {
309 obj_extract_self(obj);
310 dealloc_obj(obj);
312 if(shkp) {
313 ESHK(shkp)->billct = 0;
314 ESHK(shkp)->credit = 0L;
315 ESHK(shkp)->debit = 0L;
316 ESHK(shkp)->loan = 0L;
320 STATIC_OVL long
321 addupbill(shkp)
322 register struct monst *shkp;
324 register int ct = ESHK(shkp)->billct;
325 register struct bill_x *bp = ESHK(shkp)->bill_p;
326 register long total = 0L;
328 while(ct--){
329 total += bp->price * bp->bquan;
330 bp++;
332 return(total);
335 #endif /* OVLB */
336 #ifdef OVL1
338 STATIC_OVL void
339 call_kops(shkp, nearshop)
340 register struct monst *shkp;
341 register boolean nearshop;
343 /* Keystone Kops srt@ucla */
344 register boolean nokops;
345 char kopname[20];
347 strcpy(kopname, "Keystone Kops");
349 if(!shkp) return;
351 if (flags.soundok) {
352 pline("An alarm sounds!");
353 if (PlayerHearsSoundEffects) pline(issoviet ? "Veselites' vmeste s politseyskimi. Oni budut vas arestovat', ili na samom dele, tak kak vash personazh tak pateticheski slaby, oni mogut prosto ubit' vas skhodu, a zatem vy mozhete svernut' novuyu. Da!" : "Wueueueueueue! Wueueueueueue! Wueueueueueue! Wueueueueueue! Wueueueueueue!");
356 /* make new ones appear over time for a while, even if you switch dungeon levels to escape them --Amy */
357 u.copwantedlevel += rnz(1000);
359 nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) &&
360 (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) &&
361 (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) &&
362 (mvitals[PM_KOP_KOMMISSIONER].mvflags & G_GONE) &&
363 (mvitals[PM_KOP_KCHIEF].mvflags & G_GONE) &&
364 (mvitals[PM_KOP_KATCHER].mvflags & G_GONE) &&
365 (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE));
367 if (Is_blackmarket(&u.uz)) {
368 nokops = ((mvitals[PM_SOLDIER].mvflags & G_GONE) &&
369 (mvitals[PM_SERGEANT].mvflags & G_GONE) &&
370 (mvitals[PM_LIEUTENANT].mvflags & G_GONE) &&
371 (mvitals[PM_CAPTAIN].mvflags & G_GONE));
373 strcpy(kopname, "guards");
376 /* Let's just assume not all K are genocided. --Amy */
378 /*if(!angry_guards(!flags.soundok) && nokops) {
379 if(flags.verbose && flags.soundok)
380 pline("But no one seems to respond to it.");
381 return;
384 if(nokops) return;*/
387 coord mm;
389 if (nearshop)
390 if (!Is_blackmarket(&u.uz))
392 /* Create swarm around you, if you merely "stepped out" */
393 if (flags.verbose)
394 pline_The("%s appear!", kopname);
395 mm.x = u.ux;
396 mm.y = u.uy;
397 makekops(&mm);
398 return;
400 if (flags.verbose)
401 pline_The("%s are after you!", kopname);
402 /* Create swarm near down staircase (hinders return to level) */
403 if (Is_blackmarket(&u.uz)) {
404 struct trap *trap = ftrap;
405 while (trap) {
406 if (trap->ttyp == MAGIC_PORTAL) {
407 mm.x = trap->tx;
408 mm.y = trap->ty;
410 trap = trap->ntrap;
412 } else {
413 mm.x = xdnstair;
414 mm.y = ydnstair;
416 makekops(&mm);
417 /* Create swarm near shopkeeper (hinders return to shop) */
418 mm.x = shkp->mx;
419 mm.y = shkp->my;
420 makekops(&mm);
425 void
426 blkmar_guards(shkp)
427 register struct monst *shkp;
429 register struct monst *mt;
430 register struct eshk *eshkp = ESHK(shkp);
431 boolean mesg_given = FALSE; /* Only give message if assistants peaceful */
432 static boolean rlock = FALSE; /* Prevent recursive calls (via wakeup) */
434 if (rlock) return;
435 rlock = TRUE;
437 /* wake up assistants */
438 for (mt = fmon; mt; mt = mt->nmon) {
439 if (DEADMONSTER(mt)) continue;
440 /* non-tame named monsters are presumably
441 * black marketeer's assistants */
442 if (!mt->mtame && NAME(mt) && *NAME(mt) && mt->mpeaceful &&
443 mt != shkp && inside_shop(mt->mx, mt->my) == eshkp->shoproom) {
444 if (!mesg_given) {
445 pline("%s calls for %s assistants!",
446 noit_Monnam(shkp), mhis(shkp));
447 mesg_given = TRUE;
449 wakeup(mt);
452 rlock = FALSE;
455 /* x,y is strictly inside shop */
456 char
457 inside_shop(x, y)
458 register xchar x, y;
460 register char rno;
462 rno = levl[x][y].roomno;
463 if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET))
464 return(NO_ROOM);
465 else
466 return(rno);
469 void
470 u_left_shop(leavestring, newlev)
471 char *leavestring;
472 boolean newlev;
474 struct monst *shkp;
475 struct eshk *eshkp;
478 * IF player
479 * ((didn't leave outright) AND
480 * ((he is now strictly-inside the shop) OR
481 * (he wasn't strictly-inside last turn anyway)))
482 * THEN (there's nothing to do, so just return)
484 if(!*leavestring &&
485 (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
486 return;
488 shkp = shop_keeper(*u.ushops0);
489 if (!shkp || !inhishop(shkp))
490 return; /* shk died, teleported, changed levels... */
492 eshkp = ESHK(shkp);
493 if (!eshkp->billct && !eshkp->debit) /* bill is settled */
494 return;
496 if (!*leavestring && shkp->mcanmove && !shkp->msleeping) {
498 * Player just stepped onto shop-boundary (known from above logic).
499 * Try to intimidate him into paying his bill
501 verbalize(NOTANGRY(shkp) ?
502 "%s! Please pay before leaving." :
503 "%s! Don't you leave without paying!",
504 playeraliasname);
505 return;
508 if (rob_shop(shkp)) {
510 if (Is_blackmarket(&u.uz))
511 blkmar_guards(shkp);
513 call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
517 /* robbery from outside the shop via telekinesis or grappling hook */
518 void
519 remote_burglary(x, y)
520 xchar x, y;
522 struct monst *shkp;
523 struct eshk *eshkp;
525 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
526 if (!shkp || !inhishop(shkp))
527 return; /* shk died, teleported, changed levels... */
529 eshkp = ESHK(shkp);
530 if (!eshkp->billct && !eshkp->debit) /* bill is settled */
531 return;
533 if (rob_shop(shkp)) {
535 if (Is_blackmarket(&u.uz))
536 blkmar_guards(shkp);
538 /*[might want to set 2nd arg based on distance from shop doorway]*/
539 call_kops(shkp, FALSE);
543 /* shop merchandise has been taken; pay for it with any credit available;
544 return false if the debt is fully covered by credit, true otherwise */
545 static boolean
546 rob_shop(shkp)
547 struct monst *shkp;
549 struct eshk *eshkp;
550 long total;
552 eshkp = ESHK(shkp);
553 rouse_shk(shkp, TRUE);
554 total = (addupbill(shkp) + eshkp->debit);
555 if (eshkp->credit >= total) {
556 Your("credit of %ld %s is used to cover your shopping bill.",
557 eshkp->credit, currency(eshkp->credit));
558 total = 0L; /* credit gets cleared by setpaid() */
559 } else {
560 You("escaped the shop without paying!");
561 total -= eshkp->credit;
563 setpaid(shkp);
564 if (!total) return FALSE;
566 /* by this point, we know an actual robbery has taken place */
567 eshkp->robbed += total;
569 /* it was annoying that the total was completely irrelevant unless you somehow wanted to compensate the shopkeeper,
570 * and therefore I decided to have it influence the kop wanted level --Amy */
571 if ((!rn2(5) || Role_if(PM_CELLAR_CHILD)) && (total > 10)) u.copwantedlevel += rnz(total / 5);
573 You("stole %ld %s worth of merchandise.",
574 total, currency(total));
575 u.cnd_stealamount += total;
576 if (!Role_if(PM_ROGUE)) { /* stealing is unlawful */
577 adjalign(-sgn(u.ualign.type));
578 You_feel("like an evil rogue.");
579 if (u.ualign.type == A_LAWFUL) {
580 increasesincounter(1);
581 u.alignlim--;
585 hot_pursuit(shkp);
587 if (practicantterror && total > 0) { /* can happen several times --Amy */
588 pline("%s thunders: 'That's theft! You have to pay twice the amount that the stolen goods cost, you hear? Be glad that I'm not giving you hall exclusion!'", noroelaname());
589 fineforpracticant(total * 2, 0, 0);
592 return TRUE;
595 void
596 u_entered_shop(enterstring)
597 register char *enterstring;
600 register int rt;
601 register struct monst *shkp;
602 register struct eshk *eshkp;
603 static const char no_shk[] = "This shop appears to be deserted.";
604 static char empty_shops[5];
606 if(!*enterstring)
607 return;
609 if(!(shkp = shop_keeper(*enterstring))) {
610 if (!index(empty_shops, *enterstring) &&
611 in_rooms(u.ux, u.uy, SHOPBASE) !=
612 in_rooms(u.ux0, u.uy0, SHOPBASE))
613 pline(no_shk);
614 strcpy(empty_shops, u.ushops);
615 u.ushops[0] = '\0';
616 return;
619 eshkp = ESHK(shkp);
621 if (!inhishop(shkp)) {
622 /* dump core when referenced */
623 eshkp->bill_p = (struct bill_x *) -1000;
624 if (!index(empty_shops, *enterstring))
625 pline(no_shk);
626 strcpy(empty_shops, u.ushops);
627 u.ushops[0] = '\0';
628 return;
631 eshkp->bill_p = &(eshkp->bill[0]);
633 if ((!eshkp->visitct || *eshkp->customer) &&
634 strncmpi(eshkp->customer, plname, PL_NSIZ)) {
635 /* You seem to be new here */
636 eshkp->visitct = 0;
637 eshkp->following = 0;
638 (void) strncpy(eshkp->customer,plname,PL_NSIZ);
639 pacify_shk(shkp);
642 if (shkp->msleeping || !shkp->mcanmove || eshkp->following)
643 return; /* no dialog */
645 if (Invis && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY) ) {
646 pline("%s senses your presence.", shkname(shkp));
647 if (!Is_blackmarket(&u.uz)) {
648 verbalize("Invisible customers are not welcome!");
649 return;
653 if (Is_blackmarket(&u.uz) && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY) &&
654 u.umonnum>0 && mons[u.umonnum].mlet != S_HUMAN) {
655 verbalize("Non-human customers are not welcome!");
656 return;
659 /* Visible striped prison shirt */
660 if ((uarmu && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY) && (uarmu->otyp == STRIPED_SHIRT)) && !uarm && !uarmc) {
661 eshkp->pbanned = TRUE;
663 if (Race_if(PM_ALBAE) && !Upolyd) eshkp->pbanned = TRUE;
664 if (Race_if(PM_IRAHA)) eshkp->pbanned = TRUE;
666 rt = rooms[*enterstring - ROOMOFFSET].rtype;
668 if (ANGRY(shkp)) {
669 verbalize("So, %s, you dare return to %s %s?!",
670 playeraliasname,
671 s_suffix(shkname(shkp)),
672 shtypes[rt - SHOPBASE].name);
673 } else if (eshkp->robbed) {
674 pline("%s mutters imprecations against shoplifters.", shkname(shkp));
675 } else {
676 if (!eshkp->pbanned || inside_shop(u.ux, u.uy))
677 verbalize("%s, %s! Welcome%s to %s %s!",
678 Hello(shkp), playeraliasname,
679 eshkp->visitct++ ? " again" : "",
680 s_suffix(shkname(shkp)),
681 shtypes[rt - SHOPBASE].name);
683 /* can't do anything about blocking if teleported in */
684 if (!inside_shop(u.ux, u.uy) && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY) ) {
685 boolean should_block;
686 int cnt;
687 const char *tool;
688 struct obj *pick = carrying(PICK_AXE),
689 *pickB = carrying(CONGLOMERATE_PICK),
690 *pickC = carrying(BRONZE_PICK),
691 *pickD = carrying(BRICK_PICK),
692 *pickE = carrying(NANO_PICK),
693 *pickF = carrying(MYSTERY_PICK),
694 *pickG = carrying(CONUNDRUM_PICK),
695 *pickH = carrying(MYSTERIOUS_PICK),
696 *pickI = carrying(UNWIELDY_PICK),
697 *mattock = carrying(DWARVISH_MATTOCK),
698 *mattockB = carrying(SOFT_MATTOCK),
699 *mattockC = carrying(ETERNIUM_MATTOCK);
701 if (pick || pickB || pickC || pickD || pickE || pickF || pickG || pickH || pickI || mattock || mattockB || mattockC) {
702 cnt = 1;
703 if (pick && mattock) { /* carrying both types */
704 tool = "digging tool";
705 cnt = 2; /* `more than 1' is all that matters */
706 } else if (pick) {
707 tool = "pick-axe";
708 /* hack: `pick' already points somewhere into inventory */
709 while ((pick = pick->nobj) != 0)
710 if (pick->otyp == PICK_AXE) ++cnt;
711 } else if (pickB) {
712 tool = "conglomerate pick";
713 while ((pickB = pickB->nobj) != 0)
714 if (pickB->otyp == CONGLOMERATE_PICK) ++cnt;
715 } else if (pickC) {
716 tool = "bronze pick";
717 while ((pickC = pickC->nobj) != 0)
718 if (pickC->otyp == BRONZE_PICK) ++cnt;
719 } else if (pickD) {
720 tool = "brick pick";
721 while ((pickD = pickD->nobj) != 0)
722 if (pickD->otyp == BRICK_PICK) ++cnt;
723 } else if (pickE) {
724 tool = "nano pick";
725 while ((pickE = pickE->nobj) != 0)
726 if (pickE->otyp == NANO_PICK) ++cnt;
727 } else if (pickF) {
728 tool = "mystery pick";
729 while ((pickF = pickF->nobj) != 0)
730 if (pickF->otyp == MYSTERY_PICK) ++cnt;
731 } else if (pickG) {
732 tool = "conundrum pick";
733 while ((pickG = pickG->nobj) != 0)
734 if (pickG->otyp == CONUNDRUM_PICK) ++cnt;
735 } else if (pickH) {
736 tool = "mysterious pick";
737 while ((pickH = pickH->nobj) != 0)
738 if (pickH->otyp == MYSTERIOUS_PICK) ++cnt;
739 } else if (pickI) {
740 tool = "unwieldy pick";
741 while ((pickI = pickI->nobj) != 0)
742 if (pickI->otyp == UNWIELDY_PICK) ++cnt;
743 } else if (mattock) {
744 tool = "mattock";
745 while ((mattock = mattock->nobj) != 0)
746 if (mattock->otyp == DWARVISH_MATTOCK) ++cnt;
747 /* [ALI] Shopkeeper indicates mattock(s) */
748 if (!Blind) makeknown(DWARVISH_MATTOCK);
749 } else if (mattockB) {
750 tool = "mattock";
751 while ((mattockB = mattockB->nobj) != 0)
752 if (mattockB->otyp == ETERNIUM_MATTOCK) ++cnt;
753 } else { /* mattockC */
754 tool = "mattock";
755 while ((mattockC = mattockC->nobj) != 0)
756 if (mattockC->otyp == SOFT_MATTOCK) ++cnt;
758 verbalize(NOTANGRY(shkp) ?
759 "Will you please leave your %s%s outside?" :
760 "Leave the %s%s outside.",
761 tool, plur(cnt));
762 should_block = TRUE;
763 } else if (u.usteed && !(uarm && uarm->oartifact == ART_FAER_ME) ) {
764 verbalize(NOTANGRY(shkp) ?
765 "Will you please leave %s outside?" :
766 "Leave %s outside.", y_monnam(u.usteed));
767 should_block = TRUE;
768 } else if (eshkp->pbanned && !(Is_blackmarket(&u.uz)) ) {
769 verbalize("I don't sell to your kind here.");
770 should_block = TRUE;
771 } else {
772 should_block = (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(CONGLOMERATE_PICK, u.ux, u.uy) || sobj_at(UNWIELDY_PICK, u.ux, u.uy) || sobj_at(CONUNDRUM_PICK, u.ux, u.uy) || sobj_at(MYSTERY_PICK, u.ux, u.uy) || sobj_at(BRONZE_PICK, u.ux, u.uy) || sobj_at(BRICK_PICK, u.ux, u.uy) || sobj_at(MYSTERIOUS_PICK, u.ux, u.uy) || sobj_at(NANO_PICK, u.ux, u.uy) || sobj_at(SOFT_MATTOCK, u.ux, u.uy) || sobj_at(ETERNIUM_MATTOCK, u.ux, u.uy) ||
773 sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)));
775 if (should_block) (void) dochug(shkp); /* shk gets extra move */
777 return;
781 Decide whether two unpaid items are mergable; caller is responsible for
782 making sure they're unpaid and the same type of object; we check the price
783 quoted by the shopkeeper and also that they both belong to the same shk.
785 boolean
786 same_price(obj1, obj2)
787 struct obj *obj1, *obj2;
789 register struct monst *shkp1, *shkp2;
790 register struct bill_x *bp1 = 0, *bp2 = 0;
791 register boolean are_mergable = FALSE;
793 /* look up the first object by finding shk whose bill it's on */
794 for (shkp1 = next_shkp(fmon, TRUE); shkp1;
795 shkp1 = next_shkp(shkp1->nmon, TRUE))
796 if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0) break;
797 /* second object is probably owned by same shk; if not, look harder */
798 if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) {
799 shkp2 = shkp1;
800 } else {
801 for (shkp2 = next_shkp(fmon, TRUE); shkp2;
802 shkp2 = next_shkp(shkp2->nmon, TRUE))
803 if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0) break;
806 if (!bp1 || !bp2) impossible("same_price: object wasn't on any bill!");
807 else are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price);
808 return are_mergable;
812 * Figure out how much is owed to a given shopkeeper.
813 * At present, we ignore any amount robbed from the shop, to avoid
814 * turning the `$' command into a way to discover that the current
815 * level is bones data which has a shk on the warpath.
817 STATIC_OVL long
818 shop_debt(eshkp)
819 struct eshk *eshkp;
821 struct bill_x *bp;
822 int ct;
823 long debt = eshkp->debit;
825 for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--)
826 debt += bp->price * bp->bquan;
827 return debt;
830 /* called in response to the `$' command */
831 void
832 shopper_financial_report()
834 struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy));
835 struct eshk *eshkp;
836 long amt;
837 int pass;
839 if (this_shkp &&
840 !(ESHK(this_shkp)->credit || shop_debt(ESHK(this_shkp)))) {
841 You("have no credit or debt in here.");
842 this_shkp = 0; /* skip first pass */
845 /* pass 0: report for the shop we're currently in, if any;
846 pass 1: report for all other shops on this level. */
847 for (pass = this_shkp ? 0 : 1; pass <= 1; pass++)
848 for (shkp = next_shkp(fmon, FALSE);
849 shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
850 if ((shkp != this_shkp) ^ pass) continue;
851 eshkp = ESHK(shkp);
852 if ((amt = eshkp->credit) != 0)
853 You("have %ld %s credit at %s %s.",
854 amt, currency(amt), s_suffix(shkname(shkp)),
855 shtypes[eshkp->shoptype - SHOPBASE].name);
856 else if (shkp == this_shkp)
857 You("have no credit in here.");
858 if ((amt = shop_debt(eshkp)) != 0)
859 You("owe %s %ld %s.",
860 shkname(shkp), amt, currency(amt));
861 else if (shkp == this_shkp)
862 You("don't owe any money here.");
866 #endif /* OVL1 */
867 #ifdef OVLB
870 inhishop(mtmp)
871 register struct monst *mtmp;
873 return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE),
874 ESHK(mtmp)->shoproom) &&
875 on_level(&(ESHK(mtmp)->shoplevel), &u.uz));
878 struct monst *
879 shop_keeper(rmno)
880 register char rmno;
882 struct monst *shkp = rmno >= ROOMOFFSET ?
883 rooms[rmno - ROOMOFFSET].resident : 0;
885 if (shkp) {
886 if (NOTANGRY(shkp)) {
887 if (ESHK(shkp)->surcharge) pacify_shk(shkp);
888 } else {
889 if (!ESHK(shkp)->surcharge) rile_shk(shkp);
892 return shkp;
895 boolean
896 tended_shop(sroom)
897 register struct mkroom *sroom;
899 register struct monst *mtmp = sroom->resident;
901 if (!mtmp)
902 return(FALSE);
903 else
904 return((boolean)(inhishop(mtmp)));
907 STATIC_OVL struct bill_x *
908 onbill(obj, shkp, silent)
909 register struct obj *obj;
910 register struct monst *shkp;
911 register boolean silent;
913 if (shkp) {
914 register struct bill_x *bp = ESHK(shkp)->bill_p;
915 register int ct = ESHK(shkp)->billct;
917 while (--ct >= 0)
918 if (bp->bo_id == obj->o_id) {
919 if (!obj->unpaid) pline("onbill: paid obj on bill?");
920 return bp;
921 } else bp++;
923 if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?");
924 return (struct bill_x *)0;
927 /* Delete the contents of the given object. */
928 void
929 delete_contents(obj)
930 register struct obj *obj;
932 register struct obj *curr;
934 while ((curr = obj->cobj) != 0) {
935 if (Has_contents(curr)) delete_contents(curr);
936 obj_extract_self(curr);
937 if (evades_destruction(curr)) {
938 switch (obj->where) {
939 case OBJ_FREE:
940 case OBJ_ONBILL:
941 impossible("indestructible object %s",
942 obj->where == OBJ_FREE ? "free" : "on bill");
943 obfree(curr, (struct obj *)0);
944 break;
945 case OBJ_FLOOR:
946 place_object(curr, obj->ox, obj->oy);
947 /* No indestructible objects currently stack */
948 break;
949 case OBJ_CONTAINED:
950 add_to_container(obj->ocontainer, curr, TRUE);
951 break;
952 case OBJ_INVENT:
953 if (!flooreffects(curr, u.ux, u.uy, "fall"))
954 place_object(curr, u.ux, u.uy);
955 break;
956 case OBJ_MINVENT:
957 if (!flooreffects(curr,
958 obj->ocarry->mx, obj->ocarry->my, "fall"))
959 place_object(curr, obj->ocarry->mx, obj->ocarry->my);
960 break;
961 case OBJ_MIGRATING:
962 add_to_migration(curr);
963 /* Copy migration destination */
964 curr->ox = obj->ox;
965 curr->oy = obj->oy;
966 curr->owornmask = obj->owornmask;
967 break;
968 case OBJ_BURIED:
969 add_to_buried(curr);
970 curr->ox = obj->ox;
971 curr->oy = obj->oy;
972 break;
973 default:
974 panic("delete_contents");
975 break;
978 else
979 obfree(curr, (struct obj *)0);
983 /* called with two args on merge */
984 void
985 obfree(obj, merge)
986 register struct obj *obj, *merge;
988 register struct bill_x *bp;
989 register struct bill_x *bpm;
990 register struct monst *shkp;
992 if (obj == usaddle) dismount_steed(DISMOUNT_GENERIC);
994 if (obj->otyp == LEATHER_LEASH && obj->leashmon) o_unleash(obj);
995 if (obj->otyp == INKA_LEASH && obj->leashmon) o_unleash(obj);
996 if (obj->otyp == ADAMANT_LEASH && obj->leashmon) o_unleash(obj);
997 if (obj->oclass == SPBOOK_CLASS) book_disappears(obj);
998 if (obj->oclass == FOOD_CLASS) food_disappears(obj);
999 /* [ALI] Enforce new rules: Containers must have their contents
1000 * deleted while still in situ so that we can place any
1001 * indestructible objects they may contain.
1002 * Amy edit: the buglog file would laaaaag like hell with thousands of faux objects, so we'll scrap that
1004 if (Has_contents(obj)) {
1005 impossible("BUG: obfree() called on non-empty container");
1006 delete_contents(obj);
1009 shkp = 0;
1010 if (obj->unpaid) {
1011 /* look for a shopkeeper who owns this object */
1012 for (shkp = next_shkp(fmon, TRUE); shkp;
1013 shkp = next_shkp(shkp->nmon, TRUE))
1014 if (onbill(obj, shkp, TRUE)) break;
1016 /* sanity check, more or less */
1017 if (!shkp) shkp = shop_keeper(*u.ushops);
1019 * Note: `shkp = shop_keeper(*u.ushops)' used to be
1020 * unconditional. But obfree() is used all over
1021 * the place, so making its behavior be dependent
1022 * upon player location doesn't make much sense.
1025 if ((bp = onbill(obj, shkp, FALSE)) != 0) {
1026 if(!merge){
1027 bp->useup = 1;
1028 obj->unpaid = 0; /* only for doinvbill */
1029 add_to_billobjs(obj);
1030 return;
1032 bpm = onbill(merge, shkp, FALSE);
1033 if(!bpm){
1034 /* this used to be a rename */
1035 impossible("obfree: not on bill??");
1036 return;
1037 } else {
1038 /* this was a merger */
1039 bpm->bquan += bp->bquan;
1040 ESHK(shkp)->billct--;
1041 #ifdef DUMB
1043 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
1044 int indx = ESHK(shkp)->billct;
1045 *bp = ESHK(shkp)->bill_p[indx];
1047 #else
1048 *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
1049 #endif
1053 if ((Race_if(PM_PLAYER_MUSHROOM) || (uchain && uchain->oartifact == ART_ERO_ERO_ERO_ERO_MUSHROOM_M)) && u.mushroompoleused) {
1054 setnotworn(obj);
1055 obj_extract_self(obj);
1058 dealloc_obj(obj);
1060 #endif /* OVLB */
1061 #ifdef OVL3
1063 STATIC_OVL long
1064 check_credit(tmp, shkp)
1065 long tmp;
1066 register struct monst *shkp;
1068 long credit = ESHK(shkp)->credit;
1070 if(credit == 0L) return(tmp);
1071 if(credit >= tmp) {
1072 pline_The("price is deducted from your credit.");
1073 ESHK(shkp)->credit -=tmp;
1074 tmp = 0L;
1075 } else {
1076 pline_The("price is partially covered by your credit.");
1077 ESHK(shkp)->credit = 0L;
1078 tmp -= credit;
1080 return(tmp);
1083 STATIC_OVL void
1084 pay(tmp,shkp)
1085 long tmp;
1086 register struct monst *shkp;
1088 long robbed = ESHK(shkp)->robbed;
1089 long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
1091 #ifndef GOLDOBJ
1092 u.ugold -= balance;
1093 if (rn2(2) || balance < 0) shkp->mgold += balance;
1094 #else
1095 if (balance > 0) money2mon(shkp, balance);
1096 else if (balance < 0) money2u(shkp, -balance);
1097 #endif
1098 flags.botl = 1;
1099 if(robbed) {
1100 robbed -= tmp;
1101 if(robbed < 0) robbed = 0L;
1102 ESHK(shkp)->robbed = robbed;
1105 #endif /*OVL3*/
1106 #ifdef OVLB
1108 /* return shkp to home position */
1109 void
1110 home_shk(shkp, killkops)
1111 register struct monst *shkp;
1112 register boolean killkops;
1114 register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
1116 (void) mnearto(shkp, x, y, TRUE);
1117 level.flags.has_shop = 1;
1118 if (killkops) {
1119 /* kops_gone(TRUE); */
1120 pacify_guards();
1122 after_shk_move(shkp);
1125 STATIC_OVL boolean
1126 angry_shk_exists()
1128 register struct monst *shkp;
1130 for (shkp = next_shkp(fmon, FALSE);
1131 shkp; shkp = next_shkp(shkp->nmon, FALSE))
1132 if (ANGRY(shkp)) return(TRUE);
1133 return(FALSE);
1136 /* remove previously applied surcharge from all billed items */
1137 STATIC_OVL void
1138 pacify_shk(shkp)
1139 register struct monst *shkp;
1141 NOTANGRY(shkp) = TRUE; /* make peaceful */
1142 if (ESHK(shkp)->surcharge) {
1143 register struct bill_x *bp = ESHK(shkp)->bill_p;
1144 register int ct = ESHK(shkp)->billct;
1146 ESHK(shkp)->surcharge = FALSE;
1147 while (ct-- > 0) {
1148 register long reduction = (bp->price + 3L) / 4L;
1149 bp->price -= reduction; /* undo 33% increase */
1150 bp++;
1155 /* add aggravation surcharge to all billed items */
1156 STATIC_OVL void
1157 rile_shk(shkp)
1158 register struct monst *shkp;
1160 NOTANGRY(shkp) = FALSE; /* make angry */
1161 if (!ESHK(shkp)->surcharge) {
1162 register struct bill_x *bp = ESHK(shkp)->bill_p;
1163 register int ct = ESHK(shkp)->billct;
1165 ESHK(shkp)->surcharge = TRUE;
1166 while (ct-- > 0) {
1167 register long surcharge = (bp->price + 2L) / 3L;
1168 bp->price += surcharge;
1169 bp++;
1174 /* wakeup and/or unparalyze shopkeeper */
1175 STATIC_OVL void
1176 rouse_shk(shkp, verbosely)
1177 struct monst *shkp;
1178 boolean verbosely;
1180 if (!shkp->mcanmove || shkp->msleeping) {
1181 /* greed induced recovery... */
1182 if (verbosely && canspotmon(shkp))
1183 pline("%s %s.", Monnam(shkp),
1184 shkp->msleeping ? "wakes up" : "can move again");
1185 shkp->msleeping = 0;
1186 shkp->mfrozen = 0;
1187 shkp->masleep = 0;
1188 shkp->mcanmove = 1;
1192 void
1193 make_happy_shk(shkp, silentkops)
1194 register struct monst *shkp;
1195 register boolean silentkops;
1197 boolean wasmad = ANGRY(shkp);
1198 struct eshk *eshkp = ESHK(shkp);
1199 boolean guilty = wasmad ||
1200 eshkp->surcharge || eshkp->following || eshkp->robbed;
1202 pacify_shk(shkp);
1203 eshkp->following = 0;
1204 eshkp->robbed = 0L;
1205 if (guilty && !Role_if(PM_ROGUE)) {
1206 adjalign(sgn(u.ualign.type));
1207 You_feel("your guilt vanish.");
1209 if(!inhishop(shkp)) {
1210 char shk_nam[BUFSZ];
1211 boolean vanished = canseemon(shkp);
1213 strcpy(shk_nam, mon_nam(shkp));
1214 if (on_level(&eshkp->shoplevel, &u.uz)) {
1215 home_shk(shkp, FALSE);
1216 /* didn't disappear if shk can still be seen */
1217 if (canseemon(shkp)) vanished = FALSE;
1218 } else {
1219 /* if sensed, does disappear regardless whether seen */
1220 if (sensemon(shkp)) vanished = TRUE;
1221 /* can't act as porter for the Amulet, even if shk
1222 happens to be going farther down rather than up */
1223 mdrop_special_objs(shkp);
1224 /* arrive near shop's door */
1225 migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
1226 MIGR_APPROX_XY, &eshkp->shd);
1228 if (vanished)
1229 pline("Satisfied, %s suddenly disappears!", shk_nam);
1230 } else if(wasmad)
1231 pline("%s calms down.", Monnam(shkp));
1233 if(!angry_shk_exists()) {
1234 /*#ifdef KOPS
1235 kops_gone(silentkops);
1236 #endif*/
1237 pacify_guards();
1241 void
1242 hot_pursuit(shkp)
1243 register struct monst *shkp;
1245 if(!shkp->isshk) return;
1247 rile_shk(shkp);
1248 (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
1249 ESHK(shkp)->following = 1;
1252 /* used when the shkp is teleported or falls (ox == 0) out of his shop,
1253 * or when the player is not on a costly_spot and he
1254 * damages something inside the shop. these conditions
1255 * must be checked by the calling function.
1257 void
1258 make_angry_shk(shkp, ox, oy)
1259 register struct monst *shkp;
1260 register xchar ox,oy;
1262 xchar sx, sy;
1263 struct eshk *eshkp = ESHK(shkp);
1265 /* all pending shop transactions are now "past due" */
1266 if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) {
1267 eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan);
1268 eshkp->robbed -= eshkp->credit;
1269 if (eshkp->robbed < 0L) eshkp->robbed = 0L;
1270 /* billct, debit, loan, and credit will be cleared by setpaid */
1271 setpaid(shkp);
1274 /* If you just used a wand of teleportation to send the shk away, you
1275 might not be able to see her any more. Monnam would yield "it",
1276 which makes this message look pretty silly, so temporarily restore
1277 her original location during the call to Monnam. */
1278 sx = shkp->mx, sy = shkp->my;
1279 if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy))
1280 shkp->mx = ox, shkp->my = oy;
1281 pline("%s %s!", Monnam(shkp),
1282 !ANGRY(shkp) ? "gets angry" : "is furious");
1283 shkp->mx = sx, shkp->my = sy;
1284 hot_pursuit(shkp);
1287 STATIC_VAR const char no_money[] = "Moreover, you%s have no money.";
1288 STATIC_VAR const char not_enough_money[] =
1289 "Besides, you don't have enough to interest %s.";
1291 #else
1292 STATIC_VAR const char no_money[];
1293 STATIC_VAR const char not_enough_money[];
1294 #endif /*OVLB*/
1296 #ifdef OVL3
1298 STATIC_OVL long
1299 cheapest_item(shkp) /* delivers the cheapest item on the list */
1300 register struct monst *shkp;
1302 register int ct = ESHK(shkp)->billct;
1303 register struct bill_x *bp = ESHK(shkp)->bill_p;
1304 register long gmin = (bp->price * bp->bquan);
1306 while(ct--){
1307 if(bp->price * bp->bquan < gmin)
1308 gmin = bp->price * bp->bquan;
1309 bp++;
1311 return(gmin);
1313 #endif /*OVL3*/
1314 #ifdef OVL0
1317 dopay()
1319 /* are you a practicant that currently has a fine? if so, you can only pay that and nothing else */
1320 if (practicantterror && (u.practicantpenalty || u.practicantstones || u.practicantarrows)) {
1321 practicant_payup();
1322 return 0;
1325 if (Race_if(PM_PLAYER_DYNAMO)) {
1326 You("can't pay because no one wants to accept payment by you, criminal.");
1327 return 0;
1330 if (MenuIsBugged) {
1331 pline("The pay command is currently unavailable!");
1332 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1333 return 0;
1336 register struct eshk *eshkp;
1337 register struct monst *shkp;
1338 struct monst *nxtm, *resident;
1339 long ltmp;
1340 #ifdef GOLDOBJ
1341 long umoney;
1342 #endif
1343 int pass, tmp, sk = 0, seensk = 0;
1344 boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
1346 multi = 0;
1348 /* find how many shk's there are, how many are in */
1349 /* sight, and are you in a shop room with one. */
1350 nxtm = resident = 0;
1351 for (shkp = next_shkp(fmon, FALSE);
1352 shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
1353 sk++;
1354 if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp;
1355 if (canspotmon(shkp)) seensk++;
1356 if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
1357 resident = shkp;
1360 if (nxtm) { /* Player should always appease an */
1361 shkp = nxtm; /* irate shk standing next to them. */
1362 goto proceed;
1365 /* KMH -- Permit paying adjacent gypsies */
1366 for (nxtm = fmon; nxtm; nxtm = nxtm->nmon) {
1367 if (!nxtm->isgyp || !nxtm->mpeaceful ||
1368 distu(nxtm->mx, nxtm->my) > 2 || !canspotmon(nxtm))
1369 continue;
1370 shkp = nxtm;
1371 sk++;
1372 seensk++;
1375 if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) {
1376 There("appears to be no shopkeeper here to receive your payment.");
1377 return(0);
1380 if(!seensk) {
1381 You_cant("see...");
1382 return(0);
1385 /* the usual case. allow paying at a distance when */
1386 /* inside a tended shop. should we change that? */
1387 if(sk == 1 && resident) {
1388 shkp = resident;
1389 goto proceed;
1392 if (seensk == 1) {
1393 /* KMH -- Permit paying gypsies */
1394 if (shkp && shkp->isgyp) {
1395 gypsy_chat(shkp);
1396 return (1);
1399 for (shkp = next_shkp(fmon, FALSE);
1400 shkp; shkp = next_shkp(shkp->nmon, FALSE))
1401 if (canspotmon(shkp)) break;
1402 if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
1403 pline("%s is not near enough to receive your payment.",
1404 Monnam(shkp));
1405 return(0);
1407 } else {
1408 struct monst *mtmp;
1409 coord cc;
1410 int cx, cy;
1412 pline("Pay whom?");
1413 cc.x = u.ux;
1414 cc.y = u.uy;
1415 if (getpos(&cc, TRUE, "the creature you want to pay") < 0)
1416 return 0; /* player pressed ESC */
1417 cx = cc.x;
1418 cy = cc.y;
1419 if(cx < 0) {
1420 pline("Try again...");
1421 return(0);
1423 if(u.ux == cx && u.uy == cy) {
1424 You("are generous to yourself.");
1425 return(0);
1427 mtmp = m_at(cx, cy);
1428 if (!cansee(cx, cy) && (!mtmp || !canspotmon(mtmp))) { /* bugfix from 3.7 - yeah I'm a filthy heretic :P --Amy */
1429 You("can't see that location from here!");
1430 return(0);
1432 if(!mtmp) {
1433 There("is no one there to receive your payment.");
1434 return(0);
1436 /* KMH -- Permit paying gypsies */
1437 if (mtmp->isgyp && mtmp->mpeaceful) {
1438 if (distu(mtmp->mx, mtmp->my) <= 2) {
1439 gypsy_chat(mtmp);
1440 return (1);
1442 } else
1443 if(!mtmp->isshk) {
1444 pline("%s is not interested in your payment.",
1445 Monnam(mtmp));
1446 return(0);
1448 if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
1449 pline("%s is too far to receive your payment.",
1450 Monnam(mtmp));
1451 return(0);
1453 shkp = mtmp;
1456 if(!shkp) {
1457 #ifdef DEBUG
1458 pline("dopay: null shkp.");
1459 #endif
1460 return(0);
1462 proceed:
1463 eshkp = ESHK(shkp);
1464 ltmp = eshkp->robbed;
1466 /* wake sleeping shk when someone who owes money offers payment */
1467 if (ltmp || eshkp->billct || eshkp->debit)
1468 rouse_shk(shkp, TRUE);
1470 if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */
1471 pline("%s %s.", Monnam(shkp),
1472 rn2(2) ? "seems to be napping" : "doesn't respond");
1473 return 0;
1476 if(shkp != resident && NOTANGRY(shkp)) {
1477 #ifdef GOLDOBJ
1478 umoney = money_cnt(invent);
1479 #endif
1480 if(!ltmp)
1481 You("do not owe %s anything.", mon_nam(shkp));
1482 #ifndef GOLDOBJ
1483 else if(!u.ugold) {
1484 #else
1485 else if(!umoney) {
1486 #endif
1487 You("%shave no money.", stashed_gold ? "seem to " : "");
1488 if(stashed_gold)
1490 #ifndef GOLDOBJ
1491 pline("But you have some gold stashed away.");
1492 #else
1493 pline("But you have some money stashed away.");
1494 #endif
1495 } else {
1496 #ifndef GOLDOBJ
1497 long ugold = u.ugold;
1498 if(ugold > ltmp) {
1499 #else
1500 if(umoney > ltmp) {
1501 #endif
1502 You("give %s the %ld gold piece%s %s asked for.",
1503 mon_nam(shkp), ltmp, plur(ltmp), mhe(shkp));
1504 pay(ltmp, shkp);
1505 } else {
1506 #ifndef GOLDOBJ
1507 You("give %s all your%s gold.", mon_nam(shkp),
1508 #else
1509 You("give %s all your%s money.", mon_nam(shkp),
1510 #endif
1511 stashed_gold ? " openly kept" : "");
1512 #ifndef GOLDOBJ
1513 pay(u.ugold, shkp);
1514 if (stashed_gold) pline("But you have hidden gold!");
1515 #else
1516 pay(umoney, shkp);
1517 if (stashed_gold) pline("But you have hidden money!");
1518 #endif
1520 #ifndef GOLDOBJ
1521 if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold))
1522 #else
1523 if((umoney < ltmp/2L) || (umoney < ltmp && stashed_gold))
1524 #endif
1525 pline("Unfortunately, %s doesn't look satisfied.",
1526 mhe(shkp));
1527 else
1528 make_happy_shk(shkp, FALSE);
1530 return(1);
1533 /* ltmp is still eshkp->robbed here */
1534 if (!eshkp->billct && !eshkp->debit) {
1535 #ifdef GOLDOBJ
1536 umoney = money_cnt(invent);
1537 #endif
1538 if(!ltmp && NOTANGRY(shkp)) {
1539 You("do not owe %s anything.", mon_nam(shkp));
1540 #ifndef GOLDOBJ
1541 if (!u.ugold)
1542 #else
1543 if (!umoney)
1544 #endif
1545 pline(no_money, stashed_gold ? " seem to" : "");
1547 /* else */
1548 shk_other_services();
1550 } else if(ltmp) {
1551 pline("%s is after blood, not money!", Monnam(shkp));
1552 #ifndef GOLDOBJ
1553 if(u.ugold < ltmp/2L ||
1554 (u.ugold < ltmp && stashed_gold)) {
1555 if (!u.ugold)
1556 #else
1557 if(umoney < ltmp/2L ||
1558 (umoney < ltmp && stashed_gold)) {
1559 if (!umoney)
1560 #endif
1561 pline(no_money, stashed_gold ? " seem to" : "");
1562 else pline(not_enough_money, mhim(shkp));
1563 return(1);
1565 pline("But since %s shop has been robbed recently,",
1566 mhis(shkp));
1567 pline("you %scompensate %s for %s losses.",
1568 #ifndef GOLDOBJ
1569 (u.ugold < ltmp) ?
1570 #else
1571 (umoney < ltmp) ?
1572 #endif
1573 "partially " : "",
1574 mon_nam(shkp), mhis(shkp));
1575 #ifndef GOLDOBJ
1576 pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
1577 #else
1578 pay(umoney < ltmp ? umoney : ltmp, shkp);
1579 #endif
1580 make_happy_shk(shkp, FALSE);
1581 } else {
1582 /* shopkeeper is angry, but has not been robbed --
1583 * door broken, attacked, etc. */
1584 pline("%s is after your hide, not your money!",
1585 Monnam(shkp));
1586 #ifndef GOLDOBJ
1587 if(u.ugold < 1000L) {
1588 if (!u.ugold)
1589 #else
1590 if(umoney < 1000L) {
1591 if (!umoney)
1592 #endif
1593 pline(no_money, stashed_gold ? " seem to" : "");
1594 else pline(not_enough_money, mhim(shkp));
1595 return(1);
1597 You("try to appease %s by giving %s 1000 gold pieces.",
1598 x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE),
1599 mhim(shkp));
1600 pay(1000L,shkp);
1601 if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
1602 make_happy_shk(shkp, FALSE);
1603 else
1604 pline("But %s is as angry as ever.", mon_nam(shkp));
1606 return(1);
1608 if(shkp != resident) {
1609 impossible("dopay: not to shopkeeper?");
1610 if(resident) setpaid(resident);
1611 return(0);
1613 /* pay debt, if any, first */
1614 if(eshkp->debit) {
1615 long dtmp = eshkp->debit;
1616 long loan = eshkp->loan;
1617 char sbuf[BUFSZ];
1618 #ifdef GOLDOBJ
1619 umoney = money_cnt(invent);
1620 #endif
1621 sprintf(sbuf, "You owe %s %ld %s ",
1622 shkname(shkp), dtmp, currency(dtmp));
1623 if(loan) {
1624 if(loan == dtmp)
1625 strcat(sbuf, "you picked up in the store.");
1626 else strcat(sbuf,
1627 "for gold picked up and the use of merchandise.");
1628 } else strcat(sbuf, "for the use of merchandise.");
1629 pline("%s", sbuf);
1630 #ifndef GOLDOBJ
1631 if (u.ugold + eshkp->credit < dtmp) {
1632 pline("But you don't%s have enough gold%s.",
1633 #else
1634 if (umoney + eshkp->credit < dtmp) {
1635 pline("But you don't%s have enough money%s.",
1636 #endif
1638 stashed_gold ? " seem to" : "",
1639 eshkp->credit ? " or credit" : "");
1640 return(1);
1641 } else {
1642 if (eshkp->credit >= dtmp) {
1643 eshkp->credit -= dtmp;
1644 eshkp->debit = 0L;
1645 eshkp->loan = 0L;
1646 Your("debt is covered by your credit.");
1647 } else if (!eshkp->credit) {
1648 #ifndef GOLDOBJ
1649 u.ugold -= dtmp;
1650 if (rn2(2) || dtmp < 0) shkp->mgold += dtmp;
1651 #else
1652 money2mon(shkp, dtmp);
1653 #endif
1654 eshkp->debit = 0L;
1655 eshkp->loan = 0L;
1656 You("pay that debt.");
1657 flags.botl = 1;
1658 } else {
1659 dtmp -= eshkp->credit;
1660 eshkp->credit = 0L;
1661 #ifndef GOLDOBJ
1662 u.ugold -= dtmp;
1663 if (rn2(2) || dtmp < 0) shkp->mgold += dtmp;
1664 #else
1665 money2mon(shkp, dtmp);
1666 #endif
1667 eshkp->debit = 0L;
1668 eshkp->loan = 0L;
1669 pline("That debt is partially offset by your credit.");
1670 You("pay the remainder.");
1671 flags.botl = 1;
1673 paid = TRUE;
1676 /* now check items on bill */
1677 if (eshkp->billct) {
1678 register boolean itemize;
1679 #ifndef GOLDOBJ
1680 if (!u.ugold && !eshkp->credit) {
1681 #else
1682 umoney = money_cnt(invent);
1683 if (!umoney && !eshkp->credit) {
1684 #endif
1685 You("%shave no money or credit%s.",
1686 stashed_gold ? "seem to " : "",
1687 paid ? " left" : "");
1688 return(0);
1690 #ifndef GOLDOBJ
1691 if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) {
1692 #else
1693 if ((umoney + eshkp->credit) < cheapest_item(shkp)) {
1694 #endif
1695 You("don't have enough money to buy%s the item%s you picked.",
1696 eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
1697 if(stashed_gold)
1698 #ifndef GOLDOBJ
1699 pline("Maybe you have some gold stashed away?");
1700 #else
1701 pline("Maybe you have some money stashed away?");
1702 #endif
1703 return(0);
1706 /* this isn't quite right; it itemizes without asking if the
1707 * single item on the bill is partly used up and partly unpaid */
1708 itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1);
1710 for (pass = 0; pass <= 1; pass++) {
1711 tmp = 0;
1712 while (tmp < eshkp->billct) {
1713 struct obj *otmp;
1714 register struct bill_x *bp = &(eshkp->bill_p[tmp]);
1716 /* find the object on one of the lists */
1717 if ((otmp = bp_to_obj(bp)) != 0) {
1718 /* if completely used up, object quantity is stale;
1719 restoring it to its original value here avoids
1720 making the partly-used-up code more complicated */
1721 if (bp->useup) otmp->quan = bp->bquan;
1722 } else {
1723 impossible("Shopkeeper administration out of order.");
1724 setpaid(shkp); /* be nice to the player */
1725 return 1;
1727 if (pass == bp->useup && otmp->quan == bp->bquan) {
1728 /* pay for used-up items on first pass and others
1729 * on second, so player will be stuck in the store
1730 * less often; things which are partly used up
1731 * are processed on both passes */
1732 tmp++;
1733 } else {
1734 switch (dopayobj(shkp, bp, &otmp, pass, itemize)) {
1735 case PAY_CANT:
1736 return 1; /*break*/
1737 case PAY_BROKE:
1738 paid = TRUE;
1739 goto thanks; /*break*/
1740 case PAY_SKIP:
1741 tmp++;
1742 continue; /*break*/
1743 case PAY_SOME:
1744 paid = TRUE;
1745 if (itemize) bot();
1746 continue; /*break*/
1747 case PAY_BUY:
1748 paid = TRUE;
1749 break;
1751 if (itemize) bot();
1752 *bp = eshkp->bill_p[--eshkp->billct];
1756 thanks:
1757 if (!itemize)
1758 update_inventory(); /* Done in dopayobj() if itemize. */
1760 if(!ANGRY(shkp) && paid)
1761 verbalize("Thank you for shopping in %s %s!",
1762 s_suffix(shkname(shkp)),
1763 shtypes[eshkp->shoptype - SHOPBASE].name);
1764 return(1);
1768 ** FUNCTION shk_other_services
1770 ** Called when you don't owe any money. Called after all checks have been
1771 ** made (in shop, not angry shopkeeper, etc.)
1773 static void
1774 shk_other_services()
1776 char *slang; /* What shk calls you */
1777 struct monst *shkp; /* The shopkeeper */
1778 /*WAC - Windowstuff*/
1779 winid tmpwin;
1780 anything any;
1781 menu_item *selected;
1782 int n;
1784 /* Do you want to use other services */
1785 if (yn("Do you wish to try our other services?") != 'y' ) return;
1787 if (Race_if(PM_IRAHA)) {
1788 verbalize("Get the fuck out of here, insufferable scumbag!");
1789 return;
1792 /* Init your name */
1793 if (Role_if(PM_CONVICT))
1794 slang = "scumbag";
1795 else if (Role_if(PM_MURDERER))
1796 slang = "killer";
1797 else if (Race_if(PM_ALBAE))
1798 slang = "murderer";
1799 else if (!is_human(youmonst.data))
1800 slang = "ugly";
1801 else
1802 slang = (flags.female) ? "lady" : "buddy";
1804 /* Init the shopkeeper */
1805 shkp = shop_keeper(/* roomno= */*u.ushops);
1806 if (!ESHK(shkp)->services) {
1807 verbalize("Sorry. We're all out of services.");
1808 return;
1812 ** Figure out what services he offers
1814 ** i = identify
1815 ** a = appraise weapon's worth
1816 ** u = uncurse
1817 ** w = weapon-works (including poison)
1818 ** p = poison weapon
1819 ** r = armor-works
1820 ** c = charge wands
1821 ** e = establish credit
1823 /*WAC - did this using the windowing system...*/
1824 any.a_void = 0; /* zero out all bits */
1825 tmpwin = create_nhwindow(NHW_MENU);
1826 start_menu(tmpwin);
1828 /* All shops can identify (some better than others) */
1829 any.a_int = 1;
1830 if (ESHK(shkp)->services & (SHK_ID_BASIC|SHK_ID_PREMIUM))
1831 add_menu(tmpwin, NO_GLYPH, &any , 'i', 0, ATR_NONE,
1832 "Identify", MENU_UNSELECTED);
1834 /* All shops can uncurse */
1835 any.a_int = 2;
1836 if (ESHK(shkp)->services & (SHK_UNCURSE))
1837 add_menu(tmpwin, NO_GLYPH, &any , 'u', 0, ATR_NONE,
1838 "Uncurse", MENU_UNSELECTED);
1840 /* Weapon appraisals. Weapon & general stores can do this. */
1841 if ((ESHK(shkp)->services & (SHK_APPRAISE)) &&
1842 (shk_class_match(WEAPON_CLASS, shkp))) {
1843 any.a_int = 3;
1844 add_menu(tmpwin, NO_GLYPH, &any , 'a', 0, ATR_NONE,
1845 "Appraise", MENU_UNSELECTED);
1848 /* Weapon-works! Only a weapon store. */
1849 if ((ESHK(shkp)->services & (SHK_SPECIAL_A|SHK_SPECIAL_B|SHK_SPECIAL_C))
1850 && (shk_class_match(WEAPON_CLASS, shkp) == SHK_MATCH)) {
1851 any.a_int = 4;
1852 if (ESHK(shkp)->services & (SHK_SPECIAL_A|SHK_SPECIAL_B))
1853 add_menu(tmpwin, NO_GLYPH, &any , 'w', 0, ATR_NONE,
1854 "Weapon-works", MENU_UNSELECTED);
1855 else
1856 add_menu(tmpwin, NO_GLYPH, &any , 'p', 0, ATR_NONE,
1857 "Poison", MENU_UNSELECTED);
1860 /* Armor-works */
1861 if ((ESHK(shkp)->services & (SHK_SPECIAL_A|SHK_SPECIAL_B))
1862 && (shk_class_match(ARMOR_CLASS, shkp) == SHK_MATCH)) {
1863 any.a_int = 5;
1864 add_menu(tmpwin, NO_GLYPH, &any , 'r', 0, ATR_NONE,
1865 "Armor-works", MENU_UNSELECTED);
1868 /* Charging: / ( = */
1869 if ((ESHK(shkp)->services & (SHK_SPECIAL_A|SHK_SPECIAL_B)) &&
1870 ((shk_class_match(WAND_CLASS, shkp) == SHK_MATCH) ||
1871 (shk_class_match(TOOL_CLASS, shkp) == SHK_MATCH) ||
1872 (shk_class_match(SPBOOK_CLASS, shkp) == SHK_MATCH) ||
1873 (shk_class_match(IMPLANT_CLASS, shkp) == SHK_MATCH) ||
1874 (shk_class_match(RING_CLASS, shkp) == SHK_MATCH))) {
1875 any.a_int = 6;
1876 add_menu(tmpwin, NO_GLYPH, &any , 'c', 0, ATR_NONE,
1877 "Charge", MENU_UNSELECTED);
1880 any.a_int = 7;
1881 if (ESHK(shkp)->services & (SHK_CREDITSRV))
1882 add_menu(tmpwin, NO_GLYPH, &any , 'e', 0, ATR_NONE,
1883 "Establish Credit", MENU_UNSELECTED);
1885 any.a_int = 8;
1886 if (ESHK(shkp)->services & (SHK_BLESS))
1887 add_menu(tmpwin, NO_GLYPH, &any , 'b', 0, ATR_NONE,
1888 "Blessing", MENU_UNSELECTED);
1890 end_menu(tmpwin, "Services Available:");
1891 n = select_menu(tmpwin, PICK_ONE, &selected);
1892 destroy_nhwindow(tmpwin);
1894 if (n > 0)
1895 switch (selected[0].item.a_int) {
1896 case 1:
1897 shk_identify(slang, shkp);
1898 break;
1900 case 2:
1901 shk_uncurse(slang, shkp);
1902 break;
1904 case 3:
1905 shk_appraisal(slang, shkp);
1906 break;
1908 case 4:
1909 shk_weapon_works(slang, shkp);
1910 break;
1912 case 5:
1913 shk_armor_works(slang, shkp);
1914 break;
1916 case 6:
1917 shk_charge(slang, shkp);
1918 break;
1919 case 7:
1920 shk_estcredit(slang, shkp);
1921 break;
1922 case 8:
1923 shk_bless(slang, shkp);
1924 break;
1926 default:
1927 pline ("Unknown Service");
1928 break;
1932 #endif /*OVL0*/
1933 #ifdef OVL3
1935 /* return 2 if used-up portion paid */
1936 /* 1 if paid successfully */
1937 /* 0 if not enough money */
1938 /* -1 if skip this object */
1939 /* -2 if no money/credit left */
1940 STATIC_OVL int
1941 dopayobj(shkp, bp, obj_p, which, itemize)
1942 register struct monst *shkp;
1943 register struct bill_x *bp;
1944 struct obj **obj_p;
1945 int which; /* 0 => used-up item, 1 => other (unpaid or lost) */
1946 boolean itemize;
1948 register struct obj *obj = *obj_p;
1949 long ltmp, quan, save_quan;
1950 #ifdef GOLDOBJ
1951 long umoney = money_cnt(invent);
1952 #endif
1953 int buy;
1954 boolean stashed_gold = (hidden_gold() > 0L),
1955 consumed = (which == 0);
1957 if(!obj->unpaid && !bp->useup){
1958 impossible("Paid object on bill??");
1959 return PAY_BUY;
1961 #ifndef GOLDOBJ
1962 if(itemize && u.ugold + ESHK(shkp)->credit == 0L){
1963 #else
1964 if(itemize && umoney + ESHK(shkp)->credit == 0L){
1965 #endif
1966 You("%shave no money or credit left.",
1967 stashed_gold ? "seem to " : "");
1968 return PAY_BROKE;
1970 /* we may need to temporarily adjust the object, if part of the
1971 original quantity has been used up but part remains unpaid */
1972 save_quan = obj->quan;
1973 if (consumed) {
1974 /* either completely used up (simple), or split needed */
1975 quan = bp->bquan;
1976 if (quan > obj->quan) /* difference is amount used up */
1977 quan -= obj->quan;
1978 } else {
1979 /* dealing with ordinary unpaid item */
1980 quan = obj->quan;
1982 obj->quan = quan; /* to be used by doname() */
1983 obj->unpaid = 0; /* ditto */
1984 ltmp = bp->price * quan;
1985 buy = PAY_BUY; /* flag; if changed then return early */
1987 if (itemize) {
1988 char qbuf[BUFSZ];
1989 sprintf(qbuf,"%s for %ld %s. Pay?", quan == 1L ?
1990 Doname2(obj) : doname(obj), ltmp, currency(ltmp));
1991 if (yn(qbuf) == 'n') {
1992 buy = PAY_SKIP; /* don't want to buy */
1993 } else if (quan < bp->bquan && !consumed) { /* partly used goods */
1994 obj->quan = bp->bquan - save_quan; /* used up amount */
1995 verbalize("%s for the other %s before buying %s.",
1996 ANGRY(shkp) ? "Pay" : "Please pay", xname(obj),
1997 save_quan > 1L ? "these" : "this one");
1998 buy = PAY_SKIP; /* shk won't sell */
2001 #ifndef GOLDOBJ
2002 if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) {
2003 You("don't%s have gold%s enough to pay for %s.",
2004 #else
2005 if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) {
2006 You("don't%s have money%s enough to pay for %s.",
2007 #endif
2008 stashed_gold ? " seem to" : "",
2009 (ESHK(shkp)->credit > 0L) ? " or credit" : "",
2010 doname(obj));
2011 buy = itemize ? PAY_SKIP : PAY_CANT;
2014 if (buy != PAY_BUY) {
2015 /* restore unpaid object to original state */
2016 obj->quan = save_quan;
2017 obj->unpaid = 1;
2018 return buy;
2021 pay(ltmp, shkp);
2022 shk_names_obj(shkp, obj, consumed ?
2023 "paid for %s at a cost of %ld gold piece%s.%s" :
2024 "bought %s for %ld gold piece%s.%s", ltmp, "");
2025 obj->quan = save_quan; /* restore original count */
2026 /* quan => amount just bought, save_quan => remaining unpaid count */
2027 if (consumed) {
2028 if (quan != bp->bquan) {
2029 /* eliminate used-up portion; remainder is still unpaid */
2030 bp->bquan = obj->quan;
2031 obj->unpaid = 1;
2032 bp->useup = 0;
2033 buy = PAY_SOME;
2034 } else { /* completely used-up, so get rid of it */
2035 obj_extract_self(obj);
2036 /* assert( obj == *obj_p ); */
2037 dealloc_obj(obj);
2038 *obj_p = 0; /* destroy pointer to freed object */
2040 } else if (itemize)
2041 update_inventory(); /* Done just once in dopay() if !itemize. */
2042 return buy;
2044 #endif /*OVL3*/
2045 #ifdef OVLB
2047 static coord repo_location; /* repossession context */
2049 /* routine called after dying (or quitting) */
2050 boolean
2051 paybill(croaked)
2052 int croaked; /* -1: escaped dungeon; 0: quit; 1: died */
2054 register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
2055 register boolean taken = FALSE;
2056 register int numsk = 0;
2058 /* if we escaped from the dungeon, shopkeepers can't reach us;
2059 shops don't occur on level 1, but this could happen if hero
2060 level teleports out of the dungeon and manages not to die */
2061 if (croaked < 0) return FALSE;
2063 /* this is where inventory will end up if any shk takes it */
2064 repo_location.x = repo_location.y = 0;
2066 /* give shopkeeper first crack */
2067 if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) {
2068 numsk++;
2069 resident = mtmp;
2070 taken = inherits(resident, numsk, croaked);
2072 for (mtmp = next_shkp(fmon, FALSE);
2073 mtmp; mtmp = next_shkp(mtmp2, FALSE)) {
2074 mtmp2 = mtmp->nmon;
2075 if (mtmp != resident) {
2076 /* for bones: we don't want a shopless shk around */
2077 if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz))
2078 mongone(mtmp);
2079 else {
2080 numsk++;
2081 taken |= inherits(mtmp, numsk, croaked);
2082 ESHK(mtmp)->pbanned = FALSE; /* Un-ban for bones levels */
2086 if(numsk == 0) return(FALSE);
2087 return(taken);
2090 STATIC_OVL boolean
2091 inherits(shkp, numsk, croaked)
2092 struct monst *shkp;
2093 int numsk;
2094 int croaked;
2096 long loss = 0L;
2097 #ifdef GOLDOBJ
2098 long umoney;
2099 #endif
2100 struct eshk *eshkp = ESHK(shkp);
2101 boolean take = FALSE, taken = FALSE;
2102 int roomno = *u.ushops;
2103 char takes[BUFSZ];
2105 /* the simplifying principle is that first-come */
2106 /* already took everything you had. */
2107 if (numsk > 1) {
2108 if (cansee(shkp->mx, shkp->my) && croaked)
2109 pline("%s %slooks at your corpse%s and %s.",
2110 Monnam(shkp),
2111 (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "",
2112 !rn2(2) ? (shkp->female ? ", shakes her head," :
2113 ", shakes his head,") : "",
2114 !inhishop(shkp) ? "disappears" : "sighs");
2115 rouse_shk(shkp, FALSE); /* wake shk for bones */
2116 taken = (roomno == eshkp->shoproom);
2117 goto skip;
2120 /* get one case out of the way: you die in the shop, the */
2121 /* shopkeeper is peaceful, nothing stolen, nothing owed. */
2122 if(roomno == eshkp->shoproom && inhishop(shkp) &&
2123 !eshkp->billct && !eshkp->robbed && !eshkp->debit &&
2124 NOTANGRY(shkp) && !eshkp->following) {
2125 if (invent)
2126 pline("%s gratefully inherits all your possessions.",
2127 shkname(shkp));
2128 set_repo_loc(eshkp);
2129 goto clear;
2132 if (eshkp->billct || eshkp->debit || eshkp->robbed) {
2133 if(roomno == eshkp->shoproom && inhishop(shkp))
2134 loss = addupbill(shkp) + eshkp->debit;
2135 if (loss < eshkp->robbed) loss = eshkp->robbed;
2136 take = TRUE;
2139 if (eshkp->following || ANGRY(shkp) || take) {
2140 #ifndef GOLDOBJ
2141 if (!invent && !u.ugold) goto skip;
2142 #else
2143 if (!invent) goto skip;
2144 umoney = money_cnt(invent);
2145 #endif
2146 takes[0] = '\0';
2147 if (!shkp->mcanmove || shkp->msleeping)
2148 strcat(takes, "wakes up and ");
2149 if (distu(shkp->mx, shkp->my) > 2)
2150 strcat(takes, "comes and ");
2151 strcat(takes, "takes");
2153 #ifndef GOLDOBJ
2154 if (loss > u.ugold || !loss || roomno == eshkp->shoproom) {
2155 eshkp->robbed -= u.ugold;
2156 if (eshkp->robbed < 0L) eshkp->robbed = 0L;
2157 if (rn2(2)) shkp->mgold += u.ugold;
2158 u.ugold = 0L;
2159 #else
2160 if (loss > umoney || !loss || roomno == eshkp->shoproom) {
2161 eshkp->robbed -= umoney;
2162 if (eshkp->robbed < 0L) eshkp->robbed = 0L;
2163 if (umoney > 0) money2mon(shkp, umoney);
2164 #endif
2165 flags.botl = 1;
2166 pline("%s %s all your possessions.",
2167 shkname(shkp), takes);
2168 taken = TRUE;
2169 /* where to put player's invent (after disclosure) */
2170 set_repo_loc(eshkp);
2171 } else {
2172 #ifndef GOLDOBJ
2173 if (rn2(2) || loss < 0) shkp->mgold += loss;
2174 u.ugold -= loss;
2175 #else
2176 money2mon(shkp, loss);
2177 #endif
2178 flags.botl = 1;
2179 pline("%s %s the %ld %s %sowed %s.",
2180 Monnam(shkp), takes,
2181 loss, currency(loss),
2182 strncmp(eshkp->customer, plname, PL_NSIZ) ?
2183 "" : "you ",
2184 shkp->female ? "her" : "him");
2185 /* shopkeeper has now been paid in full */
2186 pacify_shk(shkp);
2187 eshkp->following = 0;
2188 eshkp->robbed = 0L;
2190 skip:
2191 /* in case we create bones */
2192 rouse_shk(shkp, FALSE); /* wake up */
2193 if(!inhishop(shkp))
2194 home_shk(shkp, FALSE);
2196 clear:
2197 setpaid(shkp);
2198 return(taken);
2201 STATIC_OVL void
2202 set_repo_loc(eshkp)
2203 struct eshk *eshkp;
2205 register xchar ox, oy;
2207 /* if you're not in this shk's shop room, or if you're in its doorway
2208 or entry spot, then your gear gets dumped all the way inside */
2209 if (*u.ushops != eshkp->shoproom ||
2210 IS_DOOR(levl[u.ux][u.uy].typ) ||
2211 (u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) {
2212 /* shk.x,shk.y is the position immediately in
2213 * front of the door -- move in one more space
2215 ox = eshkp->shk.x;
2216 oy = eshkp->shk.y;
2217 ox += sgn(ox - eshkp->shd.x);
2218 oy += sgn(oy - eshkp->shd.y);
2219 } else { /* already inside this shk's shop */
2220 ox = u.ux;
2221 oy = u.uy;
2223 /* finish_paybill will deposit invent here */
2224 repo_location.x = ox;
2225 repo_location.y = oy;
2228 /* called at game exit, after inventory disclosure but before making bones */
2229 void
2230 finish_paybill()
2232 register struct obj *otmp;
2233 int ox = repo_location.x,
2234 oy = repo_location.y;
2236 #if 0 /* don't bother */
2237 if (ox == 0 && oy == 0) impossible("finish_paybill: no location");
2238 #endif
2239 /* normally done by savebones(), but that's too late in this case */
2240 unleash_all();
2241 /* transfer all of the character's inventory to the shop floor */
2242 while ((otmp = invent) != 0) {
2243 otmp->owornmask = 0L; /* perhaps we should call setnotworn? */
2244 otmp->lamplit = 0; /* avoid "goes out" msg from freeinv */
2245 if (rn2(5)) curse(otmp); /* normal bones treatment for invent */
2246 obj_extract_self(otmp);
2247 place_object(otmp, ox, oy);
2251 /* find obj on one of the lists */
2252 STATIC_OVL struct obj *
2253 bp_to_obj(bp)
2254 register struct bill_x *bp;
2256 register struct obj *obj;
2257 register unsigned int id = bp->bo_id;
2259 if(bp->useup)
2260 obj = o_on(id, billobjs);
2261 else
2262 obj = find_oid(id);
2263 return obj;
2267 * Look for o_id on all lists but billobj. Return obj or NULL if not found.
2268 * Its OK for restore_timers() to call this function, there should not
2269 * be any timeouts on the billobjs chain.
2271 struct obj *
2272 find_oid(id)
2273 unsigned id;
2275 struct obj *obj;
2276 struct monst *mon, *mmtmp[3];
2277 int i;
2279 /* first check various obj lists directly */
2280 if ((obj = o_on(id, invent)) != 0) return obj;
2281 if ((obj = o_on(id, fobj)) != 0) return obj;
2282 if ((obj = o_on(id, level.buriedobjlist)) != 0) return obj;
2283 if ((obj = o_on(id, migrating_objs)) != 0) return obj;
2285 /* not found yet; check inventory for members of various monst lists */
2286 mmtmp[0] = fmon;
2287 mmtmp[1] = migrating_mons;
2288 mmtmp[2] = mydogs; /* for use during level changes */
2289 for (i = 0; i < 3; i++)
2290 for (mon = mmtmp[i]; mon; mon = mon->nmon)
2291 if ((obj = o_on(id, mon->minvent)) != 0) return obj;
2293 /* not found at all */
2294 return (struct obj *)0;
2296 #endif /*OVLB*/
2297 #ifdef OVL3
2299 /* calculate the value that the shk will charge for [one of] an object */
2300 STATIC_OVL long
2301 get_cost(obj, shkp)
2302 register struct obj *obj;
2303 register struct monst *shkp; /* if angry, impose a surcharge */
2305 register long tmp = getprice(obj, FALSE);
2307 if (!tmp) tmp = 5L;
2308 /* shopkeeper may notice if the player isn't very knowledgeable -
2309 especially when gem prices are concerned */
2310 if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
2311 if (obj->oclass == GEM_CLASS &&
2312 objects[obj->otyp].oc_material == MT_GLASS) {
2313 int i;
2314 /* get a value that's 'random' from game to game, but the
2315 same within the same game */
2316 boolean pseudorand =
2317 (((int)u.ubirthday % obj->otyp) >= obj->otyp/2);
2319 /* all gems are priced high - real or not */
2320 switch(obj->otyp - LAST_GEM) {
2321 case 1: /* white */
2322 i = pseudorand ? DIAMOND : OPAL;
2323 break;
2324 case 2: /* blue */
2325 i = pseudorand ? SAPPHIRE : AQUAMARINE;
2326 break;
2327 case 3: /* red */
2328 i = pseudorand ? RUBY : JASPER;
2329 break;
2330 case 4: /* yellowish brown */
2331 i = pseudorand ? AMBER : TOPAZ;
2332 break;
2333 case 5: /* orange */
2334 i = pseudorand ? JACINTH : AGATE;
2335 break;
2336 case 6: /* yellow */
2337 i = pseudorand ? CITRINE : CHRYSOBERYL;
2338 break;
2339 case 7: /* black */
2340 i = pseudorand ? BLACK_OPAL : JET;
2341 break;
2342 case 8: /* pink */
2343 i = pseudorand ? ROSE_QUARTZ : MORGANITE ;
2344 break;
2345 case 9: /* cyan */
2346 i = pseudorand ? AMAZONITE : VIVIANITE ;
2347 break;
2348 case 10: /* teal */
2349 i = pseudorand ? CYAN_STONE : DISTHENE ;
2350 break;
2351 case 11: /* green */
2352 i = pseudorand ? EMERALD : JADE;
2353 break;
2354 case 12: /* radiant */
2355 i = pseudorand ? DIOPTASE : ANDALUSITE ;
2356 break;
2357 case 13: /* violet */
2358 i = pseudorand ? AMETHYST : FLUORITE;
2359 break;
2360 case 14: /* dark blue */
2361 i = pseudorand ? IOLITE : LARIMAR;
2362 break;
2363 default: impossible("bad glass gem %ld?", obj->otyp);
2364 i = /*STRANGE_OBJECT*/MORGANITE; /* fail safe - in case of doubt have it be something expensive --Amy */
2365 break;
2367 tmp = (long) objects[i].oc_cost;
2368 } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
2369 tmp += tmp / 3L;
2371 if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
2372 || ((uarmu && !uarmu->oinvis) && (!uarm || uarm->oinvis)
2373 && (!uarmc || uarmc->oinvis))) /* touristy shirt visible */
2374 tmp += tmp / 3L;
2375 else
2376 if (uarmh && !uarmh->oinvis && uarmh->otyp == DUNCE_CAP)
2377 tmp += tmp / 3L;
2379 if (Race_if(PM_ZAUR)) tmp *= 2L;
2380 if (Race_if(PM_WYLVAN)) tmp *= 2L;
2381 if (Race_if(PM_URGOTH)) tmp *= 3L;
2382 if (ACURR(A_CHA) == 2) tmp *= 2L;
2383 if (ACURR(A_CHA) == 1) tmp *= 3L;
2385 if (Race_if(PM_DUTHOL)) tmp *= 2L;
2386 if (Role_if(PM_OTAKU)) tmp += tmp / 3L; /* bad at making deals */
2387 if (ublindf && ublindf->oartifact == ART_STRIKE_OVER_THE_EARS) tmp *= 2;
2389 if (u.usteed && uarm && uarm->oartifact == ART_FAER_ME) tmp -= (tmp / 4L);
2390 if (uarmu && uarmu->oartifact == ART_PLEINLY) tmp -= (tmp / 4L);
2392 if (ACURR(A_CHA) > 18) tmp /= 2L;
2393 else if (ACURR(A_CHA) > 17) tmp -= tmp / 3L;
2394 else if (ACURR(A_CHA) > 15) tmp -= tmp / 4L;
2395 else if (ACURR(A_CHA) < 6) tmp *= 2L;
2396 else if (ACURR(A_CHA) < 8) tmp += tmp / 2L;
2397 else if (ACURR(A_CHA) < 11) tmp += tmp / 3L;
2398 if (tmp <= 0L) tmp = 1L;
2399 else if (obj->oartifact) tmp *= 4L;
2401 /* character classes who are discriminated against... */
2402 /* barbarians are gullible... */
2403 if (Role_if(PM_BARBARIAN)) tmp *= 3L;
2404 if (Role_if(PM_NOOB_MODE_BARB)) tmp *= 5L;
2405 /* rogues are untrustworthy... */
2406 if (Role_if(PM_ROGUE)) tmp *= 2L;
2407 /* samurais are from out of town... */
2408 if (Role_if(PM_SAMURAI)) tmp *= 2L;
2409 if (uarmf && uarmf->oartifact == ART_CARMARK) tmp *= 2L;
2411 /* anger surcharge should match rile_shk's */
2412 if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
2414 /* KMH, balance patch -- healthstone replaces rotting/health */
2415 if (Is_blackmarket(&u.uz)) {
2416 if (obj->oclass==RING_CLASS || obj->oclass==AMULET_CLASS || obj->oclass == IMPLANT_CLASS ||
2417 obj->oclass==POTION_CLASS || obj->oclass==SCROLL_CLASS ||
2418 obj->oclass==SPBOOK_CLASS || obj->oclass==WAND_CLASS ||
2419 obj->otyp==LUCKSTONE || obj->otyp==LOADSTONE ||
2420 obj->otyp==HEALTHSTONE || objects[obj->otyp].oc_magic) {
2421 tmp *= (Role_if(PM_CONVICT) ? 10 : 50);
2422 } else {
2423 tmp *= (Role_if(PM_CONVICT) ? 5 : 25);
2427 return tmp;
2429 #endif /*OVL3*/
2430 #ifdef OVLB
2432 /* returns the price of a container's content. the price
2433 * of the "top" container is added in the calling functions.
2434 * a different price quoted for selling as vs. buying.
2436 long
2437 contained_cost(obj, shkp, price, usell, unpaid_only)
2438 register struct obj *obj;
2439 register struct monst *shkp;
2440 long price;
2441 register boolean usell;
2442 register boolean unpaid_only;
2444 register struct obj *otmp;
2446 /* the price of contained objects */
2447 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2448 if (otmp->oclass == COIN_CLASS) continue;
2449 /* the "top" container is evaluated by caller */
2450 if (usell) {
2451 if (saleable(shkp, otmp) &&
2452 !otmp->unpaid && otmp->oclass != BALL_CLASS &&
2453 !is_hazy(otmp) &&
2454 !(otmp->oclass == FOOD_CLASS && otmp->oeaten) )
2455 price += set_cost(otmp, shkp);
2456 } else if (!otmp->no_charge &&
2457 (!unpaid_only || (unpaid_only && otmp->unpaid))) {
2458 price += get_cost(otmp, shkp) * otmp->quan;
2461 if (Has_contents(otmp))
2462 price += contained_cost(otmp, shkp, price, usell, unpaid_only);
2465 return(price);
2468 long
2469 contained_gold(obj)
2470 register struct obj *obj;
2472 register struct obj *otmp;
2473 register long value = 0L;
2475 /* accumulate contained gold */
2476 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
2477 if (otmp->oclass == COIN_CLASS)
2478 value += otmp->quan;
2479 else if (Has_contents(otmp))
2480 value += contained_gold(otmp);
2482 return(value);
2485 STATIC_OVL void
2486 dropped_container(obj, shkp, sale)
2487 register struct obj *obj;
2488 register struct monst *shkp;
2489 register boolean sale;
2491 register struct obj *otmp;
2493 /* the "top" container is treated in the calling fn */
2494 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2495 if (otmp->oclass == COIN_CLASS) continue;
2497 if (!otmp->unpaid && !(sale && saleable(shkp, otmp)))
2498 otmp->no_charge = 1;
2500 if (Has_contents(otmp))
2501 dropped_container(otmp, shkp, sale);
2505 void
2506 picked_container(obj)
2507 register struct obj *obj;
2509 register struct obj *otmp;
2511 /* the "top" container is treated in the calling fn */
2512 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2513 if (otmp->oclass == COIN_CLASS) continue;
2515 if (otmp->no_charge)
2516 otmp->no_charge = 0;
2518 if (Has_contents(otmp))
2519 picked_container(otmp);
2522 #endif /*OVLB*/
2523 #ifdef OVL3
2525 /* calculate how much the shk will pay when buying [all of] an object */
2526 STATIC_OVL long
2527 set_cost(obj, shkp)
2528 register struct obj *obj;
2529 register struct monst *shkp;
2531 long tmp = getprice(obj, TRUE) * obj->quan;
2533 if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
2534 || ((uarmu && !uarmu->oinvis) && (!uarm || uarm->oinvis)
2535 && (!uarmc || uarmc->oinvis))) /* touristy shirt visible */
2536 tmp /= 3L;
2537 else
2538 if (uarmh && !uarmh->oinvis && uarmh->otyp == DUNCE_CAP)
2539 tmp /= 3L;
2540 else
2541 tmp /= 2L;
2543 if (ACURR(A_CHA) == 2) tmp /= 2L;
2544 if (ACURR(A_CHA) == 1) tmp /= 3L;
2546 if (Role_if(PM_OTAKU)) tmp /= 3L; /* bad at making deals */
2547 if (Race_if(PM_DUTHOL)) tmp /= 2L;
2549 if (Race_if(PM_ZAUR)) tmp /= 2L;
2550 if (Race_if(PM_WYLVAN)) tmp /= 2L;
2551 if (Race_if(PM_URGOTH)) tmp /= 3L;
2553 if (Role_if(PM_BARBARIAN)) tmp /= 3L;
2554 if (Role_if(PM_NOOB_MODE_BARB)) tmp /= 5L;
2555 /* rogues are untrustworthy... */
2556 if (Role_if(PM_ROGUE)) tmp /= 2L;
2557 /* samurais are from out of town... */
2558 if (Role_if(PM_SAMURAI)) tmp /= 2L;
2559 if (uarmf && uarmf->oartifact == ART_CARMARK) tmp /= 2L;
2561 /* shopkeeper may notice if the player isn't very knowledgeable -
2562 especially when gem prices are concerned */
2563 if (!obj->dknown || !objects[obj->otyp].oc_name_known) {
2564 if (obj->oclass == GEM_CLASS) {
2565 /* different shop keepers give different prices */
2566 if (objects[obj->otyp].oc_material == MT_GEMSTONE ||
2567 objects[obj->otyp].oc_material == MT_GLASS) {
2568 tmp = (obj->otyp % (6 - shkp->m_id % 3));
2569 tmp = (tmp + 3) * obj->quan;
2571 } else if (tmp > 1L && !rn2(4))
2572 tmp -= tmp / 4L;
2574 /* reduce player's ability to gain tons of money from selling common items --Amy */
2575 if (tmp > 1) {
2576 if (obj->otyp == IC && obj->cursed) tmp /= 20L;
2577 if (obj->otyp == IC && !obj->cursed) tmp /= 10L;
2578 if (obj->otyp == SPOON) tmp /= 100L; /* base price 5000??? ridiculous */
2579 if (objects[obj->otyp].oc_skill == P_FIREARM) tmp /= 10L;
2580 if (objects[obj->otyp].oc_skill == -P_FIREARM) tmp /= 3L;
2581 if (tmp < 1) tmp = 1; /* fail safe */
2582 if (obj->oclass == RING_CLASS) tmp /= 10L;
2583 if (obj->oclass == AMULET_CLASS) tmp /= 10L;
2584 if (obj->oclass == IMPLANT_CLASS) tmp /= 10L;
2585 if (obj->oclass == POTION_CLASS) tmp /= 10L;
2586 if (obj->oclass == SCROLL_CLASS) tmp /= 10L;
2587 if (obj->oclass == SPBOOK_CLASS) tmp /= 10L;
2588 if (obj->oclass == WAND_CLASS) tmp /= 10L;
2589 if (obj->otyp >= LUCKSTONE && obj->otyp <= SLING_AMMO) tmp /= 10L;
2591 /* after all, we nuked the thing that should not exist (price id) by making many item types always have the price
2592 * of the most expensive item in that type; if you can sell common scrolls, potions etc. for that price, it's way
2593 * too easy to gain money or (worst of all) credit clone! */
2595 return tmp;
2598 #endif /*OVL3*/
2599 #ifdef OVLB
2601 /* called from doinv(invent.c) for inventory of unpaid objects */
2602 long
2603 unpaid_cost(unp_obj)
2604 register struct obj *unp_obj; /* known to be unpaid */
2606 register struct bill_x *bp = (struct bill_x *)0;
2607 register struct monst *shkp;
2609 for(shkp = next_shkp(fmon, TRUE); shkp;
2610 shkp = next_shkp(shkp->nmon, TRUE))
2611 if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break;
2613 /* onbill() gave no message if unexpected problem occurred */
2614 if(!bp) {
2615 impossible("unpaid_cost: object wasn't on any bill!");
2616 unp_obj->unpaid = 0;
2619 return bp ? unp_obj->quan * bp->price : 0L;
2622 STATIC_OVL void
2623 add_one_tobill(obj, dummy)
2624 register struct obj *obj;
2625 register boolean dummy;
2627 register struct monst *shkp;
2628 register struct bill_x *bp;
2629 register int bct;
2630 register char roomno = *u.ushops;
2632 if (!roomno) return;
2633 if (!(shkp = shop_keeper(roomno))) return;
2634 if (!inhishop(shkp)) return;
2636 if (onbill(obj, shkp, FALSE) || /* perhaps thrown away earlier */
2637 (obj->oclass == FOOD_CLASS && obj->oeaten))
2638 return;
2640 if (ESHK(shkp)->billct == BILLSZ) {
2641 You("got that for free!");
2642 if (!rn2(5) && shkp->mpeaceful) {
2643 verbalize("That's it, thief! I'm calling the kops!");
2644 call_kops(shkp, FALSE);
2645 hot_pursuit(shkp);
2647 return;
2650 /* To recognize objects the shopkeeper is not interested in. -dgk
2652 if (obj->no_charge) {
2653 obj->no_charge = 0;
2654 return;
2657 bct = ESHK(shkp)->billct;
2658 bp = &(ESHK(shkp)->bill_p[bct]);
2659 if (!bp) {
2660 impossible("add_one_tobill error?!");
2661 return;
2663 bp->bo_id = obj->o_id;
2664 bp->bquan = obj->quan;
2665 if(dummy) { /* a dummy object must be inserted into */
2666 bp->useup = 1; /* the billobjs chain here. crucial for */
2667 add_to_billobjs(obj); /* eating floorfood in shop. see eat.c */
2668 } else bp->useup = 0;
2669 bp->price = get_cost(obj, shkp);
2670 ESHK(shkp)->billct++;
2671 obj->unpaid = 1;
2674 STATIC_OVL void
2675 add_to_billobjs(obj)
2676 struct obj *obj;
2678 if (obj->where != OBJ_FREE)
2679 panic("add_to_billobjs: obj not free");
2680 if (obj->timed)
2681 obj_stop_timers(obj);
2683 obj->nobj = billobjs;
2684 billobjs = obj;
2685 obj->where = OBJ_ONBILL;
2688 /* recursive billing of objects within containers. */
2689 STATIC_OVL void
2690 bill_box_content(obj, ininv, dummy, shkp)
2691 register struct obj *obj;
2692 register boolean ininv, dummy;
2693 register struct monst *shkp;
2695 register struct obj *otmp;
2697 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2698 if (otmp->oclass == COIN_CLASS) continue;
2700 /* the "top" box is added in addtobill() */
2701 if (!otmp->no_charge)
2702 add_one_tobill(otmp, dummy);
2703 if (Has_contents(otmp))
2704 bill_box_content(otmp, ininv, dummy, shkp);
2709 /* shopkeeper tells you what you bought or sold, sometimes partly IDing it */
2710 STATIC_OVL void
2711 shk_names_obj(shkp, obj, fmt, amt, arg)
2712 struct monst *shkp;
2713 struct obj *obj;
2714 const char *fmt; /* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */
2715 long amt;
2716 const char *arg;
2718 char *obj_name, fmtbuf[BUFSZ];
2719 boolean was_unknown = !obj->dknown;
2721 obj->objwassold = TRUE; /* so you can't sell it again for credit cloning --Amy */
2722 obj->dknown = TRUE;
2723 /* Use real name for ordinary weapons/armor, and spell-less
2724 * scrolls/books (that is, blank and mail), but only if the
2725 * object is within the shk's area of interest/expertise.
2727 if (!objects[obj->otyp].oc_magic && saleable(shkp, obj) &&
2728 (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS ||
2729 obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS ||
2730 obj->otyp == MIRROR)) {
2731 was_unknown |= !objects[obj->otyp].oc_name_known;
2732 makeknown(obj->otyp);
2734 obj_name = doname(obj);
2735 /* Use an alternate message when extra information is being provided */
2736 if (was_unknown) {
2737 sprintf(fmtbuf, "%%s; you %s", fmt);
2738 obj_name[0] = highc(obj_name[0]);
2739 pline(fmtbuf, obj_name, (obj->quan > 1) ? "them" : "it",
2740 amt, plur(amt), arg);
2741 } else {
2742 You(fmt, obj_name, amt, plur(amt), arg);
2746 void
2747 addtobill(obj, ininv, dummy, silent)
2748 register struct obj *obj;
2749 register boolean ininv, dummy, silent;
2751 register struct monst *shkp;
2752 register char roomno = *u.ushops;
2753 long ltmp = 0L, cltmp = 0L, gltmp = 0L;
2754 register boolean container = Has_contents(obj);
2756 if(!*u.ushops) return;
2758 if(!(shkp = shop_keeper(roomno))) return;
2760 if(!inhishop(shkp)) return;
2762 if(/* perhaps we threw it away earlier */
2763 onbill(obj, shkp, FALSE) ||
2764 (obj->oclass == FOOD_CLASS && obj->oeaten)
2765 ) return;
2767 if (Race_if(PM_IRAHA)) {
2768 verbalize("You just signed your own death warrant, thief!");
2769 hot_pursuit(shkp);
2772 if(ESHK(shkp)->billct == BILLSZ) {
2773 You("got that for free!");
2774 if (!rn2(5) && shkp->mpeaceful) {
2775 verbalize("That's it, thief! I'm calling the kops!");
2776 call_kops(shkp, FALSE);
2777 hot_pursuit(shkp);
2779 return;
2782 if(obj->oclass == COIN_CLASS) {
2783 costly_gold(obj->ox, obj->oy, obj->quan);
2784 return;
2787 if(!obj->no_charge)
2788 ltmp = get_cost(obj, shkp);
2790 if (obj->no_charge && !container) {
2791 obj->no_charge = 0;
2792 return;
2795 if(container) {
2796 if(obj->cobj == (struct obj *)0) {
2797 if(obj->no_charge) {
2798 obj->no_charge = 0;
2799 return;
2800 } else {
2801 add_one_tobill(obj, dummy);
2802 goto speak;
2804 } else {
2805 cltmp += contained_cost(obj, shkp, cltmp, FALSE, FALSE);
2806 gltmp += contained_gold(obj);
2809 if(ltmp) add_one_tobill(obj, dummy);
2810 if(cltmp) bill_box_content(obj, ininv, dummy, shkp);
2811 picked_container(obj); /* reset contained obj->no_charge */
2813 ltmp += cltmp;
2815 if(gltmp) {
2816 costly_gold(obj->ox, obj->oy, gltmp);
2817 if(!ltmp) return;
2820 if(obj->no_charge)
2822 obj->no_charge = 0;
2823 if(!ltmp) return;
2826 } else /* i.e., !container */
2827 add_one_tobill(obj, dummy);
2828 speak:
2829 if (shkp->mcanmove && !shkp->msleeping && !silent) {
2830 char buf[BUFSZ];
2832 if(!ltmp) {
2833 pline("%s has no interest in %s.", Monnam(shkp),
2834 the(xname(obj)));
2835 return;
2837 strcpy(buf, "\"For you, ");
2838 if (ANGRY(shkp)) strcat(buf, "scum ");
2839 else if (Role_if(PM_CONVICT) || Role_if(PM_MURDERER) || Race_if(PM_ALBAE) || Race_if(PM_PLAYER_DYNAMO) ) strcat(buf, "criminal ");
2840 else {
2841 static const char *honored[5] = {
2842 "good", "honored", "most gracious", "esteemed",
2843 "most renowned and sacred"
2845 strcat(buf, honored[rn2(4) + u.uevent.udemigod]);
2846 if (!is_human(youmonst.data)) strcat(buf, " creature");
2847 else
2848 strcat(buf, (flags.female) ? " lady" : " sir");
2850 if(ininv) {
2851 long quan = obj->quan;
2852 obj->quan = 1L; /* fool xname() into giving singular */
2853 pline("%s; only %ld %s %s.\"", buf, ltmp,
2854 (quan > 1L) ? "per" : "for this", xname(obj));
2855 obj->quan = quan;
2856 } else
2857 pline("%s will cost you %ld %s%s.",
2858 The(xname(obj)), ltmp, currency(ltmp),
2859 (obj->quan > 1L) ? " each" : "");
2860 } else if(!silent) {
2861 if(ltmp) pline_The("list price of %s is %ld %s%s.",
2862 the(xname(obj)), ltmp, currency(ltmp),
2863 (obj->quan > 1L) ? " each" : "");
2864 else pline("%s does not notice.", Monnam(shkp));
2868 void
2869 splitbill(obj, otmp)
2870 register struct obj *obj, *otmp;
2872 /* otmp has been split off from obj */
2873 register struct bill_x *bp;
2874 register long tmp;
2875 register struct monst *shkp = shop_keeper(*u.ushops);
2877 if(!shkp || !inhishop(shkp)) {
2878 impossible("splitbill: no resident shopkeeper??");
2879 return;
2881 bp = onbill(obj, shkp, FALSE);
2882 if(!bp) {
2883 impossible("splitbill: not on bill?");
2884 return;
2886 if(bp->bquan < otmp->quan) {
2887 impossible("Negative quantity on bill??");
2889 if(bp->bquan == otmp->quan) {
2890 impossible("Zero quantity on bill??");
2892 bp->bquan -= otmp->quan;
2893 tmp = bp->price; /* according to amateurhour this needs to be here to prevent a read after free --Amy */
2895 if(ESHK(shkp)->billct == BILLSZ) otmp->unpaid = 0;
2896 else {
2897 bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]);
2898 bp->bo_id = otmp->o_id;
2899 bp->bquan = otmp->quan;
2900 bp->useup = 0;
2901 bp->price = tmp;
2902 ESHK(shkp)->billct++;
2906 STATIC_OVL void
2907 sub_one_frombill(obj, shkp)
2908 register struct obj *obj;
2909 register struct monst *shkp;
2911 register struct bill_x *bp;
2913 if((bp = onbill(obj, shkp, FALSE)) != 0) {
2914 register struct obj *otmp;
2916 obj->unpaid = 0;
2917 if(bp->bquan > obj->quan){
2918 otmp = newobj(0);
2919 *otmp = *obj;
2920 bp->bo_id = otmp->o_id = flags.ident++;
2921 otmp->where = OBJ_FREE;
2922 otmp->quan = (bp->bquan -= obj->quan);
2923 otmp->owt = 0; /* superfluous */
2924 otmp->onamelth = 0;
2925 otmp->oxlth = 0;
2926 otmp->oattached = OATTACHED_NOTHING;
2927 bp->useup = 1;
2928 add_to_billobjs(otmp);
2929 return;
2931 ESHK(shkp)->billct--;
2932 #ifdef DUMB
2934 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
2935 int indx = ESHK(shkp)->billct;
2936 *bp = ESHK(shkp)->bill_p[indx];
2938 #else
2939 *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
2940 #endif
2941 return;
2942 } else if (obj->unpaid) {
2943 impossible("sub_one_frombill: unpaid object not on bill");
2944 obj->unpaid = 0;
2948 /* recursive check of unpaid objects within nested containers. */
2949 void
2950 subfrombill(obj, shkp)
2951 register struct obj *obj;
2952 register struct monst *shkp;
2954 register struct obj *otmp;
2956 sub_one_frombill(obj, shkp);
2958 if (Has_contents(obj))
2959 for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2960 if(otmp->oclass == COIN_CLASS) continue;
2962 if (Has_contents(otmp))
2963 subfrombill(otmp, shkp);
2964 else
2965 sub_one_frombill(otmp, shkp);
2969 #endif /*OVLB*/
2970 #ifdef OVL3
2972 STATIC_OVL long
2973 stolen_container(obj, shkp, price, ininv, destruction)
2974 register struct obj *obj;
2975 register struct monst *shkp;
2976 long price;
2977 register boolean ininv, destruction;
2979 register struct obj *otmp;
2981 if (!(destruction && evades_destruction(obj))) {
2982 if(ininv && obj->unpaid)
2983 price += get_cost(obj, shkp);
2984 else {
2985 if(!obj->no_charge)
2986 price += get_cost(obj, shkp);
2987 obj->no_charge = 0;
2991 /* the price of contained objects, if any */
2992 for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
2994 if(otmp->oclass == COIN_CLASS) continue;
2996 if (!Has_contents(otmp)) {
2997 if (!(destruction && evades_destruction(otmp))) {
2998 if(ininv) {
2999 if(otmp->unpaid)
3000 price += otmp->quan * get_cost(otmp, shkp);
3001 } else {
3002 if(!otmp->no_charge) {
3003 if(otmp->oclass != FOOD_CLASS || !otmp->oeaten)
3004 price += otmp->quan * get_cost(otmp, shkp);
3006 otmp->no_charge = 0;
3009 } else
3010 price += stolen_container(otmp, shkp, price, ininv,
3011 destruction);
3014 return(price);
3016 #endif /*OVL3*/
3017 #ifdef OVLB
3019 long
3020 stolen_value(obj, x, y, peaceful, silent, destruction)
3021 register struct obj *obj;
3022 register xchar x, y;
3023 register boolean peaceful, silent, destruction;
3025 register long value = 0L, gvalue = 0L;
3026 register struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
3028 if (!shkp || !inhishop(shkp))
3029 return (0L);
3031 if(obj->oclass == COIN_CLASS) {
3032 gvalue += obj->quan;
3033 } else if (Has_contents(obj)) {
3034 register boolean ininv = !!count_unpaid(obj->cobj);
3036 value += stolen_container(obj, shkp, value, ininv, destruction);
3037 if(!ininv) gvalue += contained_gold(obj);
3038 } else if (!obj->no_charge && saleable(shkp, obj) &&
3039 !(destruction && evades_destruction(obj))) {
3040 value += get_cost(obj, shkp);
3043 if(gvalue + value == 0L) return(0L);
3045 value += gvalue;
3047 if(peaceful) {
3048 boolean credit_use = !!ESHK(shkp)->credit;
3049 value = check_credit(value, shkp);
3050 /* 'peaceful' affects general treatment, but doesn't affect
3051 * the fact that other code expects that all charges after the
3052 * shopkeeper is angry are included in robbed, not debit */
3053 if (ANGRY(shkp))
3054 ESHK(shkp)->robbed += value;
3055 else
3056 ESHK(shkp)->debit += value;
3058 if(!silent) {
3059 const char *still = "";
3061 if (credit_use) {
3062 if (ESHK(shkp)->credit) {
3063 You("have %ld %s credit remaining.",
3064 ESHK(shkp)->credit, currency(ESHK(shkp)->credit));
3065 return value;
3066 } else if (!value) {
3067 You("have no credit remaining.");
3068 return 0;
3070 still = "still ";
3072 if(obj->oclass == COIN_CLASS)
3073 You("%sowe %s %ld %s!", still,
3074 mon_nam(shkp), value, currency(value));
3075 else
3076 You("%sowe %s %ld %s for %s!", still,
3077 mon_nam(shkp), value, currency(value),
3078 obj->quan > 1L ? "them" : "it");
3080 } else {
3081 ESHK(shkp)->robbed += value;
3083 if(!silent) {
3084 if(cansee(shkp->mx, shkp->my)) {
3085 Norep("%s booms: \"%s, you are a thief!\"",
3086 Monnam(shkp), playeraliasname);
3087 } else Norep("You hear a scream, \"Thief!\"");
3089 hot_pursuit(shkp);
3090 (void) angry_guards(FALSE);
3092 return(value);
3095 /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
3096 static char sell_response = 'a';
3097 static int sell_how = SELL_NORMAL;
3098 /* can't just use sell_response='y' for auto_credit because the 'a' response
3099 shouldn't carry over from ordinary selling to credit selling */
3100 static boolean auto_credit = FALSE;
3102 void
3103 sellobj_state(deliberate)
3104 int deliberate;
3106 /* If we're deliberately dropping something, there's no automatic
3107 response to the shopkeeper's "want to sell" query; however, if we
3108 accidentally drop anything, the shk will buy it/them without asking.
3109 This retains the old pre-query risk that slippery fingers while in
3110 shops entailed: you drop it, you've lost it.
3112 sell_response = (deliberate != SELL_NORMAL) ? '\0' : 'a';
3113 sell_how = deliberate;
3114 auto_credit = FALSE;
3117 void
3118 sellobj(obj, x, y)
3119 register struct obj *obj;
3120 xchar x, y;
3122 register struct monst *shkp;
3123 register struct eshk *eshkp;
3124 long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer;
3125 boolean saleitem, cgold = FALSE, container = Has_contents(obj);
3126 boolean isgold = (obj->oclass == COIN_CLASS);
3127 boolean only_partially_your_contents = FALSE;
3129 if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) ||
3130 !inhishop(shkp)) return;
3131 if(!costly_spot(x, y)) return;
3132 if(!*u.ushops) return;
3134 if(obj->unpaid && !container && !isgold) {
3135 sub_one_frombill(obj, shkp);
3136 return;
3138 if(container) {
3139 /* find the price of content before subfrombill */
3140 cltmp += contained_cost(obj, shkp, cltmp, TRUE, FALSE);
3141 /* find the value of contained gold */
3142 gltmp += contained_gold(obj);
3143 cgold = (gltmp > 0L);
3146 saleitem = saleable(shkp, obj);
3147 if(!isgold && !obj->unpaid && saleitem)
3148 ltmp = set_cost(obj, shkp);
3150 offer = ltmp + cltmp;
3152 /* get one case out of the way: nothing to sell, and no gold */
3153 if(!isgold &&
3154 ((offer + gltmp) == 0L || (obj->objwassold) || (sell_how == SELL_DONTSELL && !(uarmf && uarmf->oartifact == ART_KRISTIN_S_NOBILITY) ) )) {
3155 register boolean unpaid = (obj->unpaid ||
3156 (container && count_unpaid(obj->cobj)));
3158 if(container) {
3159 dropped_container(obj, shkp, FALSE);
3160 if(!obj->unpaid && !saleitem)
3161 obj->no_charge = 1;
3162 if(obj->unpaid || count_unpaid(obj->cobj))
3163 subfrombill(obj, shkp);
3164 } else obj->no_charge = 1;
3166 if(!unpaid && (sell_how != SELL_DONTSELL)) {
3167 pline("%s seems uninterested%s.", Monnam(shkp), (obj && obj->objwassold) ? " in items that already got sold earlier" : "");
3169 return;
3172 /* you dropped something of your own - probably want to sell it */
3173 rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */
3174 eshkp = ESHK(shkp);
3176 if (ANGRY(shkp)) { /* they become shop-objects, no pay */
3177 pline("Thank you, scum!");
3178 subfrombill(obj, shkp);
3179 return;
3182 if(eshkp->robbed) { /* shkp is not angry? */
3183 if(isgold) offer = obj->quan;
3184 else if(cgold) offer += cgold;
3185 if((eshkp->robbed -= offer < 0L))
3186 eshkp->robbed = 0L;
3187 if(offer) verbalize(
3188 "Thank you for your contribution to restock this recently plundered shop.");
3189 subfrombill(obj, shkp);
3190 return;
3193 if(isgold || cgold) {
3194 if(!cgold) gltmp = obj->quan;
3196 if(eshkp->debit >= gltmp) {
3197 if(eshkp->loan) { /* you carry shop's gold */
3198 if(eshkp->loan >= gltmp)
3199 eshkp->loan -= gltmp;
3200 else eshkp->loan = 0L;
3202 eshkp->debit -= gltmp;
3203 Your("debt is %spaid off.",
3204 eshkp->debit ? "partially " : "");
3205 } else {
3206 long delta = gltmp - eshkp->debit;
3208 /* credit limit as a nerf for cloning exploits: this exists mainly so you can't get 10000s of credit and enchant everything to +3 in an armor shop --Amy */
3209 if (eshkp->totalcredit >= eshkp->creditlimit) {
3210 verbalize("Sorry. I'm not offering credit anymore because you've already had so much credit in my shop. From now on I can only pay you in cash. Why don't you buy something so I can pay you again?");
3211 } else if (rn2(2)) { /* make the shopkeeper devious --Amy */
3212 if (eshkp->totalcredit + delta > eshkp->creditlimit) {
3213 eshkp->totalcredit = eshkp->creditlimit;
3214 verbalize("You've exceeded your credit limit in this shop. Sorry.");
3215 } else {
3216 eshkp->credit += delta;
3217 eshkp->totalcredit += delta;
3219 } else verbalize(isevilvariant ? "I own your stuff now. Fight me." : "What? You want credit? Well, sucks to be you, but I ain't giving you any!");
3220 if(eshkp->debit) {
3221 eshkp->debit = 0L;
3222 eshkp->loan = 0L;
3223 Your("debt is paid off.");
3225 if (eshkp->credit) pline("%ld %s %s added to your credit.",
3226 delta, currency(delta), delta > 1L ? "are" : "is");
3228 if(offer) goto move_on;
3229 else {
3230 if(!isgold) {
3231 if (container)
3232 dropped_container(obj, shkp, FALSE);
3233 if (!obj->unpaid && !saleitem) obj->no_charge = 1;
3234 subfrombill(obj, shkp);
3236 return;
3239 move_on:
3240 if((!saleitem && !(container && cltmp > 0L))
3241 || eshkp->billct == BILLSZ
3242 || obj->oclass == BALL_CLASS
3243 || obj->objwassold
3244 || obj->oclass == CHAIN_CLASS || offer == 0L
3245 || is_hazy(obj)
3246 || (obj->oclass == FOOD_CLASS && obj->oeaten) ) {
3247 pline("%s seems uninterested%s.", Monnam(shkp),
3248 cgold ? " in the rest" : "");
3249 if (container)
3250 dropped_container(obj, shkp, FALSE);
3251 obj->no_charge = 1;
3252 return;
3255 #ifndef GOLDOBJ
3256 if(!shkp->mgold) {
3257 #else
3258 if(!money_cnt(shkp->minvent)) {
3259 #endif
3260 char c, qbuf[BUFSZ];
3261 long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L);
3262 if (!issoviet && tmpcr > 0) {
3263 /* if the shk has no money then he has no money. Giving credit is all fine and dandy, but there's way too much
3264 * potential for abuse so from now on credit is one third of the # of zorkmids the shk would have paid. --Amy */
3265 tmpcr /= 3;
3266 if (tmpcr < 1) tmpcr = 1;
3269 if (sell_how == SELL_NORMAL || auto_credit) {
3270 c = sell_response = 'y';
3271 } else if (sell_response != 'n') {
3272 pline("%s cannot pay you at present.", Monnam(shkp));
3273 sprintf(qbuf,
3274 "Will you accept %ld %s in credit for %s?",
3275 tmpcr, currency(tmpcr), doname(obj));
3276 /* won't accept 'a' response here */
3277 /* KLY - 3/2000 yes, we will, it's a damn nuisance
3278 to have to constantly hit 'y' to sell for credit */
3279 c = ynaq(qbuf);
3280 if (c == 'a') {
3281 c = 'y';
3282 auto_credit = TRUE;
3284 } else /* previously specified "quit" */
3285 c = 'n';
3287 if (c == 'y') {
3288 shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ?
3289 "traded %s for %ld zorkmid%s in %scredit." :
3290 "relinquish %s and acquire %ld zorkmid%s in %scredit.",
3291 tmpcr, (eshkp->credit > 0L) ? "additional " : "");
3292 if (eshkp->totalcredit >= eshkp->creditlimit) {
3293 verbalize("Sorry. I'm not offering credit anymore because you've already had so much credit in my shop. From now on I can only pay you in cash. Why don't you buy something so I can pay you again?");
3294 } else if (rn2(2)) { /* fail sometimes --Amy */
3296 if (eshkp->totalcredit + tmpcr > eshkp->creditlimit) {
3297 eshkp->totalcredit = eshkp->creditlimit;
3298 verbalize("You've exceeded your credit limit in this shop. Sorry.");
3299 } else {
3300 eshkp->credit += tmpcr;
3301 eshkp->totalcredit += tmpcr;
3304 } else verbalize(isevilvariant ? "I own your stuff now. Fight me." : "What? You want credit? Well, sucks to be you, but I ain't giving you any!");
3305 subfrombill(obj, shkp);
3306 } else {
3307 if (c == 'q') sell_response = 'n';
3308 if (container)
3309 dropped_container(obj, shkp, FALSE);
3310 if (!obj->unpaid) obj->no_charge = 1;
3311 subfrombill(obj, shkp);
3313 } else {
3314 char qbuf[BUFSZ];
3315 #ifndef GOLDOBJ
3316 boolean short_funds = (offer > shkp->mgold);
3317 if (short_funds) offer = shkp->mgold;
3318 #else
3319 long shkmoney = money_cnt(shkp->minvent);
3320 boolean short_funds = (offer > shkmoney);
3321 if (short_funds) offer = shkmoney;
3322 #endif
3323 if (!sell_response) {
3324 only_partially_your_contents =
3325 (contained_cost(obj, shkp, 0L, FALSE, FALSE) !=
3326 contained_cost(obj, shkp, 0L, FALSE, TRUE));
3327 sprintf(qbuf,
3328 "%s offers%s %ld gold piece%s for%s %s %s. Sell %s?",
3329 Monnam(shkp), short_funds ? " only" : "",
3330 offer, plur(offer),
3331 (!ltmp && cltmp && only_partially_your_contents) ?
3332 " your items in" : (!ltmp && cltmp) ? " the contents of" : "",
3333 obj->unpaid ? "the" : "your", cxname(obj),
3334 (obj->quan == 1L &&
3335 !(!ltmp && cltmp && only_partially_your_contents)) ?
3336 "it" : "them");
3337 } else qbuf[0] = '\0'; /* just to pacify lint */
3339 switch (sell_response ? sell_response : ynaq(qbuf)) {
3340 case 'q': sell_response = 'n';
3341 case 'n': if (container)
3342 dropped_container(obj, shkp, FALSE);
3343 if (!obj->unpaid) obj->no_charge = 1;
3344 subfrombill(obj, shkp);
3345 break;
3346 case 'a': sell_response = 'y';
3347 case 'y': if (container)
3348 dropped_container(obj, shkp, TRUE);
3349 if (!obj->unpaid && !saleitem) obj->no_charge = 1;
3350 subfrombill(obj, shkp);
3351 pay(-offer, shkp);
3352 shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ?
3353 (!ltmp && cltmp && only_partially_your_contents) ?
3354 "sold some items inside %s for %ld gold pieces%s.%s" :
3355 "sold %s for %ld gold piece%s.%s" :
3356 "relinquish %s and receive %ld gold piece%s in compensation.%s",
3357 offer, "");
3358 break;
3359 default: impossible("invalid sell response");
3365 doinvbill(mode)
3366 int mode; /* 0: deliver count 1: paged */
3368 #ifdef __SASC
3369 void sasc_bug(struct obj *, unsigned);
3370 #endif
3371 struct monst *shkp;
3372 struct eshk *eshkp;
3373 struct bill_x *bp, *end_bp;
3374 struct obj *obj;
3375 long totused;
3376 char *buf_p;
3377 winid datawin;
3379 shkp = shop_keeper(*u.ushops);
3380 if (!shkp || !inhishop(shkp)) {
3381 if (mode != 0) impossible("doinvbill: no shopkeeper?");
3382 return 0;
3384 eshkp = ESHK(shkp);
3386 if (mode == 0) {
3387 /* count expended items, so that the `I' command can decide
3388 whether to include 'x' in its prompt string */
3389 int cnt = !eshkp->debit ? 0 : 1;
3391 for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
3392 bp < end_bp; bp++)
3393 if (bp->useup ||
3394 ((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan))
3395 cnt++;
3396 return cnt;
3399 datawin = create_nhwindow(NHW_MENU);
3400 putstr(datawin, 0, "Unpaid articles already used up:");
3401 putstr(datawin, 0, "");
3403 totused = 0L;
3404 for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct];
3405 bp < end_bp; bp++) {
3406 obj = bp_to_obj(bp);
3407 if(!obj) {
3408 impossible("Bad shopkeeper administration.");
3409 goto quit;
3411 if(bp->useup || bp->bquan > obj->quan) {
3412 long oquan, uquan, thisused;
3413 unsigned save_unpaid;
3415 save_unpaid = obj->unpaid;
3416 oquan = obj->quan;
3417 uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
3418 thisused = bp->price * uquan;
3419 totused += thisused;
3420 obj->unpaid = 0; /* ditto */
3421 /* Why 'x'? To match `I x', more or less. */
3422 buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused, uquan);
3423 #ifdef __SASC
3424 /* SAS/C 6.2 can't cope for some reason */
3425 sasc_bug(obj,save_unpaid);
3426 #else
3427 obj->unpaid = save_unpaid;
3428 #endif
3429 putstr(datawin, 0, buf_p);
3432 if (eshkp->debit) {
3433 /* additional shop debt which has no itemization available */
3434 if (totused) putstr(datawin, 0, "");
3435 totused += eshkp->debit;
3436 buf_p = xprname((struct obj *)0,
3437 "usage charges and/or other fees",
3438 GOLD_SYM, FALSE, eshkp->debit, 0L);
3439 putstr(datawin, 0, buf_p);
3441 buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused, 0L);
3442 putstr(datawin, 0, "");
3443 putstr(datawin, 0, buf_p);
3444 display_nhwindow(datawin, FALSE);
3445 quit:
3446 destroy_nhwindow(datawin);
3447 return(0);
3450 #define HUNGRY 2
3452 STATIC_OVL long
3453 getprice(obj, shk_buying)
3454 register struct obj *obj;
3455 boolean shk_buying;
3457 register long tmp = (long) objects[obj->otyp].oc_cost;
3459 if (obj->oartifact) {
3460 tmp = arti_cost(obj);
3461 if (shk_buying) tmp /= 4;
3463 switch(obj->oclass) {
3464 case FOOD_CLASS:
3465 /* simpler hunger check, (2-4)*cost */
3466 if (u.uhs >= HUNGRY && !shk_buying) tmp *= (long) u.uhs;
3467 if (obj->oeaten) tmp = 0L;
3468 break;
3469 case WAND_CLASS:
3470 /*if (obj->spe == -1) tmp = 0L;*/ /* he'll try to sell them to you anyway --Amy */
3471 break;
3472 case POTION_CLASS:
3473 /*if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
3474 tmp = 0L;*/ /* no, you can't price-ID :P --Amy */
3475 break;
3476 case ARMOR_CLASS:
3477 case WEAPON_CLASS:
3478 /*if (obj->spe > 0) tmp += 10L * (long) obj->spe;*/ /* fuck price ID :P --Amy */
3479 /* Don't buy activated explosives! */
3480 if (is_grenade(obj) && obj->oarmed) tmp = 0L;
3481 break;
3483 /* used to be that partly used light sources made it cheaper here... FUCK PRICE ID :P --Amy */
3486 return tmp;
3489 /* shk catches thrown pick-axe */
3490 struct monst *
3491 shkcatch(obj, x, y)
3492 register struct obj *obj;
3493 register xchar x, y;
3495 register struct monst *shkp;
3497 if (!(shkp = shop_keeper(inside_shop(x, y))) ||
3498 !inhishop(shkp)) return(0);
3500 if (shkp->mcanmove && !shkp->msleeping &&
3501 (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy)) &&
3502 dist2(shkp->mx, shkp->my, x, y) < 3 &&
3503 /* if it is the shk's pos, you hit and anger him */
3504 (shkp->mx != x || shkp->my != y)) {
3505 if (mnearto(shkp, x, y, TRUE))
3506 verbalize("Out of my way, scum!");
3507 if (cansee(x, y)) {
3508 pline("%s nimbly%s catches %s.",
3509 Monnam(shkp),
3510 (x == shkp->mx && y == shkp->my) ? "" : " reaches over and",
3511 the(xname(obj)));
3512 if (!canspotmon(shkp) && !(shkp->data->msound == MS_DEEPSTATE) && !(shkp->egotype_deepstatemember))
3513 map_invisible(x, y);
3514 delay_output();
3515 mark_synch();
3517 subfrombill(obj, shkp);
3518 (void) mpickobj(shkp, obj, FALSE);
3519 return shkp;
3521 return (struct monst *)0;
3524 void
3525 add_damage(x, y, cost)
3526 register xchar x, y;
3527 long cost;
3529 struct damage *tmp_dam;
3530 char *shops;
3532 if (IS_DOOR(levl[x][y].typ)) {
3533 struct monst *mtmp;
3535 /* Don't schedule for repair unless it's a real shop entrance */
3536 for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++)
3537 if ((mtmp = shop_keeper(*shops)) != 0 &&
3538 x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y)
3539 break;
3540 if (!*shops) return;
3542 for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next)
3543 if (tmp_dam->place.x == x && tmp_dam->place.y == y) {
3544 tmp_dam->cost += cost;
3545 return;
3547 tmp_dam = (struct damage *)alloc((unsigned)sizeof(struct damage));
3548 tmp_dam->when = monstermoves;
3549 tmp_dam->place.x = x;
3550 tmp_dam->place.y = y;
3551 tmp_dam->cost = cost;
3552 tmp_dam->typ = levl[x][y].typ;
3553 tmp_dam->next = level.damagelist;
3554 level.damagelist = tmp_dam;
3555 /* If player saw damage, display as a wall forever */
3556 if (cansee(x, y))
3557 levl[x][y].seenv = SVALL;
3560 #endif /*OVLB*/
3561 #ifdef OVL0
3564 * Do something about damage. Either (!croaked) try to repair it, or
3565 * (croaked) just discard damage structs for non-shared locations, since
3566 * they'll never get repaired. Assume that shared locations will get
3567 * repaired eventually by the other shopkeeper(s). This might be an erroneous
3568 * assumption (they might all be dead too), but we have no reasonable way of
3569 * telling that.
3571 STATIC_OVL
3572 void
3573 remove_damage(shkp, croaked)
3574 register struct monst *shkp;
3575 register boolean croaked;
3577 register struct damage *tmp_dam, *tmp2_dam;
3578 register boolean did_repair = FALSE, saw_door = FALSE;
3579 register boolean saw_floor = FALSE, stop_picking = FALSE;
3580 register boolean saw_untrap = FALSE;
3581 uchar saw_walls = 0;
3583 tmp_dam = level.damagelist;
3584 tmp2_dam = 0;
3585 while (tmp_dam) {
3586 register xchar x = tmp_dam->place.x, y = tmp_dam->place.y;
3587 char shops[5];
3588 int disposition;
3590 disposition = 0;
3591 strcpy(shops, in_rooms(x, y, SHOPBASE));
3592 if (index(shops, ESHK(shkp)->shoproom)) {
3593 if (croaked)
3594 disposition = (shops[1])? 0 : 1;
3595 else if (stop_picking)
3596 disposition = repair_damage(shkp, tmp_dam, FALSE);
3597 else {
3598 /* Defer the stop_occupation() until after repair msgs */
3599 if (closed_door(x, y))
3600 stop_picking = picking_at(x, y);
3601 disposition = repair_damage(shkp, tmp_dam, FALSE);
3602 if (!disposition)
3603 stop_picking = FALSE;
3607 if (!disposition) {
3608 tmp2_dam = tmp_dam;
3609 tmp_dam = tmp_dam->next;
3610 continue;
3613 if (disposition > 1) {
3614 did_repair = TRUE;
3615 if (cansee(x, y)) {
3616 if (IS_WALL(levl[x][y].typ))
3617 saw_walls++;
3618 else if (IS_DOOR(levl[x][y].typ))
3619 saw_door = TRUE;
3620 else if (disposition == 3) /* untrapped */
3621 saw_untrap = TRUE;
3622 else
3623 saw_floor = TRUE;
3627 tmp_dam = tmp_dam->next;
3628 if (!tmp2_dam) {
3629 free((void *)level.damagelist);
3630 level.damagelist = tmp_dam;
3631 } else {
3632 free((void *)tmp2_dam->next);
3633 tmp2_dam->next = tmp_dam;
3636 if (!did_repair)
3637 return;
3638 if (saw_walls) {
3639 pline("Suddenly, %s section%s of wall close%s up!",
3640 (saw_walls == 1) ? "a" : (saw_walls <= 3) ?
3641 "some" : "several",
3642 (saw_walls == 1) ? "" : "s", (saw_walls == 1) ? "s" : "");
3643 if (saw_door)
3644 pline_The("shop door reappears!");
3645 if (saw_floor)
3646 pline_The("floor is repaired!");
3647 } else {
3648 if (saw_door)
3649 pline("Suddenly, the shop door reappears!");
3650 else if (saw_floor)
3651 pline("Suddenly, the floor damage is gone!");
3652 else if (saw_untrap)
3653 pline("Suddenly, the trap is removed from the floor!");
3654 else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom)
3655 You_feel("more claustrophobic than before.");
3656 else if (flags.soundok && !rn2(10))
3657 Norep("The dungeon acoustics noticeably change.");
3659 if (stop_picking)
3660 stop_occupation();
3664 * 0: repair postponed, 1: silent repair (no messages), 2: normal repair
3665 * 3: untrap
3668 repair_damage(shkp, tmp_dam, catchup)
3669 register struct monst *shkp;
3670 register struct damage *tmp_dam;
3671 boolean catchup; /* restoring a level */
3673 register xchar x, y, i;
3674 xchar litter[9];
3675 register struct monst *mtmp;
3676 register struct obj *otmp;
3677 register struct trap *ttmp;
3679 if ((monstermoves - tmp_dam->when) < REPAIR_DELAY)
3680 return(0);
3681 if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following)
3682 return(0);
3683 x = tmp_dam->place.x;
3684 y = tmp_dam->place.y;
3685 if (!IS_ROOM(tmp_dam->typ)) {
3686 if (x == u.ux && y == u.uy)
3687 if (!Passes_walls)
3688 return(0);
3689 if (x == shkp->mx && y == shkp->my)
3690 return(0);
3691 if ((mtmp = m_at(x, y)) && (!mtmp->egotype_wallwalk) && (!passes_walls(mtmp->data)))
3692 return(0);
3694 if ((ttmp = t_at(x, y)) != 0) {
3696 if ((ttmp->ttyp != RUST_TRAP
3697 || shkp->data == &mons[PM_FLAMING_SPHERE]
3698 || shkp->data == &mons[PM_SUMMONED_FLAMING_SPHERE]
3699 || shkp->data == &mons[PM_IRON_GOLEM])
3700 && ttmp->ttyp != STATUE_TRAP
3701 && ttmp->ttyp != SHIT_TRAP
3702 && ttmp->ttyp != ANIMATION_TRAP
3703 && ttmp->ttyp != RMB_LOSS_TRAP
3704 && ttmp->ttyp != SUPERSCROLLER_TRAP
3705 && ttmp->ttyp != ACTIVE_SUPERSCROLLER_TRAP
3706 && ttmp->ttyp != SPEED_TRAP
3707 && ttmp->ttyp != MENU_TRAP
3708 && ttmp->ttyp != SWARM_TRAP
3709 && ttmp->ttyp != AUTOMATIC_SWITCHER
3710 && ttmp->ttyp != HEEL_TRAP
3711 && ttmp->ttyp != VULN_TRAP
3712 && ttmp->ttyp != DISPLAY_TRAP
3713 && ttmp->ttyp != SPELL_LOSS_TRAP
3714 && ttmp->ttyp != YELLOW_SPELL_TRAP
3715 && ttmp->ttyp != AUTO_DESTRUCT_TRAP
3716 && ttmp->ttyp != MEMORY_TRAP
3717 && ttmp->ttyp != INVENTORY_TRAP
3718 && ttmp->ttyp != BLACK_NG_WALL_TRAP
3719 && ttmp->ttyp != UNKNOWN_TRAP
3720 && ttmp->ttyp != TRAP_PERCENTS
3721 && ttmp->ttyp != LAVA_TRAP
3722 && ttmp->ttyp != FLOOD_TRAP
3723 && ttmp->ttyp != FREE_HAND_TRAP
3724 && ttmp->ttyp != UNIDENTIFY_TRAP
3725 && ttmp->ttyp != THIRST_TRAP
3726 && ttmp->ttyp != LUCK_TRAP
3727 && ttmp->ttyp != SHADES_OF_GREY_TRAP
3728 && ttmp->ttyp != GRAVITY_TRAP
3729 && ttmp->ttyp != STONE_TO_FLESH_TRAP
3730 && ttmp->ttyp != QUICKSAND_TRAP
3731 && ttmp->ttyp != FAINT_TRAP
3732 && ttmp->ttyp != CURSE_TRAP
3733 && ttmp->ttyp != DIFFICULTY_TRAP
3734 && ttmp->ttyp != SOUND_TRAP
3735 && ttmp->ttyp != CASTER_TRAP
3736 && ttmp->ttyp != WEAKNESS_TRAP
3737 && ttmp->ttyp != ROT_THIRTEEN_TRAP
3738 && ttmp->ttyp != BISHOP_TRAP
3739 && ttmp->ttyp != CONFUSION_TRAP
3740 && ttmp->ttyp != NUPESELL_TRAP
3741 && ttmp->ttyp != DROP_TRAP
3742 && ttmp->ttyp != DSTW_TRAP
3743 && ttmp->ttyp != STATUS_TRAP
3744 && ttmp->ttyp != PESTILENCE_TRAP
3745 && ttmp->ttyp != FAMINE_TRAP
3746 && ttmp->ttyp != ALIGNMENT_TRAP
3747 && ttmp->ttyp != STAIRS_TRAP
3748 && ttmp->ttyp != UNINFORMATION_TRAP
3749 && ttmp->ttyp != TIMERUN_TRAP
3750 && ttmp->ttyp != SPELL_COOLDOWN_TRAP
3751 && ttmp->ttyp != TURBODULL_TRAP
3752 && ttmp->ttyp != REDDAM_TRAP
3753 && ttmp->ttyp != REDINC_TRAP
3754 && ttmp->ttyp != MULCH_TRAP
3755 && ttmp->ttyp != INACCURACY_TRAP
3756 && ttmp->ttyp != MONSTER_MULTISHOT_TRAP
3757 && ttmp->ttyp != DO_YOU_HAVE_A_PIN_TRAP
3758 && ttmp->ttyp != COSTLY_FAILURE_TRAP
3759 && ttmp->ttyp != INVENTORY_SIZE_TRAP
3760 && ttmp->ttyp != AEFDE_TRAP
3761 && ttmp->ttyp != EPVI_TRAP
3762 && ttmp->ttyp != FUCKFUCKFUCK_TRAP
3763 && ttmp->ttyp != OPTION_TRAP
3764 && ttmp->ttyp != MISCOLOR_TRAP
3765 && ttmp->ttyp != ONE_RAINBOW_TRAP
3766 && ttmp->ttyp != COLORSHIFT_TRAP
3767 && ttmp->ttyp != TOP_LINE_TRAP
3768 && ttmp->ttyp != CAPS_TRAP
3769 && ttmp->ttyp != UN_KNOWLEDGE_TRAP
3770 && ttmp->ttyp != DARKHANCE_TRAP
3771 && ttmp->ttyp != DSCHUEUEUET_TRAP
3772 && ttmp->ttyp != NOPESKILL_TRAP
3773 && ttmp->ttyp != REAL_LIE_TRAP
3774 && ttmp->ttyp != ESCAPE_PAST_TRAP
3775 && ttmp->ttyp != PETHATE_TRAP
3776 && ttmp->ttyp != PET_LASHOUT_TRAP
3777 && ttmp->ttyp != PETSTARVE_TRAP
3778 && ttmp->ttyp != PETSCREW_TRAP
3779 && ttmp->ttyp != TECH_LOSS_TRAP
3780 && ttmp->ttyp != PROOFLOSS_TRAP
3781 && ttmp->ttyp != UN_INVIS_TRAP
3782 && ttmp->ttyp != DETECTATION_TRAP
3783 && ttmp->ttyp != REALLY_BAD_TRAP
3784 && ttmp->ttyp != COVID_TRAP
3785 && ttmp->ttyp != ARTIBLAST_TRAP
3786 && ttmp->ttyp != GIANT_EXPLORER_TRAP
3787 && ttmp->ttyp != TRAPWARP_TRAP
3788 && ttmp->ttyp != YAWM_TRAP
3789 && ttmp->ttyp != CRADLE_OF_CHAOS_TRAP
3790 && ttmp->ttyp != TEZCATLIPOCA_TRAP
3791 && ttmp->ttyp != ENTHUMESIS_TRAP
3792 && ttmp->ttyp != MIKRAANESIS_TRAP
3793 && ttmp->ttyp != GOTS_TOO_GOOD_TRAP
3794 && ttmp->ttyp != KILLER_ROOM_TRAP
3795 && ttmp->ttyp != NO_FUN_WALLS_TRAP
3796 && ttmp->ttyp != S_PRESSING_TRAP
3797 && ttmp->ttyp != BAD_PART_TRAP
3798 && ttmp->ttyp != COMPLETELY_BAD_PART_TRAP
3799 && ttmp->ttyp != EVIL_VARIANT_TRAP
3800 && ttmp->ttyp != INTRINSIC_LOSS_TRAP
3801 && ttmp->ttyp != BLOOD_LOSS_TRAP
3802 && ttmp->ttyp != BAD_EFFECT_TRAP
3803 && ttmp->ttyp != MULTIPLY_TRAP
3804 && ttmp->ttyp != AUTO_VULN_TRAP
3805 && ttmp->ttyp != NASTINESS_TRAP
3806 && ttmp->ttyp != RECURSION_TRAP
3807 && ttmp->ttyp != RESPAWN_TRAP
3808 && ttmp->ttyp != WARP_ZONE
3809 && ttmp->ttyp != CAPTCHA_TRAP
3810 && ttmp->ttyp != MIND_WIPE_TRAP
3811 && ttmp->ttyp != LOCK_TRAP
3812 && ttmp->ttyp != MAGIC_CANCELLATION_TRAP
3813 && ttmp->ttyp != FARLOOK_TRAP
3814 && ttmp->ttyp != GATEWAY_FROM_HELL
3815 && ttmp->ttyp != GROWING_TRAP
3816 && ttmp->ttyp != COOLING_TRAP
3817 && ttmp->ttyp != BAR_TRAP
3818 && ttmp->ttyp != LOCKING_TRAP
3819 && ttmp->ttyp != AIR_TRAP
3820 && ttmp->ttyp != TERRAIN_TRAP
3822 && ttmp->ttyp != ORANGE_SPELL_TRAP
3823 && ttmp->ttyp != VIOLET_SPELL_TRAP
3824 && ttmp->ttyp != TRAP_OF_LONGING
3825 && ttmp->ttyp != CURSED_PART_TRAP
3826 && ttmp->ttyp != QUAVERSAL_TRAP
3827 && ttmp->ttyp != APPEARANCE_SHUFFLING_TRAP
3828 && ttmp->ttyp != BROWN_SPELL_TRAP
3829 && ttmp->ttyp != CHOICELESS_TRAP
3830 && ttmp->ttyp != GOLDSPELL_TRAP
3831 && ttmp->ttyp != DEPROVEMENT_TRAP
3832 && ttmp->ttyp != INITIALIZATION_TRAP
3833 && ttmp->ttyp != GUSHLUSH_TRAP
3834 && ttmp->ttyp != SOILTYPE_TRAP
3835 && ttmp->ttyp != DANGEROUS_TERRAIN_TRAP
3836 && ttmp->ttyp != FALLOUT_TRAP
3837 && ttmp->ttyp != MOJIBAKE_TRAP
3838 && ttmp->ttyp != GRAVATION_TRAP
3839 && ttmp->ttyp != UNCALLED_TRAP
3840 && ttmp->ttyp != EXPLODING_DICE_TRAP
3841 && ttmp->ttyp != PERMACURSE_TRAP
3842 && ttmp->ttyp != SHROUDED_IDENTITY_TRAP
3843 && ttmp->ttyp != FEELER_GAUGES_TRAP
3844 && ttmp->ttyp != LONG_SCREWUP_TRAP
3845 && ttmp->ttyp != WING_YELLOW_CHANGER
3846 && ttmp->ttyp != LIFE_SAVING_TRAP
3847 && ttmp->ttyp != CURSEUSE_TRAP
3848 && ttmp->ttyp != CUT_NUTRITION_TRAP
3849 && ttmp->ttyp != SKILL_LOSS_TRAP
3850 && ttmp->ttyp != AUTOPILOT_TRAP
3851 && ttmp->ttyp != FORCE_TRAP
3852 && ttmp->ttyp != MONSTER_GLYPH_TRAP
3853 && ttmp->ttyp != CHANGING_DIRECTIVE_TRAP
3854 && ttmp->ttyp != CONTAINER_KABOOM_TRAP
3855 && ttmp->ttyp != STEAL_DEGRADE_TRAP
3856 && ttmp->ttyp != LEFT_INVENTORY_TRAP
3857 && ttmp->ttyp != FLUCTUATING_SPEED_TRAP
3858 && ttmp->ttyp != TARMUSTROKINGNORA_TRAP
3859 && ttmp->ttyp != FAILURE_TRAP
3860 && ttmp->ttyp != BRIGHT_CYAN_SPELL_TRAP
3861 && ttmp->ttyp != FREQUENTATION_SPAWN_TRAP
3862 && ttmp->ttyp != PET_AI_TRAP
3863 && ttmp->ttyp != SATAN_TRAP
3864 && ttmp->ttyp != REMEMBERANCE_TRAP
3865 && ttmp->ttyp != POKELIE_TRAP
3866 && ttmp->ttyp != AUTOPICKUP_TRAP
3867 && ttmp->ttyp != DYWYPI_TRAP
3868 && ttmp->ttyp != SILVER_SPELL_TRAP
3869 && ttmp->ttyp != METAL_SPELL_TRAP
3870 && ttmp->ttyp != PLATINUM_SPELL_TRAP
3871 && ttmp->ttyp != MANLER_TRAP
3872 && ttmp->ttyp != DOORNING_TRAP
3873 && ttmp->ttyp != NOWNSIBLE_TRAP
3874 && ttmp->ttyp != ELM_STREET_TRAP
3875 && ttmp->ttyp != MONNOISE_TRAP
3876 && ttmp->ttyp != RANG_CALL_TRAP
3877 && ttmp->ttyp != RECURRING_SPELL_LOSS_TRAP
3878 && ttmp->ttyp != ANTITRAINING_TRAP
3879 && ttmp->ttyp != TECHOUT_TRAP
3880 && ttmp->ttyp != STAT_DECAY_TRAP
3881 && ttmp->ttyp != MOVEMORK_TRAP
3883 && ttmp->ttyp != GRAVE_WALL_TRAP
3884 && ttmp->ttyp != TUNNEL_TRAP
3885 && ttmp->ttyp != FARMLAND_TRAP
3886 && ttmp->ttyp != MOUNTAIN_TRAP
3887 && ttmp->ttyp != WATER_TUNNEL_TRAP
3888 && ttmp->ttyp != CRYSTAL_FLOOD_TRAP
3889 && ttmp->ttyp != MOORLAND_TRAP
3890 && ttmp->ttyp != URINE_TRAP
3891 && ttmp->ttyp != SHIFTING_SAND_TRAP
3892 && ttmp->ttyp != STYX_TRAP
3893 && ttmp->ttyp != PENTAGRAM_TRAP
3894 && ttmp->ttyp != SNOW_TRAP
3895 && ttmp->ttyp != ASH_TRAP
3896 && ttmp->ttyp != SAND_TRAP
3897 && ttmp->ttyp != PAVEMENT_TRAP
3898 && ttmp->ttyp != HIGHWAY_TRAP
3899 && ttmp->ttyp != GRASSLAND_TRAP
3900 && ttmp->ttyp != NETHER_MIST_TRAP
3901 && ttmp->ttyp != STALACTITE_TRAP
3902 && ttmp->ttyp != CRYPTFLOOR_TRAP
3903 && ttmp->ttyp != BUBBLE_TRAP
3904 && ttmp->ttyp != RAIN_CLOUD_TRAP
3906 && ttmp->ttyp != ITEM_NASTIFICATION_TRAP
3907 && ttmp->ttyp != SANITY_INCREASE_TRAP
3908 && ttmp->ttyp != PSI_TRAP
3909 && ttmp->ttyp != GAY_TRAP
3911 && ttmp->ttyp != SARAH_TRAP
3912 && ttmp->ttyp != CLAUDIA_TRAP
3913 && ttmp->ttyp != LUDGERA_TRAP
3914 && ttmp->ttyp != KATI_TRAP
3916 && ttmp->ttyp != SANITY_TREBLE_TRAP
3917 && ttmp->ttyp != STAT_DECREASE_TRAP
3918 && ttmp->ttyp != SIMEOUT_TRAP
3920 && ttmp->ttyp != WALL_TRAP
3921 && ttmp->ttyp != MONSTER_GENERATOR
3922 && ttmp->ttyp != POTION_DISPENSER
3923 && ttmp->ttyp != SPACEWARS_SPAWN_TRAP
3924 && ttmp->ttyp != TV_TROPES_TRAP
3925 && ttmp->ttyp != SYMBIOTE_TRAP
3926 && ttmp->ttyp != KILL_SYMBIOTE_TRAP
3927 && ttmp->ttyp != SYMBIOTE_REPLACEMENT_TRAP
3928 && ttmp->ttyp != SHUTDOWN_TRAP
3929 && ttmp->ttyp != CORONA_TRAP
3930 && ttmp->ttyp != UNPROOFING_TRAP
3931 && ttmp->ttyp != VISIBILITY_TRAP
3932 && ttmp->ttyp != FEMINISM_STONE_TRAP
3933 && ttmp->ttyp != SHUEFT_TRAP
3934 && ttmp->ttyp != MOTH_LARVAE_TRAP
3935 && ttmp->ttyp != WORTHINESS_TRAP
3936 && ttmp->ttyp != CONDUCT_TRAP
3937 && ttmp->ttyp != STRIKETHROUGH_TRAP
3938 && ttmp->ttyp != MULTIPLE_GATHER_TRAP
3939 && ttmp->ttyp != VIVISECTION_TRAP
3940 && ttmp->ttyp != INSTAFEMINISM_TRAP
3941 && ttmp->ttyp != INSTANASTY_TRAP
3942 && ttmp->ttyp != SKILL_POINT_LOSS_TRAP
3943 && ttmp->ttyp != PERFECT_MATCH_TRAP
3944 && ttmp->ttyp != DUMBIE_LIGHTSABER_TRAP
3945 && ttmp->ttyp != WRONG_STAIRS
3946 && ttmp->ttyp != TECHSTOP_TRAP
3947 && ttmp->ttyp != AMNESIA_SWITCH_TRAP
3948 && ttmp->ttyp != SKILL_SWAP_TRAP
3949 && ttmp->ttyp != SKILL_UPORDOWN_TRAP
3950 && ttmp->ttyp != SKILL_RANDOMIZE_TRAP
3952 && ttmp->ttyp != CALLING_OUT_TRAP
3953 && ttmp->ttyp != FIELD_BREAK_TRAP
3954 && ttmp->ttyp != TENTH_TRAP
3955 && ttmp->ttyp != DEBT_TRAP
3956 && ttmp->ttyp != INVERSION_TRAP
3957 && ttmp->ttyp != WINCE_TRAP
3958 && ttmp->ttyp != FUCK_OVER_TRAP
3959 && ttmp->ttyp != U_HAVE_BEEN_TRAP
3960 && ttmp->ttyp != PERSISTENT_FART_TRAP
3961 && ttmp->ttyp != ATTACKING_HEEL_TRAP
3962 && ttmp->ttyp != TRAP_TELEPORTER
3963 && ttmp->ttyp != ALIGNMENT_TRASH_TRAP
3964 && ttmp->ttyp != RESHUFFLE_TRAP
3965 && ttmp->ttyp != MUSEHAND_TRAP
3966 && ttmp->ttyp != DOGSIDE_TRAP
3967 && ttmp->ttyp != BANKRUPT_TRAP
3968 && ttmp->ttyp != FILLUP_TRAP
3969 && ttmp->ttyp != AIRSTRIKE_TRAP
3970 && ttmp->ttyp != DYNAMITE_TRAP
3971 && ttmp->ttyp != MALEVOLENCE_TRAP
3972 && ttmp->ttyp != CORROSION_TRAP
3973 && ttmp->ttyp != FLAME_TRAP
3974 && ttmp->ttyp != LEAFLET_TRAP
3975 && ttmp->ttyp != RAZOR_TRAP
3976 && ttmp->ttyp != PHOSGENE_TRAP
3977 && ttmp->ttyp != CHLOROFORM_TRAP
3978 && ttmp->ttyp != WITHER_TRAP
3979 && ttmp->ttyp != PHASEPORTER
3980 && ttmp->ttyp != PHASE_BEAMER
3981 && ttmp->ttyp != VULNERATE_TRAP
3982 && ttmp->ttyp != TENTADEEP_TRAP
3983 && ttmp->ttyp != STATHALF_TRAP
3984 && ttmp->ttyp != CUTSTAT_TRAP
3985 && ttmp->ttyp != RARE_SPAWN_TRAP
3986 && ttmp->ttyp != YOU_ARE_AN_IDIOT_TRAP
3987 && ttmp->ttyp != NASTYCURSE_TRAP
3988 && ttmp->ttyp != REPEATING_NASTYCURSE_TRAP
3990 && ttmp->ttyp != FALLING_ROCK_COLD
3991 && ttmp->ttyp != RETURN_TRAP
3992 && ttmp->ttyp != INTRINSIC_STEAL_TRAP
3993 && ttmp->ttyp != SCORE_AXE_TRAP
3994 && ttmp->ttyp != SCORE_DRAIN_TRAP
3995 && ttmp->ttyp != SINGLE_UNIDENTIFY_TRAP
3996 && ttmp->ttyp != UNLUCKY_TRAP
3997 && ttmp->ttyp != ALIGNMENT_REDUCTION_TRAP
3998 && ttmp->ttyp != MALIGNANT_TRAP
3999 && ttmp->ttyp != STAT_DAMAGE_TRAP
4000 && ttmp->ttyp != HALF_MEMORY_TRAP
4001 && ttmp->ttyp != HALF_TRAINING_TRAP
4002 && ttmp->ttyp != DEBUFF_TRAP
4003 && ttmp->ttyp != TRIP_ONCE_TRAP
4004 && ttmp->ttyp != NARCOLEPSY_TRAP
4005 && ttmp->ttyp != MARTIAL_ARTS_TRAP
4007 && ttmp->ttyp != MEAN_BURDEN_TRAP
4008 && ttmp->ttyp != CARRCAP_TRAP
4009 && ttmp->ttyp != UMENG_TRAP
4010 && ttmp->ttyp != HYBRID_TRAP
4011 && ttmp->ttyp != SHAPECHANGE_TRAP
4012 && ttmp->ttyp != MELTEM_TRAP
4013 && ttmp->ttyp != MIGUC_TRAP
4014 && ttmp->ttyp != DIRECTIVE_TRAP
4015 && ttmp->ttyp != SATATUE_TRAP
4016 && ttmp->ttyp != FARTING_WEB
4017 && ttmp->ttyp != CATACLYSM_TRAP
4018 && ttmp->ttyp != DATA_DELETE_TRAP
4019 && ttmp->ttyp != ELDER_TENTACLING_TRAP
4020 && ttmp->ttyp != FOOTERER_TRAP
4022 && ttmp->ttyp != SKILL_MULTIPLY_TRAP
4023 && ttmp->ttyp != TRAPWALK_TRAP
4024 && ttmp->ttyp != CLUSTER_TRAP
4025 && ttmp->ttyp != FIELD_TRAP
4026 && ttmp->ttyp != MONICIDE_TRAP
4027 && ttmp->ttyp != TRAP_CREATION_TRAP
4028 && ttmp->ttyp != LEOLD_TRAP
4029 && ttmp->ttyp != BURDEN_TRAP
4030 && ttmp->ttyp != MAGIC_VACUUM_TRAP
4031 && ttmp->ttyp != ANIMEBAND_TRAP
4032 && ttmp->ttyp != PERFUME_TRAP
4033 && ttmp->ttyp != COURT_TRAP
4034 && ttmp->ttyp != ELDER_SCROLLS_TRAP
4035 && ttmp->ttyp != JOKE_TRAP
4036 && ttmp->ttyp != DUNGEON_LORDS_TRAP
4037 && ttmp->ttyp != FORTYTWO_TRAP
4038 && ttmp->ttyp != RANDOMIZE_TRAP
4039 && ttmp->ttyp != EVILROOM_TRAP
4040 && ttmp->ttyp != AOE_TRAP
4041 && ttmp->ttyp != ELONA_TRAP
4042 && ttmp->ttyp != RELIGION_TRAP
4043 && ttmp->ttyp != STEAMBAND_TRAP
4044 && ttmp->ttyp != HARDCORE_TRAP
4045 && ttmp->ttyp != MACHINE_TRAP
4046 && ttmp->ttyp != BEE_TRAP
4047 && ttmp->ttyp != MIGO_TRAP
4048 && ttmp->ttyp != ANGBAND_TRAP
4049 && ttmp->ttyp != DNETHACK_TRAP
4050 && ttmp->ttyp != EVIL_SPAWN_TRAP
4051 && ttmp->ttyp != SHOE_TRAP
4052 && ttmp->ttyp != INSIDE_TRAP
4053 && ttmp->ttyp != DOOM_TRAP
4054 && ttmp->ttyp != MILITARY_TRAP
4055 && ttmp->ttyp != ILLUSION_TRAP
4056 && ttmp->ttyp != DIABLO_TRAP
4058 && ttmp->ttyp != EVIL_HEEL_TRAP
4059 && ttmp->ttyp != BAD_EQUIPMENT_TRAP
4060 && ttmp->ttyp != TEMPOCONFLICT_TRAP
4061 && ttmp->ttyp != TEMPOHUNGER_TRAP
4062 && ttmp->ttyp != TELEPORTITIS_TRAP
4063 && ttmp->ttyp != POLYMORPHITIS_TRAP
4064 && ttmp->ttyp != PREMATURE_DEATH_TRAP
4065 && ttmp->ttyp != LASTING_AMNESIA_TRAP
4066 && ttmp->ttyp != RAGNAROK_TRAP
4067 && ttmp->ttyp != SINGLE_DISENCHANT_TRAP
4069 && ttmp->ttyp != SEVERE_DISENCHANT_TRAP
4070 && ttmp->ttyp != PAIN_TRAP
4071 && ttmp->ttyp != TREMBLING_TRAP
4072 && ttmp->ttyp != TECHCAP_TRAP
4073 && ttmp->ttyp != SPELL_MEMORY_TRAP
4074 && ttmp->ttyp != SKILL_REDUCTION_TRAP
4075 && ttmp->ttyp != SKILLCAP_TRAP
4076 && ttmp->ttyp != PERMANENT_STAT_DAMAGE_TRAP
4078 && ttmp->ttyp != LOOTCUT_TRAP
4079 && ttmp->ttyp != MONSTER_SPEED_TRAP
4080 && ttmp->ttyp != SCALING_TRAP
4081 && ttmp->ttyp != ENMITY_TRAP
4082 && ttmp->ttyp != WHITE_SPELL_TRAP
4083 && ttmp->ttyp != COMPLETE_GRAY_SPELL_TRAP
4084 && ttmp->ttyp != QUASAR_TRAP
4085 && ttmp->ttyp != MOMMA_TRAP
4086 && ttmp->ttyp != HORROR_TRAP
4087 && ttmp->ttyp != ARTIFICER_TRAP
4088 && ttmp->ttyp != WEREFORM_TRAP
4089 && ttmp->ttyp != NON_PRAYER_TRAP
4090 && ttmp->ttyp != EVIL_PATCH_TRAP
4091 && ttmp->ttyp != HARD_MODE_TRAP
4092 && ttmp->ttyp != SECRET_ATTACK_TRAP
4093 && ttmp->ttyp != EATER_TRAP
4094 && ttmp->ttyp != COVETOUSNESS_TRAP
4095 && ttmp->ttyp != NOT_SEEN_TRAP
4096 && ttmp->ttyp != DARK_MODE_TRAP
4097 && ttmp->ttyp != ANTISEARCH_TRAP
4098 && ttmp->ttyp != HOMICIDE_TRAP
4099 && ttmp->ttyp != NASTY_NATION_TRAP
4100 && ttmp->ttyp != WAKEUP_CALL_TRAP
4101 && ttmp->ttyp != GRAYOUT_TRAP
4102 && ttmp->ttyp != GRAY_CENTER_TRAP
4103 && ttmp->ttyp != CHECKERBOARD_TRAP
4104 && ttmp->ttyp != CLOCKWISE_SPIN_TRAP
4105 && ttmp->ttyp != COUNTERCLOCKWISE_SPIN_TRAP
4106 && ttmp->ttyp != LAG_TRAP
4107 && ttmp->ttyp != BLESSCURSE_TRAP
4108 && ttmp->ttyp != DE_LIGHT_TRAP
4109 && ttmp->ttyp != DISCHARGE_TRAP
4110 && ttmp->ttyp != TRASHING_TRAP
4111 && ttmp->ttyp != FILTERING_TRAP
4112 && ttmp->ttyp != DEFORMATTING_TRAP
4113 && ttmp->ttyp != FLICKER_STRIP_TRAP
4114 && ttmp->ttyp != UNDRESSING_TRAP
4115 && ttmp->ttyp != HYPERBLUEWALL_TRAP
4116 && ttmp->ttyp != NOLITE_TRAP
4117 && ttmp->ttyp != PARANOIA_TRAP
4118 && ttmp->ttyp != FLEECESCRIPT_TRAP
4119 && ttmp->ttyp != INTERRUPT_TRAP
4120 && ttmp->ttyp != DUSTBIN_TRAP
4121 && ttmp->ttyp != MANA_BATTERY_TRAP
4122 && ttmp->ttyp != MONSTERFINGERS_TRAP
4123 && ttmp->ttyp != MISCAST_TRAP
4124 && ttmp->ttyp != MESSAGE_SUPPRESSION_TRAP
4125 && ttmp->ttyp != STUCK_ANNOUNCEMENT_TRAP
4126 && ttmp->ttyp != BLOODTHIRSTY_TRAP
4127 && ttmp->ttyp != MAXIMUM_DAMAGE_TRAP
4128 && ttmp->ttyp != LATENCY_TRAP
4129 && ttmp->ttyp != STARLIT_TRAP
4130 && ttmp->ttyp != KNOWLEDGE_TRAP
4131 && ttmp->ttyp != HIGHSCORE_TRAP
4132 && ttmp->ttyp != PINK_SPELL_TRAP
4133 && ttmp->ttyp != GREEN_SPELL_TRAP
4134 && ttmp->ttyp != EVC_TRAP
4135 && ttmp->ttyp != UNDERLAYER_TRAP
4136 && ttmp->ttyp != DAMAGE_METER_TRAP
4137 && ttmp->ttyp != ARBITRARY_WEIGHT_TRAP
4138 && ttmp->ttyp != FUCKED_INFO_TRAP
4139 && ttmp->ttyp != BLACK_SPELL_TRAP
4140 && ttmp->ttyp != CYAN_SPELL_TRAP
4141 && ttmp->ttyp != HEAP_TRAP
4142 && ttmp->ttyp != BLUE_SPELL_TRAP
4143 && ttmp->ttyp != TRON_TRAP
4144 && ttmp->ttyp != RED_SPELL_TRAP
4145 && ttmp->ttyp != TOO_HEAVY_TRAP
4146 && ttmp->ttyp != ELONGATION_TRAP
4147 && ttmp->ttyp != WRAPOVER_TRAP
4148 && ttmp->ttyp != DESTRUCTION_TRAP
4149 && ttmp->ttyp != MELEE_PREFIX_TRAP
4150 && ttmp->ttyp != AUTOMORE_TRAP
4151 && ttmp->ttyp != UNFAIR_ATTACK_TRAP
4153 && ttmp->ttyp != LOUDSPEAKER
4154 && ttmp->ttyp != NEST_TRAP
4155 && ttmp->ttyp != CYANIDE_TRAP
4156 && ttmp->ttyp != LASER_TRAP
4157 && ttmp->ttyp != FART_TRAP
4158 && ttmp->ttyp != CONFUSE_TRAP
4159 && ttmp->ttyp != STUN_TRAP
4160 && ttmp->ttyp != HALLUCINATION_TRAP
4161 && ttmp->ttyp != PETRIFICATION_TRAP
4162 && ttmp->ttyp != NUMBNESS_TRAP
4163 && ttmp->ttyp != FREEZING_TRAP
4164 && ttmp->ttyp != BURNING_TRAP
4165 && ttmp->ttyp != FEAR_TRAP
4166 && ttmp->ttyp != BLINDNESS_TRAP
4167 && ttmp->ttyp != GLIB_TRAP
4168 && ttmp->ttyp != SLIME_TRAP
4169 && ttmp->ttyp != INERTIA_TRAP
4170 && ttmp->ttyp != TIME_TRAP
4171 && ttmp->ttyp != LYCANTHROPY_TRAP
4172 && ttmp->ttyp != UNLIGHT_TRAP
4173 && ttmp->ttyp != ELEMENTAL_TRAP
4174 && ttmp->ttyp != ESCALATING_TRAP
4175 && ttmp->ttyp != NEGATIVE_TRAP
4176 && ttmp->ttyp != MANA_TRAP
4177 && ttmp->ttyp != SIN_TRAP
4178 && ttmp->ttyp != DESTROY_ARMOR_TRAP
4179 && ttmp->ttyp != DIVINE_ANGER_TRAP
4180 && ttmp->ttyp != GENETIC_TRAP
4181 && ttmp->ttyp != MISSINGNO_TRAP
4182 && ttmp->ttyp != CANCELLATION_TRAP
4183 && ttmp->ttyp != HOSTILITY_TRAP
4184 && ttmp->ttyp != BOSS_TRAP
4185 && ttmp->ttyp != WISHING_TRAP
4186 && ttmp->ttyp != RECURRING_AMNESIA_TRAP
4187 && ttmp->ttyp != BIGSCRIPT_TRAP
4188 && ttmp->ttyp != BANK_TRAP
4189 && ttmp->ttyp != ONLY_TRAP
4190 && ttmp->ttyp != MAP_TRAP
4191 && ttmp->ttyp != TECH_TRAP
4192 && ttmp->ttyp != DISENCHANT_TRAP
4193 && ttmp->ttyp != VERISIERT
4194 && ttmp->ttyp != CHAOS_TRAP
4195 && ttmp->ttyp != MUTENESS_TRAP
4196 && ttmp->ttyp != NTLL_TRAP
4197 && ttmp->ttyp != ENGRAVING_TRAP
4198 && ttmp->ttyp != MAGIC_DEVICE_TRAP
4199 && ttmp->ttyp != BOOK_TRAP
4200 && ttmp->ttyp != LEVEL_TRAP
4201 && ttmp->ttyp != QUIZ_TRAP
4203 && ttmp->ttyp != BOMB_TRAP
4204 && ttmp->ttyp != EARTHQUAKE_TRAP
4205 && ttmp->ttyp != GLUE_TRAP
4206 && ttmp->ttyp != GUILLOTINE_TRAP
4207 && ttmp->ttyp != BISECTION_TRAP
4208 && ttmp->ttyp != VOLT_TRAP
4209 && ttmp->ttyp != HORDE_TRAP
4210 && ttmp->ttyp != IMMOBILITY_TRAP
4211 && ttmp->ttyp != GREEN_GLYPH
4212 && ttmp->ttyp != BLUE_GLYPH
4213 && ttmp->ttyp != YELLOW_GLYPH
4214 && ttmp->ttyp != ORANGE_GLYPH
4215 && ttmp->ttyp != BLACK_GLYPH
4216 && ttmp->ttyp != PURPLE_GLYPH
4217 && ttmp->ttyp != METABOLIC_TRAP
4218 && ttmp->ttyp != TRAP_OF_NO_RETURN
4219 && ttmp->ttyp != EGOTRAP
4220 && ttmp->ttyp != FAST_FORWARD_TRAP
4221 && ttmp->ttyp != TRAP_OF_ROTTENNESS
4222 && ttmp->ttyp != UNSKILLED_TRAP
4223 && ttmp->ttyp != LOW_STATS_TRAP
4224 && ttmp->ttyp != TRAINING_TRAP
4225 && ttmp->ttyp != EXERCISE_TRAP
4226 && ttmp->ttyp != FALLING_LOADSTONE_TRAP
4227 && ttmp->ttyp != SUMMON_UNDEAD_TRAP
4228 && ttmp->ttyp != FALLING_NASTYSTONE_TRAP
4230 && ttmp->ttyp != SPINED_BALL_TRAP
4231 && ttmp->ttyp != PENDULUM_TRAP
4232 && ttmp->ttyp != TURN_TABLE
4233 && ttmp->ttyp != SCENT_TRAP
4234 && ttmp->ttyp != BANANA_TRAP
4235 && ttmp->ttyp != FALLING_TUB_TRAP
4236 && ttmp->ttyp != ALARM
4237 && ttmp->ttyp != CALTROPS_TRAP
4238 && ttmp->ttyp != BLADE_WIRE
4239 && ttmp->ttyp != MAGNET_TRAP
4240 && ttmp->ttyp != SLINGSHOT_TRAP
4241 && ttmp->ttyp != CANNON_TRAP
4242 && ttmp->ttyp != VENOM_SPRINKLER
4243 && ttmp->ttyp != FUMAROLE
4245 && ttmp->ttyp != NEXUS_TRAP
4246 && ttmp->ttyp != LEG_TRAP
4247 && ttmp->ttyp != ARTIFACT_JACKPOT_TRAP
4248 && ttmp->ttyp != MAP_AMNESIA_TRAP
4249 && ttmp->ttyp != SPREADING_TRAP
4250 && ttmp->ttyp != ADJACENT_TRAP
4251 && ttmp->ttyp != SUPERTHING_TRAP
4252 && ttmp->ttyp != LEVITATION_TRAP
4253 && ttmp->ttyp != BOWEL_CRAMPS_TRAP
4254 && ttmp->ttyp != UNEQUIPPING_TRAP
4255 && ttmp->ttyp != GOOD_ARTIFACT_TRAP
4256 && ttmp->ttyp != GENDER_TRAP
4257 && ttmp->ttyp != TRAP_OF_OPPOSITE_ALIGNMENT
4258 && ttmp->ttyp != SINCOUNT_TRAP
4259 && ttmp->ttyp != WRENCHING_TRAP
4260 && ttmp->ttyp != TRACKER_TRAP
4261 && ttmp->ttyp != NURSE_TRAP
4262 && ttmp->ttyp != BACK_TO_START_TRAP
4263 && ttmp->ttyp != NEMESIS_TRAP
4264 && ttmp->ttyp != STREW_TRAP
4265 && ttmp->ttyp != OUTTA_DEPTH_TRAP
4266 && ttmp->ttyp != PUNISHMENT_TRAP
4267 && ttmp->ttyp != BOON_TRAP
4268 && ttmp->ttyp != FOUNTAIN_TRAP
4269 && ttmp->ttyp != THRONE_TRAP
4270 && ttmp->ttyp != ARABELLA_SPEAKER
4271 && ttmp->ttyp != FEMMY_TRAP
4272 && ttmp->ttyp != MADELEINE_TRAP
4273 && ttmp->ttyp != MARLENA_TRAP
4274 && ttmp->ttyp != SABRINA_TRAP
4275 && ttmp->ttyp != TANJA_TRAP
4276 && ttmp->ttyp != SONJA_TRAP
4277 && ttmp->ttyp != RHEA_TRAP
4278 && ttmp->ttyp != LARA_TRAP
4279 && ttmp->ttyp != NADINE_TRAP
4280 && ttmp->ttyp != LUISA_TRAP
4281 && ttmp->ttyp != IRINA_TRAP
4282 && ttmp->ttyp != LISELOTTE_TRAP
4283 && ttmp->ttyp != GRETA_TRAP
4284 && ttmp->ttyp != JANE_TRAP
4285 && ttmp->ttyp != SUE_LYN_TRAP
4286 && ttmp->ttyp != CHARLOTTE_TRAP
4287 && ttmp->ttyp != HANNAH_TRAP
4288 && ttmp->ttyp != LITTLE_MARIE_TRAP
4289 && ttmp->ttyp != RUTH_TRAP
4290 && ttmp->ttyp != MAGDALENA_TRAP
4291 && ttmp->ttyp != MARLEEN_TRAP
4292 && ttmp->ttyp != KLARA_TRAP
4293 && ttmp->ttyp != FRIEDERIKE_TRAP
4294 && ttmp->ttyp != NAOMI_TRAP
4295 && ttmp->ttyp != UTE_TRAP
4296 && ttmp->ttyp != JASIEEN_TRAP
4297 && ttmp->ttyp != YASAMAN_TRAP
4298 && ttmp->ttyp != MAY_BRITT_TRAP
4299 && ttmp->ttyp != KSENIA_TRAP
4300 && ttmp->ttyp != LYDIA_TRAP
4301 && ttmp->ttyp != CONNY_TRAP
4302 && ttmp->ttyp != KATIA_TRAP
4303 && ttmp->ttyp != MARIYA_TRAP
4304 && ttmp->ttyp != ELISE_TRAP
4305 && ttmp->ttyp != RONJA_TRAP
4306 && ttmp->ttyp != ARIANE_TRAP
4307 && ttmp->ttyp != JOHANNA_TRAP
4308 && ttmp->ttyp != INGE_TRAP
4309 && ttmp->ttyp != ROSA_TRAP
4310 && ttmp->ttyp != JANINA_TRAP
4311 && ttmp->ttyp != KRISTIN_TRAP
4312 && ttmp->ttyp != ANNA_TRAP
4313 && ttmp->ttyp != RUEA_TRAP
4314 && ttmp->ttyp != DORA_TRAP
4315 && ttmp->ttyp != MARIKE_TRAP
4316 && ttmp->ttyp != JETTE_TRAP
4317 && ttmp->ttyp != INA_TRAP
4318 && ttmp->ttyp != SING_TRAP
4319 && ttmp->ttyp != VICTORIA_TRAP
4320 && ttmp->ttyp != MELISSA_TRAP
4321 && ttmp->ttyp != ANITA_TRAP
4322 && ttmp->ttyp != HENRIETTA_TRAP
4323 && ttmp->ttyp != VERENA_TRAP
4324 && ttmp->ttyp != ARABELLA_TRAP
4325 && ttmp->ttyp != NELLY_TRAP
4326 && ttmp->ttyp != EVELINE_TRAP
4327 && ttmp->ttyp != KARIN_TRAP
4328 && ttmp->ttyp != JUEN_TRAP
4329 && ttmp->ttyp != KRISTINA_TRAP
4330 && ttmp->ttyp != ALMUT_TRAP
4331 && ttmp->ttyp != JULIETTA_TRAP
4332 && ttmp->ttyp != LOU_TRAP
4333 && ttmp->ttyp != ANASTASIA_TRAP
4334 && ttmp->ttyp != FILLER_TRAP
4335 && ttmp->ttyp != TOXIC_VENOM_TRAP
4336 && ttmp->ttyp != INSANITY_TRAP
4337 && ttmp->ttyp != MADNESS_TRAP
4338 && ttmp->ttyp != JESSICA_TRAP
4339 && ttmp->ttyp != SOLVEJG_TRAP
4340 && ttmp->ttyp != WENDY_TRAP
4341 && ttmp->ttyp != KATHARINA_TRAP
4342 && ttmp->ttyp != ELENA_TRAP
4343 && ttmp->ttyp != THAI_TRAP
4344 && ttmp->ttyp != ELIF_TRAP
4345 && ttmp->ttyp != NADJA_TRAP
4346 && ttmp->ttyp != SANDRA_TRAP
4347 && ttmp->ttyp != NATALJE_TRAP
4348 && ttmp->ttyp != JEANETTA_TRAP
4349 && ttmp->ttyp != YVONNE_TRAP
4350 && ttmp->ttyp != MAURAH_TRAP
4351 && ttmp->ttyp != ANNEMARIE_TRAP
4352 && ttmp->ttyp != JIL_TRAP
4353 && ttmp->ttyp != JANA_TRAP
4354 && ttmp->ttyp != KATRIN_TRAP
4355 && ttmp->ttyp != GUDRUN_TRAP
4356 && ttmp->ttyp != ELLA_TRAP
4357 && ttmp->ttyp != MANUELA_TRAP
4358 && ttmp->ttyp != JENNIFER_TRAP
4359 && ttmp->ttyp != PATRICIA_TRAP
4360 && ttmp->ttyp != ANTJE_TRAP
4361 && ttmp->ttyp != ANTJE_TRAP_X
4362 && ttmp->ttyp != KERSTIN_TRAP
4363 && ttmp->ttyp != LAURA_TRAP
4364 && ttmp->ttyp != LARISSA_TRAP
4365 && ttmp->ttyp != NORA_TRAP
4366 && ttmp->ttyp != NATALIA_TRAP
4367 && ttmp->ttyp != SUSANNE_TRAP
4368 && ttmp->ttyp != LISA_TRAP
4369 && ttmp->ttyp != BRIDGHITTE_TRAP
4370 && ttmp->ttyp != JULIA_TRAP
4371 && ttmp->ttyp != NICOLE_TRAP
4372 && ttmp->ttyp != RITA_TRAP
4374 && ttmp->ttyp != ELEMENTAL_PORTAL
4375 && ttmp->ttyp != GIRLINESS_TRAP
4376 && ttmp->ttyp != FUMBLING_TRAP
4377 && ttmp->ttyp != EGOMONSTER_TRAP
4378 && ttmp->ttyp != FLOODING_TRAP
4379 && ttmp->ttyp != MONSTER_CUBE
4380 && ttmp->ttyp != CURSED_GRAVE
4381 && ttmp->ttyp != LIMITATION_TRAP
4382 && ttmp->ttyp != WEAK_SIGHT_TRAP
4383 && ttmp->ttyp != RANDOM_MESSAGE_TRAP
4385 && ttmp->ttyp != DESECRATION_TRAP
4386 && ttmp->ttyp != STARVATION_TRAP
4387 && ttmp->ttyp != DROPLESS_TRAP
4388 && ttmp->ttyp != LOW_EFFECT_TRAP
4389 && ttmp->ttyp != INVISIBLE_TRAP
4390 && ttmp->ttyp != GHOST_WORLD_TRAP
4391 && ttmp->ttyp != DEHYDRATION_TRAP
4392 && ttmp->ttyp != HATE_TRAP
4393 && ttmp->ttyp != SPACEWARS_TRAP
4394 && ttmp->ttyp != TEMPORARY_RECURSION_TRAP
4395 && ttmp->ttyp != TOTTER_TRAP
4396 && ttmp->ttyp != NONINTRINSICAL_TRAP
4397 && ttmp->ttyp != DROPCURSE_TRAP
4398 && ttmp->ttyp != NAKEDNESS_TRAP
4399 && ttmp->ttyp != ANTILEVEL_TRAP
4400 && ttmp->ttyp != VENTILATOR
4401 && ttmp->ttyp != STEALER_TRAP
4402 && ttmp->ttyp != REBELLION_TRAP
4403 && ttmp->ttyp != CRAP_TRAP
4404 && ttmp->ttyp != MISFIRE_TRAP
4405 && ttmp->ttyp != TRAP_OF_WALLS
4406 && ttmp->ttyp != DISCONNECT_TRAP
4407 && ttmp->ttyp != INTERFACE_SCREW_TRAP
4408 && ttmp->ttyp != BOSSFIGHT_TRAP
4409 && ttmp->ttyp != ENTIRE_LEVEL_TRAP
4410 && ttmp->ttyp != BONES_TRAP
4411 && ttmp->ttyp != AUTOCURSE_TRAP
4412 && ttmp->ttyp != HIGHLEVEL_TRAP
4413 && ttmp->ttyp != SPELL_FORGETTING_TRAP
4414 && ttmp->ttyp != SOUND_EFFECT_TRAP
4415 && ttmp->ttyp != CONTAMINATION_TRAP
4416 && ttmp->ttyp != BOSS_SPAWNER
4417 && ttmp->ttyp != KOP_CUBE
4419 && (ttmp->ttyp != DEATH_TRAP ||
4420 (nonliving(shkp->data) || is_demon(shkp->data) || resists_death(shkp) || shkp->data->msound == MS_NEMESIS || resists_magm(shkp)) )
4422 && (ttmp->ttyp != DISINTEGRATION_TRAP ||
4423 (!resists_disint(shkp)) )
4425 && (ttmp->ttyp != DRAIN_TRAP ||
4426 (!resists_drli(shkp)) )
4428 && (ttmp->ttyp != SLP_GAS_TRAP ||
4429 (!resists_sleep(shkp) && !breathless(shkp->data) && (!shkp->egotype_undead) ) )
4430 && (ttmp->ttyp != POISON_GAS_TRAP ||
4431 (!resists_poison(shkp) && !breathless(shkp->data) && (!shkp->egotype_undead) ) )
4432 && (ttmp->ttyp != SLOW_GAS_TRAP ||
4433 (!breathless(shkp->data) && (!shkp->egotype_undead) ) )
4434 && (ttmp->ttyp != BEAR_TRAP ||
4435 (shkp->data->msize > MZ_SMALL &&
4436 !amorphous(shkp->data) && !is_flyer(shkp->data) && (!shkp->egotype_flying) ))
4437 && (ttmp->ttyp != FIRE_TRAP ||
4438 !resists_fire(shkp))
4439 && (ttmp->ttyp != SHOCK_TRAP ||
4440 !resists_elec(shkp))
4441 && (ttmp->ttyp != ICE_TRAP ||
4442 !resists_cold(shkp))
4443 && (ttmp->ttyp != SQKY_BOARD || (!is_flyer(shkp->data) && (!shkp->egotype_flying) ))
4444 && (ttmp->ttyp != ACID_POOL || (!is_flyer(shkp->data) && (!shkp->egotype_flying) && !is_floater(shkp->data) && !resists_acid(shkp)) )
4445 && (ttmp->ttyp != WATER_POOL || (!is_flyer(shkp->data) && (!shkp->egotype_flying) && !is_floater(shkp->data) && !is_swimmer(shkp->data) && !shkp->egotype_watersplasher && !amphibious(shkp->data) && !breathless(shkp->data) && (!shkp->egotype_undead) ) )
4446 && (ttmp->ttyp != WEB || (!amorphous(shkp->data) && !shkp->egotype_webber &&
4447 !webmaker(shkp->data) && !dmgtype(shkp->data, AD_WEBS) ))
4450 if (x == u.ux && y == u.uy)
4451 if (!Passes_walls)
4452 return(0);
4453 if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) {
4454 /* convert to an object */
4455 otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP, TRUE, FALSE, FALSE);
4456 if (otmp) {
4457 otmp->quan= 1;
4458 otmp->owt = weight(otmp);
4459 (void) mpickobj(shkp, otmp, FALSE);
4462 deltrap(ttmp);
4463 if(IS_DOOR(tmp_dam->typ)) {
4464 levl[x][y].doormask = D_CLOSED; /* arbitrary */
4465 block_point(x, y);
4466 } else if (IS_WALL(tmp_dam->typ)) {
4467 levl[x][y].typ = tmp_dam->typ;
4468 block_point(x, y);
4470 newsym(x, y);
4471 return(3);
4474 if (IS_ROOM(tmp_dam->typ)) {
4475 /* No messages, because player already filled trap door */
4476 return(1);
4478 if ((tmp_dam->typ == levl[x][y].typ) &&
4479 (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN)))
4480 /* No messages if player already replaced shop door */
4481 return(1);
4482 levl[x][y].typ = tmp_dam->typ;
4483 (void) memset((void *)litter, 0, sizeof(litter));
4484 if ((otmp = level.objects[x][y]) != 0) {
4485 /* Scatter objects haphazardly into the shop */
4486 #define NEED_UPDATE 1
4487 #define OPEN 2
4488 #define INSHOP 4
4489 #define horiz(i) ((i%3)-1)
4490 #define vert(i) ((i/3)-1)
4491 for (i = 0; i < 9; i++) {
4492 if ((i == 4) || (!ZAP_POS(levl[x+horiz(i)][y+vert(i)].typ)))
4493 continue;
4494 litter[i] = OPEN;
4495 if (inside_shop(x+horiz(i),
4496 y+vert(i)) == ESHK(shkp)->shoproom)
4497 litter[i] |= INSHOP;
4499 if (Punished && !u.uswallow &&
4500 ((uchain->ox == x && uchain->oy == y) ||
4501 (uball->ox == x && uball->oy == y))) {
4503 * Either the ball or chain is in the repair location.
4505 * Take the easy way out and put ball&chain under hero.
4507 verbalize("Get your junk out of my wall!");
4508 unplacebc(); /* pick 'em up */
4509 placebc(); /* put 'em down */
4511 while ((otmp = level.objects[x][y]) != 0)
4512 /* Don't mess w/ boulders -- just merge into wall */
4513 if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) {
4514 obj_extract_self(otmp);
4515 obfree(otmp, (struct obj *)0);
4516 } else {
4517 while (!(litter[i = rn2(9)] & INSHOP));
4518 remove_object(otmp);
4519 place_object(otmp, x+horiz(i), y+vert(i));
4520 litter[i] |= NEED_UPDATE;
4523 if (catchup) return 1; /* repair occurred while off level */
4525 block_point(x, y);
4526 if(IS_DOOR(tmp_dam->typ)) {
4527 levl[x][y].doormask = D_CLOSED; /* arbitrary */
4528 newsym(x, y);
4529 } else {
4530 /* don't set doormask - it is (hopefully) the same as it was */
4531 /* if not, perhaps save it with the damage array... */
4533 if (IS_WALL(tmp_dam->typ) && cansee(x, y)) {
4534 /* Player sees actual repair process, so they KNOW it's a wall */
4535 levl[x][y].seenv = SVALL;
4536 newsym(x, y);
4538 /* Mark this wall as "repaired". There currently is no code */
4539 /* to do anything about repaired walls, so don't do it. */
4541 for (i = 0; i < 9; i++)
4542 if (litter[i] & NEED_UPDATE)
4543 newsym(x+horiz(i), y+vert(i));
4544 return(2);
4545 #undef NEED_UPDATE
4546 #undef OPEN
4547 #undef INSHOP
4548 #undef vert
4549 #undef horiz
4551 #endif /*OVL0*/
4552 #ifdef OVL3
4554 * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died
4557 shk_move(shkp)
4558 register struct monst *shkp;
4560 register xchar gx,gy,omx,omy;
4561 register int udist;
4562 register schar appr;
4563 register struct eshk *eshkp = ESHK(shkp);
4564 int z;
4565 boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv;
4567 omx = shkp->mx;
4568 omy = shkp->my;
4570 if (inhishop(shkp))
4571 remove_damage(shkp, FALSE);
4573 if((udist = distu(omx,omy)) < 3 &&
4574 (!(isgridbug(shkp->data)) || (omx==u.ux || omy==u.uy))) {
4575 if(ANGRY(shkp) ||
4576 (Conflict && !resist(shkp, RING_CLASS, 0, 0)) ||
4577 (StrongConflict && !resist(shkp, RING_CLASS, 0, 0))) {
4578 if(Displaced)
4579 Your("displaced image doesn't fool %s!",
4580 mon_nam(shkp));
4581 (void) mattacku(shkp);
4582 return(0);
4584 if(eshkp->following) {
4585 if(strncmp(eshkp->customer, plname, PL_NSIZ)) {
4586 verbalize("%s, %s! I was looking for %s.",
4587 Hello(shkp), playeraliasname, eshkp->customer);
4588 eshkp->following = 0;
4589 return(0);
4591 if(moves > followmsg+4) {
4592 verbalize("%s, %s! Didn't you forget to pay?",
4593 Hello(shkp), playeraliasname);
4594 followmsg = moves;
4595 if (!rn2(9)) {
4596 pline("%s doesn't like customers who don't pay.",
4597 Monnam(shkp));
4598 rile_shk(shkp);
4601 if(udist < 2)
4602 return(0);
4606 appr = 1;
4607 gx = eshkp->shk.x;
4608 gy = eshkp->shk.y;
4609 satdoor = (gx == omx && gy == omy);
4610 if(eshkp->following || ((z = holetime()) >= 0 && z*z <= udist)){
4611 /* [This distance check used to apply regardless of
4612 whether the shk was following, but that resulted in
4613 m_move() sometimes taking the shk out of the shop if
4614 the player had fenced him in with boulders or traps.
4615 Such voluntary abandonment left unpaid objects in
4616 invent, triggering billing impossibilities on the
4617 next level once the character fell through the hole.] */
4618 if (udist > 4 && eshkp->following && !eshkp->billct)
4619 return(-1); /* leave it to m_move */
4620 gx = u.ux;
4621 gy = u.uy;
4622 } else if(ANGRY(shkp)) {
4623 /* Move towards the hero if the shopkeeper can see him. */
4624 if(shkp->mcansee && m_canseeu(shkp)) {
4625 gx = u.ux;
4626 gy = u.uy;
4628 avoid = FALSE;
4629 } else {
4630 #define GDIST(x,y) (dist2(x,y,gx,gy))
4631 if ((Is_blackmarket(&u.uz) && u.umonnum>0 &&
4632 mons[u.umonnum].mlet != S_HUMAN) ||
4633 /* WAC Let you out if you're stuck inside */
4634 (!Is_blackmarket(&u.uz) && (Invis || (u.usteed && !(uarm && uarm->oartifact == ART_FAER_ME)) ) && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY) && !inside_shop(u.ux, u.uy)))
4636 avoid = FALSE;
4637 } else {
4638 uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y);
4639 if(uondoor) {
4640 badinv = (carrying(PICK_AXE) || carrying(CONGLOMERATE_PICK) || carrying(UNWIELDY_PICK) || carrying(CONUNDRUM_PICK) || carrying(MYSTERY_PICK) || carrying(BRONZE_PICK) || carrying(BRICK_PICK) || carrying(MYSTERIOUS_PICK) || carrying(NANO_PICK) || carrying(DWARVISH_MATTOCK) || carrying(SOFT_MATTOCK) || carrying(ETERNIUM_MATTOCK) ||
4641 eshkp->pbanned ||
4642 (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(CONGLOMERATE_PICK, u.ux, u.uy) || sobj_at(UNWIELDY_PICK, u.ux, u.uy) || sobj_at(CONUNDRUM_PICK, u.ux, u.uy) || sobj_at(MYSTERY_PICK, u.ux, u.uy) || sobj_at(BRONZE_PICK, u.ux, u.uy) || sobj_at(BRICK_PICK, u.ux, u.uy) || sobj_at(MYSTERIOUS_PICK, u.ux, u.uy) || sobj_at(NANO_PICK, u.ux, u.uy) || sobj_at(SOFT_MATTOCK, u.ux, u.uy) || sobj_at(ETERNIUM_MATTOCK, u.ux, u.uy) ||
4643 sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))));
4644 if(satdoor && badinv && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY))
4645 return(0);
4646 avoid = !badinv;
4647 } else {
4648 avoid = (*u.ushops && distu(gx,gy) > 8);
4649 badinv = FALSE;
4652 if(((!eshkp->robbed && !eshkp->billct && !eshkp->debit)
4653 || avoid) && GDIST(omx,omy) < 3) {
4654 if (!badinv && !onlineu(omx,omy))
4655 return(0);
4656 if(satdoor)
4657 appr = gx = gy = 0;
4662 z = move_special(shkp,inhishop(shkp),appr,uondoor,avoid,omx,omy,gx,gy);
4663 if (z > 0) after_shk_move(shkp);
4665 return z;
4668 /* called after shopkeeper moves, in case the move causes re-entry into shop */
4669 void
4670 after_shk_move(shkp)
4671 struct monst *shkp;
4673 struct eshk *eshkp = ESHK(shkp);
4675 if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) {
4676 /* reset bill_p, need to re-calc player's occupancy too */
4677 eshkp->bill_p = &eshkp->bill[0];
4678 check_special_room(FALSE);
4682 #endif /*OVL3*/
4683 #ifdef OVLB
4685 /* for use in levl_follower (mondata.c) */
4686 boolean
4687 is_fshk(mtmp)
4688 register struct monst *mtmp;
4690 return((boolean)(mtmp->isshk && ESHK(mtmp)->following));
4693 /* You are digging in the shop. */
4694 void
4695 shopdig(fall)
4696 register int fall;
4698 register struct monst *shkp = shop_keeper(*u.ushops);
4699 int lang;
4700 const char *grabs = "grabs";
4702 if(!shkp) return;
4704 /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */
4705 lang = 0;
4706 if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data))
4707 ; /* lang stays 0 */
4708 else if (shkp->data->msound <= MS_ANIMAL)
4709 lang = 1;
4710 else if (shkp->data->msound >= MS_HUMANOID)
4711 lang = 2;
4713 if(!inhishop(shkp)) {
4714 if (Role_if(PM_KNIGHT) || (uwep && uwep->otyp == HONOR_KATANA) || (u.twoweap && uswapwep && uswapwep->otyp == HONOR_KATANA) || Role_if(PM_CHEVALIER) || Role_if(PM_PALADIN)) {
4715 You_feel("like a common thief.");
4716 adjalign(-sgn(u.ualign.type));
4718 /* WAC He may not be here now, but... */
4719 make_angry_shk(shkp, 0, 0); /* No spot in particular*/
4720 return;
4723 if(!fall) {
4724 if (lang == 2) {
4725 if(u.utraptype == TT_PIT)
4726 verbalize(
4727 "Be careful, %s, or you might fall through the floor.",
4728 flags.female ? "madam" : "sir");
4729 else
4730 verbalize("%s, do not damage the floor here!",
4731 flags.female ? "Madam" : "Sir");
4733 if (Role_if(PM_KNIGHT) || (uwep && uwep->otyp == HONOR_KATANA) || (u.twoweap && uswapwep && uswapwep->otyp == HONOR_KATANA) || Role_if(PM_CHEVALIER) || Role_if(PM_PALADIN)) {
4734 You_feel("like a common thief.");
4735 adjalign(-sgn(u.ualign.type));
4737 } else if(!um_dist(shkp->mx, shkp->my, 5) &&
4738 !shkp->msleeping && shkp->mcanmove &&
4739 (ESHK(shkp)->billct || ESHK(shkp)->debit)) {
4740 register struct obj *obj, *obj2;
4741 if (nolimbs(shkp->data)) {
4742 grabs = "knocks off";
4743 #if 0
4744 /* This is what should happen, but for balance
4745 * reasons, it isn't currently.
4747 if (lang == 2)
4748 pline("%s curses %s inability to grab your backpack!",
4749 shkname(shkp), mhim(shkp));
4750 rile_shk(shkp);
4751 return;
4752 #endif
4754 if (distu(shkp->mx, shkp->my) > 2) {
4755 mnexto(shkp);
4756 /* for some reason the shopkeeper can't come next to you */
4757 if (distu(shkp->mx, shkp->my) > 2) {
4758 if (lang == 2)
4759 pline("%s curses you in anger and frustration!",
4760 shkname(shkp));
4761 rile_shk(shkp);
4762 return;
4763 } else
4764 pline("%s %s, and %s your backpack!",
4765 shkname(shkp),
4766 makeplural(locomotion(shkp->data,"leap")), grabs);
4767 } else
4768 pline("%s %s your backpack!", shkname(shkp), grabs);
4770 for(obj = invent; obj; obj = obj2) {
4771 obj2 = obj->nobj;
4772 if ((obj->owornmask & ~(W_SWAPWEP|W_QUIVER)) != 0 ||
4773 (obj == uswapwep && u.twoweap) ||
4774 (obj->otyp == LEATHER_LEASH && obj->leashmon) || (obj->otyp == INKA_LEASH && obj->leashmon) || (obj->otyp == ADAMANT_LEASH && obj->leashmon) ) continue;
4775 if (obj == current_wand) continue;
4776 setnotworn(obj);
4777 freeinv(obj);
4778 subfrombill(obj, shkp);
4779 (void) add_to_minv(shkp, obj); /* may free obj */
4781 } else
4782 /* WAC He may not be here now, but... */
4783 rile_shk(shkp);
4786 /* modified by M. Campostrini (campo@sunthpi3.difi.unipi.it) */
4787 /* to allow for multiple choices of kops */
4788 /* modified even more by Amy to allow for even greater choice */
4789 STATIC_OVL void
4790 makekops(mm)
4791 coord *mm;
4793 int kop_cnt[6];
4794 int kop_pm[7];
4795 int ik, cnt;
4796 coord *mc;
4798 kop_pm[0] = PM_KEYSTONE_KOP;
4799 kop_pm[1] = PM_KOP_SERGEANT;
4800 kop_pm[2] = PM_KOP_LIEUTENANT;
4801 kop_pm[3] = PM_KOP_KAPTAIN;
4802 kop_pm[4] = PM_KOP_KOMMISSIONER;
4803 kop_pm[5] = PM_KOP_KCHIEF;
4804 kop_pm[6] = 0;
4806 cnt = abs(depth(&u.uz)) + rnd(5);
4808 if (Is_blackmarket(&u.uz)) {
4809 kop_pm[0] = PM_SOLDIER;
4810 kop_pm[1] = PM_SERGEANT;
4811 kop_pm[2] = PM_LIEUTENANT;
4812 kop_pm[3] = PM_CAPTAIN;
4813 kop_pm[4] = 0;
4814 kop_pm[5] = 0;
4815 kop_pm[6] = 0;
4817 cnt = 7 + rnd(5);
4819 if (Role_if(PM_CAMPERSTRIKER)) cnt *= (rn2(5) ? 2 : rn2(5) ? 3 : 5);
4822 kop_cnt[0] = cnt;
4823 kop_cnt[1] = (cnt / 3) + 1; /* at least one sarge */
4824 kop_cnt[2] = (cnt / 5) + 1; /* maybe a lieutenant */
4825 kop_cnt[3] = (cnt / 8) + 1; /* and maybe a kaptain */
4826 kop_cnt[4] = (cnt / 12) + 1; /* and maybe a kaptain */
4827 kop_cnt[5] = (cnt / 16) + 1; /* and maybe a kaptain */
4829 if (uarmh && itemhasappearance(uarmh, APP_ANTI_GOVERNMENT_HELMET) ) {
4830 kop_cnt[0] = ( kop_cnt[0] / 2) + 1;
4831 kop_cnt[1] = ( kop_cnt[1] / 2) + 1;
4832 kop_cnt[2] = ( kop_cnt[2] / 2) + 1;
4833 kop_cnt[3] = ( kop_cnt[3] / 2) + 1;
4834 kop_cnt[4] = ( kop_cnt[4] / 2) + 1;
4835 kop_cnt[5] = ( kop_cnt[5] / 2) + 1;
4838 if (RngeAntiGovernment) {
4839 kop_cnt[0] = ( kop_cnt[0] / 2) + 1;
4840 kop_cnt[1] = ( kop_cnt[1] / 2) + 1;
4841 kop_cnt[2] = ( kop_cnt[2] / 2) + 1;
4842 kop_cnt[3] = ( kop_cnt[3] / 2) + 1;
4843 kop_cnt[4] = ( kop_cnt[4] / 2) + 1;
4844 kop_cnt[5] = ( kop_cnt[5] / 2) + 1;
4847 if (Aggravate_monster) {
4848 u.aggravation = 1;
4849 reset_rndmonst(NON_PM);
4852 mc = (coord *)alloc(cnt * sizeof(coord));
4853 for (ik=0; kop_pm[ik]; ik++) {
4854 /*if (!(mvitals[kop_pm[ik]].mvflags & G_GONE)) {*/
4855 cnt = epathto(mc, kop_cnt[ik], mm->x, mm->y, &mons[kop_pm[ik]]);
4856 while(--cnt >= 0) {
4857 switch (rnd(303)) {
4858 case 1:
4859 case 2:
4860 case 3:
4861 case 4:
4862 case 5:
4863 case 6:
4864 case 7:
4865 case 8:
4866 case 9:
4867 case 10:
4868 (void) makemon(&mons[PM_ANGRY_WATCHMAN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4869 break;
4870 case 11:
4871 (void) makemon(&mons[rn2(2) ? PM_MEDIEVAL_SOLDIER : PM_VIDEO_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4872 break;
4873 case 12:
4874 (void) makemon(&mons[PM_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4875 break;
4876 case 13:
4877 (void) makemon(&mons[PM_COPPER_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4878 break;
4879 case 14:
4880 (void) makemon(&mons[PM_TEUTON_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4881 break;
4882 case 15:
4883 (void) makemon(&mons[PM_PAD_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4884 break;
4885 case 16:
4886 (void) makemon(&mons[PM_FRANKISH_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4887 break;
4888 case 17:
4889 (void) makemon(&mons[PM_GAUCHE_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4890 break;
4891 case 18:
4892 (void) makemon(&mons[PM_BRITISH_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4893 break;
4894 case 19:
4895 (void) makemon(&mons[PM_JAVA_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4896 break;
4897 case 20:
4898 (void) makemon(&mons[PM_AMERICAN_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4899 break;
4900 case 21:
4901 (void) makemon(&mons[PM_SWAMP_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4902 break;
4903 case 22:
4904 (void) makemon(&mons[PM_ARAB_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4905 break;
4906 case 23:
4907 (void) makemon(&mons[PM_VIKING_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4908 break;
4909 case 24:
4910 (void) makemon(&mons[PM_ASIAN_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4911 break;
4912 case 25:
4913 (void) makemon(&mons[PM_VANILLA_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4914 break;
4915 case 26:
4916 (void) makemon(&mons[PM_SEAFARING_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4917 break;
4918 case 27:
4919 (void) makemon(&mons[PM_ROHIRRIM_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4920 break;
4921 case 28:
4922 (void) makemon(&mons[PM_BYZANTINE_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4923 break;
4924 case 29:
4925 (void) makemon(&mons[PM_IBERIAN_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4926 break;
4927 case 30:
4928 (void) makemon(&mons[PM_CELTIC_SOLDIER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
4929 break;
4930 case 31:
4931 case 32:
4932 case 33:
4933 case 34:
4934 case 35:
4935 case 36:
4936 case 37:
4937 case 38:
4938 case 39:
4939 case 40:
4940 case 41:
4941 case 42:
4942 case 43:
4943 case 44:
4944 case 45:
4945 case 46:
4946 case 47:
4947 case 48:
4948 case 49:
4949 case 50:
4950 case 51:
4951 case 52:
4952 case 53:
4953 case 54:
4954 case 55:
4955 case 56:
4956 case 57:
4957 case 58:
4958 case 59:
4959 case 60:
4960 case 61:
4961 case 62:
4962 case 63:
4963 case 64:
4964 case 65:
4965 case 66:
4966 case 67:
4967 case 68:
4968 case 69:
4969 case 70:
4970 case 71:
4971 case 72:
4972 case 73:
4973 case 74:
4974 case 75:
4975 case 76:
4976 case 77:
4977 case 78:
4978 case 79:
4979 case 80:
4980 case 81:
4981 case 82:
4982 case 83:
4983 case 84:
4984 case 85:
4985 case 86:
4986 case 87:
4987 case 88:
4988 case 89:
4989 case 90:
4990 case 91:
4991 case 92:
4992 case 93:
4993 case 94:
4994 case 95:
4995 case 96:
4996 case 97:
4997 case 98:
4998 case 99:
4999 case 100:
5000 (void) makemon(&mons[PM_KEYSTONE_KOP], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5001 break;
5002 case 101:
5003 case 102:
5004 case 103:
5005 case 104:
5006 case 105:
5007 case 106:
5008 (void) makemon(&mons[PM_ANGRY_WATCH_CAPTAIN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5009 break;
5010 case 107:
5011 case 108:
5012 case 109:
5013 (void) makemon(&mons[PM_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5014 break;
5015 case 110:
5016 (void) makemon(&mons[PM_ORANGE_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5017 break;
5018 case 111:
5019 (void) makemon(&mons[PM_TWOWEAP_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5020 break;
5021 case 112:
5022 (void) makemon(&mons[PM_EXTRATERRESTRIAL_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5023 break;
5024 case 113:
5025 (void) makemon(&mons[PM_MINOAN_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5026 break;
5027 case 114:
5028 (void) makemon(&mons[PM_HUN_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5029 break;
5030 case 115:
5031 (void) makemon(&mons[PM_MONGOL_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5032 break;
5033 case 116:
5034 (void) makemon(&mons[PM_PERSIAN_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5035 break;
5036 case 117:
5037 case 118:
5038 case 119:
5039 case 120:
5040 case 121:
5041 case 122:
5042 case 123:
5043 case 124:
5044 case 125:
5045 case 126:
5046 case 127:
5047 case 128:
5048 case 129:
5049 case 130:
5050 case 131:
5051 case 132:
5052 case 133:
5053 case 134:
5054 case 135:
5055 case 136:
5056 case 137:
5057 case 138:
5058 case 139:
5059 case 140:
5060 case 141:
5061 case 142:
5062 case 143:
5063 case 144:
5064 case 145:
5065 case 146:
5066 case 147:
5067 case 148:
5068 case 149:
5069 case 150:
5070 (void) makemon(&mons[PM_KOP_SERGEANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5071 break;
5072 case 151:
5073 case 152:
5074 case 153:
5075 (void) makemon(&mons[PM_ANGRY_WATCH_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5076 break;
5077 case 154:
5078 case 155:
5079 (void) makemon(&mons[PM_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5080 break;
5081 case 156:
5082 (void) makemon(&mons[PM_YAMATO_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5083 break;
5084 case 157:
5085 (void) makemon(&mons[PM_CARTHAGE_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5086 break;
5087 case 158:
5088 (void) makemon(&mons[PM_ROMAN_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5089 break;
5090 case 159:
5091 case 160:
5092 case 161:
5093 case 162:
5094 case 163:
5095 case 164:
5096 case 165:
5097 case 166:
5098 case 167:
5099 case 168:
5100 case 169:
5101 case 170:
5102 case 171:
5103 case 172:
5104 case 173:
5105 case 174:
5106 case 175:
5107 case 176:
5108 case 177:
5109 case 178:
5110 case 179:
5111 case 180:
5112 (void) makemon(&mons[PM_KOP_LIEUTENANT], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5113 break;
5114 case 181:
5115 (void) makemon(&mons[PM_CAPTAIN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5116 break;
5117 case 182:
5118 (void) makemon(&mons[PM_URBAN_CAMO_CAPTAIN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5119 break;
5120 case 183:
5121 (void) makemon(&mons[PM_GOTHIC_CAPTAIN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5122 break;
5123 case 184:
5124 case 185:
5125 case 186:
5126 case 187:
5127 case 188:
5128 case 189:
5129 case 190:
5130 case 191:
5131 (void) makemon(&mons[PM_KOP_KAPTAIN], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5132 break;
5133 case 192:
5134 (void) makemon(&mons[PM_GENERAL], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5135 break;
5136 case 193:
5137 case 194:
5138 case 195:
5139 case 196:
5140 case 197:
5141 (void) makemon(&mons[PM_KOP_KOMMISSIONER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5142 break;
5143 case 198:
5144 case 199:
5145 case 200:
5146 (void) makemon(&mons[PM_KOP_KCHIEF], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5147 break;
5148 case 201:
5149 (void) makemon(&mons[PM_UNGENOCIDABLE_ARCH_LICH], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5150 break;
5151 case 202:
5152 (void) makemon(&mons[PM_ANGRY_WATCH_LEADER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5153 break;
5154 case 203:
5155 (void) makemon(&mons[PM_KOP_KATCHER], mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5156 break;
5157 default: /* can spawn sephirahs and similar things --Amy */
5158 (void) makemon(mkclass(S_KOP,0), mc[cnt].x, mc[cnt].y, MM_ANGRY|MM_ADJACENTOK|MM_FRENZIED);
5159 break;
5160 } /* switch */
5162 if (!rn2(100)) {
5164 int koptryct = 0;
5165 int kox, koy;
5167 for (koptryct = 0; koptryct < 2000; koptryct++) {
5168 kox = rn1(COLNO-3,2);
5169 koy = rn2(ROWNO);
5171 if (kox && koy && isok(kox, koy) && (levl[kox][koy].typ > DBWALL) && !(t_at(kox, koy)) ) {
5172 (void) maketrap(kox, koy, KOP_CUBE, 0, FALSE);
5173 break;
5181 /*}*/
5184 u.aggravation = 0;
5186 free((void *)mc);
5189 void
5190 pay_for_damage(dmgstr, cant_mollify)
5191 const char *dmgstr;
5192 boolean cant_mollify;
5194 register struct monst *shkp = (struct monst *)0;
5195 char shops_affected[5];
5196 register boolean uinshp = (*u.ushops != '\0');
5197 char qbuf[80];
5198 register xchar x, y;
5199 boolean dugwall = !strcmp(dmgstr, "dig into") || /* wand */
5200 !strcmp(dmgstr, "damage"); /* pick-axe */
5201 struct damage *tmp_dam, *appear_here = 0;
5202 /* any number >= (80*80)+(24*24) would do, actually */
5203 long cost_of_damage = 0L;
5204 unsigned int nearest_shk = 7000, nearest_damage = 7000;
5205 int picks = 0;
5207 for (tmp_dam = level.damagelist;
5208 (tmp_dam && (tmp_dam->when == monstermoves));
5209 tmp_dam = tmp_dam->next) {
5210 char *shp;
5212 if (!tmp_dam->cost)
5213 continue;
5214 cost_of_damage += tmp_dam->cost;
5215 strcpy(shops_affected,
5216 in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
5217 for (shp = shops_affected; *shp; shp++) {
5218 struct monst *tmp_shk;
5219 unsigned int shk_distance;
5221 if (!(tmp_shk = shop_keeper(*shp)))
5222 continue;
5223 if (tmp_shk == shkp) {
5224 unsigned int damage_distance =
5225 distu(tmp_dam->place.x, tmp_dam->place.y);
5227 if (damage_distance < nearest_damage) {
5228 nearest_damage = damage_distance;
5229 appear_here = tmp_dam;
5231 continue;
5233 if (!inhishop(tmp_shk))
5234 continue;
5235 shk_distance = distu(tmp_shk->mx, tmp_shk->my);
5236 if (shk_distance > nearest_shk)
5237 continue;
5238 if ((shk_distance == nearest_shk) && picks) {
5239 if (rn2(++picks))
5240 continue;
5241 } else
5242 picks = 1;
5243 shkp = tmp_shk;
5244 nearest_shk = shk_distance;
5245 appear_here = tmp_dam;
5246 nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y);
5250 if (!cost_of_damage || !shkp)
5251 return;
5253 x = appear_here->place.x;
5254 y = appear_here->place.y;
5256 /* not the best introduction to the shk... */
5257 (void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ);
5259 /* if the shk is already on the war path, be sure it's all out */
5260 if(ANGRY(shkp) || ESHK(shkp)->following) {
5261 hot_pursuit(shkp);
5262 return;
5265 /* if the shk is not in their shop.. */
5266 if(!*in_rooms(shkp->mx,shkp->my,SHOPBASE)) {
5267 if(!cansee(shkp->mx, shkp->my))
5268 return;
5269 goto getcad;
5272 if(uinshp) {
5273 if(um_dist(shkp->mx, shkp->my, 1) &&
5274 !um_dist(shkp->mx, shkp->my, 3)) {
5275 pline("%s leaps towards you!", shkname(shkp));
5276 mnexto(shkp);
5278 if(um_dist(shkp->mx, shkp->my, 1)) goto getcad;
5279 } else {
5281 * Make shkp show up at the door. Effect: If there is a monster
5282 * in the doorway, have the hero hear the shopkeeper yell a bit,
5283 * pause, then have the shopkeeper appear at the door, having
5284 * yanked the hapless critter out of the way.
5286 if (MON_AT(x, y)) {
5287 if(flags.soundok) {
5288 You_hear("an angry voice:");
5289 verbalize("Out of my way, scum!");
5290 wait_synch();
5291 #if defined(UNIX) || defined(VMS)
5292 # if defined(SYSV) || defined(ULTRIX) || defined(VMS)
5293 (void)
5294 # endif
5295 sleep(1);
5296 #endif
5299 (void) mnearto(shkp, x, y, TRUE);
5302 if((um_dist(x, y, 1) && !uinshp) || cant_mollify ||
5303 #ifndef GOLDOBJ
5304 (u.ugold + ESHK(shkp)->credit) < cost_of_damage
5305 #else
5306 (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage
5307 #endif
5308 || !rn2(50)) {
5309 if(um_dist(x, y, 1) && !uinshp) {
5310 pline("%s shouts:", shkname(shkp));
5311 verbalize("Who dared %s my %s?", dmgstr,
5312 dugwall ? "shop" : "door");
5313 } else {
5314 getcad:
5315 verbalize("How dare you %s my %s?", dmgstr,
5316 dugwall ? "shop" : "door");
5318 hot_pursuit(shkp);
5319 return;
5322 if (Invis) Your("invisibility does not fool %s!", shkname(shkp));
5323 sprintf(qbuf,"\"Cad! You did %ld %s worth of damage!\" Pay? ",
5324 cost_of_damage, currency(cost_of_damage));
5325 if(yn(qbuf) != 'n') {
5326 cost_of_damage = check_credit(cost_of_damage, shkp);
5327 #ifndef GOLDOBJ
5328 u.ugold -= cost_of_damage;
5329 if (rn2(2) || cost_of_damage < 0) shkp->mgold += cost_of_damage;
5330 #else
5331 money2mon(shkp, cost_of_damage);
5332 #endif
5333 flags.botl = 1;
5334 pline("Mollified, %s accepts your restitution.",
5335 shkname(shkp));
5336 /* move shk back to his home loc */
5337 home_shk(shkp, FALSE);
5338 pacify_shk(shkp);
5339 } else {
5340 verbalize("Oh, yes! You'll pay!");
5341 hot_pursuit(shkp);
5342 adjalign(-sgn(u.ualign.type));
5345 #endif /*OVLB*/
5346 #ifdef OVL0
5347 /* called in dokick.c when we kick an object that might be in a store */
5348 boolean
5349 costly_spot(x, y)
5350 register xchar x, y;
5352 register struct monst *shkp;
5354 if (!level.flags.has_shop) return FALSE;
5355 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
5356 if(!shkp || !inhishop(shkp)) return(FALSE);
5358 return((boolean)(inside_shop(x, y) &&
5359 !(x == ESHK(shkp)->shk.x &&
5360 y == ESHK(shkp)->shk.y)));
5362 #endif /*OVL0*/
5363 #ifdef OVLB
5365 /* called by dotalk(sounds.c) when #chatting; returns obj if location
5366 contains shop goods and shopkeeper is willing & able to speak */
5367 struct obj *
5368 shop_object(x, y)
5369 register xchar x, y;
5371 register struct obj *otmp;
5372 register struct monst *shkp;
5374 if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp))
5375 return(struct obj *)0;
5377 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
5378 if (otmp->oclass != COIN_CLASS)
5379 break;
5380 /* note: otmp might have ->no_charge set, but that's ok */
5381 return (otmp && costly_spot(x, y) && NOTANGRY(shkp)
5382 && shkp->mcanmove && !shkp->msleeping)
5383 ? otmp : (struct obj *)0;
5386 /* give price quotes for all objects linked to this one (ie, on this spot) */
5387 void
5388 price_quote(first_obj)
5389 register struct obj *first_obj;
5391 register struct obj *otmp;
5392 char buf[BUFSZ], price[40];
5393 long cost;
5394 int cnt = 0;
5395 winid tmpwin;
5396 struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy));
5398 tmpwin = create_nhwindow(NHW_MENU);
5399 putstr(tmpwin, 0, "Fine goods for sale:");
5400 putstr(tmpwin, 0, "");
5401 for (otmp = first_obj; otmp; otmp = otmp->nexthere) {
5402 if (otmp->oclass == COIN_CLASS) continue;
5403 cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L :
5404 get_cost(otmp, (struct monst *)0);
5405 if (Has_contents(otmp))
5406 cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
5407 if (!cost) {
5408 strcpy(price, "no charge");
5409 } else {
5410 sprintf(price, "%ld %s%s", cost, currency(cost),
5411 otmp->quan > 1L ? " each" : "");
5413 sprintf(buf, "%s, %s", doname(otmp), price);
5414 putstr(tmpwin, 0, buf), cnt++;
5416 if (cnt > 1) {
5417 display_nhwindow(tmpwin, TRUE);
5418 } else if (cnt == 1) {
5419 if (first_obj->no_charge || first_obj == uball || first_obj == uchain){
5420 pline("%s!", buf); /* buf still contains the string */
5421 } else {
5422 /* print cost in slightly different format, so can't reuse buf */
5423 cost = get_cost(first_obj, (struct monst *)0);
5424 if (Has_contents(first_obj))
5425 cost += contained_cost(first_obj, shkp, 0L, FALSE, FALSE);
5426 pline("%s, price %ld %s%s%s", doname(first_obj),
5427 cost, currency(cost), first_obj->quan > 1L ? " each" : "",
5428 shk_embellish(first_obj, cost));
5431 destroy_nhwindow(tmpwin);
5433 #endif /*OVLB*/
5434 #ifdef OVL3
5436 STATIC_OVL const char *
5437 shk_embellish(itm, cost)
5438 register struct obj *itm;
5439 long cost;
5441 if (!rn2(3)) {
5442 register int o, choice = rn2(5);
5443 if (choice == 0) choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3);
5444 switch (choice) {
5445 case 4:
5446 if (cost < 10L) break; else o = itm->oclass;
5447 if (o == FOOD_CLASS) return ", gourmets' delight!";
5448 if (objects[itm->otyp].oc_name_known
5449 ? objects[itm->otyp].oc_magic
5450 : (o == AMULET_CLASS || o == IMPLANT_CLASS || o == RING_CLASS ||
5451 o == WAND_CLASS || o == POTION_CLASS ||
5452 o == SCROLL_CLASS || o == SPBOOK_CLASS))
5453 return ", painstakingly developed!";
5454 return ", superb craftsmanship!";
5455 case 3: return ", finest quality.";
5456 case 2: return ", an excellent choice.";
5457 case 1: return ", a real bargain.";
5458 default: break;
5460 } else if (itm->oartifact) {
5461 return ", one of a kind!";
5463 return ".";
5465 #endif /*OVL3*/
5466 #ifdef OVLB
5468 /* First 4 supplied by Ronen and Tamar, remainder by development team
5469 * Amy edit: added two lines about poofy coffee */
5470 const char *Izchak_speaks[]={
5471 "%s says: 'These shopping malls give me a headache.'",
5472 "%s says: 'Slow down. Think clearly.'",
5473 "%s says: 'You need to take things one at a time.'",
5474 "%s says: 'I don't like poofy coffee... give me Columbian Supremo.'",
5475 "%s says: 'I don't like it if the 'poofy' word in my original line is changed to something else.'",
5476 "%s says: 'If I were still alive, seeing the 'poofy' from my original quote changed would cause me to turn over in my grave.'",
5477 "%s says that getting the devteam's agreement on anything is difficult.",
5478 "%s says that he has noticed those who serve their deity will prosper.",
5479 "%s says: 'Don't try to steal from me - I have friends in high places!'",
5480 "%s says: 'You may well need something from this shop in the future.'",
5481 "%s comments about the Valley of the Dead as being a gateway."
5484 void
5485 shk_chat(shkp)
5486 struct monst *shkp;
5488 struct eshk *eshk;
5489 #ifdef GOLDOBJ
5490 long shkmoney;
5491 #endif
5492 if (!shkp->isshk) {
5493 /* The monster type is shopkeeper, but this monster is
5494 not actually a shk, which could happen if someone
5495 wishes for a shopkeeper statue and then animates it.
5496 (Note: shkname() would be "" in a case like this.) */
5497 pline("%s asks whether you've seen any untended shops recently.",
5498 Monnam(shkp));
5499 /* [Perhaps we ought to check whether this conversation
5500 is taking place inside an untended shop, but a shopless
5501 shk can probably be expected to be rather disoriented.] */
5502 return;
5505 eshk = ESHK(shkp);
5506 if (ANGRY(shkp))
5507 pline("%s mentions how much %s dislikes %s customers.",
5508 shkname(shkp), mhe(shkp),
5509 eshk->robbed ? "non-paying" : "rude");
5510 else if (eshk->following) {
5511 if (strncmp(eshk->customer, plname, PL_NSIZ)) {
5512 verbalize("%s %s! I was looking for %s.",
5513 Hello(shkp), playeraliasname, eshk->customer);
5514 eshk->following = 0;
5515 } else {
5516 verbalize("%s %s! Didn't you forget to pay?",
5517 Hello(shkp), playeraliasname);
5519 } else if (eshk->billct) {
5520 register long total = addupbill(shkp) + eshk->debit;
5521 pline("%s says that your bill comes to %ld %s.",
5522 shkname(shkp), total, currency(total));
5523 } else if (eshk->debit)
5524 pline("%s reminds you that you owe %s %ld %s.",
5525 shkname(shkp), mhim(shkp),
5526 eshk->debit, currency(eshk->debit));
5527 else if (eshk->credit)
5528 pline("%s encourages you to use your %ld %s of credit.",
5529 shkname(shkp), eshk->credit, currency(eshk->credit));
5530 else if (eshk->robbed)
5531 pline("%s complains about a recent robbery.", shkname(shkp));
5532 #ifndef GOLDOBJ
5533 else if (shkp->mgold < 50)
5534 #else
5535 else if ((shkmoney = money_cnt(shkp->minvent)) < 50)
5536 #endif
5537 pline("%s complains that business is bad.", shkname(shkp));
5538 #ifndef GOLDOBJ
5539 else if (shkp->mgold > 4000)
5540 #else
5541 else if (shkmoney > 4000)
5542 #endif
5543 pline("%s says that business is good.", shkname(shkp));
5544 else if (strcmp(shkname(shkp), "Izchak") == 0)
5545 pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))],shkname(shkp));
5546 else
5547 pline("%s talks about the problem of shoplifters.",shkname(shkp));
5550 STATIC_OVL void
5551 kops_gone(silent) /* will no longer be called --Amy */
5552 register boolean silent;
5554 register int cnt = 0;
5555 register struct monst *mtmp, *mtmp2;
5557 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
5558 mtmp2 = mtmp->nmon;
5559 if (mtmp->data->mlet == S_KOP) {
5560 if (canspotmon(mtmp)) cnt++;
5561 mongone(mtmp);
5564 if (cnt && !silent)
5565 pline_The("Kop%s (disappointed) vanish%s into thin air.",
5566 plur(cnt), cnt == 1 ? "es" : "");
5569 #endif /*OVLB*/
5570 #ifdef OVL3
5572 STATIC_OVL long
5573 cost_per_charge(shkp, otmp, altusage)
5574 struct monst *shkp;
5575 struct obj *otmp;
5576 boolean altusage; /* some items have an "alternate" use with different cost */
5578 long tmp = 0L;
5580 if(!shkp || !inhishop(shkp)) return(0L); /* insurance */
5581 tmp = get_cost(otmp, shkp);
5583 /* The idea is to make the exhaustive use of */
5584 /* an unpaid item more expensive than buying */
5585 /* it outright. */
5586 /* KMH, balance patch -- removed abusive orbs */
5587 if(otmp->otyp == MAGIC_LAMP /*||
5588 otmp->otyp == ORB_OF_DESTRUCTION*/) { /* 1 */
5589 /* normal use (ie, as light source) of a magic lamp never
5590 degrades its value, but not charging anything would make
5591 identifcation too easy; charge an amount comparable to
5592 what is charged for an ordinary lamp (don't bother with
5593 angry shk surchage) */
5594 if (!altusage) tmp = (long) objects[OIL_LAMP].oc_cost;
5595 else tmp += tmp / 3L; /* djinni is being released */
5596 } else if(otmp->otyp == MAGIC_MARKER) { /* 70 - 100 */
5597 /* no way to determine in advance */
5598 /* how many charges will be wasted. */
5599 /* so, arbitrarily, one half of the */
5600 /* price per use. */
5601 tmp /= 2L;
5602 } else if(otmp->otyp == BAG_OF_TRICKS || /* 1 - 20 */
5603 otmp->otyp == MEDICAL_KIT ||
5604 otmp->otyp == HORN_OF_PLENTY) {
5605 tmp /= 5L;
5606 } else if(otmp->otyp == CRYSTAL_BALL || /* 1 - 5 */
5607 otmp->otyp == ORB_OF_ENCHANTMENT ||
5608 otmp->otyp == ORB_OF_CHARGING ||
5609 otmp->otyp == OIL_LAMP || /* 1 - 10 */
5610 otmp->otyp == BRASS_LANTERN ||
5611 otmp->otyp == DIM_LANTERN ||
5612 (otmp->otyp >= MAGIC_FLUTE &&
5613 otmp->otyp <= DRUM_OF_EARTHQUAKE) || /* 5 - 9 */
5614 otmp->oclass == WAND_CLASS) { /* 3 - 11 */
5615 if (otmp->spe > 1) tmp /= 4L;
5616 } else if (otmp->otyp == TORCH) {
5617 tmp /= 2L;
5618 } else if (otmp->oclass == SPBOOK_CLASS) {
5619 /* Normal use is studying. Alternate use is using up a charge */
5620 if (altusage) tmp /= 10L; /* 2 - 4 */
5621 else tmp -= tmp / 5L;
5622 } else if (otmp->otyp == CAN_OF_GREASE || otmp->otyp == LUBRICANT_CAN ||
5623 otmp->otyp == TINNING_KIT || otmp->otyp == BINNING_KIT
5624 || otmp->otyp == EXPENSIVE_CAMERA
5626 tmp /= 10L;
5627 } else if (otmp->otyp == POT_OIL) {
5628 tmp /= 5L;
5630 return(tmp);
5632 #endif /*OVL3*/
5633 #ifdef OVLB
5635 /* Charge the player for partial use of an unpaid object.
5637 * Note that bill_dummy_object() should be used instead
5638 * when an object is completely used.
5640 void
5641 check_unpaid_usage(otmp, altusage)
5642 struct obj *otmp;
5643 boolean altusage;
5645 struct monst *shkp;
5646 const char *fmt, *arg1, *arg2;
5647 long tmp;
5649 /* MRKR: Torches are a special case. As weapons they can have */
5650 /* a 'charge' == plus value, which is independent of their */
5651 /* use as a light source. */
5653 /* WAC - now checks for items that aren't carried */
5654 if ((!otmp->unpaid || !*u.ushops ||
5655 (otmp->spe <= 0 && objects[otmp->otyp].oc_charged &&
5656 otmp->otyp != TORCH))
5657 && (carried(otmp) || !costly_spot(otmp->ox, otmp->oy) ||
5658 otmp->no_charge))
5659 return;
5660 if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp))
5661 return;
5662 if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L)
5663 return;
5665 arg1 = arg2 = "";
5666 if (otmp->oclass == SPBOOK_CLASS && !altusage) {
5667 fmt = "%sYou owe%s %ld %s.";
5668 arg1 = rn2(2) ? "This is no free library, cad! " : "";
5669 arg2 = ESHK(shkp)->debit > 0L ? " an additional" : "";
5670 } else if (otmp->otyp == POT_OIL) {
5671 fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax).";
5672 } else {
5673 fmt = "%s%sUsage fee, %ld %s.";
5674 if (!rn2(3)) arg1 = "Hey! ";
5675 if (!rn2(3)) arg2 = "Ahem. ";
5678 if (shkp->mcanmove || !shkp->msleeping)
5679 verbalize(fmt, arg1, arg2, tmp, currency(tmp));
5680 ESHK(shkp)->debit += tmp;
5681 exercise(A_WIS, TRUE); /* you just got info */
5684 /* for using charges of unpaid objects "used in the normal manner" */
5685 void
5686 check_unpaid(otmp)
5687 struct obj *otmp;
5689 check_unpaid_usage(otmp, FALSE); /* normal item use */
5692 void
5693 costly_gold(x, y, amount)
5694 register xchar x, y;
5695 register long amount;
5697 register long delta;
5698 register struct monst *shkp;
5699 register struct eshk *eshkp;
5701 if(!costly_spot(x, y)) return;
5703 /* shkp now guaranteed to exist by costly_spot() */
5704 shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
5706 if (Race_if(PM_IRAHA) && shkp) {
5707 verbalize("You just signed your own death warrant, thief!");
5708 hot_pursuit(shkp);
5711 eshkp = ESHK(shkp);
5712 if(eshkp->credit >= amount) {
5713 if(eshkp->credit > amount)
5714 Your("credit is reduced by %ld %s.",
5715 amount, currency(amount));
5716 else Your("credit is erased.");
5717 eshkp->credit -= amount;
5718 } else {
5719 delta = amount - eshkp->credit;
5720 if(eshkp->credit)
5721 Your("credit is erased.");
5722 if(eshkp->debit)
5723 Your("debt increases by %ld %s.",
5724 delta, currency(delta));
5725 else You("owe %s %ld %s.",
5726 shkname(shkp), delta, currency(delta));
5727 eshkp->debit += delta;
5728 eshkp->loan += delta;
5729 eshkp->credit = 0L;
5733 /* used in domove to block diagonal shop-exit */
5734 /* x,y should always be a door */
5735 boolean
5736 block_door(x,y)
5737 register xchar x, y;
5739 register int roomno = *in_rooms(x, y, SHOPBASE);
5740 register struct monst *shkp;
5742 if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
5743 if(!IS_DOOR(levl[x][y].typ)) return(FALSE);
5744 if(roomno != *u.ushops) return(FALSE);
5746 if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
5747 return(FALSE);
5749 if(shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y
5750 /* Actually, the shk should be made to block _any_
5751 * door, including a door the player digs, if the
5752 * shk is within a 'jumping' distance.
5754 && ESHK(shkp)->shd.x == x && ESHK(shkp)->shd.y == y
5755 && shkp->mcanmove && !shkp->msleeping
5756 && (ESHK(shkp)->debit || ESHK(shkp)->billct ||
5757 ESHK(shkp)->robbed)) {
5758 pline("%s%s blocks your way!", shkname(shkp),
5759 Invis ? " senses your motion and" : "");
5760 return(TRUE);
5762 return(FALSE);
5765 /* used in domove to block diagonal shop-entry */
5766 /* u.ux, u.uy should always be a door */
5767 boolean
5768 block_entry(x,y)
5769 register xchar x, y;
5771 register xchar sx, sy;
5772 register int roomno;
5773 register struct monst *shkp;
5775 if(!(IS_DOOR(levl[u.ux][u.uy].typ) &&
5776 levl[u.ux][u.uy].doormask == D_BROKEN)) return(FALSE);
5778 roomno = *in_rooms(x, y, SHOPBASE);
5779 if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE);
5780 if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp))
5781 return(FALSE);
5783 if(ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy)
5784 return(FALSE);
5786 sx = ESHK(shkp)->shk.x;
5787 sy = ESHK(shkp)->shk.y;
5789 /* KMH, balacne patch -- allow other picks */
5790 if(shkp->mx == sx && shkp->my == sy
5791 && !(uarm && uarm->oartifact == ART_DEMANDING_ENTRY)
5792 && shkp->mcanmove && !shkp->msleeping
5793 && (x == sx-1 || x == sx+1 || y == sy-1 || y == sy+1)
5794 && (Invis || carrying(PICK_AXE) || carrying(CONGLOMERATE_PICK) || carrying(UNWIELDY_PICK) || carrying(CONUNDRUM_PICK) || carrying(MYSTERY_PICK) || carrying(BRONZE_PICK) || carrying(BRICK_PICK) || carrying(MYSTERIOUS_PICK) || carrying(NANO_PICK) || carrying(DWARVISH_MATTOCK) || carrying(SOFT_MATTOCK) || carrying(ETERNIUM_MATTOCK) || (u.usteed && !(uarm && uarm->oartifact == ART_FAER_ME) )
5795 )) {
5796 pline("%s%s blocks your way!", shkname(shkp),
5797 Invis ? " senses your motion and" : "");
5798 return(TRUE);
5800 return(FALSE);
5803 #endif /* OVLB */
5804 #ifdef OVL2
5806 char *
5807 shk_your(buf, obj)
5808 char *buf;
5809 struct obj *obj;
5811 if (!shk_owns(buf, obj) && !mon_owns(buf, obj))
5812 strcpy(buf, carried(obj) ? "your" : "the");
5813 return buf;
5816 char *
5817 Shk_Your(buf, obj)
5818 char *buf;
5819 struct obj *obj;
5821 (void) shk_your(buf, obj);
5822 *buf = highc(*buf);
5823 return buf;
5826 STATIC_OVL char *
5827 shk_owns(buf, obj)
5828 char *buf;
5829 struct obj *obj;
5831 struct monst *shkp;
5832 xchar x, y;
5834 if (get_obj_location(obj, &x, &y, 0) &&
5835 (obj->unpaid ||
5836 (obj->where==OBJ_FLOOR && !obj->no_charge && costly_spot(x,y)))) {
5837 shkp = shop_keeper(inside_shop(x, y));
5838 return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : "the");
5840 return (char *)0;
5843 STATIC_OVL char *
5844 mon_owns(buf, obj)
5845 char *buf;
5846 struct obj *obj;
5848 if (obj->where == OBJ_MINVENT)
5849 return strcpy(buf, s_suffix(mon_nam(obj->ocarry)));
5850 return (char *)0;
5853 #endif /* OVL2 */
5854 #ifdef OVLB
5856 #ifdef __SASC
5857 void
5858 sasc_bug(struct obj *op, unsigned x){
5859 op->unpaid=x;
5861 #endif
5863 static NEARDATA const char identify_types[] = { ALL_CLASSES, 0 };
5864 static NEARDATA const char weapon_types[] = { WEAPON_CLASS, TOOL_CLASS, CHAIN_CLASS, VENOM_CLASS, BALL_CLASS, GEM_CLASS, 0 };
5865 static NEARDATA const char armor_types[] = { ARMOR_CLASS, 0 };
5868 ** FUNCTION shk_identify
5870 ** Pay the shopkeeper to identify an item.
5872 static NEARDATA const char ident_chars[] = "bp";
5874 static void
5875 shk_identify(slang, shkp)
5876 char *slang;
5877 struct monst *shkp;
5879 register struct obj *obj; /* The object to identify */
5880 int charge, mult; /* Cost to identify */
5882 char sbuf[BUFSZ];
5884 boolean guesswork; /* Will shkp be guessing? */
5885 boolean ripoff=FALSE; /* Shkp ripping you off? */
5886 char ident_type;
5888 /* Pick object */
5889 if ( !(obj = getobj(identify_types, "have identified"))) return;
5891 /* Will shk be guessing? */
5892 if ((guesswork = !shk_obj_match(obj, shkp)))
5894 verbalize("I don't handle that sort of item, but I could try...");
5897 /* Here we go */
5898 /* KMH -- fixed */
5899 if ((ESHK(shkp)->services & (SHK_ID_BASIC|SHK_ID_PREMIUM)) ==
5900 (SHK_ID_BASIC|SHK_ID_PREMIUM)) {
5901 ident_type = yn_function("[B]asic service or [P]remier",
5902 ident_chars, '\0');
5903 if (ident_type == '\0') return;
5904 } else if (ESHK(shkp)->services & SHK_ID_BASIC) {
5905 verbalize("I only offer basic identification.");
5906 ident_type = 'b';
5907 } else if (ESHK(shkp)->services & SHK_ID_PREMIUM) {
5908 verbalize("I only make complete identifications.");
5909 ident_type = 'p';
5913 ** Shopkeeper is ripping you off if:
5914 ** Basic service and object already known.
5915 ** Premier service, object known, + know blessed/cursed and
5916 ** rustproof, etc.
5918 if (obj->dknown && objects[obj->otyp].oc_name_known)
5920 if (ident_type=='b') ripoff=TRUE;
5921 if (ident_type=='p' && obj->bknown && obj->rknown && obj->known) ripoff=TRUE;
5924 /* Compute the charge */
5926 if (ripoff)
5928 if (no_cheat) {
5929 verbalize("That item's already identified!");
5930 return;
5932 /* Object already identified: Try and cheat the customer. */
5933 pline("%s chuckles greedily...", mon_nam(shkp));
5934 mult = 1;
5936 /* basic */
5937 } else if (ident_type=='b') mult = 1;
5939 /* premier */
5940 else mult = 2;
5942 /* note by Amy: greatly increased cost for items that are supposed to be hard to id, so that having access to this
5943 * service combined with lots of money doesn't completely trivialize the ID game... */
5945 switch (obj->oclass) {
5946 case AMULET_CLASS: charge = 1600 * mult;
5947 break;
5948 case IMPLANT_CLASS: charge = 2000 * mult;
5949 break;
5950 case WEAPON_CLASS: charge = 100 * mult;
5951 break;
5952 case ARMOR_CLASS: charge = 500 * mult;
5953 break;
5954 case FOOD_CLASS: charge = 50 * mult;
5955 break;
5956 case SCROLL_CLASS: charge = 750 * mult;
5957 break;
5958 case SPBOOK_CLASS: charge = 1250 * mult;
5959 break;
5960 case POTION_CLASS: charge = 750 * mult;
5961 break;
5962 case RING_CLASS: charge = 1500 * mult;
5963 break;
5964 case WAND_CLASS: charge = 1000 * mult;
5965 break;
5966 case TOOL_CLASS: charge = 250 * mult;
5967 break;
5968 case GEM_CLASS: charge = 2000 * mult;
5969 break;
5970 default: charge = 400 * mult;
5971 break;
5974 /* Artifacts cost more to deal with */
5975 /* KMH -- Avoid floating-point */
5976 if (obj->oartifact) charge = charge * 3 / 2;
5978 /* Smooth out the charge a bit (lower bound only) */
5979 shk_smooth_charge(&charge, 25, NOBOUND);
5981 /* Go ahead? */
5982 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
5984 /* evil patch idea: buying the same service many times will eventually cause the shk to run out. --Amy */
5986 if (!rn2(10)) {
5987 if (ident_type == 'b') ESHK(shkp)->services &= ~SHK_ID_BASIC;
5988 if (ident_type == 'p') ESHK(shkp)->services &= ~SHK_ID_PREMIUM;
5991 /* Shopkeeper deviousness */
5992 if (ident_type == 'b') {
5993 if (Hallucination) {
5994 pline("You hear %s tell you it's a pot of flowers.",
5995 mon_nam(shkp));
5996 return;
5997 } else if (Confusion && !Conf_resist) {
5998 pline("%s tells you but you forget.", mon_nam(shkp));
5999 return;
6003 /* Is shopkeeper guessing? */
6004 if (guesswork)
6007 ** Identify successful if rn2() < #.
6009 if (!rn2(ident_type == 'b' ? 4 : 2)) {
6010 verbalize("Success! Let's try to identify your item...");
6011 /* Rest of msg will come from identify();
6012 * known quirk: the item may resist the identification attempt, this is not a bug
6013 * I added some extra message to make it clear that success isn't really guaranteed --Amy */
6014 } else {
6015 verbalize("Sorry. I guess it's not your lucky day.");
6016 return;
6020 /* Premier service */
6021 if (ident_type == 'p') {
6022 if (obj->oclass == SCROLL_CLASS && rnd(u.idscrollpenalty) > 100) pline("The scroll resisted your identification attempt!");
6023 else if (obj->oclass == POTION_CLASS && rnd(u.idpotionpenalty) > 3) pline("The potion resisted your identification attempt!");
6024 else if (obj->oclass == RING_CLASS && (!(obj->owornmask & W_RING) || ((rnd(u.idringpenalty) > 4) && (rnd(u.idringpenalty) > 4)) ) && rnd(u.idringpenalty) > 4) pline("The ring resisted your identification attempt!");
6025 else if (obj->oclass == AMULET_CLASS && (!(obj->owornmask & W_AMUL) || ((rnd(u.idamuletpenalty) > 15) && (rnd(u.idamuletpenalty) > 15)) )&& rnd(u.idamuletpenalty) > 15) pline("The amulet resisted your identification attempt!");
6026 else if (obj->oclass == IMPLANT_CLASS && (!(obj->owornmask & W_IMPLANT) || ((rnd(u.idimplantpenalty) > 1) && (rnd(u.idimplantpenalty) > 1)) )&& rnd(u.idimplantpenalty) > 1) pline("The implant resisted your identification attempt!");
6027 else if (obj->oclass == WAND_CLASS && rnd(u.idwandpenalty) > 3) pline("The wand resisted your identification attempt!");
6028 else if (obj->oclass == ARMOR_CLASS && (!(obj->owornmask & W_ARMOR) || ((rnd(u.idarmorpenalty) > 15) && (rnd(u.idarmorpenalty) > 15)) ) && rnd(u.idarmorpenalty) > 15) pline("The armor resisted your identification attempt!");
6029 else if (obj->oclass == SPBOOK_CLASS && rnd(u.idspellbookpenalty) > 2) pline("The spellbook resisted your identification attempt!");
6030 else if (obj->oclass == GEM_CLASS && rnd(u.idgempenalty) > 100) pline("The gem resisted your identification attempt!");
6031 else if (obj->oclass == TOOL_CLASS && rnd(u.idtoolpenalty) > 5) pline("The tool resisted your identification attempt!");
6032 else makeknown(obj->otyp);
6033 identify(obj);
6034 } else {
6035 /* Basic */
6036 if (obj->oclass == SCROLL_CLASS && rnd(u.idscrollpenalty) > 100) pline("The scroll resisted your identification attempt!");
6037 else if (obj->oclass == POTION_CLASS && rnd(u.idpotionpenalty) > 3) pline("The potion resisted your identification attempt!");
6038 else if (obj->oclass == RING_CLASS && (!(obj->owornmask & W_RING) || ((rnd(u.idringpenalty) > 4) && (rnd(u.idringpenalty) > 4)) ) && rnd(u.idringpenalty) > 4) pline("The ring resisted your identification attempt!");
6039 else if (obj->oclass == AMULET_CLASS && (!(obj->owornmask & W_AMUL) || ((rnd(u.idamuletpenalty) > 15) && (rnd(u.idamuletpenalty) > 15)) )&& rnd(u.idamuletpenalty) > 15) pline("The amulet resisted your identification attempt!");
6040 else if (obj->oclass == IMPLANT_CLASS && (!(obj->owornmask & W_IMPLANT) || ((rnd(u.idimplantpenalty) > 1) && (rnd(u.idimplantpenalty) > 1)) )&& rnd(u.idimplantpenalty) > 1) pline("The implant resisted your identification attempt!");
6041 else if (obj->oclass == WAND_CLASS && rnd(u.idwandpenalty) > 3) pline("The wand resisted your identification attempt!");
6042 else if (obj->oclass == ARMOR_CLASS && (!(obj->owornmask & W_ARMOR) || ((rnd(u.idarmorpenalty) > 15) && (rnd(u.idarmorpenalty) > 15)) ) && rnd(u.idarmorpenalty) > 15) pline("The armor resisted your identification attempt!");
6043 else if (obj->oclass == SPBOOK_CLASS && rnd(u.idspellbookpenalty) > 2) pline("The spellbook resisted your identification attempt!");
6044 else if (obj->oclass == GEM_CLASS && rnd(u.idgempenalty) > 100) pline("The gem resisted your identification attempt!");
6045 else if (obj->oclass == TOOL_CLASS && rnd(u.idtoolpenalty) > 5) pline("The tool resisted your identification attempt!");
6046 else makeknown(obj->otyp);
6047 obj->dknown = 1;
6048 prinv((char *)0, obj, 0L); /* Print result */
6054 ** FUNCTION shk_uncurse
6056 ** Uncurse an item for the customer
6058 static void
6059 shk_uncurse(slang, shkp)
6060 char *slang;
6061 struct monst *shkp;
6063 struct obj *obj; /* The object picked */
6064 int charge; /* How much to uncurse */
6065 boolean guesswork; /* Will shkp be guessing? */
6067 /* Pick object */
6068 if ( !(obj = getobj(identify_types, "uncurse"))) return;
6070 /* Will shk be guessing? */
6071 if ((guesswork = !shk_obj_match(obj, shkp)))
6073 verbalize("I don't handle that sort of item, but I could try...");
6076 /* Charge is same as cost */
6077 charge = get_cost(obj, shop_keeper(/* roomno= */*u.ushops));
6078 charge *= 3; /* uncursing shouldn't be possible for peanuts! --Amy */
6079 if (charge < 300) charge = 300; /* uncursing REALLY shouldn't be possible for peanuts */
6081 /* Artifacts cost more to deal with */
6082 /* KMH -- Avoid floating-point */
6083 if (obj->oartifact) charge = charge * 3 / 2;
6085 /* Smooth out the charge a bit */
6086 shk_smooth_charge(&charge, 50, NOBOUND);
6088 /* Go ahead? */
6089 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6091 if (!rn2(5)) { /* curses should not be meaningless --Amy */
6092 ESHK(shkp)->services &= ~SHK_UNCURSE;
6095 /* Shopkeeper responses */
6096 /* KMH -- fixed bknown, curse(), bless(), uncurse() */
6097 if (!obj->bknown && !Role_if(PM_PRIEST) && !Role_if(PM_NECROMANCER) && !Role_if(PM_CHEVALIER) &&
6098 !no_cheat)
6100 /* Not identified! */
6101 pline("%s snickers and says \"See, nice and uncursed!\"",
6102 mon_nam(shkp));
6103 obj->bknown = FALSE;
6105 else if (Confusion)
6107 if (rn2(10)) {
6108 You("accidentally point to the wrong item in your confusion.");
6109 } else {
6110 /* Curse the item! */
6111 You("accidentally ask for the item to be cursed");
6112 if (!stack_too_big(obj)) {
6113 curse(obj);
6114 if (obj->cursed && !rn2(3)) obj->hvycurse = TRUE;
6115 if (obj->cursed && !rn2(20)) obj->stckcurse = TRUE;
6116 if (obj->cursed && !rn2(100)) obj->prmcurse = TRUE;
6118 else pline("But the stack was so big that the shopkeeper failed to curse it.");
6121 else if (Hallucination)
6124 ** Let's have some fun: If you're hallucinating,
6125 ** then there's a chance for the object to be blessed!
6127 if (!rn2(10)) {
6128 pline("Distracted by your blood-shot %s, the shopkeeper",
6129 makeplural(body_part(EYE)));
6130 pline("accidentally curses the item!");
6131 if (!stack_too_big(obj)) {
6132 curse(obj);
6133 if (obj->cursed && !rn2(3)) obj->hvycurse = TRUE;
6134 if (obj->cursed && !rn2(20)) obj->stckcurse = TRUE;
6135 if (obj->cursed && !rn2(100)) obj->prmcurse = TRUE;
6137 else pline("But the stack was so big that the shopkeeper failed to curse it.");
6138 } else if (!rn2(10))
6140 pline("Distracted by your blood-shot %s, the shopkeeper",
6141 makeplural(body_part(EYE)));
6142 pline("accidentally blesses the item!");
6143 if (!stack_too_big(obj)) bless(obj);
6144 else pline("But the stack was so big that the blessing failed.");
6146 else
6148 You("can't see straight and point to the wrong item");
6151 /* Is shopkeeper guessing? */
6152 else if (guesswork) /* ported from identify function by Amy, because it makes no sense that they can uncurse everything */
6155 ** Uncurse successful 1 out of 5 times.
6157 if (!rn2(5)) {
6158 verbalize("Success!");
6159 if (!stack_too_big(obj)) uncurse(obj, TRUE);
6160 else pline("Whoops, sorry, actually no success because the stack was too big!");
6161 } else {
6162 verbalize("Sorry. I guess it's not your lucky day.");
6163 return;
6166 else
6168 verbalize("All done - safe to handle, now!");
6169 if (!stack_too_big(obj)) uncurse(obj, TRUE);
6170 else pline("But the stack was so big that the shopkeeper failed to uncurse it.");
6175 ** FUNCTION shk_bless
6177 ** Bless an item for the customer, by Amy, based on the uncurse code above
6179 static void
6180 shk_bless(slang, shkp)
6181 char *slang;
6182 struct monst *shkp;
6184 struct obj *obj; /* The object picked */
6185 int charge; /* How much to uncurse */
6186 boolean guesswork; /* Will shkp be guessing? */
6188 /* Pick object */
6189 if ( !(obj = getobj(identify_types, "bless"))) return;
6191 /* Will shk be guessing? */
6192 if ((guesswork = !shk_obj_match(obj, shkp)))
6194 verbalize("I don't handle that sort of item, but I could try...");
6197 /* Charge is same as cost */
6198 charge = get_cost(obj, shop_keeper(/* roomno= */*u.ushops));
6199 charge *= 5; /* blessing shouldn't be possible for peanuts! --Amy */
6200 if (charge < 500) charge = 500; /* uncursing REALLY shouldn't be possible for peanuts */
6202 /* Artifacts cost more to deal with */
6203 /* KMH -- Avoid floating-point */
6204 if (obj->oartifact) charge = charge * 3 / 2;
6206 /* Smooth out the charge a bit */
6207 shk_smooth_charge(&charge, 50, NOBOUND);
6209 /* Go ahead? */
6210 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6212 if (!rn2(5)) {
6213 ESHK(shkp)->services &= ~SHK_BLESS;
6216 /* Shopkeeper responses */
6217 /* KMH -- fixed bknown, curse(), bless(), uncurse() */
6218 if (!obj->bknown && !Role_if(PM_PRIEST) && !Role_if(PM_NECROMANCER) && !Role_if(PM_CHEVALIER) &&
6219 !no_cheat)
6221 /* Not identified! */
6222 pline("%s snickers and says \"Look, I blessed your item!\"", mon_nam(shkp));
6223 obj->bknown = FALSE;
6225 else if (obj->cursed) { /* this is not a "super-uncurse" service - it only works on uncursed stuff --Amy */
6226 verbalize("The blessing magic only works on items that aren't cursed! Get it uncursed first!");
6228 else if (Confusion)
6230 if (rn2(10)) {
6231 You("accidentally point to the wrong item in your confusion.");
6232 } else {
6233 /* Curse the item! */
6234 You("accidentally ask for the item to be cursed");
6235 if (!stack_too_big(obj)) {
6236 curse(obj);
6237 if (obj->cursed && !rn2(3)) obj->hvycurse = TRUE;
6238 if (obj->cursed && !rn2(20)) obj->stckcurse = TRUE;
6239 if (obj->cursed && !rn2(100)) obj->prmcurse = TRUE;
6241 else pline("But the stack was so big that the shopkeeper failed to curse it.");
6245 /* no special effect if you hallucinate */
6247 /* Is shopkeeper guessing? */
6248 else if (guesswork) /* ported from identify function by Amy, because it makes no sense that they can bless everything */
6251 ** Blessing successful 1 out of 5 times.
6253 if (!rn2(5)) {
6254 verbalize("Success!");
6255 if (!stack_too_big(obj)) bless(obj);
6256 else pline("Whoops, sorry, actually no success because the stack was too big!");
6257 } else {
6258 verbalize("Sorry. I guess it's not your lucky day.");
6259 return;
6262 else
6264 verbalize("All done - the gods themselves will watch over your item now!");
6265 if (!stack_too_big(obj)) bless(obj);
6266 else pline("But the stack was so big that the shopkeeper failed to bless it.");
6272 ** FUNCTION shk_appraisal
6274 ** Appraise a weapon or armor
6276 static const char basic_damage[] =
6277 "Basic damage against small foes %s, against large foes %s.";
6279 static void
6280 shk_appraisal(slang, shkp)
6281 char *slang;
6282 struct monst *shkp;
6284 struct obj *obj; /* The object picked */
6285 int charge; /* How much for appraisal */
6286 boolean guesswork; /* Shopkeeper unsure? */
6287 char ascii_wsdam[5]; /* Ascii form of damage */
6288 char ascii_wldam[5];
6291 /* Pick object */
6292 if ( !(obj = getobj(weapon_types, "appraise"))) return;
6294 charge = get_cost(obj, shop_keeper(/* roomno= */*u.ushops)) / 3;
6296 /* Smooth out the charge a bit */
6297 shk_smooth_charge(&charge, 5, NOBOUND);
6299 /* If not identified, complain. */
6300 /* KMH -- Why should it matter? */
6301 /* if ( ! (obj->known && objects[obj->otyp].oc_name_known) )
6303 verbalize("This weapon needs to be identified first!");
6304 return;
6305 } else */
6306 if (shk_class_match(WEAPON_CLASS, shkp) == SHK_MATCH)
6308 verbalize("Ok, %s, let's see what we have here.", slang);
6309 guesswork = FALSE;
6311 else
6313 verbalize("Mind you, I'm not an expert in this field.");
6314 guesswork = TRUE;
6317 /* Go ahead? */
6318 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6320 if (!rn2(1000)) {
6321 ESHK(shkp)->services &= ~SHK_APPRAISE;
6324 /* Shopkeeper deviousness */
6325 if (Confusion && !Conf_resist)
6327 pline("The numbers get all mixed up in your head.");
6328 return;
6330 else if (Hallucination)
6332 You("hear %s say it'll \"knock 'em dead\"",
6333 mon_nam(shkp));
6334 return;
6337 /* Convert damage to ascii */
6338 sprintf(ascii_wsdam, "%d", objects[obj->otyp].oc_wsdam);
6339 sprintf(ascii_wldam, "%d", objects[obj->otyp].oc_wldam);
6341 /* Will shopkeeper be unsure? */
6342 if (guesswork)
6344 switch (rn2(10))
6346 case 1:
6347 /* Shkp's an idiot */
6348 verbalize("Sorry, %s, but I'm not certain.", slang);
6349 break;
6351 case 2:
6352 /* Not sure about large foes */
6353 verbalize(basic_damage, ascii_wsdam, "?");
6354 break;
6356 case 3:
6357 /* Not sure about small foes */
6358 verbalize(basic_damage, "?", ascii_wldam);
6359 break;
6361 default:
6362 verbalize(basic_damage, ascii_wsdam, ascii_wldam);
6363 if (!issoviet) {
6364 obj->known = TRUE;
6365 if (u.weapchantrecskill < 1 || !rn2(u.weapchantrecskill)) {
6366 u.weapchantrecskill++;
6367 if (u.weapchantrecskill > 250) u.weapchantrecskill = 250;
6369 verbalize("It is %s", doname(obj));
6371 else pline("Sovetskiy khochet, chtoby vse bylo der'mo, dazhe izmeneniya, kotoryye, ochevidno, vygodny, schitayutsya im zlymi, potomu chto Emi sdelala ikh. Takim obrazom, plyus vashego oruzhiya ne oboznachen khar khar!");
6373 break;
6377 else
6379 verbalize(basic_damage, ascii_wsdam, ascii_wldam);
6381 /* Appraisal was too useless for way too long, so I decided to make it more useful. After all,
6382 * the appraisal technique also identifies the + of a weapon, so the service should do so too. --Amy
6383 * In Soviet Russia, nothing is ever allowed to be different from regular SLASH'EM, because SLASHTHEM
6384 * basically is SLASH'EM with some very minor changes. */
6386 if (!issoviet) {
6387 obj->known = TRUE;
6388 if (u.weapchantrecskill < 1 || !rn2(u.weapchantrecskill)) {
6389 u.weapchantrecskill++;
6390 if (u.weapchantrecskill > 250) u.weapchantrecskill = 250;
6392 verbalize("It is %s", doname(obj));
6394 else pline("Sovetskiy khochet, chtoby vse bylo der'mo, dazhe izmeneniya, kotoryye, ochevidno, vygodny, schitayutsya im zlymi, potomu chto Emi sdelala ikh. Takim obrazom, plyus vashego oruzhiya ne oboznachen khar khar!");
6400 ** FUNCTION shk_weapon_works
6402 ** Perform ops on weapon for customer
6404 static const char we_offer[] = "We offer the finest service available!";
6405 static void
6406 shk_weapon_works(slang, shkp)
6407 char *slang;
6408 struct monst *shkp;
6410 struct obj *obj;
6411 int charge;
6412 winid tmpwin;
6413 anything any;
6414 menu_item *selected;
6415 int service;
6416 int n;
6418 /* Pick weapon */
6419 if (ESHK(shkp)->services & (SHK_SPECIAL_A | SHK_SPECIAL_B))
6420 obj = getobj(weapon_types, "improve");
6421 else
6422 obj = getobj(weapon_types, "poison");
6423 if (!obj) return;
6425 /* Check if you asked for a non weapon tool to be improved */
6426 if (obj->oclass == TOOL_CLASS && !is_weptool(obj))
6427 pline("%s grins greedily...", mon_nam(shkp));
6429 if (ESHK(shkp)->services & (SHK_SPECIAL_A | SHK_SPECIAL_B)) {
6430 any.a_void = 0; /* zero out all bits */
6431 tmpwin = create_nhwindow(NHW_MENU);
6432 start_menu(tmpwin);
6434 if (ESHK(shkp)->services & SHK_SPECIAL_A) {
6435 any.a_int = 1;
6436 add_menu(tmpwin, NO_GLYPH, &any , 'w', 0, ATR_NONE,
6437 "Ward against damage", MENU_UNSELECTED);
6439 if (ESHK(shkp)->services & SHK_SPECIAL_B) {
6440 any.a_int = 2;
6441 add_menu(tmpwin, NO_GLYPH, &any , 'e', 0, ATR_NONE,
6442 "Enchant", MENU_UNSELECTED);
6445 /* Can object be poisoned? */
6446 if (ESHK(shkp)->services & SHK_SPECIAL_C) {
6447 any.a_int = 3;
6448 add_menu(tmpwin, NO_GLYPH, &any , 'p', 0, ATR_NONE,
6449 "Poison", MENU_UNSELECTED);
6452 end_menu(tmpwin, "Weapon-works:");
6453 n = select_menu(tmpwin, PICK_ONE, &selected);
6454 destroy_nhwindow(tmpwin);
6455 if (n > 0)
6456 service = selected[0].item.a_int;
6457 else
6458 service = 0;
6459 } else
6460 service = 3;
6462 /* Here we go */
6463 if (service > 0)
6464 verbalize(we_offer);
6465 else {
6466 pline("%s", Never_mind);
6467 if (FailureEffects || u.uprops[FAILURE_EFFECTS].extrinsic || have_failurestone()) {
6468 pline("Oh wait, actually I do mind...");
6469 badeffect();
6474 switch(service) {
6475 case 0:
6476 break;
6478 case 1:
6479 verbalize("This'll leave your %s untouchable!", xname(obj));
6481 /* Costs more the more eroded it is (oeroded 0-3 * 2) */
6482 charge = 5000;
6483 charge += ((obj->oeroded + obj->oeroded2) * 500);
6484 if (obj->oeroded + obj->oeroded2 > 2)
6485 verbalize("This thing's in pretty sad condition, %s", slang);
6487 /* Another warning if object is naturally rustproof */
6488 if (obj->oerodeproof || !is_damageable(obj))
6489 pline("%s gives you a suspciously happy smile...",
6490 mon_nam(shkp));
6492 /* Artifacts cost more to deal with */
6493 if (obj->oartifact) charge = charge * 3 / 2;
6495 /* Smooth out the charge a bit */
6496 shk_smooth_charge(&charge, 200, NOBOUND);
6498 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6500 if (!rn2(10)) {
6501 ESHK(shkp)->services &= ~SHK_SPECIAL_A;
6504 /* Have some fun, but for this $$$ it better work. */
6505 if (Confusion)
6506 You("fall over in appreciation");
6507 else if (Hallucination)
6508 Your(" - tin roof, un-rusted!");
6510 if (!stack_too_big(obj)) {obj->oeroded = obj->oeroded2 = 0;
6511 obj->rknown = TRUE;
6512 obj->oerodeproof = TRUE;
6513 } else pline("But it failed due to the stack being too big!");
6514 break;
6516 case 2:
6517 verbalize("Guaranteed not to harm your weapon, or your money back!");
6519 ** The higher the enchantment, the more costly!
6520 ** Gets to the point where you need to rob fort ludios
6521 ** in order to get it to +5!!
6523 charge = (obj->spe+1) * (obj->spe+1) * 625 * (obj->spe+1 > 5 ? (obj->spe+1) : 1);
6524 /* removed upper limit, but enchanting stuff beyond the former limit is much more expensive --Amy */
6526 if (obj->spe < 0) charge = 100;
6528 /* Artifacts cost more to deal with */
6529 if (obj->oartifact) charge *= 2;
6531 /* Smooth out the charge a bit (lower bound only) */
6532 shk_smooth_charge(&charge, 50, NOBOUND);
6534 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6536 if (!rn2(50)) {
6537 ESHK(shkp)->services &= ~SHK_SPECIAL_B;
6540 /*if (obj->spe+1 > 5) {
6541 verbalize("I can't enchant this any higher!");
6542 charge = 0;
6543 break;
6545 /* Have some fun! */
6546 if (Confusion)
6547 Your("%s unexpectedly!", aobjnam(obj, "vibrate"));
6548 else if (Hallucination)
6549 Your("%s to evaporate into thin air!", aobjnam(obj, "seem"));
6550 /* ...No actual vibrating and no evaporating */
6552 if (obj->otyp == WORM_TOOTH && !stack_too_big(obj) ) {
6553 obj->otyp = CRYSKNIFE;
6554 Your("weapon seems sharper now.");
6556 if ((obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(100) ) {
6557 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6559 else if (obj->prmcurse && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(10) ) {
6560 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6562 else if (!(obj->prmcurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && obj->hvycurse && !rn2(3) ) {
6563 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6565 else if (!(obj->prmcurse) && !(obj->hvycurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) ) obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6567 break;
6570 if (!stack_too_big(obj)) obj->spe++;
6571 else pline("The enchantment failed because the stack was too big.");
6572 break;
6574 case 3:
6576 if (!is_poisonable(obj)) {
6577 verbalize("That cannot be poisoned!");
6578 break;
6581 verbalize("Just imagine what poisoned %s can do!", xname(obj));
6583 charge = 10 * obj->quan;
6585 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6587 if (!rn2(100)) {
6588 ESHK(shkp)->services &= ~SHK_SPECIAL_C;
6591 obj->opoisoned = TRUE;
6592 break;
6594 default:
6595 impossible("Unknown Weapon Enhancement");
6596 break;
6602 ** FUNCTION shk_armor_works
6604 ** Perform ops on armor for customer
6606 static void
6607 shk_armor_works(slang, shkp)
6608 char *slang;
6609 struct monst *shkp;
6611 struct obj *obj;
6612 int charge;
6613 /*WAC - Windowstuff*/
6614 winid tmpwin;
6615 anything any;
6616 menu_item *selected;
6617 int n;
6619 /* Pick armor */
6620 if ( !(obj = getobj(armor_types, "improve"))) return;
6622 /* Here we go */
6623 /*WAC - did this using the windowing system...*/
6624 any.a_void = 0; /* zero out all bits */
6625 tmpwin = create_nhwindow(NHW_MENU);
6626 start_menu(tmpwin);
6627 any.a_int = 1;
6628 if (ESHK(shkp)->services & (SHK_SPECIAL_A))
6629 add_menu(tmpwin, NO_GLYPH, &any , 'r', 0, ATR_NONE, "Rust/Fireproof", MENU_UNSELECTED);
6630 any.a_int = 2;
6631 if (ESHK(shkp)->services & (SHK_SPECIAL_B))
6632 add_menu(tmpwin, NO_GLYPH, &any , 'e', 0, ATR_NONE, "Enchant", MENU_UNSELECTED);
6633 end_menu(tmpwin, "Armor-works:");
6634 n = select_menu(tmpwin, PICK_ONE, &selected);
6635 destroy_nhwindow(tmpwin);
6637 verbalize(we_offer);
6639 if (n > 0)
6640 switch(selected[0].item.a_int) {
6641 case 1:
6642 if (!flags.female && is_human(youmonst.data))
6643 verbalize("They'll call you the man of stainless steel!");
6645 /* Costs more the more rusty it is (oeroded 0-3), Amy edit: oeroded2 is also fixed */
6646 charge = 3000;
6647 charge += (obj->oeroded * 300);
6648 charge += (obj->oeroded2 * 300);
6649 if ((obj->oeroded + obj->oeroded2) > 2) verbalize("Yikes! This thing's a mess!");
6651 /* Artifacts cost more to deal with */
6652 /* KMH -- Avoid floating-point */
6653 if (obj->oartifact) charge = charge * 3 / 2;
6655 /* Smooth out the charge a bit */
6656 shk_smooth_charge(&charge, 100, NOBOUND);
6658 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6660 if (!rn2(10)) {
6661 ESHK(shkp)->services &= ~SHK_SPECIAL_A;
6664 /* Have some fun, but for this $$$ it better work. */
6665 if (Confusion)
6666 You("forget how to put your %s back on!", xname(obj));
6667 else if (Hallucination)
6668 You("mistake your %s for a pot and...", xname(obj));
6670 obj->oeroded = 0;
6671 obj->oeroded2 = 0;
6672 obj->rknown = TRUE;
6673 obj->oerodeproof = TRUE;
6674 break;
6676 case 2:
6677 verbalize("Nobody will ever hit on you again.");
6679 /* Higher enchantment levels cost more. */
6680 charge = (obj->spe+1) * (obj->spe+1) * 500 * (obj->spe+1 > 3 ? (obj->spe+1) : 1);
6681 /* removed upper limit, but enchanting stuff beyond the former limit is much more expensive --Amy */
6683 if (obj->spe < 0) charge = 100;
6685 /* Artifacts cost more to deal with */
6686 if (obj->oartifact) charge *= 2;
6688 /* Smooth out the charge a bit */
6689 shk_smooth_charge(&charge, 50, NOBOUND);
6691 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6693 if (!rn2(50)) {
6694 ESHK(shkp)->services &= ~SHK_SPECIAL_B;
6697 /*if (obj->spe+1 > 3) {
6698 verbalize("I can't enchant this any higher!");
6699 charge = 0;
6700 break;
6702 /* Have some fun! */
6703 if (Hallucination) Your("%s looks dented.", xname(obj));
6705 if (obj->otyp >= GRAY_DRAGON_SCALES &&
6706 obj->otyp <= YELLOW_DRAGON_SCALES) {
6707 /* dragon scales get turned into dragon scale mail */
6708 Your("%s merges and hardens!", xname(obj));
6709 setworn((struct obj *)0, W_ARM);
6710 /* assumes same order */
6711 obj->otyp = GRAY_DRAGON_SCALE_MAIL +
6712 obj->otyp - GRAY_DRAGON_SCALES;
6714 if ((obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(100) ) {
6715 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6717 else if (obj->prmcurse && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(10) ) {
6718 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6720 else if (!(obj->prmcurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && obj->hvycurse && !rn2(3) ) {
6721 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6723 else if (!(obj->prmcurse) && !(obj->hvycurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) ) obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6725 obj->known = 1;
6726 setworn(obj, W_ARM);
6727 break;
6730 if (obj->otyp == LIZARD_SCALES) {
6731 Your("%s merges and hardens!", xname(obj));
6732 setworn((struct obj *)0, W_ARM);
6733 obj->otyp = LIZARD_SCALE_MAIL;
6734 if ((obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(100) ) {
6735 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6737 else if (obj->prmcurse && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && !rn2(10) ) {
6738 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6740 else if (!(obj->prmcurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) && obj->hvycurse && !rn2(3) ) {
6741 obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6743 else if (!(obj->prmcurse) && !(obj->hvycurse) && !(obj->morgcurse || obj->evilcurse || obj->bbrcurse) ) obj->prmcurse = obj->hvycurse = obj->cursed = obj->morgcurse = obj->evilcurse = obj->bbrcurse = obj->stckcurse = 0;
6745 obj->known = 1;
6746 setworn(obj, W_ARM);
6747 break;
6750 obj->spe++;
6751 break;
6753 default:
6754 pline ("Unknown Armor Enhancement");
6755 break;
6761 ** FUNCTION shk_charge
6763 ** Charge something (for a price!)
6765 static NEARDATA const char wand_types[] = { WAND_CLASS, 0 };
6766 static NEARDATA const char tool_types[] = { TOOL_CLASS, 0 };
6767 static NEARDATA const char ring_types[] = { RING_CLASS, IMPLANT_CLASS, 0 };
6768 static NEARDATA const char spbook_types[] = { SPBOOK_CLASS, 0 };
6770 static void
6771 shk_charge(slang, shkp)
6772 char *slang;
6773 struct monst *shkp;
6775 struct obj *obj = NULL; /* The object picked */
6776 struct obj *tobj; /* Temp obj */
6777 char type; /* Basic/premier service */
6778 int charge; /* How much to charge customer */
6779 char invlet; /* Inventory letter */
6781 /* What type of shop are we? */
6782 if (shk_class_match(WAND_CLASS, shkp) == SHK_MATCH)
6783 obj = getobj(wand_types, "charge");
6784 else if (shk_class_match(TOOL_CLASS, shkp) == SHK_MATCH)
6785 obj = getobj(tool_types, "charge");
6786 else if (shk_class_match(RING_CLASS, shkp) == SHK_MATCH)
6787 obj = getobj(ring_types, "charge");
6788 else if (shk_class_match(SPBOOK_CLASS, shkp) == SHK_MATCH)
6789 obj = getobj(spbook_types, "charge");
6790 if (!obj) return;
6793 ** Wand shops can offer special service!
6794 ** Extra charges (for a lot of extra money!)
6795 * Amy edit: fuck you, why only wands? other items can also be either uncursed- or blessed-charged by scrolls,
6796 * so why the everloving fuck should only wand shops get that?
6799 /* What type of service? */
6800 if ((ESHK(shkp)->services & (SHK_SPECIAL_A|SHK_SPECIAL_B)) ==
6801 (SHK_SPECIAL_A|SHK_SPECIAL_B)) {
6802 type = yn_function("[B]asic service or [P]remier",
6803 ident_chars, '\0');
6804 if (type == '\0') return;
6805 } else if (ESHK(shkp)->services & SHK_SPECIAL_A) {
6806 pline ("I only perform basic charging.");
6807 type = 'b';
6808 } else if (ESHK(shkp)->services & SHK_SPECIAL_B) {
6809 pline ("I only perform complete charging.");
6810 type = 'p';
6813 /* Compute charge */
6814 if (type == 'b')
6815 charge = 3000;
6816 else
6817 charge = 10000;
6819 /* Wands of wishing should be hard to get recharged */
6820 if (obj->otyp == WAN_WISHING || obj->otyp == WAN_ACQUIREMENT)
6821 charge *= 3;
6822 else /* Smooth out the charge a bit */
6823 shk_smooth_charge(&charge, 100, NOBOUND);
6825 /* Go for it? */
6826 if (shk_offer_price(slang, charge, shkp) == FALSE) return;
6828 if (!rn2(15)) {
6829 if (type == 'b') ESHK(shkp)->services &= ~SHK_SPECIAL_A;
6830 if (type == 'p') ESHK(shkp)->services &= ~SHK_SPECIAL_B;
6833 /* Shopkeeper deviousness */
6834 if (( (Confusion && !Conf_resist) || Hallucination) && !no_cheat)
6836 pline("%s says it's charged and pushes you toward the door",
6837 Monnam(shkp));
6838 return;
6841 /* Do it */
6842 invlet = obj->invlet;
6843 recharge(obj, (type=='b') ? 0 : 1);
6846 ** Did the object blow up? We need to check this in a way
6847 ** that has nothing to do with dereferencing the obj pointer.
6848 ** We saved the inventory letter of this item; now cycle
6849 ** through all objects and see if there is an object
6850 ** with that letter.
6852 for(obj=0, tobj=invent; tobj; tobj=tobj->nobj)
6853 if(tobj->invlet == invlet)
6855 obj = tobj;
6856 break;
6858 if (!obj)
6860 verbalize("Oops! Sorry about that...");
6861 return;
6864 /* Wands get special treatment */
6865 if (obj->oclass == WAND_CLASS)
6867 /* Wand of wishing? */
6868 if (obj->otyp == WAN_WISHING || obj->otyp == WAN_CHARGING || obj->otyp == WAN_BAD_EQUIPMENT || obj->otyp == WAN_ACQUIREMENT)
6870 /* Premier gives you ONE more charge */
6871 /* KMH -- Okay, but that's pretty generous */
6872 if (type == 'p') obj->spe++;
6874 /* Fun */
6875 if (obj->otyp == WAN_WISHING) {
6876 verbalize("Since you'll have everything you always wanted,");
6877 verbalize("...How about loaning me some money?");
6878 #ifndef GOLDOBJ
6879 if (rn2(2)) shkp->mgold += u.ugold;
6880 u.ugold = 0;
6881 #else
6882 money2mon(shkp, money_cnt(invent));
6883 #endif
6884 makeknown(obj->otyp);
6886 bot();
6888 else if (type == 'p')
6891 ** Basic: recharge() will have given 1 charge.
6892 ** Premier: recharge() will have given 5-10, say.
6893 ** Add a few more still. Note by Amy: but only if the player uses premier charging.
6895 if (obj->spe < 120) obj->spe += (obj->otyp == WAN_GENOCIDE ? rnd(2) : obj->otyp == WAN_GAIN_LEVEL ? rnd(2) : obj->otyp == WAN_INCREASE_MAX_HITPOINTS ? rnd(3) : rnd(5));
6896 /*else if (obj->spe < 20) obj->spe += 1;*/
6901 /* establish credit via shopkeeper service by Amy: always available on any shopkeeper, but disappears if you exceed
6902 * your credit limit. This is a way to establish credit without the shk cheating you, but the gold is deleted; this is
6903 * intentional because that way you can't steal it back or otherwise get stuff for nothing, credit cloner. :P */
6904 static void
6905 shk_estcredit(slang, shkp)
6906 char *slang;
6907 struct monst *shkp;
6909 char buf[BUFSZ];
6910 long offer;
6911 struct eshk *eshkp = ESHK(shkp);
6913 if (!u.ugold) {
6914 pline("It seems that you have no money.");
6915 return;
6918 getlin("How much credit do you want to establish?", buf);
6919 if (sscanf(buf, "%ld", &offer) != 1) offer = 0L;
6921 if (offer < 0L) {
6922 pline("Enter a positive number, please.");
6923 return;
6924 } else if (offer == 0L) {
6925 pline("You've changed your mind.");
6926 return;
6927 } else if (offer > u.ugold) {
6928 You("don't have that much!");
6929 return;
6930 } else {
6931 if ((eshkp->totalcredit + offer) > eshkp->creditlimit) {
6932 offer = (eshkp->creditlimit - eshkp->totalcredit);
6933 ESHK(shkp)->services &= ~SHK_CREDITSRV;
6934 verbalize("That would exceed your credit limit! I'll only accept %ld zorkmids.", offer);
6936 u.ugold -= offer;
6937 eshkp->totalcredit += offer;
6938 eshkp->credit += offer;
6939 verbalize("Your total credit amounts to %ld zorkmids now. Thank you!", eshkp->credit);
6944 ** FUNCTION shk_obj_match
6946 ** Does object "obj" match the type of shop?
6948 static boolean
6949 shk_obj_match(obj, shkp)
6950 struct obj *obj;
6951 struct monst *shkp;
6953 /* object matches type of shop? */
6954 return(saleable(shkp, obj));
6959 ** FUNCTION shk_offer_price
6961 ** Tell customer how much it'll cost, ask if he wants to pay,
6962 ** and deduct from $$ if agreable.
6964 static boolean
6965 shk_offer_price(slang, charge, shkp)
6966 char *slang;
6967 long charge;
6968 struct monst *shkp;
6970 char sbuf[BUFSZ];
6971 long credit = ESHK(shkp)->credit;
6973 /* Ask y/n if player wants to pay */
6974 sprintf(sbuf, "It'll cost you %ld zorkmid%s. Interested?",
6975 charge, plur(charge));
6977 if ( yn(sbuf) != 'y' ) {
6978 verbalize("It's your call, %s.", slang);
6979 return(FALSE);
6982 /* Player _wants_ to pay, but can he? */
6983 /* WAC -- Check the credit: but don't use check_credit
6984 * since we don't want to charge him for part of it if he can't pay for all of it
6985 * Amy edit: credit cloning is such a filthy cheat... so you have to use cash for services now!
6986 * otherwise, we might as well make all services cost 1 zorkmid, including high-end enchant armor, since the player
6987 * will, in the case of doubt, just steal their money back
6989 #ifndef GOLDOBJ
6990 if (charge > u.ugold) {
6991 #else
6992 if (charge > money_cnt(invent) ) {
6993 #endif
6994 if (credit > 0) {
6995 verbalize((u.ualign.record < 0) ? "Sorry, services are cash only. There have been too many adventurers like you in the past who tried to cheat me and my colleagues." : "Sorry, services are cash only.");
6996 } else {
6997 verbalize("Cash on the spot, %s, and you ain't got the dough!", slang);
7000 return(FALSE);
7003 /* Charge the customer */
7004 /* charge = check_credit (charge, shkp); */ /* Deduct the credit first */
7006 #ifndef GOLDOBJ
7007 u.ugold -= charge;
7008 if (rn2(2) || charge < 0) shkp->mgold += charge;
7009 #else
7010 money2mon(shkp, charge);
7011 #endif
7012 bot();
7014 /* here's us throwing a bone to lawful politicians or evilvariant characters --Amy */
7015 if (u.ualign.type == A_LAWFUL) adjalign(1);
7016 u.cnd_shkserviceamount++;
7018 /* rarely, purchasing a service with very low CHA can increase it --Amy */
7019 if (ABASE(A_CHA) < 10) {
7020 int chachance = 100;
7021 switch (ABASE(A_CHA)) {
7022 case 1: chachance = 33; break;
7023 case 2: chachance = 66; break;
7024 case 3: chachance = 100; break;
7025 case 4: chachance = 150; break;
7026 case 5: chachance = 200; break;
7027 case 6: chachance = 250; break;
7028 case 7: chachance = 300; break;
7029 case 8: chachance = 350; break;
7030 case 9: chachance = 400; break;
7031 default: chachance = 500; break;
7033 if (!rn2(chachance)) (void) adjattrib(A_CHA, 1, FALSE, TRUE);
7036 return(TRUE);
7041 ** FUNCTION shk_smooth_charge
7043 ** Smooth out the lower/upper bounds on the price to get something
7044 ** done. Make sure that it (1) varies depending on charisma and
7045 ** (2) is constant.
7047 static void
7048 shk_smooth_charge(pcharge, lower, upper)
7049 int *pcharge;
7050 int lower;
7051 int upper;
7053 int charisma;
7054 int bonus;
7056 /* KMH -- Avoid using floating-point arithmetic */
7057 if(ACURR(A_CHA) > 21) *pcharge *= 11;
7058 else if(ACURR(A_CHA) > 18) *pcharge *= 12;
7059 else if(ACURR(A_CHA) > 15) *pcharge *= 13;
7060 else if(ACURR(A_CHA) > 12) *pcharge *= 14;
7061 else if(ACURR(A_CHA) > 10) *pcharge *= 15;
7062 else if(ACURR(A_CHA) > 8) *pcharge *= 16;
7063 else if(ACURR(A_CHA) > 7) *pcharge *= 17;
7064 else if(ACURR(A_CHA) > 6) *pcharge *= 18;
7065 else if(ACURR(A_CHA) > 5) *pcharge *= 19;
7066 else if(ACURR(A_CHA) > 4) *pcharge *= 20;
7067 else if(ACURR(A_CHA) > 3) *pcharge *= 21;
7068 else if(ACURR(A_CHA) > 2) *pcharge *= 23;
7069 else *pcharge *= 25;
7070 *pcharge /= 10;
7072 if (uarmh && !uarmh->oinvis && uarmh->otyp == DUNCE_CAP) *pcharge *= 2L;
7074 if (Role_if(PM_OTAKU)) *pcharge *= 3L; /* bad at making deals */
7075 if (Race_if(PM_DUTHOL)) *pcharge *= 2L;
7077 if (ACURR(A_CHA) == 2) *pcharge *= 2L;
7078 if (ACURR(A_CHA) == 1) *pcharge *= 3L;
7080 if (Race_if(PM_ZAUR)) *pcharge *= 2L;
7081 if (Race_if(PM_WYLVAN)) *pcharge *= 2L;
7082 if (Race_if(PM_URGOTH)) *pcharge *= 3L;
7084 if (Role_if(PM_BARBARIAN)) *pcharge *= 3L;
7085 if (Role_if(PM_NOOB_MODE_BARB)) *pcharge *= 5L;
7086 /* rogues are untrustworthy... */
7087 if (Role_if(PM_ROGUE)) *pcharge *= 2L;
7088 /* samurais are from out of town... */
7089 if (Role_if(PM_SAMURAI)) *pcharge *= 2L;
7090 if (uarmf && uarmf->oartifact == ART_CARMARK) *pcharge *= 2L;
7092 if (ublindf && ublindf->oartifact == ART_STRIKE_OVER_THE_EARS) *pcharge *= 2;
7094 if (Is_blackmarket(&u.uz)) *pcharge *= 3;
7095 /* Skip upper stuff? */
7096 if (upper == NOBOUND) goto check_lower;
7098 /* This should give us something like a charisma of 5 to 25. */
7099 charisma = ABASE(A_CHA) + ABON(A_CHA) + ATEMP(A_CHA);
7101 /* Now: 0 to 10 = 0. 11 and up = 1 to whatever. */
7102 if (charisma <= 10)
7103 charisma = 0;
7104 else
7105 charisma -= 10;
7107 /* Charismatic players get smaller upper bounds */
7108 bonus=((upper/50)*charisma);
7110 /* Adjust upper. Upper > lower! */
7111 upper -= bonus;
7112 upper = (upper>=lower) ? upper : lower;
7114 /* Ok, do the min/max stuff */
7115 if (*pcharge > upper) *pcharge=upper;
7116 check_lower:
7117 if (*pcharge < lower) *pcharge=lower;
7122 #endif /* OVLB */
7124 #ifdef DEBUG
7126 wiz_debug_cmd() /* in this case, display your bill(s) */
7128 int win, special = 0;
7129 struct obj *obj;
7130 struct monst *shkp, *ushkp;
7131 struct bill_x *bp;
7132 int ct;
7133 char buf[BUFSIZ];
7134 char buf2[BUFSIZ];
7136 win = create_nhwindow(NHW_MENU);
7137 ushkp = shop_keeper(*u.ushops);
7138 shkp = next_shkp(fmon, TRUE);
7139 if (!shkp) {
7140 shkp = ushkp;
7141 special++;
7143 if (!shkp)
7144 putstr(win, 0, "No shopkeepers with bills");
7145 else
7146 for (; shkp; ) {
7147 bp = ESHK(shkp)->bill_p;
7148 ct = ESHK(shkp)->billct;
7149 if (ct) {
7150 sprintf(buf, "Your bill with %s", noit_mon_nam(shkp));
7151 if (shkp == ushkp) {
7152 strcat(buf, " (here)");
7153 ushkp = NULL;
7155 strcat(buf, ":");
7156 putstr(win, 0, buf);
7157 putstr(win, 0, "Price Quan Used? Object");
7158 while (--ct >= 0) {
7159 obj = bp_to_obj(bp);
7160 if (obj) {
7161 if (!obj->unpaid)
7162 *buf2='*'; /* Bad entry */
7163 strcpy(obj->unpaid ? buf2 : buf2 + 1, xname(obj));
7165 else
7166 sprintf(buf2, "Unknown, with ID %d", bp->bo_id);
7167 sprintf(buf, "%-7d %-7d %-7s %s", bp->price, bp->bquan,
7168 bp->useup ? "Yes" : "No", buf2);
7169 putstr(win, 0, buf);
7170 bp++;
7173 else {
7174 sprintf(buf, "You do not owe %s anything.", noit_mon_nam(shkp));
7175 putstr(win, 0, buf);
7177 if (special)
7178 break;
7179 shkp = next_shkp(shkp->nmon, TRUE);
7180 if (!shkp) {
7181 shkp = ushkp;
7182 special++;
7184 if (shkp)
7185 putstr(win, 0, "");
7187 display_nhwindow(win, FALSE);
7188 destroy_nhwindow(win);
7189 return 0;
7191 #endif /* DEBUG */
7193 /*shk.c*/