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). */
15 #define PAY_CANT 0 /* too poor */
17 #define PAY_BROKE (-2)
19 STATIC_DCL
void makekops(coord
*);
20 STATIC_DCL
void call_kops(struct monst
*,BOOLEAN_P
);
22 STATIC_DCL
void kops_gone(BOOLEAN_P
);
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
*);
66 static boolean
rob_shop(struct monst
*);
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);
86 invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
87 obj->quan <= bp->bquan
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.
106 money2mon(mon
, amount
)
110 struct obj
*ygold
= findgold(invent
);
113 impossible("%s payment in money2mon!", amount
? "negative" : "zero");
116 if (!ygold
|| ygold
->quan
< amount
) {
117 impossible("Paying without %s money?", ygold
? "enough" : "");
121 if (ygold
->quan
> amount
)
122 ygold
= splitobj(ygold
, amount
);
123 else if (ygold
->owornmask
)
124 remove_worn_item(ygold
, FALSE
); /* quiver */
126 add_to_minv(mon
, ygold
);
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.
142 struct obj
*mongold
= findgold(mon
->minvent
);
145 impossible("%s payment in money2u!", amount
? "negative" : "zero");
148 if (!mongold
|| mongold
->quan
< amount
) {
149 impossible("%s paying without %s money?", a_monnam(mon
),
150 mongold
? "enough" : "");
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!");
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;
179 if (NOTANGRY(shkp
)) {
180 if (ESHK(shkp
)->surcharge
) pacify_shk(shkp
);
182 if (!ESHK(shkp
)->surcharge
) rile_shk(shkp
);
189 shkname(mtmp
) /* called in do_name.c */
190 register struct monst
*mtmp
;
192 return(ESHK(mtmp
)->shknam
);
196 shkgone(mtmp
) /* called in mon.c */
199 struct eshk
*eshk
= ESHK(mtmp
);
200 struct mkroom
*sroom
= &rooms
[eshk
->shoproom
- ROOMOFFSET
];
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
)
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) {
223 eshk
->bill_p
= (struct bill_x
*)0;
224 /* remove eshk->shoproom from u.ushops */
225 do { *p
= *(p
+ 1); } while (*++p
);
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
;
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 */
252 restshk(shkp
, ghostly
)
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 */
264 assign_level(&eshkp
->shoplevel
, &u
.uz
);
265 if (ANGRY(shkp
) && strncmpi(eshkp
->customer
, plname
, PL_NSIZ
))
274 /* Clear the unpaid bit on all of the objects in the list. */
277 register struct obj
*list
;
280 if (Has_contents(list
)) clear_unpaid(list
->cobj
);
288 /* either you paid or left the shop or the shopkeeper died */
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
);
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
);
313 ESHK(shkp
)->billct
= 0;
314 ESHK(shkp
)->credit
= 0L;
315 ESHK(shkp
)->debit
= 0L;
316 ESHK(shkp
)->loan
= 0L;
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;
329 total
+= bp
->price
* bp
->bquan
;
339 call_kops(shkp
, nearshop
)
340 register struct monst
*shkp
;
341 register boolean nearshop
;
343 /* Keystone Kops srt@ucla */
344 register boolean nokops
;
347 strcpy(kopname
, "Keystone Kops");
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.");
390 if (!Is_blackmarket(&u
.uz
))
392 /* Create swarm around you, if you merely "stepped out" */
394 pline_The("%s appear!", kopname
);
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
;
406 if (trap
->ttyp
== MAGIC_PORTAL
) {
417 /* Create swarm near shopkeeper (hinders return to shop) */
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) */
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
) {
445 pline("%s calls for %s assistants!",
446 noit_Monnam(shkp
), mhis(shkp
));
455 /* x,y is strictly inside shop */
462 rno
= levl
[x
][y
].roomno
;
463 if ((rno
< ROOMOFFSET
) || levl
[x
][y
].edge
|| !IS_SHOP(rno
-ROOMOFFSET
))
470 u_left_shop(leavestring
, newlev
)
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)
485 (!levl
[u
.ux
][u
.uy
].edge
|| levl
[u
.ux0
][u
.uy0
].edge
))
488 shkp
= shop_keeper(*u
.ushops0
);
489 if (!shkp
|| !inhishop(shkp
))
490 return; /* shk died, teleported, changed levels... */
493 if (!eshkp
->billct
&& !eshkp
->debit
) /* bill is settled */
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!",
508 if (rob_shop(shkp
)) {
510 if (Is_blackmarket(&u
.uz
))
513 call_kops(shkp
, (!newlev
&& levl
[u
.ux0
][u
.uy0
].edge
));
517 /* robbery from outside the shop via telekinesis or grappling hook */
519 remote_burglary(x
, y
)
525 shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
));
526 if (!shkp
|| !inhishop(shkp
))
527 return; /* shk died, teleported, changed levels... */
530 if (!eshkp
->billct
&& !eshkp
->debit
) /* bill is settled */
533 if (rob_shop(shkp
)) {
535 if (Is_blackmarket(&u
.uz
))
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 */
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() */
560 You("escaped the shop without paying!");
561 total
-= eshkp
->credit
;
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);
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);
596 u_entered_shop(enterstring
)
597 register char *enterstring
;
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];
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
))
614 strcpy(empty_shops
, u
.ushops
);
621 if (!inhishop(shkp
)) {
622 /* dump core when referenced */
623 eshkp
->bill_p
= (struct bill_x
*) -1000;
624 if (!index(empty_shops
, *enterstring
))
626 strcpy(empty_shops
, u
.ushops
);
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 */
637 eshkp
->following
= 0;
638 (void) strncpy(eshkp
->customer
,plname
,PL_NSIZ
);
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!");
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!");
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
;
669 verbalize("So, %s, you dare return to %s %s?!",
671 s_suffix(shkname(shkp
)),
672 shtypes
[rt
- SHOPBASE
].name
);
673 } else if (eshkp
->robbed
) {
674 pline("%s mutters imprecations against shoplifters.", shkname(shkp
));
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
;
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
) {
703 if (pick
&& mattock
) { /* carrying both types */
704 tool
= "digging tool";
705 cnt
= 2; /* `more than 1' is all that matters */
708 /* hack: `pick' already points somewhere into inventory */
709 while ((pick
= pick
->nobj
) != 0)
710 if (pick
->otyp
== PICK_AXE
) ++cnt
;
712 tool
= "conglomerate pick";
713 while ((pickB
= pickB
->nobj
) != 0)
714 if (pickB
->otyp
== CONGLOMERATE_PICK
) ++cnt
;
716 tool
= "bronze pick";
717 while ((pickC
= pickC
->nobj
) != 0)
718 if (pickC
->otyp
== BRONZE_PICK
) ++cnt
;
721 while ((pickD
= pickD
->nobj
) != 0)
722 if (pickD
->otyp
== BRICK_PICK
) ++cnt
;
725 while ((pickE
= pickE
->nobj
) != 0)
726 if (pickE
->otyp
== NANO_PICK
) ++cnt
;
728 tool
= "mystery pick";
729 while ((pickF
= pickF
->nobj
) != 0)
730 if (pickF
->otyp
== MYSTERY_PICK
) ++cnt
;
732 tool
= "conundrum pick";
733 while ((pickG
= pickG
->nobj
) != 0)
734 if (pickG
->otyp
== CONUNDRUM_PICK
) ++cnt
;
736 tool
= "mysterious pick";
737 while ((pickH
= pickH
->nobj
) != 0)
738 if (pickH
->otyp
== MYSTERIOUS_PICK
) ++cnt
;
740 tool
= "unwieldy pick";
741 while ((pickI
= pickI
->nobj
) != 0)
742 if (pickI
->otyp
== UNWIELDY_PICK
) ++cnt
;
743 } else if (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
) {
751 while ((mattockB
= mattockB
->nobj
) != 0)
752 if (mattockB
->otyp
== ETERNIUM_MATTOCK
) ++cnt
;
753 } else { /* mattockC */
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.",
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
));
768 } else if (eshkp
->pbanned
&& !(Is_blackmarket(&u
.uz
)) ) {
769 verbalize("I don't sell to your kind here.");
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 */
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.
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) {
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
);
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.
823 long debt
= eshkp
->debit
;
825 for (bp
= eshkp
->bill_p
, ct
= eshkp
->billct
; ct
> 0; bp
++, ct
--)
826 debt
+= bp
->price
* bp
->bquan
;
830 /* called in response to the `$' command */
832 shopper_financial_report()
834 struct monst
*shkp
, *this_shkp
= shop_keeper(inside_shop(u
.ux
, u
.uy
));
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;
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.");
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
));
882 struct monst
*shkp
= rmno
>= ROOMOFFSET
?
883 rooms
[rmno
- ROOMOFFSET
].resident
: 0;
886 if (NOTANGRY(shkp
)) {
887 if (ESHK(shkp
)->surcharge
) pacify_shk(shkp
);
889 if (!ESHK(shkp
)->surcharge
) rile_shk(shkp
);
897 register struct mkroom
*sroom
;
899 register struct monst
*mtmp
= sroom
->resident
;
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
;
914 register struct bill_x
*bp
= ESHK(shkp
)->bill_p
;
915 register int ct
= ESHK(shkp
)->billct
;
918 if (bp
->bo_id
== obj
->o_id
) {
919 if (!obj
->unpaid
) pline("onbill: paid obj on bill?");
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. */
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
) {
941 impossible("indestructible object %s",
942 obj
->where
== OBJ_FREE
? "free" : "on bill");
943 obfree(curr
, (struct obj
*)0);
946 place_object(curr
, obj
->ox
, obj
->oy
);
947 /* No indestructible objects currently stack */
950 add_to_container(obj
->ocontainer
, curr
, TRUE
);
953 if (!flooreffects(curr
, u
.ux
, u
.uy
, "fall"))
954 place_object(curr
, u
.ux
, u
.uy
);
957 if (!flooreffects(curr
,
958 obj
->ocarry
->mx
, obj
->ocarry
->my
, "fall"))
959 place_object(curr
, obj
->ocarry
->mx
, obj
->ocarry
->my
);
962 add_to_migration(curr
);
963 /* Copy migration destination */
966 curr
->owornmask
= obj
->owornmask
;
974 panic("delete_contents");
979 obfree(curr
, (struct obj
*)0);
983 /* called with two args on 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
);
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) {
1028 obj
->unpaid
= 0; /* only for doinvbill */
1029 add_to_billobjs(obj
);
1032 bpm
= onbill(merge
, shkp
, FALSE
);
1034 /* this used to be a rename */
1035 impossible("obfree: not on bill??");
1038 /* this was a merger */
1039 bpm
->bquan
+= bp
->bquan
;
1040 ESHK(shkp
)->billct
--;
1043 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
1044 int indx
= ESHK(shkp
)->billct
;
1045 *bp
= ESHK(shkp
)->bill_p
[indx
];
1048 *bp
= ESHK(shkp
)->bill_p
[ESHK(shkp
)->billct
];
1053 if ((Race_if(PM_PLAYER_MUSHROOM
) || (uchain
&& uchain
->oartifact
== ART_ERO_ERO_ERO_ERO_MUSHROOM_M
)) && u
.mushroompoleused
) {
1055 obj_extract_self(obj
);
1064 check_credit(tmp
, shkp
)
1066 register struct monst
*shkp
;
1068 long credit
= ESHK(shkp
)->credit
;
1070 if(credit
== 0L) return(tmp
);
1072 pline_The("price is deducted from your credit.");
1073 ESHK(shkp
)->credit
-=tmp
;
1076 pline_The("price is partially covered by your credit.");
1077 ESHK(shkp
)->credit
= 0L;
1086 register struct monst
*shkp
;
1088 long robbed
= ESHK(shkp
)->robbed
;
1089 long balance
= ((tmp
<= 0L) ? tmp
: check_credit(tmp
, shkp
));
1093 if (rn2(2) || balance
< 0) shkp
->mgold
+= balance
;
1095 if (balance
> 0) money2mon(shkp
, balance
);
1096 else if (balance
< 0) money2u(shkp
, -balance
);
1101 if(robbed
< 0) robbed
= 0L;
1102 ESHK(shkp
)->robbed
= robbed
;
1108 /* return shkp to home position */
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;
1119 /* kops_gone(TRUE); */
1122 after_shk_move(shkp
);
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
);
1136 /* remove previously applied surcharge from all billed items */
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
;
1148 register long reduction
= (bp
->price
+ 3L) / 4L;
1149 bp
->price
-= reduction
; /* undo 33% increase */
1155 /* add aggravation surcharge to all billed items */
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
;
1167 register long surcharge
= (bp
->price
+ 2L) / 3L;
1168 bp
->price
+= surcharge
;
1174 /* wakeup and/or unparalyze shopkeeper */
1176 rouse_shk(shkp
, 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;
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
;
1203 eshkp
->following
= 0;
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
;
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
);
1229 pline("Satisfied, %s suddenly disappears!", shk_nam
);
1231 pline("%s calms down.", Monnam(shkp
));
1233 if(!angry_shk_exists()) {
1235 kops_gone(silentkops);
1243 register struct monst
*shkp
;
1245 if(!shkp
->isshk
) return;
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.
1258 make_angry_shk(shkp
, ox
, oy
)
1259 register struct monst
*shkp
;
1260 register xchar ox
,oy
;
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 */
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
;
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.";
1292 STATIC_VAR
const char no_money
[];
1293 STATIC_VAR
const char not_enough_money
[];
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
);
1307 if(bp
->price
* bp
->bquan
< gmin
)
1308 gmin
= bp
->price
* bp
->bquan
;
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
)) {
1325 if (Race_if(PM_PLAYER_DYNAMO
)) {
1326 You("can't pay because no one wants to accept payment by you, criminal.");
1331 pline("The pay command is currently unavailable!");
1332 if (flags
.moreforced
&& !MessagesSuppressed
) display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
1336 register struct eshk
*eshkp
;
1337 register struct monst
*shkp
;
1338 struct monst
*nxtm
, *resident
;
1343 int pass
, tmp
, sk
= 0, seensk
= 0;
1344 boolean paid
= FALSE
, stashed_gold
= (hidden_gold() > 0L);
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
)) {
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
))
1360 if (nxtm
) { /* Player should always appease an */
1361 shkp
= nxtm
; /* irate shk standing next to them. */
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
))
1375 if ((!sk
&& (!Blind
|| Blind_telepat
)) || (!Blind
&& !seensk
)) {
1376 There("appears to be no shopkeeper here to receive your payment.");
1385 /* the usual case. allow paying at a distance when */
1386 /* inside a tended shop. should we change that? */
1387 if(sk
== 1 && resident
) {
1393 /* KMH -- Permit paying gypsies */
1394 if (shkp
&& shkp
->isgyp
) {
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.",
1415 if (getpos(&cc
, TRUE
, "the creature you want to pay") < 0)
1416 return 0; /* player pressed ESC */
1420 pline("Try again...");
1423 if(u
.ux
== cx
&& u
.uy
== cy
) {
1424 You("are generous to yourself.");
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!");
1433 There("is no one there to receive your payment.");
1436 /* KMH -- Permit paying gypsies */
1437 if (mtmp
->isgyp
&& mtmp
->mpeaceful
) {
1438 if (distu(mtmp
->mx
, mtmp
->my
) <= 2) {
1444 pline("%s is not interested in your payment.",
1448 if (mtmp
!= resident
&& distu(mtmp
->mx
, mtmp
->my
) > 2) {
1449 pline("%s is too far to receive your payment.",
1458 pline("dopay: null 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");
1476 if(shkp
!= resident
&& NOTANGRY(shkp
)) {
1478 umoney
= money_cnt(invent
);
1481 You("do not owe %s anything.", mon_nam(shkp
));
1487 You("%shave no money.", stashed_gold
? "seem to " : "");
1491 pline("But you have some gold stashed away.");
1493 pline("But you have some money stashed away.");
1497 long ugold
= u
.ugold
;
1502 You("give %s the %ld gold piece%s %s asked for.",
1503 mon_nam(shkp
), ltmp
, plur(ltmp
), mhe(shkp
));
1507 You("give %s all your%s gold.", mon_nam(shkp
),
1509 You("give %s all your%s money.", mon_nam(shkp
),
1511 stashed_gold
? " openly kept" : "");
1514 if (stashed_gold
) pline("But you have hidden gold!");
1517 if (stashed_gold
) pline("But you have hidden money!");
1521 if((ugold
< ltmp
/2L) || (ugold
< ltmp
&& stashed_gold
))
1523 if((umoney
< ltmp
/2L) || (umoney
< ltmp
&& stashed_gold
))
1525 pline("Unfortunately, %s doesn't look satisfied.",
1528 make_happy_shk(shkp
, FALSE
);
1533 /* ltmp is still eshkp->robbed here */
1534 if (!eshkp
->billct
&& !eshkp
->debit
) {
1536 umoney
= money_cnt(invent
);
1538 if(!ltmp
&& NOTANGRY(shkp
)) {
1539 You("do not owe %s anything.", mon_nam(shkp
));
1545 pline(no_money
, stashed_gold
? " seem to" : "");
1548 shk_other_services();
1551 pline("%s is after blood, not money!", Monnam(shkp
));
1553 if(u
.ugold
< ltmp
/2L ||
1554 (u
.ugold
< ltmp
&& stashed_gold
)) {
1557 if(umoney
< ltmp
/2L ||
1558 (umoney
< ltmp
&& stashed_gold
)) {
1561 pline(no_money
, stashed_gold
? " seem to" : "");
1562 else pline(not_enough_money
, mhim(shkp
));
1565 pline("But since %s shop has been robbed recently,",
1567 pline("you %scompensate %s for %s losses.",
1574 mon_nam(shkp
), mhis(shkp
));
1576 pay(u
.ugold
< ltmp
? u
.ugold
: ltmp
, shkp
);
1578 pay(umoney
< ltmp
? umoney
: ltmp
, shkp
);
1580 make_happy_shk(shkp
, FALSE
);
1582 /* shopkeeper is angry, but has not been robbed --
1583 * door broken, attacked, etc. */
1584 pline("%s is after your hide, not your money!",
1587 if(u
.ugold
< 1000L) {
1590 if(umoney
< 1000L) {
1593 pline(no_money
, stashed_gold
? " seem to" : "");
1594 else pline(not_enough_money
, mhim(shkp
));
1597 You("try to appease %s by giving %s 1000 gold pieces.",
1598 x_monnam(shkp
, ARTICLE_THE
, "angry", 0, FALSE
),
1601 if (strncmp(eshkp
->customer
, plname
, PL_NSIZ
) || rn2(3))
1602 make_happy_shk(shkp
, FALSE
);
1604 pline("But %s is as angry as ever.", mon_nam(shkp
));
1608 if(shkp
!= resident
) {
1609 impossible("dopay: not to shopkeeper?");
1610 if(resident
) setpaid(resident
);
1613 /* pay debt, if any, first */
1615 long dtmp
= eshkp
->debit
;
1616 long loan
= eshkp
->loan
;
1619 umoney
= money_cnt(invent
);
1621 sprintf(sbuf
, "You owe %s %ld %s ",
1622 shkname(shkp
), dtmp
, currency(dtmp
));
1625 strcat(sbuf
, "you picked up in the store.");
1627 "for gold picked up and the use of merchandise.");
1628 } else strcat(sbuf
, "for the use of merchandise.");
1631 if (u
.ugold
+ eshkp
->credit
< dtmp
) {
1632 pline("But you don't%s have enough gold%s.",
1634 if (umoney
+ eshkp
->credit
< dtmp
) {
1635 pline("But you don't%s have enough money%s.",
1638 stashed_gold
? " seem to" : "",
1639 eshkp
->credit
? " or credit" : "");
1642 if (eshkp
->credit
>= dtmp
) {
1643 eshkp
->credit
-= dtmp
;
1646 Your("debt is covered by your credit.");
1647 } else if (!eshkp
->credit
) {
1650 if (rn2(2) || dtmp
< 0) shkp
->mgold
+= dtmp
;
1652 money2mon(shkp
, dtmp
);
1656 You("pay that debt.");
1659 dtmp
-= eshkp
->credit
;
1663 if (rn2(2) || dtmp
< 0) shkp
->mgold
+= dtmp
;
1665 money2mon(shkp
, dtmp
);
1669 pline("That debt is partially offset by your credit.");
1670 You("pay the remainder.");
1676 /* now check items on bill */
1677 if (eshkp
->billct
) {
1678 register boolean itemize
;
1680 if (!u
.ugold
&& !eshkp
->credit
) {
1682 umoney
= money_cnt(invent
);
1683 if (!umoney
&& !eshkp
->credit
) {
1685 You("%shave no money or credit%s.",
1686 stashed_gold
? "seem to " : "",
1687 paid
? " left" : "");
1691 if ((u
.ugold
+ eshkp
->credit
) < cheapest_item(shkp
)) {
1693 if ((umoney
+ eshkp
->credit
) < cheapest_item(shkp
)) {
1695 You("don't have enough money to buy%s the item%s you picked.",
1696 eshkp
->billct
> 1 ? " any of" : "", plur(eshkp
->billct
));
1699 pline("Maybe you have some gold stashed away?");
1701 pline("Maybe you have some money stashed away?");
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
++) {
1712 while (tmp
< eshkp
->billct
) {
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
;
1723 impossible("Shopkeeper administration out of order.");
1724 setpaid(shkp
); /* be nice to the player */
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 */
1734 switch (dopayobj(shkp
, bp
, &otmp
, pass
, itemize
)) {
1739 goto thanks
; /*break*/
1752 *bp
= eshkp
->bill_p
[--eshkp
->billct
];
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
);
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.)
1774 shk_other_services()
1776 char *slang
; /* What shk calls you */
1777 struct monst
*shkp
; /* The shopkeeper */
1778 /*WAC - Windowstuff*/
1781 menu_item
*selected
;
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!");
1792 /* Init your name */
1793 if (Role_if(PM_CONVICT
))
1795 else if (Role_if(PM_MURDERER
))
1797 else if (Race_if(PM_ALBAE
))
1799 else if (!is_human(youmonst
.data
))
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.");
1812 ** Figure out what services he offers
1815 ** a = appraise weapon's worth
1817 ** w = weapon-works (including poison)
1818 ** p = poison weapon
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
);
1828 /* All shops can identify (some better than others) */
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 */
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
))) {
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
)) {
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
);
1856 add_menu(tmpwin
, NO_GLYPH
, &any
, 'p', 0, ATR_NONE
,
1857 "Poison", MENU_UNSELECTED
);
1861 if ((ESHK(shkp
)->services
& (SHK_SPECIAL_A
|SHK_SPECIAL_B
))
1862 && (shk_class_match(ARMOR_CLASS
, shkp
) == SHK_MATCH
)) {
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
))) {
1876 add_menu(tmpwin
, NO_GLYPH
, &any
, 'c', 0, ATR_NONE
,
1877 "Charge", MENU_UNSELECTED
);
1881 if (ESHK(shkp
)->services
& (SHK_CREDITSRV
))
1882 add_menu(tmpwin
, NO_GLYPH
, &any
, 'e', 0, ATR_NONE
,
1883 "Establish Credit", MENU_UNSELECTED
);
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
);
1895 switch (selected
[0].item
.a_int
) {
1897 shk_identify(slang
, shkp
);
1901 shk_uncurse(slang
, shkp
);
1905 shk_appraisal(slang
, shkp
);
1909 shk_weapon_works(slang
, shkp
);
1913 shk_armor_works(slang
, shkp
);
1917 shk_charge(slang
, shkp
);
1920 shk_estcredit(slang
, shkp
);
1923 shk_bless(slang
, shkp
);
1927 pline ("Unknown Service");
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 */
1941 dopayobj(shkp
, bp
, obj_p
, which
, itemize
)
1942 register struct monst
*shkp
;
1943 register struct bill_x
*bp
;
1945 int which
; /* 0 => used-up item, 1 => other (unpaid or lost) */
1948 register struct obj
*obj
= *obj_p
;
1949 long ltmp
, quan
, save_quan
;
1951 long umoney
= money_cnt(invent
);
1954 boolean stashed_gold
= (hidden_gold() > 0L),
1955 consumed
= (which
== 0);
1957 if(!obj
->unpaid
&& !bp
->useup
){
1958 impossible("Paid object on bill??");
1962 if(itemize
&& u
.ugold
+ ESHK(shkp
)->credit
== 0L){
1964 if(itemize
&& umoney
+ ESHK(shkp
)->credit
== 0L){
1966 You("%shave no money or credit left.",
1967 stashed_gold
? "seem to " : "");
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
;
1974 /* either completely used up (simple), or split needed */
1976 if (quan
> obj
->quan
) /* difference is amount used up */
1979 /* dealing with ordinary unpaid item */
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 */
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 */
2002 if (buy
== PAY_BUY
&& u
.ugold
+ ESHK(shkp
)->credit
< ltmp
) {
2003 You("don't%s have gold%s enough to pay for %s.",
2005 if (buy
== PAY_BUY
&& umoney
+ ESHK(shkp
)->credit
< ltmp
) {
2006 You("don't%s have money%s enough to pay for %s.",
2008 stashed_gold
? " seem to" : "",
2009 (ESHK(shkp
)->credit
> 0L) ? " or credit" : "",
2011 buy
= itemize
? PAY_SKIP
: PAY_CANT
;
2014 if (buy
!= PAY_BUY
) {
2015 /* restore unpaid object to original state */
2016 obj
->quan
= save_quan
;
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 */
2028 if (quan
!= bp
->bquan
) {
2029 /* eliminate used-up portion; remainder is still unpaid */
2030 bp
->bquan
= obj
->quan
;
2034 } else { /* completely used-up, so get rid of it */
2035 obj_extract_self(obj
);
2036 /* assert( obj == *obj_p ); */
2038 *obj_p
= 0; /* destroy pointer to freed object */
2041 update_inventory(); /* Done just once in dopay() if !itemize. */
2047 static coord repo_location
; /* repossession context */
2049 /* routine called after dying (or quitting) */
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
)) {
2070 taken
= inherits(resident
, numsk
, croaked
);
2072 for (mtmp
= next_shkp(fmon
, FALSE
);
2073 mtmp
; mtmp
= next_shkp(mtmp2
, FALSE
)) {
2075 if (mtmp
!= resident
) {
2076 /* for bones: we don't want a shopless shk around */
2077 if(!on_level(&(ESHK(mtmp
)->shoplevel
), &u
.uz
))
2081 taken
|= inherits(mtmp
, numsk
, croaked
);
2082 ESHK(mtmp
)->pbanned
= FALSE
; /* Un-ban for bones levels */
2086 if(numsk
== 0) return(FALSE
);
2091 inherits(shkp
, numsk
, croaked
)
2100 struct eshk
*eshkp
= ESHK(shkp
);
2101 boolean take
= FALSE
, taken
= FALSE
;
2102 int roomno
= *u
.ushops
;
2105 /* the simplifying principle is that first-come */
2106 /* already took everything you had. */
2108 if (cansee(shkp
->mx
, shkp
->my
) && croaked
)
2109 pline("%s %slooks at your corpse%s and %s.",
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
);
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
) {
2126 pline("%s gratefully inherits all your possessions.",
2128 set_repo_loc(eshkp
);
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
;
2139 if (eshkp
->following
|| ANGRY(shkp
) || take
) {
2141 if (!invent
&& !u
.ugold
) goto skip
;
2143 if (!invent
) goto skip
;
2144 umoney
= money_cnt(invent
);
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");
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
;
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
);
2166 pline("%s %s all your possessions.",
2167 shkname(shkp
), takes
);
2169 /* where to put player's invent (after disclosure) */
2170 set_repo_loc(eshkp
);
2173 if (rn2(2) || loss
< 0) shkp
->mgold
+= loss
;
2176 money2mon(shkp
, loss
);
2179 pline("%s %s the %ld %s %sowed %s.",
2180 Monnam(shkp
), takes
,
2181 loss
, currency(loss
),
2182 strncmp(eshkp
->customer
, plname
, PL_NSIZ
) ?
2184 shkp
->female
? "her" : "him");
2185 /* shopkeeper has now been paid in full */
2187 eshkp
->following
= 0;
2191 /* in case we create bones */
2192 rouse_shk(shkp
, FALSE
); /* wake up */
2194 home_shk(shkp
, FALSE
);
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
2217 ox
+= sgn(ox
- eshkp
->shd
.x
);
2218 oy
+= sgn(oy
- eshkp
->shd
.y
);
2219 } else { /* already inside this shk's shop */
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 */
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");
2239 /* normally done by savebones(), but that's too late in this case */
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
*
2254 register struct bill_x
*bp
;
2256 register struct obj
*obj
;
2257 register unsigned int id
= bp
->bo_id
;
2260 obj
= o_on(id
, billobjs
);
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.
2276 struct monst
*mon
, *mmtmp
[3];
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 */
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;
2299 /* calculate the value that the shk will charge for [one of] an object */
2302 register struct obj
*obj
;
2303 register struct monst
*shkp
; /* if angry, impose a surcharge */
2305 register long tmp
= getprice(obj
, FALSE
);
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
) {
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
) {
2322 i
= pseudorand
? DIAMOND
: OPAL
;
2325 i
= pseudorand
? SAPPHIRE
: AQUAMARINE
;
2328 i
= pseudorand
? RUBY
: JASPER
;
2330 case 4: /* yellowish brown */
2331 i
= pseudorand
? AMBER
: TOPAZ
;
2333 case 5: /* orange */
2334 i
= pseudorand
? JACINTH
: AGATE
;
2336 case 6: /* yellow */
2337 i
= pseudorand
? CITRINE
: CHRYSOBERYL
;
2340 i
= pseudorand
? BLACK_OPAL
: JET
;
2343 i
= pseudorand
? ROSE_QUARTZ
: MORGANITE
;
2346 i
= pseudorand
? AMAZONITE
: VIVIANITE
;
2349 i
= pseudorand
? CYAN_STONE
: DISTHENE
;
2351 case 11: /* green */
2352 i
= pseudorand
? EMERALD
: JADE
;
2354 case 12: /* radiant */
2355 i
= pseudorand
? DIOPTASE
: ANDALUSITE
;
2357 case 13: /* violet */
2358 i
= pseudorand
? AMETHYST
: FLUORITE
;
2360 case 14: /* dark blue */
2361 i
= pseudorand
? IOLITE
: LARIMAR
;
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 */
2367 tmp
= (long) objects
[i
].oc_cost
;
2368 } else if (!(obj
->o_id
% 4)) /* arbitrarily impose surcharge */
2371 if ((Role_if(PM_TOURIST
) && u
.ulevel
< (MAXULEV
/2))
2372 || ((uarmu
&& !uarmu
->oinvis
) && (!uarm
|| uarm
->oinvis
)
2373 && (!uarmc
|| uarmc
->oinvis
))) /* touristy shirt visible */
2376 if (uarmh
&& !uarmh
->oinvis
&& uarmh
->otyp
== DUNCE_CAP
)
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);
2423 tmp
*= (Role_if(PM_CONVICT
) ? 5 : 25);
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.
2437 contained_cost(obj
, shkp
, price
, usell
, unpaid_only
)
2438 register struct obj
*obj
;
2439 register struct monst
*shkp
;
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 */
2451 if (saleable(shkp
, otmp
) &&
2452 !otmp
->unpaid
&& otmp
->oclass
!= BALL_CLASS
&&
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
);
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
);
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
);
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
);
2525 /* calculate how much the shk will pay when buying [all of] an object */
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 */
2538 if (uarmh
&& !uarmh
->oinvis
&& uarmh
->otyp
== DUNCE_CAP
)
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))
2574 /* reduce player's ability to gain tons of money from selling common items --Amy */
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! */
2601 /* called from doinv(invent.c) for inventory of unpaid objects */
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 */
2615 impossible("unpaid_cost: object wasn't on any bill!");
2616 unp_obj
->unpaid
= 0;
2619 return bp
? unp_obj
->quan
* bp
->price
: 0L;
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
;
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
))
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
);
2650 /* To recognize objects the shopkeeper is not interested in. -dgk
2652 if (obj
->no_charge
) {
2657 bct
= ESHK(shkp
)->billct
;
2658 bp
= &(ESHK(shkp
)->bill_p
[bct
]);
2660 impossible("add_one_tobill error?!");
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
++;
2675 add_to_billobjs(obj
)
2678 if (obj
->where
!= OBJ_FREE
)
2679 panic("add_to_billobjs: obj not free");
2681 obj_stop_timers(obj
);
2683 obj
->nobj
= billobjs
;
2685 obj
->where
= OBJ_ONBILL
;
2688 /* recursive billing of objects within containers. */
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 */
2711 shk_names_obj(shkp
, obj
, fmt
, amt
, arg
)
2714 const char *fmt
; /* "%s %ld %s %s", doname(obj), amt, plur(amt), 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 */
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 */
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
);
2742 You(fmt
, obj_name
, amt
, plur(amt
), arg
);
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
)
2767 if (Race_if(PM_IRAHA
)) {
2768 verbalize("You just signed your own death warrant, thief!");
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
);
2782 if(obj
->oclass
== COIN_CLASS
) {
2783 costly_gold(obj
->ox
, obj
->oy
, obj
->quan
);
2788 ltmp
= get_cost(obj
, shkp
);
2790 if (obj
->no_charge
&& !container
) {
2796 if(obj
->cobj
== (struct obj
*)0) {
2797 if(obj
->no_charge
) {
2801 add_one_tobill(obj
, dummy
);
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 */
2816 costly_gold(obj
->ox
, obj
->oy
, gltmp
);
2826 } else /* i.e., !container */
2827 add_one_tobill(obj
, dummy
);
2829 if (shkp
->mcanmove
&& !shkp
->msleeping
&& !silent
) {
2833 pline("%s has no interest in %s.", Monnam(shkp
),
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 ");
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");
2848 strcat(buf
, (flags
.female
) ? " lady" : " sir");
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
));
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
));
2869 splitbill(obj
, otmp
)
2870 register struct obj
*obj
, *otmp
;
2872 /* otmp has been split off from obj */
2873 register struct bill_x
*bp
;
2875 register struct monst
*shkp
= shop_keeper(*u
.ushops
);
2877 if(!shkp
|| !inhishop(shkp
)) {
2878 impossible("splitbill: no resident shopkeeper??");
2881 bp
= onbill(obj
, shkp
, FALSE
);
2883 impossible("splitbill: not on bill?");
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;
2897 bp
= &(ESHK(shkp
)->bill_p
[ESHK(shkp
)->billct
]);
2898 bp
->bo_id
= otmp
->o_id
;
2899 bp
->bquan
= otmp
->quan
;
2902 ESHK(shkp
)->billct
++;
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
;
2917 if(bp
->bquan
> obj
->quan
){
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 */
2926 otmp
->oattached
= OATTACHED_NOTHING
;
2928 add_to_billobjs(otmp
);
2931 ESHK(shkp
)->billct
--;
2934 /* DRS/NS 2.2.6 messes up -- Peter Kendell */
2935 int indx
= ESHK(shkp
)->billct
;
2936 *bp
= ESHK(shkp
)->bill_p
[indx
];
2939 *bp
= ESHK(shkp
)->bill_p
[ESHK(shkp
)->billct
];
2942 } else if (obj
->unpaid
) {
2943 impossible("sub_one_frombill: unpaid object not on bill");
2948 /* recursive check of unpaid objects within nested containers. */
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
);
2965 sub_one_frombill(otmp
, shkp
);
2973 stolen_container(obj
, shkp
, price
, ininv
, destruction
)
2974 register struct obj
*obj
;
2975 register struct monst
*shkp
;
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
);
2986 price
+= get_cost(obj
, shkp
);
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
))) {
3000 price
+= otmp
->quan
* get_cost(otmp
, shkp
);
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;
3010 price
+= stolen_container(otmp
, shkp
, price
, ininv
,
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
))
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);
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 */
3054 ESHK(shkp
)->robbed
+= value
;
3056 ESHK(shkp
)->debit
+= value
;
3059 const char *still
= "";
3062 if (ESHK(shkp
)->credit
) {
3063 You("have %ld %s credit remaining.",
3064 ESHK(shkp
)->credit
, currency(ESHK(shkp
)->credit
));
3066 } else if (!value
) {
3067 You("have no credit remaining.");
3072 if(obj
->oclass
== COIN_CLASS
)
3073 You("%sowe %s %ld %s!", still
,
3074 mon_nam(shkp
), value
, currency(value
));
3076 You("%sowe %s %ld %s for %s!", still
,
3077 mon_nam(shkp
), value
, currency(value
),
3078 obj
->quan
> 1L ? "them" : "it");
3081 ESHK(shkp
)->robbed
+= value
;
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!\"");
3090 (void) angry_guards(FALSE
);
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
;
3103 sellobj_state(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
;
3119 register struct obj
*obj
;
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
);
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 */
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
)));
3159 dropped_container(obj
, shkp
, FALSE
);
3160 if(!obj
->unpaid
&& !saleitem
)
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" : "");
3172 /* you dropped something of your own - probably want to sell it */
3173 rouse_shk(shkp
, TRUE
); /* wake up sleeping or paralyzed shk */
3176 if (ANGRY(shkp
)) { /* they become shop-objects, no pay */
3177 pline("Thank you, scum!");
3178 subfrombill(obj
, shkp
);
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))
3187 if(offer
) verbalize(
3188 "Thank you for your contribution to restock this recently plundered shop.");
3189 subfrombill(obj
, shkp
);
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 " : "");
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.");
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!");
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
;
3232 dropped_container(obj
, shkp
, FALSE
);
3233 if (!obj
->unpaid
&& !saleitem
) obj
->no_charge
= 1;
3234 subfrombill(obj
, shkp
);
3240 if((!saleitem
&& !(container
&& cltmp
> 0L))
3241 || eshkp
->billct
== BILLSZ
3242 || obj
->oclass
== BALL_CLASS
3244 || obj
->oclass
== CHAIN_CLASS
|| offer
== 0L
3246 || (obj
->oclass
== FOOD_CLASS
&& obj
->oeaten
) ) {
3247 pline("%s seems uninterested%s.", Monnam(shkp
),
3248 cgold
? " in the rest" : "");
3250 dropped_container(obj
, shkp
, FALSE
);
3258 if(!money_cnt(shkp
->minvent
)) {
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 */
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
));
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 */
3284 } else /* previously specified "quit" */
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.");
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
);
3307 if (c
== 'q') sell_response
= 'n';
3309 dropped_container(obj
, shkp
, FALSE
);
3310 if (!obj
->unpaid
) obj
->no_charge
= 1;
3311 subfrombill(obj
, shkp
);
3316 boolean short_funds
= (offer
> shkp
->mgold
);
3317 if (short_funds
) offer
= shkp
->mgold
;
3319 long shkmoney
= money_cnt(shkp
->minvent
);
3320 boolean short_funds
= (offer
> shkmoney
);
3321 if (short_funds
) offer
= shkmoney
;
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
));
3328 "%s offers%s %ld gold piece%s for%s %s %s. Sell %s?",
3329 Monnam(shkp
), short_funds
? " only" : "",
3331 (!ltmp
&& cltmp
&& only_partially_your_contents
) ?
3332 " your items in" : (!ltmp
&& cltmp
) ? " the contents of" : "",
3333 obj
->unpaid
? "the" : "your", cxname(obj
),
3335 !(!ltmp
&& cltmp
&& only_partially_your_contents
)) ?
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
);
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
);
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",
3359 default: impossible("invalid sell response");
3366 int mode
; /* 0: deliver count 1: paged */
3369 void sasc_bug(struct obj
*, unsigned);
3373 struct bill_x
*bp
, *end_bp
;
3379 shkp
= shop_keeper(*u
.ushops
);
3380 if (!shkp
|| !inhishop(shkp
)) {
3381 if (mode
!= 0) impossible("doinvbill: no shopkeeper?");
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
];
3394 ((obj
= bp_to_obj(bp
)) != 0 && obj
->quan
< bp
->bquan
))
3399 datawin
= create_nhwindow(NHW_MENU
);
3400 putstr(datawin
, 0, "Unpaid articles already used up:");
3401 putstr(datawin
, 0, "");
3404 for (bp
= eshkp
->bill_p
, end_bp
= &eshkp
->bill_p
[eshkp
->billct
];
3405 bp
< end_bp
; bp
++) {
3406 obj
= bp_to_obj(bp
);
3408 impossible("Bad shopkeeper administration.");
3411 if(bp
->useup
|| bp
->bquan
> obj
->quan
) {
3412 long oquan
, uquan
, thisused
;
3413 unsigned save_unpaid
;
3415 save_unpaid
= obj
->unpaid
;
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
);
3424 /* SAS/C 6.2 can't cope for some reason */
3425 sasc_bug(obj
,save_unpaid
);
3427 obj
->unpaid
= save_unpaid
;
3429 putstr(datawin
, 0, buf_p
);
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
);
3446 destroy_nhwindow(datawin
);
3453 getprice(obj
, shk_buying
)
3454 register struct obj
*obj
;
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
) {
3465 /* simpler hunger check, (2-4)*cost */
3466 if (u
.uhs
>= HUNGRY
&& !shk_buying
) tmp
*= (long) u
.uhs
;
3467 if (obj
->oeaten
) tmp
= 0L;
3470 /*if (obj->spe == -1) tmp = 0L;*/ /* he'll try to sell them to you anyway --Amy */
3473 /*if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
3474 tmp = 0L;*/ /* no, you can't price-ID :P --Amy */
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;
3483 /* used to be that partly used light sources made it cheaper here... FUCK PRICE ID :P --Amy */
3489 /* shk catches thrown pick-axe */
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!");
3508 pline("%s nimbly%s catches %s.",
3510 (x
== shkp
->mx
&& y
== shkp
->my
) ? "" : " reaches over and",
3512 if (!canspotmon(shkp
) && !(shkp
->data
->msound
== MS_DEEPSTATE
) && !(shkp
->egotype_deepstatemember
))
3513 map_invisible(x
, y
);
3517 subfrombill(obj
, shkp
);
3518 (void) mpickobj(shkp
, obj
, FALSE
);
3521 return (struct monst
*)0;
3525 add_damage(x
, y
, cost
)
3526 register xchar x
, y
;
3529 struct damage
*tmp_dam
;
3532 if (IS_DOOR(levl
[x
][y
].typ
)) {
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
)
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
;
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 */
3557 levl
[x
][y
].seenv
= SVALL
;
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
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
;
3586 register xchar x
= tmp_dam
->place
.x
, y
= tmp_dam
->place
.y
;
3591 strcpy(shops
, in_rooms(x
, y
, SHOPBASE
));
3592 if (index(shops
, ESHK(shkp
)->shoproom
)) {
3594 disposition
= (shops
[1])? 0 : 1;
3595 else if (stop_picking
)
3596 disposition
= repair_damage(shkp
, tmp_dam
, FALSE
);
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
);
3603 stop_picking
= FALSE
;
3609 tmp_dam
= tmp_dam
->next
;
3613 if (disposition
> 1) {
3616 if (IS_WALL(levl
[x
][y
].typ
))
3618 else if (IS_DOOR(levl
[x
][y
].typ
))
3620 else if (disposition
== 3) /* untrapped */
3627 tmp_dam
= tmp_dam
->next
;
3629 free((void *)level
.damagelist
);
3630 level
.damagelist
= tmp_dam
;
3632 free((void *)tmp2_dam
->next
);
3633 tmp2_dam
->next
= tmp_dam
;
3639 pline("Suddenly, %s section%s of wall close%s up!",
3640 (saw_walls
== 1) ? "a" : (saw_walls
<= 3) ?
3642 (saw_walls
== 1) ? "" : "s", (saw_walls
== 1) ? "s" : "");
3644 pline_The("shop door reappears!");
3646 pline_The("floor is repaired!");
3649 pline("Suddenly, the shop door reappears!");
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.");
3664 * 0: repair postponed, 1: silent repair (no messages), 2: normal repair
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
;
3675 register struct monst
*mtmp
;
3676 register struct obj
*otmp
;
3677 register struct trap
*ttmp
;
3679 if ((monstermoves
- tmp_dam
->when
) < REPAIR_DELAY
)
3681 if (shkp
->msleeping
|| !shkp
->mcanmove
|| ESHK(shkp
)->following
)
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
)
3689 if (x
== shkp
->mx
&& y
== shkp
->my
)
3691 if ((mtmp
= m_at(x
, y
)) && (!mtmp
->egotype_wallwalk
) && (!passes_walls(mtmp
->data
)))
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
)
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
);
4458 otmp
->owt
= weight(otmp
);
4459 (void) mpickobj(shkp
, otmp
, FALSE
);
4463 if(IS_DOOR(tmp_dam
->typ
)) {
4464 levl
[x
][y
].doormask
= D_CLOSED
; /* arbitrary */
4466 } else if (IS_WALL(tmp_dam
->typ
)) {
4467 levl
[x
][y
].typ
= tmp_dam
->typ
;
4474 if (IS_ROOM(tmp_dam
->typ
)) {
4475 /* No messages, because player already filled trap door */
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 */
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
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
)))
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);
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 */
4526 if(IS_DOOR(tmp_dam
->typ
)) {
4527 levl
[x
][y
].doormask
= D_CLOSED
; /* arbitrary */
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
;
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
));
4554 * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died
4558 register struct monst
*shkp
;
4560 register xchar gx
,gy
,omx
,omy
;
4562 register schar appr
;
4563 register struct eshk
*eshkp
= ESHK(shkp
);
4565 boolean uondoor
= FALSE
, satdoor
, avoid
= FALSE
, badinv
;
4571 remove_damage(shkp
, FALSE
);
4573 if((udist
= distu(omx
,omy
)) < 3 &&
4574 (!(isgridbug(shkp
->data
)) || (omx
==u
.ux
|| omy
==u
.uy
))) {
4576 (Conflict
&& !resist(shkp
, RING_CLASS
, 0, 0)) ||
4577 (StrongConflict
&& !resist(shkp
, RING_CLASS
, 0, 0))) {
4579 Your("displaced image doesn't fool %s!",
4581 (void) mattacku(shkp
);
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;
4591 if(moves
> followmsg
+4) {
4592 verbalize("%s, %s! Didn't you forget to pay?",
4593 Hello(shkp
), playeraliasname
);
4596 pline("%s doesn't like customers who don't pay.",
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 */
4622 } else if(ANGRY(shkp
)) {
4623 /* Move towards the hero if the shopkeeper can see him. */
4624 if(shkp
->mcansee
&& m_canseeu(shkp
)) {
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
)))
4638 uondoor
= (u
.ux
== eshkp
->shd
.x
&& u
.uy
== eshkp
->shd
.y
);
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
) ||
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
))
4648 avoid
= (*u
.ushops
&& distu(gx
,gy
) > 8);
4652 if(((!eshkp
->robbed
&& !eshkp
->billct
&& !eshkp
->debit
)
4653 || avoid
) && GDIST(omx
,omy
) < 3) {
4654 if (!badinv
&& !onlineu(omx
,omy
))
4662 z
= move_special(shkp
,inhishop(shkp
),appr
,uondoor
,avoid
,omx
,omy
,gx
,gy
);
4663 if (z
> 0) after_shk_move(shkp
);
4668 /* called after shopkeeper moves, in case the move causes re-entry into shop */
4670 after_shk_move(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
);
4685 /* for use in levl_follower (mondata.c) */
4688 register struct monst
*mtmp
;
4690 return((boolean
)(mtmp
->isshk
&& ESHK(mtmp
)->following
));
4693 /* You are digging in the shop. */
4698 register struct monst
*shkp
= shop_keeper(*u
.ushops
);
4700 const char *grabs
= "grabs";
4704 /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */
4706 if (shkp
->msleeping
|| !shkp
->mcanmove
|| is_silent(shkp
->data
))
4707 ; /* lang stays 0 */
4708 else if (shkp
->data
->msound
<= MS_ANIMAL
)
4710 else if (shkp
->data
->msound
>= MS_HUMANOID
)
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*/
4725 if(u
.utraptype
== TT_PIT
)
4727 "Be careful, %s, or you might fall through the floor.",
4728 flags
.female
? "madam" : "sir");
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";
4744 /* This is what should happen, but for balance
4745 * reasons, it isn't currently.
4748 pline("%s curses %s inability to grab your backpack!",
4749 shkname(shkp
), mhim(shkp
));
4754 if (distu(shkp
->mx
, shkp
->my
) > 2) {
4756 /* for some reason the shopkeeper can't come next to you */
4757 if (distu(shkp
->mx
, shkp
->my
) > 2) {
4759 pline("%s curses you in anger and frustration!",
4764 pline("%s %s, and %s your backpack!",
4766 makeplural(locomotion(shkp
->data
,"leap")), grabs
);
4768 pline("%s %s your backpack!", shkname(shkp
), grabs
);
4770 for(obj
= invent
; obj
; obj
= obj2
) {
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;
4778 subfrombill(obj
, shkp
);
4779 (void) add_to_minv(shkp
, obj
); /* may free obj */
4782 /* WAC He may not be here now, but... */
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 */
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
;
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
;
4819 if (Role_if(PM_CAMPERSTRIKER
)) cnt
*= (rn2(5) ? 2 : rn2(5) ? 3 : 5);
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
) {
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
]]);
4868 (void) makemon(&mons
[PM_ANGRY_WATCHMAN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4871 (void) makemon(&mons
[rn2(2) ? PM_MEDIEVAL_SOLDIER
: PM_VIDEO_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4874 (void) makemon(&mons
[PM_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4877 (void) makemon(&mons
[PM_COPPER_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4880 (void) makemon(&mons
[PM_TEUTON_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4883 (void) makemon(&mons
[PM_PAD_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4886 (void) makemon(&mons
[PM_FRANKISH_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4889 (void) makemon(&mons
[PM_GAUCHE_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4892 (void) makemon(&mons
[PM_BRITISH_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4895 (void) makemon(&mons
[PM_JAVA_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4898 (void) makemon(&mons
[PM_AMERICAN_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4901 (void) makemon(&mons
[PM_SWAMP_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4904 (void) makemon(&mons
[PM_ARAB_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4907 (void) makemon(&mons
[PM_VIKING_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4910 (void) makemon(&mons
[PM_ASIAN_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4913 (void) makemon(&mons
[PM_VANILLA_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4916 (void) makemon(&mons
[PM_SEAFARING_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4919 (void) makemon(&mons
[PM_ROHIRRIM_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4922 (void) makemon(&mons
[PM_BYZANTINE_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4925 (void) makemon(&mons
[PM_IBERIAN_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
4928 (void) makemon(&mons
[PM_CELTIC_SOLDIER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5000 (void) makemon(&mons
[PM_KEYSTONE_KOP
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5008 (void) makemon(&mons
[PM_ANGRY_WATCH_CAPTAIN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5013 (void) makemon(&mons
[PM_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5016 (void) makemon(&mons
[PM_ORANGE_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5019 (void) makemon(&mons
[PM_TWOWEAP_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5022 (void) makemon(&mons
[PM_EXTRATERRESTRIAL_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5025 (void) makemon(&mons
[PM_MINOAN_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5028 (void) makemon(&mons
[PM_HUN_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5031 (void) makemon(&mons
[PM_MONGOL_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5034 (void) makemon(&mons
[PM_PERSIAN_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5070 (void) makemon(&mons
[PM_KOP_SERGEANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5075 (void) makemon(&mons
[PM_ANGRY_WATCH_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5079 (void) makemon(&mons
[PM_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5082 (void) makemon(&mons
[PM_YAMATO_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5085 (void) makemon(&mons
[PM_CARTHAGE_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5088 (void) makemon(&mons
[PM_ROMAN_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5112 (void) makemon(&mons
[PM_KOP_LIEUTENANT
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5115 (void) makemon(&mons
[PM_CAPTAIN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5118 (void) makemon(&mons
[PM_URBAN_CAMO_CAPTAIN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5121 (void) makemon(&mons
[PM_GOTHIC_CAPTAIN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5131 (void) makemon(&mons
[PM_KOP_KAPTAIN
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5134 (void) makemon(&mons
[PM_GENERAL
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5141 (void) makemon(&mons
[PM_KOP_KOMMISSIONER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5146 (void) makemon(&mons
[PM_KOP_KCHIEF
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5149 (void) makemon(&mons
[PM_UNGENOCIDABLE_ARCH_LICH
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5152 (void) makemon(&mons
[PM_ANGRY_WATCH_LEADER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
5155 (void) makemon(&mons
[PM_KOP_KATCHER
], mc
[cnt
].x
, mc
[cnt
].y
, MM_ANGRY
|MM_ADJACENTOK
|MM_FRENZIED
);
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
);
5167 for (koptryct
= 0; koptryct
< 2000; koptryct
++) {
5168 kox
= rn1(COLNO
-3,2);
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
);
5190 pay_for_damage(dmgstr
, cant_mollify
)
5192 boolean cant_mollify
;
5194 register struct monst
*shkp
= (struct monst
*)0;
5195 char shops_affected
[5];
5196 register boolean uinshp
= (*u
.ushops
!= '\0');
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;
5207 for (tmp_dam
= level
.damagelist
;
5208 (tmp_dam
&& (tmp_dam
->when
== monstermoves
));
5209 tmp_dam
= tmp_dam
->next
) {
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
)))
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
;
5233 if (!inhishop(tmp_shk
))
5235 shk_distance
= distu(tmp_shk
->mx
, tmp_shk
->my
);
5236 if (shk_distance
> nearest_shk
)
5238 if ((shk_distance
== nearest_shk
) && picks
) {
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
)
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
) {
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
))
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
));
5278 if(um_dist(shkp
->mx
, shkp
->my
, 1)) goto getcad
;
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.
5288 You_hear("an angry voice:");
5289 verbalize("Out of my way, scum!");
5291 #if defined(UNIX) || defined(VMS)
5292 # if defined(SYSV) || defined(ULTRIX) || defined(VMS)
5299 (void) mnearto(shkp
, x
, y
, TRUE
);
5302 if((um_dist(x
, y
, 1) && !uinshp
) || cant_mollify
||
5304 (u
.ugold
+ ESHK(shkp
)->credit
) < cost_of_damage
5306 (money_cnt(invent
) + ESHK(shkp
)->credit
) < cost_of_damage
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");
5315 verbalize("How dare you %s my %s?", dmgstr
,
5316 dugwall
? "shop" : "door");
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
);
5328 u
.ugold
-= cost_of_damage
;
5329 if (rn2(2) || cost_of_damage
< 0) shkp
->mgold
+= cost_of_damage
;
5331 money2mon(shkp
, cost_of_damage
);
5334 pline("Mollified, %s accepts your restitution.",
5336 /* move shk back to his home loc */
5337 home_shk(shkp
, FALSE
);
5340 verbalize("Oh, yes! You'll pay!");
5342 adjalign(-sgn(u
.ualign
.type
));
5347 /* called in dokick.c when we kick an object that might be in a store */
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
)));
5365 /* called by dotalk(sounds.c) when #chatting; returns obj if location
5366 contains shop goods and shopkeeper is willing & able to speak */
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
)
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) */
5388 price_quote(first_obj
)
5389 register struct obj
*first_obj
;
5391 register struct obj
*otmp
;
5392 char buf
[BUFSZ
], price
[40];
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
);
5408 strcpy(price
, "no charge");
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
++;
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 */
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
);
5436 STATIC_OVL
const char *
5437 shk_embellish(itm
, cost
)
5438 register struct obj
*itm
;
5442 register int o
, choice
= rn2(5);
5443 if (choice
== 0) choice
= (cost
< 100L ? 1 : cost
< 500L ? 2 : 3);
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.";
5460 } else if (itm
->oartifact
) {
5461 return ", one of a kind!";
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."
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.",
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.] */
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;
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
));
5533 else if (shkp
->mgold
< 50)
5535 else if ((shkmoney
= money_cnt(shkp
->minvent
)) < 50)
5537 pline("%s complains that business is bad.", shkname(shkp
));
5539 else if (shkp
->mgold
> 4000)
5541 else if (shkmoney
> 4000)
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
));
5547 pline("%s talks about the problem of shoplifters.",shkname(shkp
));
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
) {
5559 if (mtmp
->data
->mlet
== S_KOP
) {
5560 if (canspotmon(mtmp
)) cnt
++;
5565 pline_The("Kop%s (disappointed) vanish%s into thin air.",
5566 plur(cnt
), cnt
== 1 ? "es" : "");
5573 cost_per_charge(shkp
, otmp
, altusage
)
5576 boolean altusage
; /* some items have an "alternate" use with different cost */
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 */
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. */
5602 } else if(otmp
->otyp
== BAG_OF_TRICKS
|| /* 1 - 20 */
5603 otmp
->otyp
== MEDICAL_KIT
||
5604 otmp
->otyp
== HORN_OF_PLENTY
) {
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
) {
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
5627 } else if (otmp
->otyp
== POT_OIL
) {
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.
5641 check_unpaid_usage(otmp
, altusage
)
5646 const char *fmt
, *arg1
, *arg2
;
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
) ||
5660 if (!(shkp
= shop_keeper(*u
.ushops
)) || !inhishop(shkp
))
5662 if ((tmp
= cost_per_charge(shkp
, otmp
, altusage
)) == 0L)
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).";
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" */
5689 check_unpaid_usage(otmp
, FALSE
); /* normal item use */
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!");
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
;
5719 delta
= amount
- eshkp
->credit
;
5721 Your("credit is erased.");
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
;
5733 /* used in domove to block diagonal shop-exit */
5734 /* x,y should always be a door */
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
))
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" : "");
5765 /* used in domove to block diagonal shop-entry */
5766 /* u.ux, u.uy should always be a door */
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
))
5783 if(ESHK(shkp
)->shd
.x
!= u
.ux
|| ESHK(shkp
)->shd
.y
!= u
.uy
)
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
) )
5796 pline("%s%s blocks your way!", shkname(shkp
),
5797 Invis
? " senses your motion and" : "");
5811 if (!shk_owns(buf
, obj
) && !mon_owns(buf
, obj
))
5812 strcpy(buf
, carried(obj
) ? "your" : "the");
5821 (void) shk_your(buf
, obj
);
5834 if (get_obj_location(obj
, &x
, &y
, 0) &&
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");
5848 if (obj
->where
== OBJ_MINVENT
)
5849 return strcpy(buf
, s_suffix(mon_nam(obj
->ocarry
)));
5858 sasc_bug(struct obj
*op
, unsigned x
){
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";
5875 shk_identify(slang
, shkp
)
5879 register struct obj
*obj
; /* The object to identify */
5880 int charge
, mult
; /* Cost to identify */
5884 boolean guesswork
; /* Will shkp be guessing? */
5885 boolean ripoff
=FALSE
; /* Shkp ripping you off? */
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...");
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",
5903 if (ident_type
== '\0') return;
5904 } else if (ESHK(shkp
)->services
& SHK_ID_BASIC
) {
5905 verbalize("I only offer basic identification.");
5907 } else if (ESHK(shkp
)->services
& SHK_ID_PREMIUM
) {
5908 verbalize("I only make complete identifications.");
5913 ** Shopkeeper is ripping you off if:
5914 ** Basic service and object already known.
5915 ** Premier service, object known, + know blessed/cursed and
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 */
5929 verbalize("That item's already identified!");
5932 /* Object already identified: Try and cheat the customer. */
5933 pline("%s chuckles greedily...", mon_nam(shkp
));
5937 } else if (ident_type
=='b') mult
= 1;
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
;
5948 case IMPLANT_CLASS
: charge
= 2000 * mult
;
5950 case WEAPON_CLASS
: charge
= 100 * mult
;
5952 case ARMOR_CLASS
: charge
= 500 * mult
;
5954 case FOOD_CLASS
: charge
= 50 * mult
;
5956 case SCROLL_CLASS
: charge
= 750 * mult
;
5958 case SPBOOK_CLASS
: charge
= 1250 * mult
;
5960 case POTION_CLASS
: charge
= 750 * mult
;
5962 case RING_CLASS
: charge
= 1500 * mult
;
5964 case WAND_CLASS
: charge
= 1000 * mult
;
5966 case TOOL_CLASS
: charge
= 250 * mult
;
5968 case GEM_CLASS
: charge
= 2000 * mult
;
5970 default: charge
= 400 * mult
;
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
);
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 */
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.",
5997 } else if (Confusion
&& !Conf_resist
) {
5998 pline("%s tells you but you forget.", mon_nam(shkp
));
6003 /* Is shopkeeper guessing? */
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 */
6015 verbalize("Sorry. I guess it's not your lucky day.");
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
);
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
);
6048 prinv((char *)0, obj
, 0L); /* Print result */
6054 ** FUNCTION shk_uncurse
6056 ** Uncurse an item for the customer
6059 shk_uncurse(slang
, shkp
)
6063 struct obj
*obj
; /* The object picked */
6064 int charge
; /* How much to uncurse */
6065 boolean guesswork
; /* Will shkp be guessing? */
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
);
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
) &&
6100 /* Not identified! */
6101 pline("%s snickers and says \"See, nice and uncursed!\"",
6103 obj
->bknown
= FALSE
;
6108 You("accidentally point to the wrong item in your confusion.");
6110 /* Curse the item! */
6111 You("accidentally ask for the item to be cursed");
6112 if (!stack_too_big(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!
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
)) {
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.");
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.
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!");
6162 verbalize("Sorry. I guess it's not your lucky day.");
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
6180 shk_bless(slang
, shkp
)
6184 struct obj
*obj
; /* The object picked */
6185 int charge
; /* How much to uncurse */
6186 boolean guesswork
; /* Will shkp be guessing? */
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
);
6210 if (shk_offer_price(slang
, charge
, shkp
) == FALSE
) return;
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
) &&
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!");
6231 You("accidentally point to the wrong item in your confusion.");
6233 /* Curse the item! */
6234 You("accidentally ask for the item to be cursed");
6235 if (!stack_too_big(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.
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!");
6258 verbalize("Sorry. I guess it's not your lucky day.");
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.";
6280 shk_appraisal(slang
, 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];
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!");
6306 if (shk_class_match(WEAPON_CLASS
, shkp
) == SHK_MATCH
)
6308 verbalize("Ok, %s, let's see what we have here.", slang
);
6313 verbalize("Mind you, I'm not an expert in this field.");
6318 if (shk_offer_price(slang
, charge
, shkp
) == FALSE
) return;
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.");
6330 else if (Hallucination
)
6332 You("hear %s say it'll \"knock 'em dead\"",
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? */
6347 /* Shkp's an idiot */
6348 verbalize("Sorry, %s, but I'm not certain.", slang
);
6352 /* Not sure about large foes */
6353 verbalize(basic_damage
, ascii_wsdam
, "?");
6357 /* Not sure about small foes */
6358 verbalize(basic_damage
, "?", ascii_wldam
);
6362 verbalize(basic_damage
, ascii_wsdam
, ascii_wldam
);
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!");
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. */
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!";
6406 shk_weapon_works(slang
, shkp
)
6414 menu_item
*selected
;
6419 if (ESHK(shkp
)->services
& (SHK_SPECIAL_A
| SHK_SPECIAL_B
))
6420 obj
= getobj(weapon_types
, "improve");
6422 obj
= getobj(weapon_types
, "poison");
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
);
6434 if (ESHK(shkp
)->services
& SHK_SPECIAL_A
) {
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
) {
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
) {
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
);
6456 service
= selected
[0].item
.a_int
;
6464 verbalize(we_offer
);
6466 pline("%s", Never_mind
);
6467 if (FailureEffects
|| u
.uprops
[FAILURE_EFFECTS
].extrinsic
|| have_failurestone()) {
6468 pline("Oh wait, actually I do mind...");
6479 verbalize("This'll leave your %s untouchable!", xname(obj
));
6481 /* Costs more the more eroded it is (oeroded 0-3 * 2) */
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...",
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;
6501 ESHK(shkp
)->services
&= ~SHK_SPECIAL_A
;
6504 /* Have some fun, but for this $$$ it better work. */
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;
6512 obj
->oerodeproof
= TRUE
;
6513 } else pline("But it failed due to the stack being too big!");
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;
6537 ESHK(shkp
)->services
&= ~SHK_SPECIAL_B
;
6540 /*if (obj->spe+1 > 5) {
6541 verbalize("I can't enchant this any higher!");
6545 /* Have some fun! */
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;
6570 if (!stack_too_big(obj
)) obj
->spe
++;
6571 else pline("The enchantment failed because the stack was too big.");
6576 if (!is_poisonable(obj
)) {
6577 verbalize("That cannot be poisoned!");
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;
6588 ESHK(shkp
)->services
&= ~SHK_SPECIAL_C
;
6591 obj
->opoisoned
= TRUE
;
6595 impossible("Unknown Weapon Enhancement");
6602 ** FUNCTION shk_armor_works
6604 ** Perform ops on armor for customer
6607 shk_armor_works(slang
, shkp
)
6613 /*WAC - Windowstuff*/
6616 menu_item
*selected
;
6620 if ( !(obj
= getobj(armor_types
, "improve"))) return;
6623 /*WAC - did this using the windowing system...*/
6624 any
.a_void
= 0; /* zero out all bits */
6625 tmpwin
= create_nhwindow(NHW_MENU
);
6628 if (ESHK(shkp
)->services
& (SHK_SPECIAL_A
))
6629 add_menu(tmpwin
, NO_GLYPH
, &any
, 'r', 0, ATR_NONE
, "Rust/Fireproof", MENU_UNSELECTED
);
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
);
6640 switch(selected
[0].item
.a_int
) {
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 */
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;
6661 ESHK(shkp
)->services
&= ~SHK_SPECIAL_A
;
6664 /* Have some fun, but for this $$$ it better work. */
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
));
6673 obj
->oerodeproof
= TRUE
;
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;
6694 ESHK(shkp
)->services
&= ~SHK_SPECIAL_B
;
6697 /*if (obj->spe+1 > 3) {
6698 verbalize("I can't enchant this any higher!");
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;
6726 setworn(obj
, W_ARM
);
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;
6746 setworn(obj
, W_ARM
);
6754 pline ("Unknown Armor Enhancement");
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 };
6771 shk_charge(slang
, 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");
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",
6804 if (type
== '\0') return;
6805 } else if (ESHK(shkp
)->services
& SHK_SPECIAL_A
) {
6806 pline ("I only perform basic charging.");
6808 } else if (ESHK(shkp
)->services
& SHK_SPECIAL_B
) {
6809 pline ("I only perform complete charging.");
6813 /* Compute charge */
6819 /* Wands of wishing should be hard to get recharged */
6820 if (obj
->otyp
== WAN_WISHING
|| obj
->otyp
== WAN_ACQUIREMENT
)
6822 else /* Smooth out the charge a bit */
6823 shk_smooth_charge(&charge
, 100, NOBOUND
);
6826 if (shk_offer_price(slang
, charge
, shkp
) == FALSE
) return;
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",
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
)
6860 verbalize("Oops! Sorry about that...");
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
++;
6875 if (obj
->otyp
== WAN_WISHING
) {
6876 verbalize("Since you'll have everything you always wanted,");
6877 verbalize("...How about loaning me some money?");
6879 if (rn2(2)) shkp
->mgold
+= u
.ugold
;
6882 money2mon(shkp
, money_cnt(invent
));
6884 makeknown(obj
->otyp
);
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 */
6905 shk_estcredit(slang
, shkp
)
6911 struct eshk
*eshkp
= ESHK(shkp
);
6914 pline("It seems that you have no money.");
6918 getlin("How much credit do you want to establish?", buf
);
6919 if (sscanf(buf
, "%ld", &offer
) != 1) offer
= 0L;
6922 pline("Enter a positive number, please.");
6924 } else if (offer
== 0L) {
6925 pline("You've changed your mind.");
6927 } else if (offer
> u
.ugold
) {
6928 You("don't have that much!");
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
);
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?
6949 shk_obj_match(obj
, 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.
6965 shk_offer_price(slang
, charge
, shkp
)
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
);
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
6990 if (charge
> u
.ugold
) {
6992 if (charge
> money_cnt(invent
) ) {
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.");
6997 verbalize("Cash on the spot, %s, and you ain't got the dough!", slang
);
7003 /* Charge the customer */
7004 /* charge = check_credit (charge, shkp); */ /* Deduct the credit first */
7008 if (rn2(2) || charge
< 0) shkp
->mgold
+= charge
;
7010 money2mon(shkp
, charge
);
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
);
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
7048 shk_smooth_charge(pcharge
, lower
, upper
)
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;
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. */
7107 /* Charismatic players get smaller upper bounds */
7108 bonus
=((upper
/50)*charisma
);
7110 /* Adjust upper. Upper > lower! */
7112 upper
= (upper
>=lower
) ? upper
: lower
;
7114 /* Ok, do the min/max stuff */
7115 if (*pcharge
> upper
) *pcharge
=upper
;
7117 if (*pcharge
< lower
) *pcharge
=lower
;
7126 wiz_debug_cmd() /* in this case, display your bill(s) */
7128 int win
, special
= 0;
7130 struct monst
*shkp
, *ushkp
;
7136 win
= create_nhwindow(NHW_MENU
);
7137 ushkp
= shop_keeper(*u
.ushops
);
7138 shkp
= next_shkp(fmon
, TRUE
);
7144 putstr(win
, 0, "No shopkeepers with bills");
7147 bp
= ESHK(shkp
)->bill_p
;
7148 ct
= ESHK(shkp
)->billct
;
7150 sprintf(buf
, "Your bill with %s", noit_mon_nam(shkp
));
7151 if (shkp
== ushkp
) {
7152 strcat(buf
, " (here)");
7156 putstr(win
, 0, buf
);
7157 putstr(win
, 0, "Price Quan Used? Object");
7159 obj
= bp_to_obj(bp
);
7162 *buf2
='*'; /* Bad entry */
7163 strcpy(obj
->unpaid
? buf2
: buf2
+ 1, xname(obj
));
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
);
7174 sprintf(buf
, "You do not owe %s anything.", noit_mon_nam(shkp
));
7175 putstr(win
, 0, buf
);
7179 shkp
= next_shkp(shkp
->nmon
, TRUE
);
7187 display_nhwindow(win
, FALSE
);
7188 destroy_nhwindow(win
);