1 /* NetHack 3.7 apply.c $NHDT-Date: 1737275719 2025/01/19 00:35:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.464 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed. See license for details. */
8 staticfn
int use_camera(struct obj
*);
9 staticfn
int use_towel(struct obj
*);
10 staticfn boolean
its_dead(coordxy
, coordxy
, int *);
11 staticfn
int use_stethoscope(struct obj
*);
12 staticfn
void use_whistle(struct obj
*);
13 staticfn
void use_magic_whistle(struct obj
*);
14 staticfn
void magic_whistled(struct obj
*);
15 staticfn
int use_leash(struct obj
*);
16 staticfn
void use_leash_core(struct obj
*, struct monst
*, coord
*, int);
17 staticfn boolean
mleashed_next2u(struct monst
*);
18 staticfn
int use_mirror(struct obj
*);
19 staticfn
void use_bell(struct obj
**);
20 staticfn
void use_candelabrum(struct obj
*);
21 staticfn
void use_candle(struct obj
**);
22 staticfn
void use_lamp(struct obj
*);
23 staticfn
void light_cocktail(struct obj
**);
24 staticfn
int rub_ok(struct obj
*);
25 staticfn
void display_jump_positions(boolean
);
26 staticfn
void use_tinning_kit(struct obj
*);
27 staticfn
int use_figurine(struct obj
**);
28 staticfn
int grease_ok(struct obj
*);
29 staticfn
int use_grease(struct obj
*);
30 staticfn
void use_trap(struct obj
*);
31 staticfn
int touchstone_ok(struct obj
*);
32 staticfn
int use_stone(struct obj
*);
33 staticfn
int set_trap(void); /* occupation callback */
34 staticfn
void display_polearm_positions(boolean
);
35 staticfn
void calc_pole_range(int *, int *);
36 staticfn
int use_cream_pie(struct obj
*);
37 staticfn
int jelly_ok(struct obj
*);
38 staticfn
int use_royal_jelly(struct obj
**);
39 staticfn
int grapple_range(void);
40 staticfn boolean
can_grapple_location(coordxy
, coordxy
);
41 staticfn
void display_grapple_positions(boolean
);
42 staticfn
int use_grapple(struct obj
*);
43 staticfn
void discard_broken_wand(void);
44 staticfn
void broken_wand_explode(struct obj
*, int, int);
45 staticfn
int do_break_wand(struct obj
*);
46 staticfn
int apply_ok(struct obj
*);
47 staticfn
int flip_through_book(struct obj
*);
48 staticfn
int flip_coin(struct obj
*);
49 staticfn boolean
figurine_location_checks(struct obj
*, coord
*, boolean
);
50 staticfn boolean
check_jump(genericptr_t
, coordxy
, coordxy
);
51 staticfn boolean
is_valid_jump_pos(coordxy
, coordxy
, int, boolean
);
52 staticfn boolean
get_valid_jump_position(coordxy
, coordxy
);
53 staticfn boolean
get_valid_polearm_position(coordxy
, coordxy
);
54 staticfn boolean
find_poleable_mon(coord
*, int, int);
57 no_elbow_room
[] = "don't have enough elbow-room to maneuver.";
60 do_blinding_ray(struct obj
*obj
)
62 struct monst
*mtmp
= bhit(u
.dx
, u
.dy
, COLNO
, FLASHED_LIGHT
,
63 (int (*) (MONST_P
, OBJ_P
)) 0,
64 (int (*) (OBJ_P
, OBJ_P
)) 0, &obj
);
66 obj
->ox
= u
.ux
, obj
->oy
= u
.uy
; /* flash_hits_mon() wants this */
68 (void) flash_hits_mon(mtmp
, obj
);
69 if (obj
->otyp
== EXPENSIVE_CAMERA
)
70 see_monster_closeup(mtmp
);
72 /* normally bhit() would do this but for FLASHED_LIGHT we want it
73 to be deferred until after flash_hits_mon() */
74 transient_light_cleanup();
78 use_camera(struct obj
*obj
)
81 pline("Using your camera underwater would void the warranty.");
84 if (!getdir((char *) 0))
88 pline1(nothing_happens
);
91 consume_obj_charge(obj
, TRUE
);
93 if (obj
->cursed
&& !rn2(2)) {
94 (void) zapyourself(obj
, TRUE
);
95 } else if (u
.uswallow
) {
96 You("take a picture of %s %s.", s_suffix(mon_nam(u
.ustuck
)),
97 mbodypart(u
.ustuck
, STOMACH
));
99 You("take a picture of the %s.",
100 (u
.dz
> 0) ? surface(u
.ux
, u
.uy
) : ceiling(u
.ux
, u
.uy
));
101 } else if (!u
.dx
&& !u
.dy
) {
102 (void) zapyourself(obj
, TRUE
);
104 do_blinding_ray(obj
);
110 use_towel(struct obj
*obj
)
112 boolean drying_feedback
= (obj
== uwep
);
115 You("have no free %s!", body_part(HAND
));
117 } else if (obj
== ublindf
) {
118 You("cannot use it while you're wearing it!");
120 } else if (obj
->cursed
) {
125 old
= (Glib
& TIMEOUT
);
126 make_glib((int) old
+ rn1(10, 3)); /* + 3..12 */
127 Your("%s %s!", makeplural(body_part(HAND
)),
128 (old
? "are filthier than ever" : "get slimy"));
129 if (is_wet_towel(obj
))
130 dry_a_towel(obj
, -1, drying_feedback
);
135 u
.ucreamed
+= rn1(10, 3);
136 pline("Yecch! Your %s %s gunk on it!", body_part(FACE
),
137 (old
? "has more" : "now has"));
138 make_blinded(BlindedTimeout
+ (long) u
.ucreamed
- old
, TRUE
);
142 what
= (ublindf
->otyp
== LENSES
)
144 : (obj
->otyp
== ublindf
->otyp
) ? "other towel"
146 if (ublindf
->cursed
) {
147 You("push your %s %s.", what
,
148 rn2(2) ? "cock-eyed" : "crooked");
150 struct obj
*saved_ublindf
= ublindf
;
151 You("push your %s off.", what
);
153 dropx(saved_ublindf
);
156 if (is_wet_towel(obj
))
157 dry_a_towel(obj
, -1, drying_feedback
);
166 You("wipe off your %s.",
167 !uarmg
? makeplural(body_part(HAND
)) : gloves_simple_name(uarmg
));
168 if (is_wet_towel(obj
))
169 dry_a_towel(obj
, -1, drying_feedback
);
171 } else if (u
.ucreamed
) {
172 incr_itimeout(&HBlinded
, (-1 * (int) u
.ucreamed
));
175 pline("You've got the glop off.");
176 if (!gulp_blnd_check()) {
177 set_itimeout(&HBlinded
, 1L);
178 make_blinded(0L, TRUE
);
181 Your("%s feels clean now.", body_part(FACE
));
183 if (is_wet_towel(obj
))
184 dry_a_towel(obj
, -1, drying_feedback
);
188 Your("%s and %s are already clean.", body_part(FACE
),
189 makeplural(body_part(HAND
)));
194 /* maybe give a stethoscope message based on floor objects */
196 its_dead(coordxy rx
, coordxy ry
, int *resp
)
199 boolean more_corpses
;
200 struct permonst
*mptr
;
201 struct obj
*corpse
= sobj_at(CORPSE
, rx
, ry
),
202 *statue
= sobj_at(STATUE
, rx
, ry
);
204 if (!can_reach_floor(TRUE
)) { /* levitation or unskilled riding */
205 corpse
= 0; /* can't reach corpse on floor */
206 /* you can't reach tiny statues (even though you can fight
207 tiny monsters while levitating--consistency, what's that?) */
208 while (statue
&& mons
[statue
->corpsenm
].msize
== MZ_TINY
)
209 statue
= nxtobj(statue
, STATUE
, TRUE
);
211 /* when both corpse and statue are present, pick the uppermost one */
212 if (corpse
&& statue
) {
213 if (nxtobj(statue
, CORPSE
, TRUE
) == corpse
)
214 corpse
= 0; /* corpse follows statue; ignore it */
216 statue
= 0; /* corpse precedes statue; ignore statue */
218 more_corpses
= (corpse
&& nxtobj(corpse
, CORPSE
, TRUE
));
220 /* additional stethoscope messages from jyoung@apanix.apana.org.au */
221 if (!corpse
&& !statue
) {
222 ; /* nothing to do */
224 } else if (Hallucination
) {
227 Strcpy(buf
, "You're both stoned");
228 } else if (corpse
->quan
== 1L && !more_corpses
) {
229 int gndr
= 2; /* neuter: "it" */
230 struct monst
*mtmp
= get_mtraits(corpse
, FALSE
);
232 /* (most corpses don't retain the monster's sex, so
233 we're usually forced to use generic pronoun here) */
235 mtmp
->data
= &mons
[mtmp
->mnum
];
236 gndr
= pronoun_gender(mtmp
, PRONOUN_NO_IT
);
238 mptr
= &mons
[corpse
->corpsenm
];
241 else if (is_male(mptr
))
244 Sprintf(buf
, "%s's dead", genders
[gndr
].he
); /* "he"/"she"/"it" */
245 buf
[0] = highc(buf
[0]);
246 } else { /* plural */
247 Strcpy(buf
, "They're dead");
249 /* variations on "He's dead, Jim." (Star Trek's Dr McCoy) */
250 You_hear("a voice say, \"%s, Jim.\"", buf
);
255 boolean here
= u_at(rx
, ry
),
256 one
= (corpse
->quan
== 1L && !more_corpses
), reviver
= FALSE
;
257 int visglyph
, corpseglyph
;
259 visglyph
= glyph_at(rx
, ry
);
260 corpseglyph
= obj_to_glyph(corpse
, rn2
);
262 if (Blind
&& (visglyph
!= corpseglyph
))
263 map_object(corpse
, TRUE
);
265 if (Role_if(PM_HEALER
)) {
266 /* ok to reset `corpse' here; we're done with it */
268 if (obj_has_timer(corpse
, REVIVE_MON
))
271 corpse
= nxtobj(corpse
, CORPSE
, TRUE
);
272 } while (corpse
&& !reviver
);
274 You("determine that %s unfortunate being%s %s%s dead.",
275 one
? (here
? "this" : "that") : (here
? "these" : "those"),
276 one
? "" : "s", one
? "is" : "are", reviver
? " mostly" : "");
279 } else { /* statue */
280 const char *what
, *how
;
282 mptr
= &mons
[statue
->corpsenm
];
283 if (Blind
) { /* ignore statue->dknown; it'll always be set */
284 Sprintf(buf
, "%s %s",
285 u_at(rx
, ry
) ? "This" : "That",
286 humanoid(mptr
) ? "person" : "creature");
289 what
= obj_pmname(statue
);
290 if (!type_is_pname(mptr
))
294 if (Role_if(PM_HEALER
)) {
295 struct trap
*ttmp
= t_at(rx
, ry
);
297 if (ttmp
&& ttmp
->ttyp
== STATUE_TRAP
)
298 how
= "extraordinary";
299 else if (Has_contents(statue
))
303 pline("%s is in %s health for a statue.", what
, how
);
306 return FALSE
; /* no corpse or statue */
309 static const char hollow_str
[] = "a hollow sound. This must be a secret %s!";
311 /* Strictly speaking it makes no sense for usage of a stethoscope to
312 not take any time; however, unless it did, the stethoscope would be
313 almost useless. As a compromise, one use per turn is free, another
314 uses up the turn; this makes curse status have a tangible effect. */
316 use_stethoscope(struct obj
*obj
)
322 boolean interference
= (u
.uswallow
&& is_whirly(u
.ustuck
->data
)
323 && !rn2(Role_if(PM_HEALER
) ? 10 : 3));
325 if (nohands(gy
.youmonst
.data
)) {
326 You("have no hands!"); /* not `body_part(HAND)' */
329 You_cant("hear anything!");
331 } else if (!freehand()) {
332 You("have no free %s.", body_part(HAND
));
335 if (!getdir((char *) 0))
338 res
= (gh
.hero_seq
== svc
.context
.stethoscope_seq
) ? ECMD_TIME
: ECMD_OK
;
339 svc
.context
.stethoscope_seq
= gh
.hero_seq
;
341 gb
.bhitpos
.x
= u
.ux
, gb
.bhitpos
.y
= u
.uy
; /* tentative, reset below */
342 gn
.notonhead
= u
.uswallow
;
343 if (u
.usteed
&& u
.dz
> 0) {
345 pline("%s interferes.", Monnam(u
.ustuck
));
346 mstatusline(u
.ustuck
);
348 mstatusline(u
.usteed
);
350 } else if (u
.uswallow
&& (u
.dx
|| u
.dy
|| u
.dz
)) {
351 mstatusline(u
.ustuck
);
353 } else if (u
.uswallow
&& interference
) {
354 pline("%s interferes.", Monnam(u
.ustuck
));
355 mstatusline(u
.ustuck
);
359 Soundeffect(se_faint_splashing
, 35);
360 You_hear("faint splashing.");
361 } else if (u
.dz
< 0 || !can_reach_floor(TRUE
)) {
362 cant_reach_floor(u
.ux
, u
.uy
, (u
.dz
< 0), TRUE
);
363 } else if (its_dead(u
.ux
, u
.uy
, &res
)) {
364 ; /* message already given */
365 } else if (Is_stronghold(&u
.uz
)) {
366 Soundeffect(se_crackling_of_hellfire
, 35);
367 You_hear("the crackling of hellfire.");
369 pline_The("%s seems healthy enough.", surface(u
.ux
, u
.uy
));
372 } else if (obj
->cursed
&& !rn2(2)) {
373 Soundeffect(se_heart_beat
, 100);
374 You_hear("your heart beat.");
378 if (!u
.dx
&& !u
.dy
) {
385 Soundeffect(se_typing_noise
, 100);
386 You_hear("a faint typing noise.");
389 if ((mtmp
= m_at(rx
, ry
)) != 0) {
390 const char *mnm
= x_monnam(mtmp
, ARTICLE_A
, (const char *) 0,
391 SUPPRESS_IT
| SUPPRESS_INVISIBLE
, FALSE
);
393 /* gb.bhitpos needed by mstatusline() iff mtmp is a long worm */
394 gb
.bhitpos
.x
= rx
, gb
.bhitpos
.y
= ry
;
395 gn
.notonhead
= (mtmp
->mx
!= rx
|| mtmp
->my
!= ry
);
397 if (mtmp
->mundetected
) {
398 if (!canspotmon(mtmp
))
399 There("is %s hidden there.", mnm
);
400 mtmp
->mundetected
= 0;
401 newsym(mtmp
->mx
, mtmp
->my
);
402 } else if (mtmp
->mappearance
) {
403 const char *what
= "thing";
404 boolean use_plural
= FALSE
;
405 struct obj dummyobj
, *odummy
;
407 switch (M_AP_TYPE(mtmp
)) {
410 * we should probably be using object_from_map() here
412 odummy
= init_dummyobj(&dummyobj
, mtmp
->mappearance
, 1L);
413 /* simple_typename() yields "fruit" for any named fruit;
414 we want the same thing '//' or ';' shows: "slime mold"
415 or "grape" or "slice of pizza" */
416 if (odummy
->otyp
== SLIME_MOLD
&& has_mcorpsenm(mtmp
)) {
417 odummy
->spe
= MCORPSENM(mtmp
);
418 what
= simpleonames(odummy
);
420 what
= simple_typename(odummy
->otyp
);
422 use_plural
= (is_boots(odummy
) || is_gloves(odummy
)
423 || odummy
->otyp
== LENSES
);
425 case M_AP_MONSTER
: /* ignore Hallucination here */
426 what
= pmname(&mons
[mtmp
->mappearance
], Mgender(mtmp
));
429 what
= defsyms
[mtmp
->mappearance
].explanation
;
433 pline("%s %s %s really %s.",
434 use_plural
? "Those" : "That", what
,
435 use_plural
? "are" : "is", mnm
);
436 } else if (flags
.verbose
&& !canspotmon(mtmp
)) {
437 There("is %s there.", mnm
);
441 if (!canspotmon(mtmp
))
442 map_invisible(rx
, ry
);
445 if (unmap_invisible(rx
,ry
))
446 pline_The("invisible monster must have moved.");
451 Soundeffect(se_hollow_sound
, 100);
452 You_hear(hollow_str
, "door");
453 cvt_sdoor_to_door(lev
); /* ->typ = DOOR */
454 recalc_block_point(rx
, ry
);
458 You_hear(hollow_str
, "passage");
459 lev
->typ
= CORR
, lev
->flags
= 0;
460 unblock_point(rx
, ry
);
465 if (!its_dead(rx
, ry
, &res
))
466 You("hear nothing special."); /* not You_hear() */
470 static const char whistle_str
[] = "produce a %s whistling sound.",
471 alt_whistle_str
[] = "produce a %s, sharp vibration.";
474 use_whistle(struct obj
*obj
)
476 if (!can_blow(&gy
.youmonst
)) {
477 You("are incapable of using the whistle.");
478 } else if (Underwater
) {
479 You("blow bubbles through %s.", yname(obj
));
482 You_feel("rushing air tickle your %s.", body_part(NOSE
));
484 You(whistle_str
, obj
->cursed
? "shrill" : "high");
485 Soundeffect(se_shrill_whistle
, 50);
493 use_magic_whistle(struct obj
*obj
)
495 if (!can_blow(&gy
.youmonst
)) {
496 You("are incapable of using the whistle.");
497 } else if (obj
->cursed
&& !rn2(2)) {
498 You("produce a %shigh-%s.", Underwater
? "very " : "",
499 Deaf
? "frequency vibration" : "pitched humming noise");
502 /* it's magic! it works underwater too (at a higher pitch) */
503 You(Deaf
? alt_whistle_str
: whistle_str
,
504 Hallucination
? "normal"
505 : (Underwater
&& !Deaf
) ? "strange, high-pitched"
507 Soundeffect(se_shrill_whistle
, 80);
512 /* 'obj' is assumed to be a magic whistle */
514 magic_whistled(struct obj
*obj
)
516 struct monst
*mtmp
, *nextmon
;
517 char buf
[BUFSZ
], *mnam
= 0,
518 shiftbuf
[BUFSZ
+ sizeof "shifts location"],
519 appearbuf
[BUFSZ
+ sizeof "appears"],
520 disappearbuf
[BUFSZ
+ sizeof "disappears"];
521 boolean oseen
, nseen
,
522 already_discovered
= objects
[obj
->otyp
].oc_name_known
!= 0;
523 int omx
, omy
, shift
= 0, appear
= 0, disappear
= 0, trapped
= 0;
525 /* need to copy (up to 3) names as they're collected rather than just
526 save pointers to them, otherwise churning through every mbuf[] might
527 clobber the ones we care about */
528 shiftbuf
[0] = appearbuf
[0] = disappearbuf
[0] = '\0';
530 for (mtmp
= fmon
; mtmp
; mtmp
= nextmon
) {
531 nextmon
= mtmp
->nmon
; /* trap might kill mon */
532 if (DEADMONSTER(mtmp
))
534 /* only tame monsters are affected;
535 steed is already at your location, so not affected;
536 this avoids trap issues if you're on a trap location */
537 if (!mtmp
->mtame
|| mtmp
== u
.usteed
)
539 if (mtmp
->mtrapped
) {
540 /* no longer in previous trap (affects mintrap) */
542 fill_pit(mtmp
->mx
, mtmp
->my
);
545 oseen
= canspotmon(mtmp
); /* old 'seen' status */
546 if (oseen
) /* get name in case it's one we'll remember */
547 mnam
= y_monnam(mtmp
); /* before mnexto(); it might disappear */
548 /* mimic must be revealed before we know whether it
549 actually moves because line-of-sight may change */
552 omx
= mtmp
->mx
, omy
= mtmp
->my
;
553 mnexto(mtmp
, !already_discovered
? RLOC_MSG
: RLOC_NONE
);
555 if (mtmp
->mx
!= omx
|| mtmp
->my
!= omy
) {
556 if (mtmp
->mundetected
) { /* reveal non-mimic hider that moved */
557 mtmp
->mundetected
= 0;
558 newsym(mtmp
->mx
, mtmp
->my
);
562 * All relocated monsters should change positions essentially
563 * simultaneously but we're dealing with them sequentially.
564 * That could kill some off in the process, each time leaving
565 * their target position (which should be occupied at least
566 * momentarily) available as a potential death trap for others.
568 * Also, teleporting onto a trap introduces message sequencing
569 * issues. We try to avoid the most obvious non sequiturs by
570 * checking whether pline() got called during mintrap().
571 * iflags.last_msg will be changed from the value we set here
572 * to PLNMSG_UNKNOWN in that situation.
574 iflags
.last_msg
= PLNMSG_enum
; /* not a specific message */
575 if (mintrap(mtmp
, NO_TRAP_FLAGS
) == Trap_Killed_Mon
)
577 if (iflags
.last_msg
!= PLNMSG_enum
) {
581 /* dying while seen would have issued a message and not get here;
582 being sent to an unseen location and dying there should be
583 included in the disappeared case */
584 nseen
= DEADMONSTER(mtmp
) ? FALSE
: canspotmon(mtmp
);
587 mnam
= y_monnam(mtmp
);
590 Sprintf(shiftbuf
, "%s shifts location", mnam
);
593 Sprintf(appearbuf
, "%s appears", mnam
);
596 if (++disappear
== 1)
597 Sprintf(disappearbuf
, "%s disappears", mnam
);
603 * If any pets changed location, (1) they might have been in view
604 * before and still in view after, (2) out of view before but in
605 * view after, (3) in view before but out of view after (perhaps
606 * on the far side of a boulder/door/wall), or (4) out of view
607 * before and still out of view after. The first two cases are
608 * the usual ones; the fourth will happen if the hero can't see.
610 * If the magic whistle hasn't been discovered yet, rloc() issued
611 * any applicable vanishing and/or appearing messages, and we make
612 * it become discovered now if any pets moved within or into view.
613 * If it has already been discovered, we told rloc() not to issue
614 * messages and will issue one cumulative message now (for any of
615 * the first three cases, not the fourth) to reduce verbosity for
616 * the first case of a single pet (avoid "vanishes and reappears")
617 * and greatly reduce verbosity for multiple pets regardless of
621 if (!already_discovered
) {
622 /* message(s) were handled by rloc(); if only noticeable change was
623 pet(s) disappearing, the magic whistle won't become discovered */
624 if (shift
+ appear
+ trapped
> 0)
625 makeknown(obj
->otyp
);
627 /* could use array of cardinal number names like wishcmdassist() but
628 extra precision above 3 or 4 seems pedantic; not used for 0 or 1 */
629 #define HowMany(n) (((n) < 2) ? "sqrt(-1)" \
630 : ((n) == 2) ? "two" \
631 : ((n) == 3) ? "three" \
632 : ((n) == 4) ? "four" \
633 : ((n) <= 7) ? "several" \
635 /* magic whistle is already discovered so rloc() message(s)
636 were suppressed above; if any discernible relocation occurred,
637 construct a message now and issue it below */
640 Sprintf(shiftbuf
, "%s creatures shift locations",
642 copynchars(buf
, upstart(shiftbuf
), (int) sizeof buf
- 1);
646 /* shift==0: N creatures appear;
647 shift==1: Foo shifts location and N other creatures appear;
648 shift >1: M creatures shift locations and N others appear */
649 Sprintf(appearbuf
, "%s %s appear", HowMany(appear
),
650 (shift
== 0) ? "creatures"
651 : (shift
== 1) ? "other creatures"
654 copynchars(buf
, upstart(appearbuf
), (int) sizeof buf
- 1);
656 Snprintf(eos(buf
), sizeof buf
- strlen(buf
), "%s %s",
657 /* to get here: appear > 0 and shift != 0,
658 so "shifters, appearers" if disappear != 0
659 with ", and disappearers" yet to be appended,
660 or "shifters and appearers" otherwise */
661 disappear
? "," : " and", appearbuf
);
665 Sprintf(disappearbuf
, "%s %s disappear", HowMany(disappear
),
666 (shift
== 0 && appear
== 0) ? "creatures"
667 : (shift
< 2 && appear
< 2) ? "other creatures"
669 if (shift
+ appear
== 0)
670 copynchars(buf
, upstart(disappearbuf
), (int) sizeof buf
- 1);
672 Snprintf(eos(buf
), sizeof buf
- strlen(buf
), "%s and %s",
673 (shift
&& appear
) ? "," : "", disappearbuf
);
684 um_dist(coordxy x
, coordxy y
, xint16 n
)
686 return (boolean
) (abs(u
.ux
- x
) > n
|| abs(u
.uy
- y
) > n
);
695 for (obj
= gi
.invent
; obj
; obj
= obj
->nobj
)
696 if (obj
->otyp
== LEASH
&& obj
->leashmon
!= 0)
701 /* otmp is about to be destroyed or stolen */
703 o_unleash(struct obj
*otmp
)
707 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
708 if (mtmp
->m_id
== (unsigned) otmp
->leashmon
) {
716 /* mtmp is about to die, or become untame */
718 m_unleash(struct monst
*mtmp
, boolean feedback
)
724 pline_mon(mtmp
, "%s pulls free of %s leash!",
725 Monnam(mtmp
), mhis(mtmp
));
727 Your("leash falls slack.");
729 if ((otmp
= get_mleash(mtmp
)) != 0) {
736 /* player is about to die (for bones) */
743 for (otmp
= gi
.invent
; otmp
; otmp
= otmp
->nobj
)
744 if (otmp
->otyp
== LEASH
)
746 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
753 leashable(struct monst
*mtmp
)
755 return (boolean
) (mtmp
->mnum
!= PM_LONG_WORM
756 && !unsolid(mtmp
->data
)
757 && (!nolimbs(mtmp
->data
) || has_head(mtmp
->data
)));
761 use_leash(struct obj
*obj
)
767 /* if the leash isn't in use, assume we're trying to leash
768 the engulfer; if it is use, distinguish between removing
769 it from the engulfer versus from some other creature
770 (note: the two in-use cases can't actually occur; all
771 leashes are released when the hero gets engulfed) */
772 You_cant((!obj
->leashmon
773 ? "leash %s from inside."
774 : (obj
->leashmon
== (int) u
.ustuck
->m_id
)
775 ? "unleash %s from inside."
776 : "unleash anything from inside %s."),
777 noit_mon_nam(u
.ustuck
));
780 if (!obj
->leashmon
&& number_leashed() >= MAXLEASHED
) {
781 You("cannot leash any more pets.");
785 if (!get_adjacent_loc((char *) 0, (char *) 0, u
.ux
, u
.uy
, &cc
))
788 if (u_at(cc
.x
, cc
.y
)) {
789 if (u
.usteed
&& u
.dz
> 0) {
791 use_leash_core(obj
, mtmp
, &cc
, 1);
794 pline("Leash yourself? Very funny...");
799 * From here on out, return value is 1 == a move is used.
802 if (!(mtmp
= m_at(cc
.x
, cc
.y
))) {
803 There("is no creature there.");
804 (void) unmap_invisible(cc
.x
, cc
.y
);
808 use_leash_core(obj
, mtmp
, &cc
, canspotmon(mtmp
));
813 use_leash_core(struct obj
*obj
, struct monst
*mtmp
, coord
*cc
, int spotmon
)
815 if (!spotmon
&& !glyph_is_invisible(levl
[cc
->x
][cc
->y
].glyph
)) {
816 /* for the unleash case, we don't verify whether this unseen
817 monster is the creature attached to the current leash */
818 You("fail to %sleash something.", obj
->leashmon
? "un" : "");
819 /* trying again will work provided the monster is tame
820 (and also that it doesn't change location by retry time) */
821 map_invisible(cc
->x
, cc
->y
);
822 } else if (!mtmp
->mtame
) {
823 pline("%s %s leashed!", Monnam(mtmp
),
824 (!obj
->leashmon
) ? "cannot be" : "is not");
825 } else if (!obj
->leashmon
) {
826 /* applying a leash which isn't currently in use */
827 if (mtmp
->mleashed
) {
828 pline("This %s is already leashed.",
829 spotmon
? l_monnam(mtmp
) : "creature");
830 } else if (unsolid(mtmp
->data
)) {
831 pline("The leash would just fall off.");
832 } else if (nolimbs(mtmp
->data
) && !has_head(mtmp
->data
)) {
833 pline("%s has no extremities the leash would fit.",
835 } else if (!leashable(mtmp
)) {
837 char *lmonnam
= l_monnam(mtmp
);
839 if (cc
->x
!= mtmp
->mx
|| cc
->y
!= mtmp
->my
) {
840 Sprintf(lmonbuf
, "%s tail", s_suffix(lmonnam
));
843 pline("The leash won't fit onto %s%s.", spotmon
? "your " : "",
846 You("slip the leash around %s%s.", spotmon
? "your " : "",
849 obj
->leashmon
= (int) mtmp
->m_id
;
854 /* applying a leash which is currently in use */
855 if (obj
->leashmon
!= (int) mtmp
->m_id
) {
856 pline("This leash is not attached to that creature.");
857 } else if (obj
->cursed
) {
858 pline_The("leash would not come off!");
864 You("remove the leash from %s%s.",
865 spotmon
? "your " : "", l_monnam(mtmp
));
870 /* assuming mtmp->mleashed has been checked */
872 get_mleash(struct monst
*mtmp
)
876 for (otmp
= gi
.invent
; otmp
; otmp
= otmp
->nobj
)
877 if (otmp
->otyp
== LEASH
&& (unsigned) otmp
->leashmon
== mtmp
->m_id
)
883 mleashed_next2u(struct monst
*mtmp
)
885 if (mtmp
->mleashed
) {
887 mnexto(mtmp
, RLOC_NOMSG
);
888 if (!m_next2u(mtmp
)) {
889 struct obj
*otmp
= get_mleash(mtmp
);
892 impossible("leashed-unleashed mon?");
901 You_feel("%s leash go slack.",
902 (number_leashed() > 1) ? "a" : "the");
913 if (get_iter_mons(mleashed_next2u
))
916 /* no pack mules for the Amulet */
917 if (u
.usteed
&& mon_has_amulet(u
.usteed
))
923 check_leash(coordxy x
, coordxy y
)
928 for (otmp
= gi
.invent
; otmp
; otmp
= otmp
->nobj
) {
929 if (otmp
->otyp
!= LEASH
|| otmp
->leashmon
== 0)
931 mtmp
= find_mid(otmp
->leashmon
, FM_FMON
);
933 impossible("leash in use isn't attached to anything?");
937 if (dist2(u
.ux
, u
.uy
, mtmp
->mx
, mtmp
->my
)
938 > dist2(x
, y
, mtmp
->mx
, mtmp
->my
)) {
939 if (!um_dist(mtmp
->mx
, mtmp
->my
, 3)) {
940 ; /* still close enough */
941 } else if (otmp
->cursed
&& !breathless(mtmp
->data
)) {
942 if (um_dist(mtmp
->mx
, mtmp
->my
, 5)
943 || (mtmp
->mhp
-= rnd(2)) <= 0) {
944 long save_pacifism
= u
.uconduct
.killer
;
946 Your("leash chokes %s to death!", mon_nam(mtmp
));
947 /* hero might not have intended to kill pet, but
948 that's the result of his actions; gain experience,
949 lose pacifism, take alignment and luck hit, make
950 corpse less likely to remain tame after revival */
951 xkilled(mtmp
, XKILL_NOMSG
);
952 /* life-saving doesn't ordinarily reset this */
953 if (!DEADMONSTER(mtmp
))
954 u
.uconduct
.killer
= save_pacifism
;
956 pline_mon(mtmp
, "%s is choked by the leash!",
958 /* tameness eventually drops to 1 here (never 0) */
959 if (mtmp
->mtame
&& rn2(mtmp
->mtame
))
963 if (um_dist(mtmp
->mx
, mtmp
->my
, 5)) {
964 pline("%s leash snaps loose!", s_suffix(Monnam(mtmp
)));
965 m_unleash(mtmp
, FALSE
);
967 You("pull on the leash.");
968 if (mtmp
->data
->msound
!= MS_SILENT
)
986 /* charisma is supposed to include qualities like leadership and personal
987 magnetism rather than just appearance, but it has devolved to this... */
992 int cha
= ACURR(A_CHA
);
994 /* don't bother complaining about the sexism; NetHack is not real life */
995 res
= ((cha
>= 25) ? "sublime" /* 25 is the maximum possible */
996 : (cha
>= 19) ? "splendorous" /* note: not "splendiferous" */
997 : (cha
>= 16) ? ((poly_gender() == 1) ? "beautiful" : "handsome")
998 : (cha
>= 14) ? ((poly_gender() == 1) ? "winsome" : "amiable")
999 : (cha
>= 11) ? "cute"
1000 : (cha
>= 9) ? "plain"
1001 : (cha
>= 6) ? "homely"
1002 : (cha
>= 4) ? "ugly"
1003 : "hideous"); /* 3 is the minimum possible */
1007 static const char look_str
[] = "look %s.";
1010 use_mirror(struct obj
*obj
)
1012 const char *mirror
, *uvisage
;
1016 boolean vis
, invis_mirror
, useeit
, monable
;
1018 if (!getdir((char *) 0))
1020 invis_mirror
= Invis
;
1021 useeit
= !Blind
&& (!invis_mirror
|| See_invisible
);
1022 uvisage
= beautiful();
1023 mirror
= simpleonames(obj
); /* "mirror" or "looking glass" */
1024 if (obj
->cursed
&& !rn2(2)) {
1026 pline_The("%s fogs up and doesn't reflect!", mirror
);
1028 pline("%s", nothing_seems_to_happen
);
1031 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1033 You_cant("see your %s %s.", uvisage
, body_part(FACE
));
1035 if (u
.umonnum
== PM_FLOATING_EYE
) {
1037 You("stiffen momentarily under your gaze.");
1040 pline("Yow! The %s stares back!", mirror
);
1042 pline("Yikes! You've frozen yourself!");
1043 if (!Hallucination
|| !rn2(4)) {
1044 nomul(-rnd(MAXULEV
+ 6 - u
.ulevel
));
1045 gm
.multi_reason
= "gazing into a mirror";
1047 gn
.nomovemsg
= 0; /* default, "you can move again" */
1049 } else if (is_vampire(gy
.youmonst
.data
)
1050 || is_vampshifter(&gy
.youmonst
)) {
1051 You("don't have a reflection.");
1052 } else if (u
.umonnum
== PM_UMBER_HULK
) {
1053 pline("Huh? That doesn't look like you!");
1054 make_confused(HConfusion
+ d(3, 4), FALSE
);
1055 } else if (Hallucination
) {
1056 You(look_str
, hcolor((char *) 0));
1058 You(look_str
, "peaked");
1059 } else if (u
.uhs
>= WEAK
) {
1060 You(look_str
, "undernourished");
1061 } else if (Upolyd
) {
1062 You("look like %s.", an(pmname(&mons
[u
.umonnum
], Ugender
)));
1064 You("look as %s as ever.", uvisage
);
1071 You("reflect %s %s.", s_suffix(mon_nam(u
.ustuck
)),
1072 mbodypart(u
.ustuck
, STOMACH
));
1078 Hallucination
? "give the fish a chance to fix their makeup"
1079 : "reflect the murky water");
1084 You("reflect the %s.",
1085 (u
.dz
> 0) ? surface(u
.ux
, u
.uy
) : ceiling(u
.ux
, u
.uy
));
1088 mtmp
= bhit(u
.dx
, u
.dy
, COLNO
, INVIS_BEAM
,
1089 (int (*) (MONST_P
, OBJ_P
)) 0,
1090 (int (*) (OBJ_P
, OBJ_P
)) 0, &obj
);
1091 if (!mtmp
|| !haseyes(mtmp
->data
) || gn
.notonhead
)
1094 /* couldsee(mtmp->mx, mtmp->my) is implied by the fact that bhit()
1095 targeted it, so we can ignore possibility of X-ray vision */
1096 vis
= canseemon(mtmp
);
1097 /* ways to directly see monster (excludes X-ray vision, telepathy,
1098 extended detection, type-specific warning) */
1099 #define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS)
1100 how_seen
= vis
? howmonseen(mtmp
) : 0;
1101 /* whether monster is able to use its vision-based capabilities */
1102 monable
= !mtmp
->mcan
&& (!mtmp
->minvis
|| perceives(mtmp
->data
));
1103 mlet
= mtmp
->data
->mlet
;
1104 if (mtmp
->msleeping
) {
1106 pline("%s is too tired to look at your %s.", Monnam(mtmp
),
1108 } else if (!mtmp
->mcansee
) {
1110 pline("%s can't see anything right now.", Monnam(mtmp
));
1111 } else if (invis_mirror
&& !perceives(mtmp
->data
)) {
1113 pline("%s fails to notice your %s.", Monnam(mtmp
), mirror
);
1114 /* infravision doesn't produce an image in the mirror */
1115 } else if ((how_seen
& SEENMON
) == MONSEEN_INFRAVIS
) {
1116 if (vis
) /* (redundant) */
1117 pline("%s in the dark.",
1118 monverbself(mtmp
, Monnam(mtmp
), "are",
1119 "too far away to see"));
1120 /* some monsters do special things */
1121 } else if (mlet
== S_VAMPIRE
|| mlet
== S_GHOST
|| is_vampshifter(mtmp
)) {
1123 pline("%s doesn't have a reflection.", Monnam(mtmp
));
1124 } else if (monable
&& mtmp
->data
== &mons
[PM_MEDUSA
]) {
1125 if (mon_reflects(mtmp
, "The gaze is reflected away by %s %s!"))
1128 pline("%s is turned to stone!", Monnam(mtmp
));
1131 } else if (monable
&& mtmp
->data
== &mons
[PM_FLOATING_EYE
]) {
1132 int tmp
= d((int) mtmp
->m_lev
, (int) mtmp
->data
->mattk
[0].damd
);
1136 pline("%s is frozen by its reflection.", Monnam(mtmp
));
1138 You_hear("%s stop moving.", something
);
1139 paralyze_monst(mtmp
, (int) mtmp
->mfrozen
+ tmp
);
1140 } else if (monable
&& mtmp
->data
== &mons
[PM_UMBER_HULK
]) {
1142 pline("%s confuses itself!", Monnam(mtmp
));
1144 } else if (monable
&& (mlet
== S_NYMPH
1145 || mtmp
->data
== &mons
[PM_AMOROUS_DEMON
])) {
1147 char buf
[BUFSZ
]; /* "She" or "He" */
1149 pline("%s in your %s.", /* "<mon> admires self in your mirror " */
1150 monverbself(mtmp
, Monnam(mtmp
), "admire", (char *) 0),
1152 pline("%s takes it!", upstart(strcpy(buf
, mhe(mtmp
))));
1154 pline("It steals your %s!", mirror
);
1155 setnotworn(obj
); /* in case mirror was wielded */
1157 (void) mpickobj(mtmp
, obj
);
1158 if (!tele_restrict(mtmp
))
1159 (void) rloc(mtmp
, RLOC_MSG
);
1160 } else if (!is_unicorn(mtmp
->data
) && !humanoid(mtmp
->data
)
1161 && !is_demon(mtmp
->data
)
1162 && (!mtmp
->minvis
|| perceives(mtmp
->data
)) && rn2(5)) {
1163 boolean do_react
= TRUE
;
1165 if (mtmp
->mfrozen
) {
1167 You("discern no obvious reaction from %s.", mon_nam(mtmp
));
1170 "a bit silly gesturing the mirror in that direction.");
1175 pline("%s is frightened by its reflection.", Monnam(mtmp
));
1176 monflee(mtmp
, d(2, 4), FALSE
, FALSE
);
1178 } else if (!Blind
) {
1179 if (mtmp
->minvis
&& !See_invisible
)
1181 else if ((mtmp
->minvis
&& !perceives(mtmp
->data
))
1182 /* redundant: can't get here if these are true */
1183 || !haseyes(mtmp
->data
) || gn
.notonhead
|| !mtmp
->mcansee
)
1184 pline("%s doesn't seem to notice %s reflection.", Monnam(mtmp
),
1187 pline("%s ignores %s reflection.", Monnam(mtmp
), mhis(mtmp
));
1194 use_bell(struct obj
**optr
)
1196 struct obj
*obj
= *optr
;
1198 boolean wakem
= FALSE
, learno
= FALSE
,
1199 ordinary
= (obj
->otyp
!= BELL_OF_OPENING
|| !obj
->spe
),
1200 invoking
= (obj
->otyp
== BELL_OF_OPENING
1201 && invocation_pos(u
.ux
, u
.uy
)
1202 && !On_stairs(u
.ux
, u
.uy
));
1204 Hero_playnotes(obj_to_instr(obj
), "C", 100);
1205 You("ring %s.", the(xname(obj
)));
1207 if (Underwater
|| (u
.uswallow
&& ordinary
)) {
1208 pline("But the sound is muffled.");
1210 } else if (invoking
&& ordinary
) {
1211 /* needs to be recharged... */
1212 pline("But it makes no sound.");
1213 learno
= TRUE
; /* help player figure out why */
1215 } else if (ordinary
) {
1216 if (obj
->cursed
&& !rn2(4)
1217 /* note: once any of them are gone, we stop all of them */
1218 && !(svm
.mvitals
[PM_WOOD_NYMPH
].mvflags
& G_GONE
)
1219 && !(svm
.mvitals
[PM_WATER_NYMPH
].mvflags
& G_GONE
)
1220 && !(svm
.mvitals
[PM_MOUNTAIN_NYMPH
].mvflags
& G_GONE
)
1221 && (mtmp
= makemon(mkclass(S_NYMPH
, 0), u
.ux
, u
.uy
,
1222 NO_MINVENT
| MM_NOMSG
)) != 0) {
1223 You("summon %s!", a_monnam(mtmp
));
1224 if (!obj_resists(obj
, 93, 100)) {
1225 pline("%s shattered!", Tobjnam(obj
, "have"));
1233 mon_adjust_speed(mtmp
, 2, (struct obj
*) 0);
1235 case 2: /* no explanation; it just happens... */
1237 gm
.multi_reason
= NULL
;
1245 /* charged Bell of Opening */
1246 consume_obj_charge(obj
, TRUE
);
1252 pline1(nothing_happens
);
1254 } else if (obj
->cursed
) {
1259 mkundead(&mm
, FALSE
, NO_MINVENT
);
1262 } else if (invoking
) {
1263 pline("%s an unsettling shrill sound...", Tobjnam(obj
, "issue"));
1264 obj
->age
= svm
.moves
;
1268 } else if (obj
->blessed
) {
1274 } else if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
) {
1275 buried_ball_to_freedom();
1281 pline1(nothing_happens
);
1284 pline("%s opens...", Something
);
1288 pline("Things open around you...");
1293 } else { /* uncursed */
1297 pline1(nothing_happens
);
1300 } /* charged BofO */
1303 makeknown(BELL_OF_OPENING
);
1311 use_candelabrum(struct obj
*obj
)
1313 const char *s
= (obj
->spe
!= 1) ? "candles" : "candle";
1316 You("snuff the %s.", s
);
1317 end_burn(obj
, TRUE
);
1320 if (obj
->spe
<= 0) {
1323 pline("This %s has no %s.", xname(obj
), s
);
1324 /* only output tip if candles are in inventory */
1325 for (otmp
= gi
.invent
; otmp
; otmp
= otmp
->nobj
)
1326 if (Is_candle(otmp
))
1329 pline("To attach candles, apply them instead of the %s.",
1334 You("cannot make fire under water.");
1337 if (u
.uswallow
|| obj
->cursed
) {
1339 pline_The("%s %s for a moment, then %s.", s
, vtense(s
, "flicker"),
1344 There("%s only %d %s in %s.", vtense(s
, "are"), obj
->spe
, s
,
1347 pline("%s lit. %s dimly.", obj
->spe
== 1 ? "It is" : "They are",
1348 Tobjnam(obj
, "shine"));
1350 pline("%s's %s burn%s", The(xname(obj
)), s
,
1351 (Blind
? "." : " brightly!"));
1353 if (!invocation_pos(u
.ux
, u
.uy
) || On_stairs(u
.ux
, u
.uy
)) {
1354 pline_The("%s %s being rapidly consumed!", s
, vtense(s
, "are"));
1355 /* this used to be obj->age /= 2, rounding down; an age of
1356 1 would yield 0, confusing begin_burn() and producing an
1357 unlightable, unrefillable candelabrum; round up instead */
1358 obj
->age
= (obj
->age
+ 1L) / 2L;
1360 /* to make absolutely sure the game doesn't become unwinnable as
1361 a consequence of a broken candelabrum */
1362 if (obj
->age
== 0) {
1363 impossible("Candelabrum with candles but no fuel?");
1367 if (obj
->spe
== 7) {
1369 pline("%s a strange warmth!", Tobjnam(obj
, "radiate"));
1371 pline("%s with a strange light!", Tobjnam(obj
, "glow"));
1375 begin_burn(obj
, FALSE
);
1379 use_candle(struct obj
**optr
)
1381 struct obj
*obj
= *optr
;
1383 const char *s
= (obj
->quan
!= 1) ? "candles" : "candle";
1384 char qbuf
[QBUFSZ
], qsfx
[QBUFSZ
], *q
;
1385 boolean was_lamplit
;
1392 /* obj is the candle; otmp is the candelabrum */
1393 otmp
= carrying(CANDELABRUM_OF_INVOCATION
);
1394 if (!otmp
|| otmp
->spe
== 7) {
1399 /* first, minimal candelabrum suffix for formatting candles */
1400 Sprintf(qsfx
, " to\033%s?", thesimpleoname(otmp
));
1401 /* next, format the candles as a prefix for the candelabrum */
1402 (void) safe_qbuf(qbuf
, "Attach ", qsfx
, obj
, yname
, thesimpleoname
, s
);
1403 /* strip temporary candelabrum suffix */
1404 if ((q
= strstri(qbuf
, " to\033")) != 0)
1406 /* last, format final "attach candles to candelabrum?" query */
1407 if (y_n(safe_qbuf(qbuf
, qbuf
, "?", otmp
, yname
, thesimpleoname
, "it"))
1412 if ((long) otmp
->spe
+ obj
->quan
> 7L) {
1413 obj
= splitobj(obj
, 7L - (long) otmp
->spe
);
1414 /* avoid a grammatical error if obj->quan gets
1415 reduced to 1 candle from more than one */
1416 s
= (obj
->quan
!= 1) ? "candles" : "candle";
1420 /* The candle's age field doesn't correctly reflect the amount
1421 of fuel in it while it's lit, because the fuel is measured
1422 by the timer. So to get accurate age updating, we need to
1423 end the burn temporarily while attaching the candle. */
1424 was_lamplit
= obj
->lamplit
;
1426 end_burn(obj
, TRUE
);
1428 You("attach %ld%s %s to %s.", obj
->quan
, !otmp
->spe
? "" : " more", s
,
1430 if (!otmp
->spe
|| otmp
->age
> obj
->age
)
1431 otmp
->age
= obj
->age
;
1432 otmp
->spe
+= (int) obj
->quan
;
1433 if (otmp
->lamplit
&& !was_lamplit
)
1434 pline_The("new %s magically %s!", s
, vtense(s
, "ignite"));
1435 else if (!otmp
->lamplit
&& was_lamplit
)
1436 pline("%s out.", (obj
->quan
> 1L) ? "They go" : "It goes");
1438 struct monst
*shkp VOICEONLY
1439 = shop_keeper(*in_rooms(u
.ux
, u
.uy
, SHOPBASE
));
1441 SetVoice(shkp
, 0, 80, 0);
1442 verbalize("You %s %s, you bought %s!",
1443 otmp
->lamplit
? "burn" : "use",
1444 (obj
->quan
> 1L) ? "them" : "it",
1445 (obj
->quan
> 1L) ? "them" : "it");
1447 if (obj
->quan
< 7L && otmp
->spe
== 7)
1448 pline("%s now has seven%s candles attached.", The(xname(otmp
)),
1449 otmp
->lamplit
? " lit" : "");
1450 /* candelabrum's light range might increase */
1452 obj_merge_light_sources(otmp
, otmp
);
1453 /* candles are no longer a separate light source */
1454 /* candles are now gone */
1456 /* candelabrum's weight is changing */
1457 otmp
->owt
= weight(otmp
);
1462 /* call in drop, throw, and put in box, etc. */
1464 snuff_candle(struct obj
*otmp
)
1466 boolean candle
= Is_candle(otmp
);
1468 if ((candle
|| otmp
->otyp
== CANDELABRUM_OF_INVOCATION
)
1472 boolean many
= candle
? (otmp
->quan
> 1L) : (otmp
->spe
> 1);
1474 (void) get_obj_location(otmp
, &x
, &y
, 0);
1475 if (otmp
->where
== OBJ_MINVENT
? cansee(x
, y
) : !Blind
)
1476 pline("%s%scandle%s flame%s extinguished.", Shk_Your(buf
, otmp
),
1477 (candle
? "" : "candelabrum's "), (many
? "s'" : "'s"),
1478 (many
? "s are" : " is"));
1479 end_burn(otmp
, TRUE
);
1485 /* called when lit lamp is hit by water or put into a container or
1486 you've been swallowed by a monster; obj might be in transit while
1487 being thrown or dropped so don't assume that its location is valid */
1489 snuff_lit(struct obj
*obj
)
1494 if (obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
1495 || obj
->otyp
== BRASS_LANTERN
|| obj
->otyp
== POT_OIL
) {
1496 (void) get_obj_location(obj
, &x
, &y
, 0);
1497 if (obj
->where
== OBJ_MINVENT
? cansee(x
, y
) : !Blind
)
1498 pline("%s %s out!", Yname2(obj
), otense(obj
, "go"));
1499 end_burn(obj
, TRUE
);
1502 if (snuff_candle(obj
))
1508 /* called when lit object is hit by water */
1510 splash_lit(struct obj
*obj
)
1512 boolean result
, dunk
= FALSE
;
1514 /* lantern won't be extinguished by a rust trap or rust monster attack
1515 but will be if submerged or placed into a container or swallowed by
1516 a monster (for mobile light source handling, not because it ought
1517 to stop being lit in all those situations...) */
1518 if (obj
->lamplit
&& obj
->otyp
== BRASS_LANTERN
) {
1520 boolean useeit
= FALSE
, uhearit
= FALSE
, snuff
= TRUE
;
1522 if (obj
->where
== OBJ_INVENT
) {
1525 /* underwater light sources aren't allowed but if hero
1526 is just entering water, Underwater won't be set yet */
1527 dunk
= (is_pool(u
.ux
, u
.uy
)
1528 && ((!Levitation
&& !Flying
&& !Wwalking
)
1529 || Is_waterlevel(&u
.uz
)));
1531 } else if (obj
->where
== OBJ_MINVENT
1532 /* don't assume that lit lantern has been swallowed;
1533 a nymph might have stolen it or picked it up */
1534 && ((mtmp
= obj
->ocarry
), humanoid(mtmp
->data
))) {
1537 useeit
= get_obj_location(obj
, &x
, &y
, 0) && cansee(x
, y
);
1538 uhearit
= couldsee(x
, y
) && distu(x
, y
) < 5 * 5;
1539 dunk
= (is_pool(mtmp
->mx
, mtmp
->my
)
1540 && ((!is_flyer(mtmp
->data
) && !is_floater(mtmp
->data
))
1541 || Is_waterlevel(&u
.uz
)));
1547 if (useeit
|| uhearit
)
1548 pline("%s %s%s%s.", Yname2(obj
),
1549 uhearit
? "crackles" : "",
1550 (uhearit
&& useeit
) ? " and " : "",
1551 useeit
? "flickers" : "");
1552 if (!dunk
&& !snuff
)
1556 result
= snuff_lit(obj
);
1558 /* this is simpler when we wait until after lantern has been snuffed */
1560 /* drain some of the battery but don't short it out entirely */
1561 obj
->age
-= (obj
->age
> 200L) ? 100L : (obj
->age
/ 2L);
1566 /* Called when potentially lightable object is affected by fire_damage().
1567 Return TRUE if object becomes lit and FALSE otherwise --ALI */
1569 catch_lit(struct obj
*obj
)
1573 if (!obj
->lamplit
&& ignitable(obj
) && get_obj_location(obj
, &x
, &y
, 0)) {
1574 if (((obj
->otyp
== MAGIC_LAMP
/* spe==0 => no djinni inside */
1575 /* spe==0 => no candles attached */
1576 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
) && obj
->spe
== 0)
1577 /* age_is_relative && age==0 && still-exists means out of fuel */
1578 || (age_is_relative(obj
) && obj
->age
== 0)
1579 /* lantern is classified as ignitable() but not by fire */
1580 || obj
->otyp
== BRASS_LANTERN
)
1582 if (obj
->otyp
== CANDELABRUM_OF_INVOCATION
&& obj
->cursed
)
1584 if ((obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
)
1585 /* once lit, cursed lamp is as good as non-cursed one, so failure
1586 to light is a minor inconvenience to make cursed be worse */
1587 && obj
->cursed
&& !rn2(2))
1590 if (obj
->where
== OBJ_INVENT
|| cansee(x
, y
)) {
1591 if (obj
->where
== OBJ_FLOOR
&& cansee(x
, y
))
1593 pline("%s %s %s", Yname2(obj
),
1594 /* "catches light!" or "feels warm." */
1595 otense(obj
, Blind
? "feel" : "catch"),
1596 Blind
? "warm." : "light!");
1598 if (obj
->otyp
== POT_OIL
)
1599 makeknown(obj
->otyp
);
1600 if (carried(obj
) && obj
->unpaid
&& costly_spot(u
.ux
, u
.uy
)) {
1601 struct monst
*shkp VOICEONLY
1602 = shop_keeper(*in_rooms(u
.ux
, u
.uy
, SHOPBASE
));
1604 /* if it catches while you have it, then it's your tough luck */
1606 SetVoice(shkp
, 0, 80, 0);
1607 verbalize("That's in addition to the cost of %s %s, of course.",
1609 (obj
->quan
== 1L) ? "itself" : "themselves");
1610 bill_dummy_object(obj
);
1612 begin_burn(obj
, FALSE
);
1618 /* light a lamp or candle */
1620 use_lamp(struct obj
*obj
)
1623 const char *lamp
= (obj
->otyp
== OIL_LAMP
1624 || obj
->otyp
== MAGIC_LAMP
) ? "lamp"
1625 : (obj
->otyp
== BRASS_LANTERN
) ? "lantern"
1629 * When blind, lamps' and candles' on/off state can be distinguished
1630 * by heat. For brass lantern assume that there is an on/off switch
1635 if (lamp
) /* lamp or lantern */
1636 pline("%s%s is now off.", Shk_Your(buf
, obj
), lamp
);
1638 You("snuff out %s.", yname(obj
));
1639 end_burn(obj
, TRUE
);
1644 !Is_candle(obj
) ? "This is not a diving lamp"
1645 : "Sorry, fire and water don't mix");
1648 /* magic lamps with an spe == 0 (wished for) cannot be lit */
1649 if ((!Is_candle(obj
) && obj
->age
== 0)
1650 || (obj
->otyp
== MAGIC_LAMP
&& obj
->spe
== 0)) {
1651 if (obj
->otyp
== BRASS_LANTERN
) {
1653 Your("lantern is out of power.");
1655 pline("%s", nothing_seems_to_happen
);
1657 pline("This %s has no oil.", xname(obj
));
1661 if (obj
->cursed
&& !rn2(2)) {
1662 if ((obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
) && !rn2(3)) {
1663 pline_The("lamp spills and covers your %s with oil.",
1664 fingers_or_gloves(TRUE
));
1665 make_glib((int) (Glib
& TIMEOUT
) + d(2, 10));
1666 } else if (!Blind
) {
1667 pline("%s for a moment, then %s.", Tobjnam(obj
, "flicker"),
1668 otense(obj
, "die"));
1670 pline("%s", nothing_seems_to_happen
);
1673 if (lamp
) { /* lamp or lantern */
1675 pline("%s%s is now on.", Shk_Your(buf
, obj
), lamp
);
1676 } else { /* candle(s) */
1677 pline("%s flame%s %s%s", s_suffix(Yname2(obj
)), plur(obj
->quan
),
1678 otense(obj
, "burn"), Blind
? "." : " brightly!");
1679 if (obj
->unpaid
&& costly_spot(u
.ux
, u
.uy
)
1680 && obj
->age
== 20L * (long) objects
[obj
->otyp
].oc_cost
) {
1681 const char *ithem
= (obj
->quan
> 1L) ? "them" : "it";
1682 struct monst
*shkp VOICEONLY
1683 = shop_keeper(*in_rooms(u
.ux
, u
.uy
, SHOPBASE
));
1685 SetVoice(shkp
, 0, 80, 0);
1686 verbalize("You burn %s, you bought %s!", ithem
, ithem
);
1687 bill_dummy_object(obj
);
1690 begin_burn(obj
, FALSE
);
1695 light_cocktail(struct obj
**optr
)
1697 struct obj
*obj
= *optr
; /* obj is a potion of oil */
1707 You("snuff the lit potion.");
1708 end_burn(obj
, TRUE
);
1710 * Free & add to re-merge potion. This will average the
1711 * age of the potions. Not exactly the best solution,
1712 * but its easy. Don't do that unless obj is not worn (uwep,
1713 * uswapwep, or uquiver) because if wielded and other oil is
1714 * quivered a "null obj after quiver merge" panic will occur.
1716 if (!obj
->owornmask
) {
1718 *optr
= addinv(obj
);
1721 } else if (Underwater
) {
1722 There("is not enough oxygen to sustain a fire.");
1726 split1off
= (obj
->quan
> 1L);
1728 obj
= splitobj(obj
, 1L);
1730 You("light %spotion.%s", shk_your(buf
, obj
),
1731 Blind
? "" : " It gives off a dim light.");
1733 if (obj
->unpaid
&& costly_spot(u
.ux
, u
.uy
)) {
1734 struct monst
*shkp VOICEONLY
= shop_keeper(*in_rooms(u
.ux
, u
.uy
,
1737 /* Normally, we shouldn't both partially and fully charge
1738 * for an item, but (Yendorian Fuel) Taxes are inevitable...
1741 SetVoice(shkp
, 0, 80, 0);
1742 verbalize("That's in addition to the cost of the potion, of course.");
1743 bill_dummy_object(obj
);
1745 makeknown(obj
->otyp
);
1747 begin_burn(obj
, FALSE
); /* after shop billing */
1749 obj_extract_self(obj
); /* free from inv */
1751 obj
= hold_another_object(obj
, "You drop %s!", doname(obj
),
1759 /* getobj callback for object to be rubbed - not selecting a secondary object
1760 to rub on a gray stone or rub jelly on */
1762 rub_ok(struct obj
*obj
)
1765 return GETOBJ_EXCLUDE
;
1767 if (obj
->otyp
== OIL_LAMP
|| obj
->otyp
== MAGIC_LAMP
1768 || obj
->otyp
== BRASS_LANTERN
|| is_graystone(obj
)
1769 || obj
->otyp
== LUMP_OF_ROYAL_JELLY
)
1770 return GETOBJ_SUGGEST
;
1772 return GETOBJ_EXCLUDE
;
1775 /* the #rub command */
1781 if (nohands(gy
.youmonst
.data
)) {
1782 You("aren't able to rub anything without hands.");
1785 obj
= getobj("rub", rub_ok
, GETOBJ_NOFLAGS
);
1788 if (obj
->oclass
== GEM_CLASS
|| obj
->oclass
== FOOD_CLASS
) {
1789 if (is_graystone(obj
)) {
1790 return use_stone(obj
);
1791 } else if (obj
->otyp
== LUMP_OF_ROYAL_JELLY
) {
1792 return use_royal_jelly(&obj
);
1794 pline("Sorry, I don't know how to use that.");
1799 if (wield_tool(obj
, "rub")) {
1800 cmdq_add_ec(CQ_CANNED
, dorub
);
1801 cmdq_add_key(CQ_CANNED
, obj
->invlet
);
1807 /* now uwep is obj */
1808 if (uwep
->otyp
== MAGIC_LAMP
) {
1809 if (uwep
->spe
> 0 && !rn2(3)) {
1810 check_unpaid_usage(uwep
, TRUE
); /* unusual item use */
1811 /* bones preparation: perform the lamp transformation
1812 before releasing the djinni in case the latter turns out
1813 to be fatal (a hostile djinni has no chance to attack yet,
1814 but an indebted one who grants a wish might bestow an
1815 artifact which blasts the hero with lethal results) */
1816 uwep
->otyp
= OIL_LAMP
;
1817 uwep
->spe
= 0; /* for safety */
1818 uwep
->age
= rn1(500, 1000);
1820 begin_burn(uwep
, TRUE
);
1821 djinni_from_bottle(uwep
);
1822 makeknown(MAGIC_LAMP
);
1824 } else if (rn2(2)) {
1825 You("%s smoke.", !Blind
? "see a puff of" : "smell");
1827 pline1(nothing_happens
);
1828 } else if (obj
->otyp
== BRASS_LANTERN
) {
1829 /* message from Adventure */
1830 pline("Rubbing the electric lamp is not particularly rewarding.");
1831 pline("Anyway, nothing exciting happens.");
1833 pline1(nothing_happens
);
1837 /* the #jump command */
1845 enum jump_trajectory
{
1846 jAny
= 0, /* any direction => magical jump */
1849 jDiag
= 3 /* jHorz|jVert */
1852 /* callback routine for walk_path() */
1854 check_jump(genericptr arg
, coordxy x
, coordxy y
)
1856 int traj
= *(int *) arg
;
1857 struct rm
*lev
= &levl
[x
][y
];
1861 if (IS_STWALL(lev
->typ
))
1863 if (IS_DOOR(lev
->typ
)) {
1864 if (closed_door(x
, y
))
1866 if ((lev
->doormask
& D_ISOPEN
) != 0 && traj
!= jAny
1867 /* reject diagonal jump into or out-of or through open door */
1869 /* reject horizontal jump through horizontal open door
1870 and non-horizontal (ie, vertical) jump through
1871 non-horizontal (vertical) open door */
1872 || ((traj
& jHorz
) != 0) == (lev
->horizontal
!= 0)))
1874 /* empty doorways aren't restricted */
1876 /* let giants jump over boulders (what about Flying?
1877 and is there really enough head room for giants to jump
1878 at all, let alone over something tall?) */
1879 if (sobj_at(BOULDER
, x
, y
) && !throws_rocks(gy
.youmonst
.data
))
1885 is_valid_jump_pos(coordxy x
, coordxy y
, int magic
, boolean showmsg
)
1887 if (!magic
&& !(HJumping
& ~INTRINSIC
) && !EJumping
&& distu(x
, y
) != 5) {
1888 /* The Knight jumping restriction still applies when riding a
1889 * horse. After all, what shape is the knight piece in chess?
1892 pline("Illegal move!");
1894 } else if (distu(x
, y
) > (magic
? 6 + magic
* 3 : 9)) {
1898 } else if (!isok(x
, y
)) {
1900 You("cannot jump there!");
1902 } else if (!cansee(x
, y
)) {
1904 You("cannot see where to land!");
1908 struct rm
*lev
= &levl
[u
.ux
][u
.uy
];
1909 /* we want to categorize trajectory for use in determining
1910 passage through doorways: horizontal, vertical, or diagonal;
1911 since knight's jump and other irregular directions are
1912 possible, we flatten those out to simplify door checks */
1914 coordxy dx
= x
- u
.ux
, dy
= y
- u
.uy
,
1915 ax
= abs(dx
), ay
= abs(dy
);
1917 /* diag: any non-orthogonal destination classified as diagonal */
1918 diag
= (magic
|| Passes_walls
|| (!dx
&& !dy
)) ? jAny
1919 : !dy
? jHorz
: !dx
? jVert
: jDiag
;
1920 /* traj: flatten out the trajectory => some diagonals re-classified */
1923 else if (ay
>= 2 * ax
)
1925 traj
= (magic
|| Passes_walls
|| (!ax
&& !ay
)) ? jAny
1926 : !ay
? jHorz
: !ax
? jVert
: jDiag
;
1927 /* walk_path doesn't process the starting spot;
1928 this is iffy: if you're starting on a closed door spot,
1929 you _can_ jump diagonally from doorway (without needing
1930 Passes_walls); that's intentional but is it correct? */
1931 if (diag
== jDiag
&& IS_DOOR(lev
->typ
)
1932 && (lev
->doormask
& D_ISOPEN
) != 0
1934 || ((traj
& jHorz
) != 0) == (lev
->horizontal
!= 0))) {
1936 You_cant("jump diagonally out of a doorway.");
1939 uc
.x
= u
.ux
, uc
.y
= u
.uy
;
1940 tc
.x
= x
, tc
.y
= y
; /* target */
1941 if (!walk_path(&uc
, &tc
, check_jump
, (genericptr_t
) &traj
)) {
1943 There("is an obstacle preventing that jump.");
1951 get_valid_jump_position(coordxy x
, coordxy y
)
1954 && (ACCESSIBLE(levl
[x
][y
].typ
) || Passes_walls
)
1955 && is_valid_jump_pos(x
, y
, gj
.jumping_is_magic
, FALSE
));
1959 display_jump_positions(boolean on_off
)
1961 coordxy x
, y
, dx
, dy
;
1965 tmp_at(DISP_BEAM
, cmap_to_glyph(S_goodpos
));
1966 for (dx
= -4; dx
<= 4; dx
++)
1967 for (dy
= -4; dy
<= 4; dy
++) {
1970 if (get_valid_jump_position(x
, y
) && !u_at(x
, y
))
1975 tmp_at(DISP_END
, 0);
1980 jump(int magic
) /* 0=Physical, otherwise skill level */
1984 /* attempt "jumping" spell if hero has no innate jumping ability */
1985 if (!magic
&& !Jumping
&& known_spell(SPE_JUMPING
) >= spe_Fresh
)
1986 return spelleffects(SPE_JUMPING
, FALSE
, FALSE
);
1988 if (!magic
&& (nolimbs(gy
.youmonst
.data
) || slithy(gy
.youmonst
.data
))) {
1989 /* normally (nolimbs || slithy) implies !Jumping,
1990 but that isn't necessarily the case for knights */
1991 You_cant("jump; you have no legs!");
1993 } else if (!magic
&& !Jumping
) {
1994 You_cant("jump very far.");
1997 /* if steed is immobile, can't do physical jump but can do spell one */
1998 } else if (!magic
&& u
.usteed
&& stucksteed(FALSE
)) {
1999 /* stucksteed gave "<steed> won't move" message */
2001 } else if (u
.uswallow
) {
2003 You("bounce around a little.");
2006 pline("You've got to be kidding!");
2008 } else if (u
.uinwater
) {
2010 You("swish around a little.");
2013 pline("This calls for swimming, not jumping!");
2015 } else if (u
.ustuck
) {
2016 if (u
.ustuck
->mtame
&& !Conflict
&& !u
.ustuck
->mconf
) {
2017 struct monst
*mtmp
= u
.ustuck
;
2019 set_ustuck((struct monst
*) 0);
2020 You("pull free from %s.", mon_nam(mtmp
));
2024 You("writhe a little in the grasp of %s!", mon_nam(u
.ustuck
));
2027 You("cannot escape from %s!", mon_nam(u
.ustuck
));
2029 } else if (Levitation
|| Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)) {
2031 You("flail around a little.");
2034 You("don't have enough traction to jump.");
2036 } else if (!magic
&& near_capacity() > UNENCUMBERED
) {
2037 You("are carrying too much to jump!");
2039 } else if (!magic
&& (u
.uhunger
<= 100 || ACURR(A_STR
) < 6)) {
2040 You("lack the strength to jump!");
2042 } else if (!magic
&& Wounded_legs
) {
2043 legs_in_no_shape("jumping", u
.usteed
!= 0);
2045 } else if (u
.usteed
&& u
.utrap
) {
2046 pline("%s is stuck in a trap.", Monnam(u
.usteed
));
2050 pline("Where do you want to jump?");
2053 gj
.jumping_is_magic
= magic
;
2054 getpos_sethilite(display_jump_positions
, get_valid_jump_position
);
2055 if (getpos(&cc
, TRUE
, "the desired position") < 0)
2056 return ECMD_CANCEL
; /* user pressed ESC */
2057 if (!is_valid_jump_pos(cc
.x
, cc
.y
, magic
, TRUE
)) {
2059 } else if (u
.usteed
&& u_at(cc
.x
, cc
.y
)) {
2060 pline("%s isn't capable of jumping in place.", YMonnam(u
.usteed
));
2066 boolean wastrapped
= FALSE
;
2070 switch (u
.utraptype
) {
2072 side
= rn2(3) ? LEFT_SIDE
: RIGHT_SIDE
;
2073 You("rip yourself free of the bear trap! Ouch!");
2074 losehp(Maybe_Half_Phys(rnd(10)), "jumping out of a bear trap",
2076 set_wounded_legs(side
, rn1(1000, 500));
2079 You("leap from the pit!");
2082 You("tear the web apart as you pull yourself free!");
2083 deltrap(t_at(u
.ux
, u
.uy
));
2086 You("pull yourself above the %s!", hliquid("lava"));
2087 cc
.x
= u
.ux
, cc
.y
= u
.uy
; /* take u_at() 'if' below */
2091 You("strain your %s, but you're still %s.",
2092 makeplural(body_part(LEG
)),
2093 (u
.utraptype
== TT_INFLOOR
)
2094 ? "stuck in the floor"
2095 : "attached to the buried ball");
2096 set_wounded_legs(LEFT_SIDE
, rn1(10, 11));
2097 set_wounded_legs(RIGHT_SIDE
, rn1(10, 11));
2100 impossible("Jumping out of strange trap (%d)?", u
.utraptype
);
2103 /* if we reach here, hero is no longer trapped */
2106 /* jumping on hero's same spot doesn't use walk_path() and isn't
2107 allowed when riding (handled above) */
2108 if (u_at(cc
.x
, cc
.y
)) {
2111 /* escaping from a trap takes precedence over jumping in place */
2113 morehungry(rnd(10));
2116 /* jumping in place on a trap will trigger it */
2117 if ((t
= t_at(cc
.x
, cc
.y
)) != 0) {
2118 You("jump up and %s back down.", !Flying
? "come" : "fly");
2119 dotrap(t
, FORCETRAP
| TOOKPLUNGE
);
2122 /* jumping in place takes no time and doesn't exercise anything */
2123 You("%s.", Hallucination
? "hop up and down a bit"
2124 : "decide not to jump after all");
2129 * Check the path from uc to cc, calling hurtle_step at each
2130 * location. The final position actually reached will be
2135 /* calculate max(abs(dx), abs(dy)) as the range */
2136 range
= cc
.x
- uc
.x
;
2144 (void) walk_path(&uc
, &cc
, hurtle_jump
, (genericptr_t
) &range
);
2145 /* hurtle_jump -> hurtle_step results in <u.ux,u.uy> == <cc.x,cc.y>
2146 * and usually moves the ball if punished, but does not handle all
2147 * the effects of landing on the final position.
2149 teleds(cc
.x
, cc
.y
, TELEDS_NO_FLAGS
);
2151 gm
.multi_reason
= "jumping around";
2153 morehungry(rnd(25));
2159 tinnable(struct obj
*corpse
)
2163 if (!mons
[corpse
->corpsenm
].cnutrit
)
2169 use_tinning_kit(struct obj
*obj
)
2171 struct obj
*corpse
, *can
;
2172 struct permonst
*mptr
;
2174 /* This takes only 1 move. If this is to be changed to take many
2175 * moves, we've got to deal with decaying corpses...
2177 if (obj
->spe
<= 0) {
2178 You("seem to be out of tins.");
2181 if (!(corpse
= floorfood("tin", 2)))
2183 if (corpse
->oeaten
) {
2184 You("cannot tin %s which is partly eaten.", something
);
2187 mptr
= &mons
[corpse
->corpsenm
];
2188 if (touch_petrifies(mptr
) && !Stone_resistance
&& !uarmg
) {
2190 const char *corpse_name
= an(cxname(corpse
));
2192 if (poly_when_stoned(gy
.youmonst
.data
)) {
2193 You("tin %s without wearing gloves.", corpse_name
);
2196 pline("Tinning %s without wearing gloves is a fatal mistake...",
2198 Sprintf(kbuf
, "trying to tin %s without gloves", corpse_name
);
2202 if (is_rider(mptr
)) {
2203 if (revive_corpse(corpse
))
2204 verbalize("Yes... But War does not preserve its enemies...");
2206 pline_The("corpse evades your grasp.");
2209 if (mptr
->cnutrit
== 0) {
2210 pline("That's too insubstantial to tin.");
2213 consume_obj_charge(obj
, TRUE
);
2215 if ((can
= mksobj(TIN
, FALSE
, FALSE
)) != 0) {
2216 static const char you_buy_it
[] = "You tin it, you bought it!";
2218 can
->corpsenm
= corpse
->corpsenm
;
2219 can
->cursed
= obj
->cursed
;
2220 can
->blessed
= obj
->blessed
;
2221 can
->owt
= weight(can
);
2223 /* Mark tinned tins. No spinach allowed... */
2224 set_tin_variety(can
, HOMEMADE_TIN
);
2225 if (carried(corpse
)) {
2226 if (corpse
->unpaid
) {
2227 struct monst
*shkp VOICEONLY
= shop_keeper(*in_rooms(
2228 u
.ux
, u
.uy
, SHOPBASE
));
2230 SetVoice(shkp
, 0, 80, 0);
2231 verbalize(you_buy_it
);
2235 if (costly_spot(corpse
->ox
, corpse
->oy
) && !corpse
->no_charge
) {
2236 struct monst
*shkp VOICEONLY
2237 = shop_keeper(*in_rooms(corpse
->ox
, corpse
->oy
, SHOPBASE
));
2239 SetVoice(shkp
, 0, 80, 0);
2240 verbalize(you_buy_it
);
2244 (void) hold_another_object(can
, "You make, but cannot pick up, %s.",
2245 doname(can
), (const char *) 0);
2247 impossible("Tinning failed.");
2251 use_unicorn_horn(struct obj
**optr
)
2253 #define PROP_COUNT 7 /* number of properties we're dealing with */
2254 int idx
, val
, val_limit
, trouble_count
, unfixable_trbl
, did_prop
;
2255 int trouble_list
[PROP_COUNT
];
2256 struct obj
*obj
= (optr
? *optr
: (struct obj
*) 0);
2258 if (obj
&& obj
->cursed
) {
2259 long lcount
= (long) rn1(90, 10);
2261 switch (rn2(13) / 2) { /* case 6 is half as likely as the others */
2263 make_sick((Sick
& TIMEOUT
) ? (Sick
& TIMEOUT
) / 3L + 1L
2264 : (long) rn1(ACURR(A_CON
), 20),
2265 xname(obj
), TRUE
, SICK_NONVOMITABLE
);
2268 make_blinded(BlindedTimeout
+ lcount
, TRUE
);
2272 You("suddenly feel %s.",
2273 Hallucination
? "trippy" : "confused");
2274 make_confused((HConfusion
& TIMEOUT
) + lcount
, TRUE
);
2277 make_stunned((HStun
& TIMEOUT
) + lcount
, TRUE
);
2283 make_vomiting(14L, FALSE
);
2286 (void) make_hallucinated((HHallucination
& TIMEOUT
) + lcount
,
2290 if (Deaf
) /* make_deaf() won't give feedback when already deaf */
2291 pline("%s", nothing_seems_to_happen
);
2292 make_deaf((HDeaf
& TIMEOUT
) + lcount
, TRUE
);
2298 #define prop_trouble(X) trouble_list[trouble_count++] = (X)
2299 #define TimedTrouble(P) (((P) && !((P) & ~TIMEOUT)) ? ((P) & TIMEOUT) : 0L)
2301 trouble_count
= unfixable_trbl
= did_prop
= 0;
2303 /* collect property troubles */
2304 if (TimedTrouble(Sick
))
2306 if (TimedTrouble(HBlinded
) > (long) u
.ucreamed
2308 && attacktype_fordmg(u
.ustuck
->data
, AT_ENGL
, AD_BLND
)))
2309 prop_trouble(BLINDED
);
2310 if (TimedTrouble(HHallucination
))
2311 prop_trouble(HALLUC
);
2312 if (TimedTrouble(Vomiting
))
2313 prop_trouble(VOMITING
);
2314 if (TimedTrouble(HConfusion
))
2315 prop_trouble(CONFUSION
);
2316 if (TimedTrouble(HStun
))
2317 prop_trouble(STUNNED
);
2318 if (TimedTrouble(HDeaf
))
2321 if (trouble_count
== 0) {
2322 pline1(nothing_happens
);
2324 } else if (trouble_count
> 1)
2325 shuffle_int_array(trouble_list
, trouble_count
);
2328 * Chances for number of troubles to be fixed
2330 * blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8%
2331 * uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0
2333 val_limit
= rn2(d(2, (obj
&& obj
->blessed
) ? 4 : 2));
2334 if (val_limit
> trouble_count
)
2335 val_limit
= trouble_count
;
2337 /* fix [some of] the troubles */
2338 for (val
= 0; val
< val_limit
; val
++) {
2339 idx
= trouble_list
[val
];
2343 make_sick(0L, (char *) 0, TRUE
, SICK_ALL
);
2347 make_blinded((long) u
.ucreamed
, TRUE
);
2351 (void) make_hallucinated(0L, TRUE
, 0L);
2355 make_vomiting(0L, TRUE
);
2359 make_confused(0L, TRUE
);
2363 make_stunned(0L, TRUE
);
2367 make_deaf(0L, TRUE
);
2371 impossible("use_unicorn_horn: bad trouble? (%d)", idx
);
2379 pline("%s", nothing_seems_to_happen
);
2387 * Timer callback routine: turn figurine into monster
2390 fig_transform(anything
*arg
, long timeout
)
2392 struct obj
*figurine
= arg
->a_obj
;
2395 boolean cansee_spot
, silent
, okay_spot
;
2396 boolean redraw
= FALSE
;
2397 boolean suppress_see
= FALSE
;
2398 char monnambuf
[BUFSZ
], carriedby
[BUFSZ
];
2401 impossible("null figurine in fig_transform()");
2404 silent
= (timeout
!= svm
.moves
); /* happened while away */
2405 okay_spot
= get_obj_location(figurine
, &cc
.x
, &cc
.y
, 0);
2406 if (figurine
->where
== OBJ_INVENT
|| figurine
->where
== OBJ_MINVENT
)
2407 okay_spot
= enexto(&cc
, cc
.x
, cc
.y
, &mons
[figurine
->corpsenm
]);
2408 if (!okay_spot
|| !figurine_location_checks(figurine
, &cc
, TRUE
)) {
2409 /* reset the timer to try again later */
2410 (void) start_timer((long) rnd(5000), TIMER_OBJECT
, FIG_TRANSFORM
,
2411 obj_to_any(figurine
));
2415 cansee_spot
= cansee(cc
.x
, cc
.y
);
2416 mtmp
= make_familiar(figurine
, cc
.x
, cc
.y
, TRUE
);
2418 char and_vanish
[BUFSZ
];
2419 struct obj
*mshelter
= svl
.level
.objects
[mtmp
->mx
][mtmp
->my
];
2421 /* [m_monnam() yields accurate mon type, overriding hallucination] */
2422 Sprintf(monnambuf
, "%s", an(m_monnam(mtmp
)));
2423 and_vanish
[0] = '\0';
2424 if ((mtmp
->minvis
&& !See_invisible
)
2425 || (mtmp
->data
->mlet
== S_MIMIC
2426 && M_AP_TYPE(mtmp
) != M_AP_NOTHING
))
2427 suppress_see
= TRUE
;
2429 if (mtmp
->mundetected
) {
2430 if (hides_under(mtmp
->data
) && mshelter
) {
2431 Sprintf(and_vanish
, " and %s under %s",
2432 locomotion(mtmp
->data
, "crawl"), doname(mshelter
));
2433 } else if (mtmp
->data
->mlet
== S_MIMIC
2434 || mtmp
->data
->mlet
== S_EEL
) {
2435 suppress_see
= TRUE
;
2437 Strcpy(and_vanish
, " and vanish");
2440 switch (figurine
->where
) {
2442 if (Blind
|| suppress_see
)
2443 You_feel("%s %s from your pack!", something
,
2444 locomotion(mtmp
->data
, "drop"));
2446 You_see("%s %s out of your pack%s!", monnambuf
,
2447 locomotion(mtmp
->data
, "drop"), and_vanish
);
2451 if (cansee_spot
&& !silent
) {
2452 set_msg_xy(cc
.x
, cc
.y
);
2454 pline("%s suddenly vanishes!", an(xname(figurine
)));
2456 You_see("a figurine transform into %s%s!", monnambuf
,
2458 redraw
= TRUE
; /* update figurine's map location */
2463 if (cansee_spot
&& !silent
&& !suppress_see
) {
2466 mon
= figurine
->ocarry
;
2467 /* figurine carrying monster might be invisible */
2468 if (canseemon(figurine
->ocarry
)
2469 && (!mon
->wormno
|| cansee(mon
->mx
, mon
->my
)))
2470 Sprintf(carriedby
, "%s pack", s_suffix(a_monnam(mon
)));
2471 else if (is_pool(mon
->mx
, mon
->my
))
2472 Strcpy(carriedby
, "empty water");
2474 Strcpy(carriedby
, "thin air");
2475 You_see("%s %s out of %s%s!", monnambuf
,
2476 locomotion(mtmp
->data
, "drop"), carriedby
,
2486 impossible("figurine came to life where? (%d)",
2487 (int) figurine
->where
);
2491 /* free figurine now */
2492 if (carried(figurine
)) {
2495 obj_extract_self(figurine
);
2496 obfree(figurine
, (struct obj
*) 0);
2503 figurine_location_checks(struct obj
*obj
, coord
*cc
, boolean quietly
)
2507 if (carried(obj
) && u
.uswallow
) {
2509 You("don't have enough room in here.");
2512 x
= cc
? cc
->x
: u
.ux
;
2513 y
= cc
? cc
->y
: u
.uy
;
2516 You("cannot put the figurine there.");
2519 if (IS_OBSTRUCTED(levl
[x
][y
].typ
)
2520 && !(passes_walls(&mons
[obj
->corpsenm
]) && may_passwall(x
, y
))) {
2522 You("cannot place a figurine in %s!",
2523 IS_TREE(levl
[x
][y
].typ
) ? "a tree" : "solid rock");
2526 if (sobj_at(BOULDER
, x
, y
) && !passes_walls(&mons
[obj
->corpsenm
])
2527 && !throws_rocks(&mons
[obj
->corpsenm
])) {
2529 You("cannot fit the figurine on the boulder.");
2536 use_figurine(struct obj
**optr
)
2538 struct obj
*obj
= *optr
;
2543 /* can't activate a figurine while swallowed */
2544 if (!figurine_location_checks(obj
, (coord
*) 0, FALSE
))
2547 if (!getdir((char *) 0)) {
2548 svc
.context
.move
= gm
.multi
= 0;
2555 /* Passing FALSE arg here will result in messages displayed */
2556 if (!figurine_location_checks(obj
, &cc
, FALSE
))
2558 You("%s and it %stransforms.",
2559 (u
.dx
|| u
.dy
) ? "set the figurine beside you"
2560 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
2561 || is_pool(cc
.x
, cc
.y
))
2562 ? "release the figurine"
2563 : (u
.dz
< 0 ? "toss the figurine into the air"
2564 : "set the figurine on the ground"),
2565 Blind
? "supposedly " : "");
2566 (void) make_familiar(obj
, cc
.x
, cc
.y
, FALSE
);
2567 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(obj
));
2570 map_invisible(cc
.x
, cc
.y
);
2575 /* getobj callback for object to apply grease to */
2577 grease_ok(struct obj
*obj
)
2580 return GETOBJ_SUGGEST
;
2582 if (obj
->oclass
== COIN_CLASS
)
2583 return GETOBJ_EXCLUDE
;
2585 if (inaccessible_equipment(obj
, (const char *) 0, FALSE
))
2586 return GETOBJ_EXCLUDE_INACCESS
;
2588 /* Possible extension: don't suggest greasing objects which are already
2590 return GETOBJ_SUGGEST
;
2594 use_grease(struct obj
*obj
)
2599 pline("%s from your %s.", Tobjnam(obj
, "slip"),
2600 fingers_or_gloves(FALSE
));
2608 if ((obj
->cursed
|| Fumbling
) && !rn2(2)) {
2609 consume_obj_charge(obj
, TRUE
);
2611 pline("%s from your %s.", Tobjnam(obj
, "slip"),
2612 fingers_or_gloves(FALSE
));
2616 otmp
= getobj("grease", grease_ok
, GETOBJ_PROMPT
);
2619 if (inaccessible_equipment(otmp
, "grease", FALSE
))
2621 consume_obj_charge(obj
, TRUE
);
2623 oldglib
= (int) (Glib
& TIMEOUT
);
2624 if (otmp
!= &hands_obj
) {
2625 You("cover %s with a thick layer of grease.", yname(otmp
));
2627 if (obj
->cursed
&& !nohands(gy
.youmonst
.data
)) {
2628 make_glib(oldglib
+ rn1(6, 10)); /* + 10..15 */
2629 pline("Some of the grease gets all over your %s.",
2630 fingers_or_gloves(TRUE
));
2633 make_glib(oldglib
+ rn1(11, 5)); /* + 5..15 */
2634 You("coat your %s with grease.", fingers_or_gloves(TRUE
));
2638 pline("%s empty.", Tobjnam(obj
, "are"));
2640 pline("%s to be empty.", Tobjnam(obj
, "seem"));
2646 /* getobj callback for object to rub on a known touchstone */
2648 touchstone_ok(struct obj
*obj
)
2651 return GETOBJ_EXCLUDE
;
2653 /* Gold being suggested as a rub target is questionable - it fits the
2654 * real-world historic use of touchstones, but doesn't do anything
2655 * significant in the game. */
2656 if (obj
->oclass
== COIN_CLASS
)
2657 return GETOBJ_SUGGEST
;
2659 /* don't suggest identified gems */
2660 if (obj
->oclass
== GEM_CLASS
2661 && !(obj
->dknown
&& objects
[obj
->otyp
].oc_name_known
))
2662 return GETOBJ_SUGGEST
;
2664 return GETOBJ_DOWNPLAY
;
2668 /* touchstones - by Ken Arnold */
2670 use_stone(struct obj
*tstone
)
2672 static const char scritch
[] = "\"scritch, scritch\"";
2675 const char *streak_color
;
2676 char stonebuf
[QBUFSZ
];
2680 /* in case it was acquired while blinded */
2683 known
= (tstone
->otyp
== TOUCHSTONE
&& tstone
->dknown
2684 && objects
[TOUCHSTONE
].oc_name_known
);
2685 Sprintf(stonebuf
, "rub on the stone%s", plur(tstone
->quan
));
2686 /* when the touchstone is fully known, don't bother listing extra
2687 junk as likely candidates for rubbing */
2688 if ((obj
= getobj(stonebuf
, known
? touchstone_ok
: any_obj_ok
,
2689 GETOBJ_PROMPT
)) == 0)
2692 if (obj
== tstone
&& obj
->quan
== 1L) {
2693 You_cant("rub %s on itself.", the(xname(obj
)));
2697 if (tstone
->otyp
== TOUCHSTONE
&& tstone
->cursed
2698 && obj
->oclass
== GEM_CLASS
&& !is_graystone(obj
)
2699 && !obj_resists(obj
, 80, 100)) {
2701 You_feel("something shatter.");
2702 else if (Hallucination
)
2703 pline("Oh, wow, look at the pretty shards.");
2705 pline("A sharp crack shatters %s%s.",
2706 (obj
->quan
> 1L) ? "one of " : "", the(xname(obj
)));
2714 } else if (Hallucination
) {
2715 pline("Oh wow, man: Fractals!");
2722 oclass
= obj
->oclass
;
2723 /* prevent non-gemstone rings from being treated like gems */
2724 if (oclass
== RING_CLASS
2725 && objects
[obj
->otyp
].oc_material
!= GEMSTONE
2726 && objects
[obj
->otyp
].oc_material
!= MINERAL
)
2727 oclass
= RANDOM_CLASS
; /* something that's neither gem nor ring */
2730 case GEM_CLASS
: /* these have class-specific handling below */
2732 if (tstone
->otyp
!= TOUCHSTONE
) {
2734 } else if (obj
->oclass
== GEM_CLASS
2736 || (!tstone
->cursed
&& (Role_if(PM_ARCHEOLOGIST
)
2737 || Race_if(PM_GNOME
))))) {
2738 makeknown(TOUCHSTONE
);
2739 makeknown(obj
->otyp
);
2740 prinv((char *) 0, obj
, 0L);
2743 /* either a ring or the touchstone was not effective */
2744 if (objects
[obj
->otyp
].oc_material
== GLASS
) {
2749 streak_color
= c_obj_colors
[objects
[obj
->otyp
].oc_color
];
2750 break; /* gem or ring */
2753 switch (objects
[obj
->otyp
].oc_material
) {
2755 pline("%s a little more polished now.", Tobjnam(tstone
, "look"));
2758 if (!obj
->known
) /* note: not "whetstone" */
2759 You("must think this is a wetstone, do you?");
2761 pline("%s a little wetter now.", Tobjnam(tstone
, "are"));
2764 streak_color
= "waxy";
2765 break; /* okay even if not touchstone */
2767 streak_color
= "wooden";
2768 break; /* okay even if not touchstone */
2770 do_scratch
= TRUE
; /* scratching and streaks */
2771 streak_color
= "golden";
2774 do_scratch
= TRUE
; /* scratching and streaks */
2775 streak_color
= "silvery";
2778 /* Objects passing the is_flimsy() test will not
2779 scratch a stone. They will leave streaks on
2780 non-touchstones and touchstones alike. */
2782 streak_color
= c_obj_colors
[objects
[obj
->otyp
].oc_color
];
2784 do_scratch
= (tstone
->otyp
!= TOUCHSTONE
);
2787 break; /* default oclass */
2790 Sprintf(stonebuf
, "stone%s", plur(tstone
->quan
));
2792 You("make %s%sscratch marks on the %s.",
2793 streak_color
? streak_color
: (const char *) "",
2794 streak_color
? " " : "", stonebuf
);
2795 else if (streak_color
)
2796 You_see("%s streaks on the %s.", streak_color
, stonebuf
);
2805 gt
.trapinfo
.tobj
= 0;
2806 gt
.trapinfo
.force_bungle
= 0;
2809 /* Place a landmine/bear trap. Helge Hafting */
2811 use_trap(struct obj
*otmp
)
2814 const char *what
= (char *) 0;
2816 int levtyp
= levl
[u
.ux
][u
.uy
].typ
;
2817 const char *occutext
= "setting the trap";
2819 if (nohands(gy
.youmonst
.data
))
2820 what
= "without hands";
2822 what
= "while stunned";
2823 else if (u
.uswallow
)
2824 what
= digests(u
.ustuck
->data
) ? "while swallowed" : "while engulfed";
2825 else if (Underwater
)
2826 what
= "underwater";
2827 else if (Levitation
)
2828 what
= "while levitating";
2829 else if (is_pool(u
.ux
, u
.uy
))
2831 else if (is_lava(u
.ux
, u
.uy
))
2833 else if (On_stairs(u
.ux
, u
.uy
)) {
2834 stairway
*stway
= stairway_at(u
.ux
, u
.uy
);
2835 what
= stway
->isladder
? "on the ladder" : "on the stairs";
2836 } else if (IS_FURNITURE(levtyp
) || IS_OBSTRUCTED(levtyp
)
2837 || closed_door(u
.ux
, u
.uy
) || t_at(u
.ux
, u
.uy
))
2839 else if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
))
2840 what
= (levtyp
== AIR
)
2844 : "in this place"; /* Air/Water Plane catch-all */
2846 You_cant("set a trap %s!", what
);
2850 ttyp
= (otmp
->otyp
== LAND_MINE
) ? LANDMINE
: BEAR_TRAP
;
2851 if (otmp
== gt
.trapinfo
.tobj
&& u_at(gt
.trapinfo
.tx
, gt
.trapinfo
.ty
)) {
2852 You("resume setting %s%s.", shk_your(buf
, otmp
),
2853 trapname(ttyp
, FALSE
));
2854 set_occupation(set_trap
, occutext
, 0);
2857 gt
.trapinfo
.tobj
= otmp
;
2858 gt
.trapinfo
.tx
= u
.ux
, gt
.trapinfo
.ty
= u
.uy
;
2860 gt
.trapinfo
.time_needed
=
2861 (tmp
> 17) ? 2 : (tmp
> 12) ? 3 : (tmp
> 7) ? 4 : 5;
2863 gt
.trapinfo
.time_needed
*= 2;
2865 if (ttyp
== BEAR_TRAP
&& tmp
< 18)
2866 gt
.trapinfo
.time_needed
+= (tmp
> 12) ? 1 : (tmp
> 7) ? 2 : 4;
2867 /*[fumbling and/or confusion and/or cursed object check(s)
2868 should be incorporated here instead of in set_trap]*/
2869 if (u
.usteed
&& P_SKILL(P_RIDING
) < P_BASIC
) {
2872 if (Fumbling
|| otmp
->cursed
)
2873 chance
= (rnl(10) > 3);
2875 chance
= (rnl(10) > 5);
2876 You("aren't very skilled at reaching from %s.", mon_nam(u
.usteed
));
2877 Sprintf(buf
, "Continue your attempt to set %s?",
2878 the(trapname(ttyp
, FALSE
)));
2879 if (y_n(buf
) == 'y') {
2882 case LANDMINE
: /* set it off */
2883 gt
.trapinfo
.time_needed
= 0;
2884 gt
.trapinfo
.force_bungle
= TRUE
;
2886 case BEAR_TRAP
: /* drop it without arming it */
2888 You("drop %s!", the(trapname(ttyp
, FALSE
)));
2898 You("begin setting %s%s.", shk_your(buf
, otmp
), trapname(ttyp
, FALSE
));
2899 use_unpaid_trapobj(otmp
, u
.ux
, u
.uy
);
2900 set_occupation(set_trap
, occutext
, 0);
2904 /* occupation routine called each turn while arming a beartrap or landmine */
2908 struct obj
*otmp
= gt
.trapinfo
.tobj
;
2912 if (!otmp
|| !carried(otmp
) || !u_at(gt
.trapinfo
.tx
, gt
.trapinfo
.ty
)) {
2913 /* trap object might have been stolen or hero teleported */
2918 if (--gt
.trapinfo
.time_needed
> 0)
2919 return 1; /* still busy */
2921 ttyp
= (otmp
->otyp
== LAND_MINE
) ? LANDMINE
: BEAR_TRAP
;
2922 ttmp
= maketrap(u
.ux
, u
.uy
, ttyp
);
2926 if (*in_rooms(u
.ux
, u
.uy
, SHOPBASE
)) {
2927 add_damage(u
.ux
, u
.uy
, 0L); /* schedule removal */
2929 if (!gt
.trapinfo
.force_bungle
)
2930 You("finish arming %s.", the(trapname(ttyp
, FALSE
)));
2931 if (((otmp
->cursed
|| Fumbling
) && (rnl(10) > 5))
2932 || gt
.trapinfo
.force_bungle
)
2934 (unsigned) (gt
.trapinfo
.force_bungle
? FORCEBUNGLE
: 0));
2936 /* this shouldn't happen */
2937 Your("trap setting attempt fails.");
2945 use_whip(struct obj
*obj
)
2950 int rx
, ry
, proficient
, res
= ECMD_OK
;
2951 const char *msg_slipsfree
= "The bullwhip slips free.";
2952 const char *msg_snap
= "Snap!";
2955 if (wield_tool(obj
, "lash")) {
2956 cmdq_add_ec(CQ_CANNED
, doapply
);
2957 cmdq_add_key(CQ_CANNED
, obj
->invlet
);
2962 if (!getdir((char *) 0))
2963 return (res
|ECMD_CANCEL
);
2973 if (!isok(rx
, ry
)) {
2977 mtmp
= m_at(rx
, ry
);
2980 /* fake some proficiency checks */
2982 if (Role_if(PM_ARCHEOLOGIST
))
2984 if (ACURR(A_DEX
) < 6)
2986 else if (ACURR(A_DEX
) >= 14)
2987 proficient
+= (ACURR(A_DEX
) - 14);
2996 There("is not enough room to flick your bullwhip.");
2998 } else if (Underwater
) {
2999 There("is too much resistance to flick your bullwhip.");
3001 } else if (u
.dz
< 0) {
3002 You("flick a bug off of the %s.", ceiling(u
.ux
, u
.uy
));
3004 } else if (!u
.dz
&& (IS_WATERWALL(levl
[rx
][ry
].typ
)
3005 || levl
[rx
][ry
].typ
== LAVAWALL
)) {
3006 You("cause a small splash.");
3007 if (levl
[rx
][ry
].typ
== LAVAWALL
)
3008 (void) fire_damage(uwep
, FALSE
, rx
, ry
);
3010 } else if ((!u
.dx
&& !u
.dy
) || (u
.dz
> 0)) {
3013 /* Sometimes you hit your steed by mistake */
3014 if (u
.usteed
&& !rn2(proficient
+ 2)) {
3015 You("whip %s!", mon_nam(u
.usteed
));
3019 if (is_pool_or_lava(u
.ux
, u
.uy
)
3020 || IS_WATERWALL(levl
[rx
][ry
].typ
)
3021 || levl
[rx
][ry
].typ
== LAVAWALL
) {
3022 You("cause a small splash.");
3023 if (is_lava(u
.ux
, u
.uy
))
3024 (void) fire_damage(uwep
, FALSE
, u
.ux
, u
.uy
);
3027 if (Levitation
|| u
.usteed
|| Flying
) {
3028 /* Have a shot at snaring something on the floor. A flyer
3029 can reach the floor so could just pick an item up, but
3030 allow snagging by whip too. */
3031 otmp
= svl
.level
.objects
[u
.ux
][u
.uy
];
3032 if (otmp
&& otmp
->otyp
== CORPSE
3033 && (otmp
->corpsenm
== PM_HORSE
3034 || otmp
->corpsenm
== little_to_big(PM_HORSE
) /* warhorse */
3035 || otmp
->corpsenm
== big_to_little(PM_HORSE
))) { /* pony */
3036 pline("Why beat a dead horse?");
3039 if (otmp
&& proficient
) {
3040 You("wrap your bullwhip around %s on the %s.",
3041 an(singular(otmp
, xname
)), surface(u
.ux
, u
.uy
));
3042 if (rnl(6) || pickup_object(otmp
, 1L, TRUE
) < 1)
3043 pline1(msg_slipsfree
);
3047 dam
= rnd(2) + dbon() + obj
->spe
;
3050 You("hit your %s with your bullwhip.", body_part(FOOT
));
3051 Sprintf(buf
, "killed %sself with %s bullwhip", uhim(), uhis());
3052 losehp(Maybe_Half_Phys(dam
), buf
, NO_KILLER_PREFIX
);
3055 } else if ((Fumbling
|| Glib
) && !rn2(5)) {
3056 pline_The("bullwhip slips out of your %s.", body_part(HAND
));
3059 } else if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
3063 * if you're in a pit
3064 * - you are attempting to get out of the pit
3065 * - if there is no suitable boulder or furniture to target,
3066 * target a big monster for that, or if a small or medium
3067 * monster is present, attack it
3068 * [if both boulder and furniture are present, target the
3069 * former because it is on top of the latter]
3070 * else if you are applying it towards a monster
3071 * - if monster is concealed, reveal it and proceed;
3072 * - if it was not concealed and is wielding a weapon, attempt
3074 * - otherwise attack it.
3076 * if you're confused (and thus off the mark)
3077 * - you only end up hitting.
3079 const char *wrapped_what
= sobj_at(BOULDER
, rx
, ry
) ? "a boulder"
3080 : IS_FURNITURE(levl
[rx
][ry
].typ
)
3081 ? something
: (char *) 0;
3084 /* if a big monster is known to be present, target it in
3085 preference to boulder or furniture; if any small or medium
3086 monster is present, or an unseen big one, use the boulder
3087 or furniture if available, otherwise attack */
3088 if (bigmonst(mtmp
->data
) && canspotmon(mtmp
))
3089 wrapped_what
= strcpy(buf
, mon_nam(mtmp
));
3099 You("wrap your bullwhip around %s.", wrapped_what
);
3100 if (proficient
&& rn2(proficient
+ 2)) {
3101 if (!mtmp
|| enexto(&cc
, rx
, ry
, gy
.youmonst
.data
)) {
3102 You("yank yourself out of the pit!");
3103 reset_utrap(TRUE
); /* [was after teleds(); do this before
3104 * in case it has no alternative other
3105 * than to put hero in another trap] */
3106 teleds(cc
.x
, cc
.y
, TELEDS_ALLOW_DRAG
);
3107 gv
.vision_full_recalc
= 1;
3110 pline1(msg_slipsfree
);
3119 otmp
= 0; /* if monster is unseen, can't attempt to disarm it */
3120 if (!canspotmon(mtmp
)) {
3123 mtmp
->mundetected
= 0; /* bring non-mimic hider out of hiding */
3124 /* check visibility again after mundetected=0 in case being
3125 brought out of hiding has exposed it (might not if hero is
3126 blind or formerly hidden monster is also invisible) */
3127 spotitnow
= canspotmon(mtmp
);
3128 if (spotitnow
|| !glyph_is_invisible(levl
[rx
][ry
].glyph
)) {
3129 pline("%s is there that you %s.",
3130 !spotitnow
? "A monster" : Amonnam(mtmp
),
3131 !Blind
? "couldn't see" : "hadn't noticed");
3133 map_invisible(rx
, ry
);
3138 /* monster is known so if it is wielding something, try to
3139 disarm it rather than make a direct attack */
3140 otmp
= MON_WEP(mtmp
);
3144 char onambuf
[BUFSZ
];
3145 const char *mon_hand
;
3146 boolean gotit
= proficient
&& (!Fumbling
|| !rn2(10));
3148 Strcpy(onambuf
, cxname(otmp
));
3150 mon_hand
= mbodypart(mtmp
, HAND
);
3152 mon_hand
= makeplural(mon_hand
);
3154 mon_hand
= 0; /* lint suppression */
3156 You("wrap your bullwhip around %s.", yname(otmp
));
3157 if (gotit
&& mwelded(otmp
)) {
3158 pline("%s welded to %s %s%c",
3159 (otmp
->quan
== 1L) ? "It is" : "They are", mhis(mtmp
),
3160 mon_hand
, !otmp
->bknown
? '!' : '.');
3161 set_bknown(otmp
, 1);
3162 gotit
= FALSE
; /* can't pull it free */
3165 obj_extract_self(otmp
);
3166 possibly_unwield(mtmp
, FALSE
);
3167 setmnotwielded(mtmp
, otmp
);
3169 switch (rn2(proficient
+ 1)) {
3171 /* to floor near you */
3172 You("yank %s to the %s!", yname(otmp
),
3173 surface(u
.ux
, u
.uy
));
3174 place_object(otmp
, u
.ux
, u
.uy
);
3181 /* proficient with whip, but maybe not
3182 so proficient at catching weapons */
3185 hitvalu
= 8 + otmp
->spe
;
3186 hitu
= thitu(hitvalu
, dmgval(otmp
, &gy
.youmonst
),
3189 pline_The("%s hits you as you try to snatch it!",
3192 place_object(otmp
, u
.ux
, u
.uy
);
3197 /* right into your inventory */
3198 You("snatch %s!", yname(otmp
));
3199 if (otmp
->otyp
== CORPSE
3200 && touch_petrifies(&mons
[otmp
->corpsenm
]) && !uarmg
3201 && !Stone_resistance
3202 && !(poly_when_stoned(gy
.youmonst
.data
)
3203 && polymon(PM_STONE_GOLEM
))) {
3206 Strcpy(kbuf
, (otmp
->quan
== 1L) ? an(onambuf
)
3208 pline("Snatching %s is a fatal mistake.", kbuf
);
3209 /* corpse probably has a rot timer but is now
3210 OBJ_FREE; end of game cleanup will panic if
3211 it isn't part of current level; plus it would
3212 be missing from bones, so put it on the floor */
3213 place_object(otmp
, u
.ux
, u
.uy
); /* but don't stack */
3216 /* life-saved; free the corpse again */
3217 obj_extract_self(otmp
);
3219 (void) hold_another_object(otmp
, "You drop %s!",
3220 doname(otmp
), (const char *) 0);
3223 /* to floor beneath mon */
3224 You("yank %s from %s %s!", the(onambuf
),
3225 s_suffix(mon_nam(mtmp
)), mon_hand
);
3226 obj_no_longer_held(otmp
);
3227 place_object(otmp
, mtmp
->mx
, mtmp
->my
);
3232 pline1(msg_slipsfree
);
3234 } else { /* mtmp isn't wielding a weapon; attack it */
3235 boolean do_snap
= TRUE
;
3237 if (M_AP_TYPE(mtmp
) && !Protection_from_shape_changers
3238 && !sensemon(mtmp
)) {
3239 stumble_onto_mimic(mtmp
);
3242 You("flick your bullwhip towards %s.", mon_nam(mtmp
));
3244 if (proficient
&& force_attack(mtmp
, FALSE
))
3249 /* regardless of mtmp's weapon or hero's proficiency */
3252 } else if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)) {
3253 /* it must be air -- water checked above */
3254 You("snap your whip through thin air.");
3263 not_enough_room
[] = "There's not enough room here to use that.",
3264 where_to_hit
[] = "Where do you want to hit?",
3265 cant_see_spot
[] = "won't hit anything if you can't see that spot.",
3266 cant_reach
[] = "can't reach that spot from here.";
3268 #define glyph_is_poleable(G) \
3269 (glyph_is_monster(G) || glyph_is_invisible(G) || glyph_is_statue(G))
3271 /* find pos of monster in range, if only one monster */
3273 find_poleable_mon(coord
*pos
, int min_range
, int max_range
)
3276 coord mpos
= { 0, 0 }; /* no candidate location yet */
3278 coordxy x
, y
, lo_x
, hi_x
, lo_y
, hi_y
, rt
;
3281 impaired
= (Confusion
|| Stunned
|| Hallucination
);
3282 rt
= isqrt(max_range
);
3283 lo_x
= max(u
.ux
- rt
, 1), hi_x
= min(u
.ux
+ rt
, COLNO
- 1);
3284 lo_y
= max(u
.uy
- rt
, 0), hi_y
= min(u
.uy
+ rt
, ROWNO
- 1);
3285 for (x
= lo_x
; x
<= hi_x
; ++x
) {
3286 for (y
= lo_y
; y
<= hi_y
; ++y
) {
3287 if (distu(x
, y
) < min_range
|| distu(x
, y
) > max_range
3288 || !isok(x
, y
) || !cansee(x
, y
))
3290 glyph
= glyph_at(x
, y
);
3292 && glyph_is_monster(glyph
)
3293 && (mtmp
= m_at(x
, y
)) != 0
3294 && (mtmp
->mtame
|| (mtmp
->mpeaceful
&& flags
.confirm
)))
3296 if (glyph_is_poleable(glyph
)
3297 && (!glyph_is_statue(glyph
) || impaired
)) {
3299 return FALSE
; /* more than one candidate location */
3300 mpos
.x
= x
, mpos
.y
= y
;
3305 return FALSE
; /* no candidate location */
3311 get_valid_polearm_position(coordxy x
, coordxy y
)
3315 glyph
= glyph_at(x
, y
);
3317 return (isok(x
, y
) && distu(x
, y
) >= gp
.polearm_range_min
3318 && distu(x
, y
) <= gp
.polearm_range_max
3319 && (cansee(x
, y
) || (couldsee(x
, y
)
3320 && glyph_is_poleable(glyph
))));
3324 display_polearm_positions(boolean on_off
)
3326 coordxy x
, y
, dx
, dy
;
3330 tmp_at(DISP_BEAM
, cmap_to_glyph(S_goodpos
));
3331 for (dx
= -3; dx
<= 3; dx
++)
3332 for (dy
= -3; dy
<= 3; dy
++) {
3333 x
= dx
+ (int) u
.ux
;
3334 y
= dy
+ (int) u
.uy
;
3335 if (get_valid_polearm_position(x
, y
)) {
3341 tmp_at(DISP_END
, 0);
3346 * Calculate allowable range (pole's reach is always 2 steps):
3347 * unskilled and basic: orthogonal direction, 4..4;
3348 * skilled: as basic, plus knight's jump position, 4..5;
3349 * expert: as skilled, plus diagonal, 4..8.
3357 * (Note: no roles in NetHack can become expert or better
3358 * for polearm skill; Yeoman in slash'em can become expert.)
3361 calc_pole_range(int *min_range
, int *max_range
)
3363 int typ
= uwep_skill_type();
3366 if (typ
== P_NONE
|| P_SKILL(typ
) <= P_BASIC
)
3368 else if (P_SKILL(typ
) == P_SKILLED
)
3371 *max_range
= 8; /* (P_SKILL(typ) >= P_EXPERT) */
3373 gp
.polearm_range_min
= *min_range
;
3374 gp
.polearm_range_max
= *max_range
;
3378 /* return TRUE if hero is wielding a polearm and there's
3379 at least one monster they could hit with it */
3381 could_pole_mon(void)
3383 int min_range
, max_range
;
3385 struct monst
*hitm
= svc
.context
.polearm
.hitmon
;
3387 if (!uwep
|| !is_pole(uwep
))
3390 calc_pole_range(&min_range
, &max_range
);
3394 if (!find_poleable_mon(&cc
, min_range
, max_range
)) {
3395 if (hitm
&& !DEADMONSTER(hitm
) && sensemon(hitm
)
3396 && mdistu(hitm
) <= max_range
&& mdistu(hitm
) >= min_range
)
3404 /* Distance attacks by pole-weapons */
3406 use_pole(struct obj
*obj
, boolean autohit
)
3408 const char thump
[] = "Thump! Your blow bounces harmlessly off the %s.";
3409 int res
= ECMD_OK
, max_range
, min_range
, glyph
;
3412 struct monst
*hitm
= svc
.context
.polearm
.hitmon
;
3414 /* Are you allowed to use the pole? */
3416 pline(not_enough_room
);
3420 if (wield_tool(obj
, "swing")) {
3421 cmdq_add_ec(CQ_CANNED
, doapply
);
3422 cmdq_add_key(CQ_CANNED
, obj
->invlet
);
3427 /* assert(obj == uwep); */
3429 calc_pole_range(&min_range
, &max_range
);
3431 /* Prompt for a location */
3433 pline(where_to_hit
);
3436 if (!find_poleable_mon(&cc
, min_range
, max_range
) && hitm
3437 && !DEADMONSTER(hitm
) && sensemon(hitm
)
3438 && mdistu(hitm
) <= max_range
&& mdistu(hitm
) >= min_range
) {
3443 getpos_sethilite(display_polearm_positions
,
3444 get_valid_polearm_position
);
3445 if (getpos(&cc
, TRUE
, "the spot to hit") < 0)
3446 /* ESC; uses turn iff polearm became wielded */
3447 return (res
| ECMD_CANCEL
);
3450 glyph
= glyph_at(cc
.x
, cc
.y
);
3451 if (distu(cc
.x
, cc
.y
) > max_range
) {
3454 } else if (distu(cc
.x
, cc
.y
) < min_range
) {
3455 if (autohit
&& u_at(cc
.x
, cc
.y
))
3456 pline("Don't know what to hit.");
3458 pline("Too close!");
3460 } else if (!cansee(cc
.x
, cc
.y
) && !glyph_is_poleable(glyph
)) {
3463 } else if (!couldsee(cc
.x
, cc
.y
)) { /* Eyes of the Overworld */
3468 svc
.context
.polearm
.hitmon
= (struct monst
*) 0;
3469 /* Attack the monster there */
3471 if ((mtmp
= m_at(gb
.bhitpos
.x
, gb
.bhitpos
.y
)) != (struct monst
*) 0) {
3472 if (attack_checks(mtmp
, uwep
)) /* can attack proceed? */
3473 /* no, abort the attack attempt; result depends on
3474 res: 1 => polearm became wielded, 0 => already wielded;
3475 svc.context.move: 1 => discovered hidden monster at target spot,
3476 0 => answered 'n' to "Really attack?" prompt */
3477 return res
| (svc
.context
.move
? ECMD_TIME
: ECMD_OK
);
3479 return ECMD_TIME
; /* burn nutrition; maybe pass out */
3480 svc
.context
.polearm
.hitmon
= mtmp
;
3481 check_caitiff(mtmp
);
3482 gn
.notonhead
= (gb
.bhitpos
.x
!= mtmp
->mx
|| gb
.bhitpos
.y
!= mtmp
->my
);
3483 (void) thitmonst(mtmp
, uwep
);
3484 } else if (glyph_is_statue(glyph
) /* might be hallucinatory */
3485 && sobj_at(STATUE
, gb
.bhitpos
.x
, gb
.bhitpos
.y
)) {
3486 struct trap
*t
= t_at(gb
.bhitpos
.x
, gb
.bhitpos
.y
);
3488 if (t
&& t
->ttyp
== STATUE_TRAP
3489 && activate_statue_trap(t
, t
->tx
, t
->ty
, FALSE
)) {
3490 ; /* feedback has been give by animate_statue() */
3492 /* Since statues look like monsters now, we say something
3493 different from "you miss" or "there's nobody there".
3494 Note: we only do this when a statue is displayed here,
3495 because the player is probably attempting to attack it;
3496 other statues obscured by anything are just ignored. */
3497 pline(thump
, "statue");
3498 wake_nearto(gb
.bhitpos
.x
, gb
.bhitpos
.y
, 25);
3501 /* no monster here and no statue seen or remembered here */
3502 (void) unmap_invisible(gb
.bhitpos
.x
, gb
.bhitpos
.y
);
3504 if (glyph_to_obj(glyph
) == BOULDER
3505 && sobj_at(BOULDER
, gb
.bhitpos
.x
, gb
.bhitpos
.y
)) {
3506 pline(thump
, "boulder");
3507 wake_nearto(gb
.bhitpos
.x
, gb
.bhitpos
.y
, 25);
3508 } else if (!accessible(gb
.bhitpos
.x
, gb
.bhitpos
.y
)
3509 || IS_FURNITURE(levl
[gb
.bhitpos
.x
][gb
.bhitpos
.y
].typ
)) {
3510 /* similar to 'F'orcefight with a melee weapon; we know that
3511 the spot can be seen or we wouldn't have gotten this far */
3512 You("uselessly attack %s.",
3513 (levl
[gb
.bhitpos
.x
][gb
.bhitpos
.y
].typ
== STONE
3514 || levl
[gb
.bhitpos
.x
][gb
.bhitpos
.y
].typ
== SCORR
)
3516 : glyph_is_cmap(glyph
)
3517 ? the(defsyms
[glyph_to_cmap(glyph
)].explanation
)
3518 : (const char *) "an unknown obstacle");
3520 You("miss; there is no one there to hit.");
3523 u_wipe_engr(2); /* same as for melee or throwing */
3527 #undef glyph_is_poleable
3530 use_cream_pie(struct obj
*obj
)
3532 boolean wasblind
= Blind
;
3533 boolean wascreamed
= u
.ucreamed
;
3534 boolean several
= FALSE
;
3536 if (obj
->quan
> 1L) {
3538 obj
= splitobj(obj
, 1L);
3541 You("give yourself a facial.");
3543 You("immerse your %s in %s%s.", body_part(FACE
),
3544 several
? "one of " : "",
3545 several
? makeplural(the(xname(obj
))) : the(xname(obj
)));
3546 if (can_blnd((struct monst
*) 0, &gy
.youmonst
, AT_WEAP
, obj
)) {
3547 int blindinc
= rnd(25);
3549 u
.ucreamed
+= blindinc
;
3550 make_blinded(BlindedTimeout
+ (long) blindinc
, FALSE
);
3551 if (!Blind
|| (Blind
&& wasblind
))
3552 pline("There's %ssticky goop all over your %s.",
3553 wascreamed
? "more " : "", body_part(FACE
));
3554 else /* Blind && !wasblind */
3555 You_cant("see through all the sticky goop on your %s.",
3560 /* useup() is appropriate, but we want costly_alteration()'s message */
3561 costly_alteration(obj
, COST_SPLAT
);
3562 obj_extract_self(obj
);
3567 /* getobj callback for object to rub royal jelly on */
3569 jelly_ok(struct obj
*obj
)
3571 if (obj
&& obj
->otyp
== EGG
)
3572 return GETOBJ_SUGGEST
;
3574 return GETOBJ_EXCLUDE
;
3578 use_royal_jelly(struct obj
**optr
)
3582 struct obj
*eobj
, *obj
= *optr
;
3583 boolean splitit
= (obj
->quan
> 1L);
3586 obj
= splitobj(obj
, 1L);
3587 /* remove from inventory so that it won't be offered as a choice
3591 /* right now you can rub one royal jelly on an entire stack of eggs */
3592 eobj
= getobj("rub the royal jelly on", jelly_ok
, GETOBJ_PROMPT
);
3595 (void) unsplitobj(obj
);
3596 update_inventory(); /* freeinv() updated perminv w/ obj omitted */
3598 /* this lump was already separate; pervent merge */
3599 addinv_nomerge(obj
); /* put unused lump back; updates perminv */
3604 You("smear royal jelly all over %s.", yname(eobj
));
3605 if (eobj
->otyp
!= EGG
) {
3606 pline1(nothing_happens
);
3610 oldcorpsenm
= eobj
->corpsenm
;
3611 if (eobj
->corpsenm
== PM_KILLER_BEE
)
3612 eobj
->corpsenm
= PM_QUEEN_BEE
;
3615 if (eobj
->timed
|| eobj
->corpsenm
!= oldcorpsenm
)
3616 pline("The %s %s feebly.", xname(eobj
), otense(eobj
, "quiver"));
3618 pline("%s", nothing_seems_to_happen
);
3623 was_timed
= eobj
->timed
;
3624 if (eobj
->corpsenm
!= NON_PM
) {
3626 attach_egg_hatch_timeout(eobj
, 0L);
3627 /* blessed royal jelly will make the hatched creature think
3628 you're the parent - but has no effect if you laid the egg */
3629 if (obj
->blessed
&& !eobj
->spe
)
3633 if ((eobj
->timed
&& !was_timed
) || eobj
->spe
== 2
3634 || eobj
->corpsenm
!= oldcorpsenm
)
3635 pline("The %s %s briefly.", xname(eobj
), otense(eobj
, "quiver"));
3637 pline("%s", nothing_seems_to_happen
);
3640 /* not useup() because we've already done freeinv() */
3642 obfree(obj
, (struct obj
*) 0);
3650 int typ
= uwep_skill_type();
3653 if (typ
== P_NONE
|| P_SKILL(typ
) <= P_BASIC
)
3655 else if (P_SKILL(typ
) == P_SKILLED
)
3663 can_grapple_location(coordxy x
, coordxy y
)
3665 return (isok(x
, y
) && cansee(x
, y
) && distu(x
, y
) <= grapple_range());
3669 display_grapple_positions(boolean on_off
)
3671 coordxy x
, y
, dx
, dy
;
3675 tmp_at(DISP_BEAM
, cmap_to_glyph(S_goodpos
));
3676 for (dx
= -3; dx
<= 3; dx
++)
3677 for (dy
= -3; dy
<= 3; dy
++) {
3678 x
= dx
+ (int) u
.ux
;
3679 y
= dy
+ (int) u
.uy
;
3680 if (can_grapple_location(x
, y
) && !u_at(x
, y
)) {
3686 tmp_at(DISP_END
, 0);
3691 use_grapple(struct obj
*obj
)
3693 int res
= ECMD_OK
, typ
, tohit
;
3694 boolean save_confirm
;
3699 /* Are you allowed to use the hook? */
3701 pline(not_enough_room
);
3705 /* "cast": grappling hook evolved from slash'em's fishing pole */
3706 if (wield_tool(obj
, "cast")) {
3707 cmdq_add_ec(CQ_CANNED
, doapply
);
3708 cmdq_add_key(CQ_CANNED
, obj
->invlet
);
3713 /* assert(obj == uwep); */
3715 /* Prompt for a location */
3716 pline(where_to_hit
);
3719 getpos_sethilite(display_grapple_positions
, can_grapple_location
);
3720 if (getpos(&cc
, TRUE
, "the spot to hit") < 0)
3721 /* ESC; uses turn iff grapnel became wielded */
3722 return (res
| ECMD_CANCEL
);
3724 /* Calculate range; unlike use_pole(), there's no minimum for range */
3725 typ
= uwep_skill_type();
3726 if (distu(cc
.x
, cc
.y
) > grapple_range()) {
3729 } else if (!cansee(cc
.x
, cc
.y
)) {
3732 } else if (!couldsee(cc
.x
, cc
.y
)) { /* Eyes of the Overworld */
3737 /* What do you want to hit? */
3739 if (typ
!= P_NONE
&& P_SKILL(typ
) >= P_SKILLED
) {
3740 winid tmpwin
= create_nhwindow(NHW_MENU
);
3743 menu_item
*selected
;
3746 any
= cg
.zeroany
; /* set all bits to zero */
3747 any
.a_int
= 1; /* use index+1 (can't use 0) as identifier */
3748 start_menu(tmpwin
, MENU_BEHAVE_STANDARD
);
3750 Sprintf(buf
, "an object on the %s", surface(cc
.x
, cc
.y
));
3751 add_menu(tmpwin
, &nul_glyphinfo
, &any
, 0, 0, ATR_NONE
,
3752 clr
, buf
, MENU_ITEMFLAGS_NONE
);
3754 add_menu(tmpwin
, &nul_glyphinfo
, &any
, 0, 0, ATR_NONE
,
3755 clr
, "a monster", MENU_ITEMFLAGS_NONE
);
3757 Sprintf(buf
, "the %s", surface(cc
.x
, cc
.y
));
3758 add_menu(tmpwin
, &nul_glyphinfo
, &any
, 0, 0, ATR_NONE
, clr
,
3759 buf
, MENU_ITEMFLAGS_NONE
);
3760 end_menu(tmpwin
, "Aim for what?");
3762 if (select_menu(tmpwin
, PICK_ONE
, &selected
) > 0
3763 && rn2(P_SKILL(typ
) > P_SKILLED
? 20 : 2))
3764 tohit
= selected
[0].item
.a_int
- 1;
3765 free((genericptr_t
) selected
);
3766 destroy_nhwindow(tmpwin
);
3769 /* possibly scuff engraving at your feet;
3770 any engraving at the target location is unaffected */
3771 if (tohit
== 2 || !rn2(2))
3772 u_wipe_engr(rnd(2));
3774 /* What did you hit? */
3777 /* FIXME -- untrap needs to deal with non-adjacent traps */
3779 case 1: /* Object */
3780 if ((otmp
= svl
.level
.objects
[cc
.x
][cc
.y
]) != 0) {
3781 You("snag an object from the %s!", surface(cc
.x
, cc
.y
));
3782 (void) pickup_object(otmp
, 1L, FALSE
);
3783 /* If pickup fails, leave it alone */
3788 case 2: /* Monster */
3790 if ((mtmp
= m_at(cc
.x
, cc
.y
)) == (struct monst
*) 0)
3792 gn
.notonhead
= (gb
.bhitpos
.x
!= mtmp
->mx
|| gb
.bhitpos
.y
!= mtmp
->my
);
3793 save_confirm
= flags
.confirm
;
3794 if (verysmall(mtmp
->data
) && !rn2(4)
3795 && enexto(&cc
, u
.ux
, u
.uy
, (struct permonst
*) 0)) {
3796 flags
.confirm
= FALSE
;
3797 (void) attack_checks(mtmp
, uwep
);
3798 flags
.confirm
= save_confirm
;
3799 check_caitiff(mtmp
); /* despite fact there's no damage */
3800 You("pull in %s!", mon_nam(mtmp
));
3801 mtmp
->mundetected
= 0;
3802 rloc_to(mtmp
, cc
.x
, cc
.y
);
3804 } else if ((!bigmonst(mtmp
->data
) && !strongmonst(mtmp
->data
))
3806 flags
.confirm
= FALSE
;
3807 (void) attack_checks(mtmp
, uwep
);
3808 flags
.confirm
= save_confirm
;
3809 check_caitiff(mtmp
);
3810 (void) thitmonst(mtmp
, uwep
);
3815 case 3: /* Surface */
3816 if (IS_AIR(levl
[cc
.x
][cc
.y
].typ
) || is_pool(cc
.x
, cc
.y
))
3817 pline_The("hook slices through the %s.", surface(cc
.x
, cc
.y
));
3819 You("are yanked toward the %s!", surface(cc
.x
, cc
.y
));
3820 hurtle(sgn(cc
.x
- u
.ux
), sgn(cc
.y
- u
.uy
), 1, FALSE
);
3824 default: /* Yourself (oops!) */
3825 if (P_SKILL(typ
) <= P_BASIC
) {
3826 You("hook yourself!");
3827 losehp(Maybe_Half_Phys(rn1(10, 10)), "a grappling hook",
3833 pline1(nothing_happens
);
3838 discard_broken_wand(void)
3842 obj
= gc
.current_wand
; /* [see dozap() and destroy_items()] */
3843 gc
.current_wand
= 0;
3850 broken_wand_explode(struct obj
*obj
, int dmg
, int expltype
)
3852 explode(u
.ux
, u
.uy
, -(obj
->otyp
), dmg
, WAND_CLASS
, expltype
);
3853 makeknown(obj
->otyp
); /* explode describes the effect */
3854 discard_broken_wand();
3857 /* if x,y has lava or water, dunk any boulders at that location into it */
3859 maybe_dunk_boulders(coordxy x
, coordxy y
)
3863 while (is_pool_or_lava(x
, y
) && (otmp
= sobj_at(BOULDER
, x
, y
)) != 0) {
3864 obj_extract_self(otmp
);
3865 (void) boulder_hits_pool(otmp
, x
,y
, FALSE
);
3869 /* return 1 if the wand is broken, hence some time elapsed */
3871 do_break_wand(struct obj
*obj
)
3873 #define BY_OBJECT ((struct monst *) 0)
3874 static const char nothing_else_happens
[] = "But nothing else happens...";
3879 boolean affects_objects
;
3880 boolean shop_damage
= FALSE
;
3881 boolean fillmsg
= FALSE
;
3882 char confirm
[QBUFSZ
], buf
[BUFSZ
];
3883 boolean is_fragile
= (objdescr_is(obj
, "balsa")
3884 || objdescr_is(obj
, "glass"));
3886 if (nohands(gy
.youmonst
.data
)) {
3887 You_cant("break %s without hands!", yname(obj
));
3889 } else if (!freehand()) {
3890 Your("%s are occupied!", makeplural(body_part(HAND
)));
3892 } else if (ACURR(A_STR
) < (is_fragile
? 5 : 10)) {
3893 You("don't have the strength to break %s!", yname(obj
));
3896 if (!paranoid_query(ParanoidBreakwand
,
3898 "Are you really sure you want to break ",
3899 "?", obj
, yname
, ysimple_name
, "the wand")))
3901 pline("Raising %s high above your %s, you %s it in two!", yname(obj
),
3902 body_part(HEAD
), is_fragile
? "snap" : "break");
3904 /* [ALI] Do this first so that wand is removed from bill. Otherwise,
3905 * the freeinv() below also hides it from setpaid() which causes problems.
3908 check_unpaid(obj
); /* Extra charge for use */
3909 costly_alteration(obj
, COST_DSTROY
);
3912 gc
.current_wand
= obj
; /* destroy_items might reset this */
3913 freeinv(obj
); /* hide it from destroy_items instead... */
3914 setnotworn(obj
); /* so we need to do this ourselves */
3916 if (!zappable(obj
)) {
3917 pline(nothing_else_happens
);
3918 discard_broken_wand();
3921 /* successful call to zappable() consumes a charge; put it back */
3923 /* might have "wrested" a final charge, taking it from 0 to -1;
3924 if so, we just brought it back up to 0, which wouldn't do much
3925 below so give it 1..3 charges now, usually making it stronger
3926 than an ordinary last charge (the wand is already gone from
3927 inventory, so perm_invent can't accidentally reveal this) */
3934 affects_objects
= FALSE
;
3936 switch (obj
->otyp
) {
3941 makeknown(WAN_OPENING
);
3942 discard_broken_wand();
3951 case WAN_ENLIGHTENMENT
:
3952 case WAN_SECRET_DOOR_DETECTION
:
3953 pline(nothing_else_happens
);
3954 discard_broken_wand();
3958 broken_wand_explode(obj
, dmg
* 4, EXPL_MAGICAL
);
3961 broken_wand_explode(obj
, dmg
* 2, EXPL_FIERY
);
3964 broken_wand_explode(obj
, dmg
* 2, EXPL_FROSTY
);
3966 case WAN_MAGIC_MISSILE
:
3967 broken_wand_explode(obj
, dmg
, EXPL_MAGICAL
);
3970 /* we want this before the explosion instead of at the very end */
3971 Soundeffect(se_wall_of_force
, 65);
3972 pline("A wall of force smashes down around you!");
3973 dmg
= d(1 + obj
->spe
, 6); /* normally 2d12 */
3976 case WAN_CANCELLATION
:
3978 case WAN_TELEPORTATION
:
3979 case WAN_UNDEAD_TURNING
:
3980 affects_objects
= TRUE
;
3986 /* magical explosion and its visual effect occur before specific effects
3988 /* [TODO? This really ought to prevent the explosion from being
3989 fatal so that we never leave a bones file where none of the
3990 surrounding targets (or underlying objects) got affected yet.] */
3991 explode(obj
->ox
, obj
->oy
, -(obj
->otyp
), rnd(dmg
), WAND_CLASS
,
3994 /* prepare for potential feedback from polymorph... */
3997 /* this makes it hit us last, so that we can see the action first */
3998 for (i
= 0; i
<= N_DIRS
; i
++) {
3999 gb
.bhitpos
.x
= x
= obj
->ox
+ xdir
[i
];
4000 gb
.bhitpos
.y
= y
= obj
->oy
+ ydir
[i
];
4004 if (obj
->otyp
== WAN_DIGGING
) {
4006 enum digcheck_result dcres
= dig_check(BY_OBJECT
, x
, y
);
4008 if (dcres
< DIGCHECK_FAILED
|| dcres
== DIGCHECK_FAIL_BOULDER
) {
4009 if (IS_WALL(levl
[x
][y
].typ
) || IS_DOOR(levl
[x
][y
].typ
)) {
4010 /* normally, pits and holes don't anger guards, but they
4011 * do if it's a wall or door that's being dug */
4012 watch_dig((struct monst
*) 0, x
, y
, TRUE
);
4013 if (*in_rooms(x
, y
, SHOPBASE
))
4017 * Let liquid flow into the newly created pits.
4018 * Adjust corresponding code in music.c for
4019 * drum of earthquake if you alter this sequence.
4021 typ
= fillholetyp(x
, y
, FALSE
);
4023 levl
[x
][y
].typ
= typ
, levl
[x
][y
].flags
= 0;
4024 liquid_flow(x
, y
, typ
, t_at(x
, y
),
4027 : "Some holes are quickly filled with %s!");
4030 digactualhole(x
, y
, BY_OBJECT
,
4032 || (!Can_dig_down(&u
.uz
)
4033 && !levl
[x
][y
].candig
)) ? PIT
: HOLE
);
4037 maybe_dunk_boulders(x
, y
);
4038 recalc_block_point(x
, y
);
4040 } else if (obj
->otyp
== WAN_CREATE_MONSTER
) {
4041 /* u.ux,u.uy creates it near you--x,y might create it in rock */
4042 (void) makemon((struct permonst
*) 0, u
.ux
, u
.uy
, NO_MM_FLAGS
);
4044 } else if (x
!= u
.ux
|| y
!= u
.uy
) {
4046 * Wand breakage is targeting a square adjacent to the hero,
4047 * which might contain a monster or a pile of objects or both.
4048 * Handle objects last; avoids having undead turning raise an
4049 * undead's corpse and then attack resulting undead monster.
4050 * obj->bypass in bhitm() prevents the polymorphing of items
4051 * dropped due to monster's polymorph and prevents undead
4052 * turning that kills an undead from raising resulting corpse.
4054 if ((mon
= m_at(x
, y
)) != 0) {
4055 (void) bhitm(mon
, obj
);
4056 /* if (disp.botl) bot(); */
4058 if (affects_objects
&& svl
.level
.objects
[x
][y
]) {
4059 (void) bhitpile(obj
, bhito
, x
, y
, 0);
4061 bot(); /* potion effects */
4065 * Wand breakage is targeting the hero. Using xdir[]+ydir[]
4066 * deltas for location selection causes this case to happen
4067 * after all the surrounding squares have been handled.
4068 * Process objects first, in case damage is fatal and leaves
4069 * bones, or teleportation sends one or more of the objects to
4070 * same destination as hero (lookhere/autopickup); also avoids
4071 * the polymorphing of gear dropped due to hero's transformation.
4072 * (Unlike with monsters being hit by zaps, we can't rely on use
4073 * of obj->bypass in the zap code to accomplish that last case
4074 * since it's also used by retouch_equipment() for polyself.)
4076 if (affects_objects
&& svl
.level
.objects
[x
][y
]) {
4077 (void) bhitpile(obj
, bhito
, x
, y
, 0);
4079 bot(); /* potion effects */
4081 damage
= zapyourself(obj
, FALSE
);
4083 Sprintf(buf
, "killed %sself by breaking a wand", uhim());
4084 losehp(Maybe_Half_Phys(damage
), buf
, NO_KILLER_PREFIX
);
4087 bot(); /* blindness */
4091 /* potentially give post zap/break feedback */
4094 /* Note: if player fell thru, this call is a no-op.
4095 Damage is handled in digactualhole in that case */
4097 pay_for_damage("dig into", FALSE
);
4099 if (obj
->otyp
== WAN_LIGHT
)
4100 litroom(TRUE
, obj
); /* only needs to be done once */
4102 discard_broken_wand();
4107 /* getobj callback for object to apply - this is more complex than most other
4108 * callbacks because there are a lot of appliables */
4110 apply_ok(struct obj
*obj
)
4113 return GETOBJ_EXCLUDE
;
4115 /* all tools, all wands (breaking), all spellbooks (flipping through -
4116 including blank/novel/Book of the Dead) */
4117 if (obj
->oclass
== TOOL_CLASS
|| obj
->oclass
== WAND_CLASS
4118 || obj
->oclass
== SPBOOK_CLASS
)
4119 return GETOBJ_SUGGEST
;
4121 /* applying coins to flip them is a minor easter egg, so do not suggest
4122 coin application to the player */
4123 if (obj
->oclass
== COIN_CLASS
)
4124 return GETOBJ_DOWNPLAY
;
4126 /* certain weapons */
4127 if (obj
->oclass
== WEAPON_CLASS
4128 && (is_pick(obj
) || is_axe(obj
) || is_pole(obj
)
4129 || obj
->otyp
== BULLWHIP
))
4130 return GETOBJ_SUGGEST
;
4132 if (obj
->oclass
== POTION_CLASS
) {
4133 /* permit applying unknown potions, but don't suggest them */
4134 if (!obj
->dknown
|| !objects
[obj
->otyp
].oc_name_known
)
4135 return GETOBJ_DOWNPLAY
;
4137 /* only applicable potion is oil, and it will only be suggested as a
4138 choice when already discovered */
4139 if (obj
->otyp
== POT_OIL
)
4140 return GETOBJ_SUGGEST
;
4144 if (obj
->otyp
== CREAM_PIE
|| obj
->otyp
== EUCALYPTUS_LEAF
4145 || obj
->otyp
== LUMP_OF_ROYAL_JELLY
)
4146 return GETOBJ_SUGGEST
;
4148 if (obj
->otyp
== BANANA
&& Hallucination
)
4149 return GETOBJ_DOWNPLAY
;
4151 if (is_graystone(obj
)) {
4152 /* The only case where we don't suggest a gray stone is if we KNOW it
4153 isn't a touchstone. */
4155 return GETOBJ_SUGGEST
;
4157 if (obj
->otyp
!= TOUCHSTONE
4158 && (objects
[TOUCHSTONE
].oc_name_known
4159 || objects
[obj
->otyp
].oc_name_known
))
4160 return GETOBJ_EXCLUDE_SELECTABLE
;
4162 return GETOBJ_SUGGEST
;
4165 /* item can't be applied; if picked anyway,
4166 _EXCLUDE would yield "That is a silly thing to apply.",
4167 _EXCLUDE_SELECTABLE yields "Sorry, I don't know how to use that." */
4168 return GETOBJ_EXCLUDE_SELECTABLE
;
4171 /* the #apply command, 'a' */
4176 int res
= ECMD_TIME
;
4178 if (nohands(gy
.youmonst
.data
)) {
4179 You("aren't able to use or apply tools in your current form.");
4182 if (check_capacity((char *) 0))
4185 obj
= getobj("use or apply", apply_ok
, GETOBJ_NOFLAGS
);
4189 if (!retouch_object(&obj
, FALSE
))
4190 return ECMD_TIME
; /* evading your grasp costs a turn; just be
4191 grateful that you don't drop it as well */
4193 if (obj
->oclass
== WAND_CLASS
)
4194 return do_break_wand(obj
);
4196 if (obj
->oclass
== SPBOOK_CLASS
)
4197 return flip_through_book(obj
);
4199 if (obj
->oclass
== COIN_CLASS
)
4200 return flip_coin(obj
);
4202 switch (obj
->otyp
) {
4205 if (obj
== ublindf
) {
4208 } else if (!ublindf
) {
4211 You("are already %s.",
4212 (ublindf
->otyp
== TOWEL
) ? "covered by a towel"
4213 : (ublindf
->otyp
== BLINDFOLD
) ? "wearing a blindfold"
4214 : "wearing lenses");
4218 res
= use_cream_pie(obj
);
4219 obj
= (struct obj
*) 0;
4221 case LUMP_OF_ROYAL_JELLY
:
4222 res
= use_royal_jelly(&obj
);
4225 res
= use_whip(obj
);
4227 case GRAPPLING_HOOK
:
4228 res
= use_grapple(obj
);
4234 case BAG_OF_HOLDING
:
4236 res
= use_container(&obj
, TRUE
, FALSE
);
4239 (void) bagotricks(obj
, FALSE
, (int *) 0);
4242 res
= use_grease(obj
);
4247 res
= (pick_lock(obj
, 0, 0, NULL
) != 0) ? ECMD_TIME
: ECMD_OK
;
4250 case DWARVISH_MATTOCK
:
4251 res
= use_pick_axe(obj
);
4254 use_tinning_kit(obj
);
4257 res
= use_leash(obj
);
4260 res
= use_saddle(obj
);
4263 use_magic_whistle(obj
);
4268 case EUCALYPTUS_LEAF
:
4269 /* MRKR: Every Australian knows that a gum leaf makes an excellent
4270 * whistle, especially if your pet is a tame kangaroo named Skippy.
4273 use_magic_whistle(obj
);
4274 /* sometimes the blessing will be worn off */
4277 pline("%s %s.", Yobjnam2(obj
, "glow"), hcolor("brown"));
4287 res
= use_stethoscope(obj
);
4290 res
= use_mirror(obj
);
4293 case BELL_OF_OPENING
:
4296 case CANDELABRUM_OF_INVOCATION
:
4297 use_candelabrum(obj
);
4309 light_cocktail(&obj
);
4311 case EXPENSIVE_CAMERA
:
4312 res
= use_camera(obj
);
4315 res
= use_towel(obj
);
4318 use_crystal_ball(&obj
);
4324 res
= use_tin_opener(obj
);
4327 res
= use_figurine(&obj
);
4330 use_unicorn_horn(&obj
);
4341 case DRUM_OF_EARTHQUAKE
:
4342 res
= do_play_instrument(obj
);
4344 case HORN_OF_PLENTY
: /* not a musical instrument */
4345 (void) hornoplenty(obj
, FALSE
, (struct obj
*) 0);
4350 if (go
.occupation
== set_trap
)
4351 obj
= (struct obj
*) 0; /* not gone yet but behave as if it was */
4357 res
= use_stone(obj
);
4360 if (Hallucination
) {
4361 pline("It rings! ... But no-one answers.");
4367 /* Pole-weapons can strike at a distance */
4369 res
= use_pole(obj
, FALSE
);
4371 } else if (is_pick(obj
) || is_axe(obj
)) {
4372 res
= use_pick_axe(obj
);
4375 pline("Sorry, I don't know how to use that.");
4378 /* This assumes that anything that potentially destroyed obj has kept
4379 * track of it and set obj to null before this point. */
4380 if (obj
&& obj
->oartifact
) {
4381 res
|= arti_speak(obj
); /* sets ECMD_TIME bit if artifact speaks */
4386 /* Keep track of unfixable troubles for purposes of messages saying you feel
4390 unfixable_trouble_count(boolean is_horn
)
4392 int unfixable_trbl
= 0;
4400 if (ATEMP(A_DEX
) < 0 && Wounded_legs
)
4402 if (ATEMP(A_STR
) < 0 && u
.uhs
>= WEAK
)
4404 /* lycanthropy is undesirable, but it doesn't actually make you feel bad
4405 so don't count it as a trouble which can't be fixed */
4408 * Unicorn horn can fix these when they're timed but not when
4409 * they aren't. Potion of restore ability doesn't touch them,
4410 * so they're always unfixable for the not-unihorn case.
4411 * [Most of these are timed only, so always curable via horn.
4412 * An exception is Stunned, which can be forced On by certain
4413 * polymorph forms (stalker, bats).]
4415 if (Sick
&& (!is_horn
|| (Sick
& ~TIMEOUT
) != 0L))
4417 if (Stunned
&& (!is_horn
|| (HStun
& ~TIMEOUT
) != 0L))
4419 if (Confusion
&& (!is_horn
|| (HConfusion
& ~TIMEOUT
) != 0L))
4421 if (Hallucination
&& (!is_horn
|| (HHallucination
& ~TIMEOUT
) != 0L))
4423 if (Vomiting
&& (!is_horn
|| (Vomiting
& ~TIMEOUT
) != 0L))
4425 if (Deaf
&& (!is_horn
|| (HDeaf
& ~TIMEOUT
) != 0L))
4428 return unfixable_trbl
;
4432 flip_through_book(struct obj
*obj
)
4435 You("don't want to get the pages even more soggy, do you?");
4439 You("flip through the pages of %s.", thesimpleoname(obj
));
4441 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4443 if (!Hallucination
) {
4444 Soundeffect(se_rustling_paper
, 50);
4446 You_hear("the pages make an unpleasant %s sound.",
4447 Hallucination
? "chuckling"
4449 } else if (!Blind
) {
4450 You_see("the pages glow faintly %s.", hcolor(NH_RED
));
4452 You_feel("the pages tremble.");
4455 pline("The pages feel %s.",
4456 Hallucination
? "freshly picked"
4458 } else if (obj
->otyp
== SPE_BLANK_PAPER
) {
4459 pline("This spellbook %s.",
4460 Hallucination
? "doesn't have much of a plot"
4461 : "has nothing written in it");
4462 makeknown(obj
->otyp
);
4463 } else if (Hallucination
) {
4464 You("enjoy the animated initials.");
4465 } else if (obj
->otyp
== SPE_NOVEL
) {
4466 pline("This looks like it might be interesting to read.");
4468 static const char *const fadeness
[] = {
4475 int findx
= min(obj
->spestudied
, MAX_SPELL_STUDY
);
4477 pline("The%s ink in this spellbook is %s.",
4478 objects
[obj
->otyp
].oc_magic
? " magical" : "",
4486 flip_coin(struct obj
*obj
)
4488 struct obj
*otmp
= obj
;
4489 boolean lose_coin
= FALSE
;
4491 You("flip %s.", an(singular(obj
, xname
)));
4493 pline("It tumbles away.");
4495 } else if (Glib
|| Fumbling
4496 || (ACURR(A_DEX
) < 10 && !rn2(ACURR(A_DEX
)))) {
4497 pline("It slips between your %s.", fingers_or_gloves(FALSE
));
4502 if (otmp
->quan
> 1L)
4503 otmp
= splitobj(otmp
, 1L);
4507 if (Hallucination
) {
4508 pline(rn2(100) ? "Wow, a double header!"
4510 : "The coin miraculously lands on its edge!");
4512 pline("It comes up %s.", rn2(2) ? "heads" : "tails");