Move generic usernames to sysconf
[aNetHack.git] / src / apply.c
blobe00557a5593eaef06c8f3a5ae32540fb05bbe44e
1 /* NetHack 3.6 apply.c $NHDT-Date: 1457397477 2016/03/08 00:37:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.224 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 extern boolean notonhead; /* for long worms */
9 STATIC_DCL int FDECL(use_camera, (struct obj *));
10 STATIC_DCL int FDECL(use_towel, (struct obj *));
11 STATIC_DCL boolean FDECL(its_dead, (int, int, int *));
12 STATIC_DCL int FDECL(use_stethoscope, (struct obj *));
13 STATIC_DCL void FDECL(use_whistle, (struct obj *));
14 STATIC_DCL void FDECL(use_magic_whistle, (struct obj *));
15 STATIC_DCL void FDECL(use_leash, (struct obj *));
16 STATIC_DCL int FDECL(use_mirror, (struct obj *));
17 STATIC_DCL void FDECL(use_bell, (struct obj **));
18 STATIC_DCL void FDECL(use_candelabrum, (struct obj *));
19 STATIC_DCL void FDECL(use_candle, (struct obj **));
20 STATIC_DCL void FDECL(use_lamp, (struct obj *));
21 STATIC_DCL void FDECL(light_cocktail, (struct obj *));
22 STATIC_PTR void FDECL(display_jump_positions, (int));
23 STATIC_DCL void FDECL(use_tinning_kit, (struct obj *));
24 STATIC_DCL void FDECL(use_figurine, (struct obj **));
25 STATIC_DCL void FDECL(use_grease, (struct obj *));
26 STATIC_DCL void FDECL(use_trap, (struct obj *));
27 STATIC_DCL void FDECL(use_stone, (struct obj *));
28 STATIC_PTR int NDECL(set_trap); /* occupation callback */
29 STATIC_DCL int FDECL(use_whip, (struct obj *));
30 STATIC_PTR void FDECL(display_polearm_positions, (int));
31 STATIC_DCL int FDECL(use_pole, (struct obj *));
32 STATIC_DCL int FDECL(use_cream_pie, (struct obj *));
33 STATIC_DCL int FDECL(use_grapple, (struct obj *));
34 STATIC_DCL int FDECL(do_break_wand, (struct obj *));
35 STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *,
36 coord *, BOOLEAN_P));
37 STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
38 STATIC_DCL void FDECL(setapplyclasses, (char *));
39 STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P));
40 STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int));
42 #ifdef AMIGA
43 void FDECL(amii_speaker, (struct obj *, char *, int));
44 #endif
46 static const char no_elbow_room[] =
47 "don't have enough elbow-room to maneuver.";
49 STATIC_OVL int
50 use_camera(obj)
51 struct obj *obj;
53 struct monst *mtmp;
55 if (Underwater) {
56 pline("Using your camera underwater would void the warranty.");
57 return 0;
59 if (!getdir((char *) 0))
60 return 0;
62 if (obj->spe <= 0) {
63 pline1(nothing_happens);
64 return 1;
66 consume_obj_charge(obj, TRUE);
68 if (obj->cursed && !rn2(2)) {
69 (void) zapyourself(obj, TRUE);
70 } else if (u.uswallow) {
71 You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)),
72 mbodypart(u.ustuck, STOMACH));
73 } else if (u.dz) {
74 You("take a picture of the %s.",
75 (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy));
76 } else if (!u.dx && !u.dy) {
77 (void) zapyourself(obj, TRUE);
78 } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
79 (int FDECL((*), (MONST_P, OBJ_P))) 0,
80 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj)) != 0) {
81 obj->ox = u.ux, obj->oy = u.uy;
82 (void) flash_hits_mon(mtmp, obj);
84 return 1;
87 STATIC_OVL int
88 use_towel(obj)
89 struct obj *obj;
91 boolean drying_feedback = (obj == uwep);
93 if (!freehand()) {
94 You("have no free %s!", body_part(HAND));
95 return 0;
96 } else if (obj == ublindf) {
97 You("cannot use it while you're wearing it!");
98 return 0;
99 } else if (obj->cursed) {
100 long old;
102 switch (rn2(3)) {
103 case 2:
104 old = Glib;
105 incr_itimeout(&Glib, rn1(10, 3));
106 Your("%s %s!", makeplural(body_part(HAND)),
107 (old ? "are filthier than ever" : "get slimy"));
108 if (is_wet_towel(obj))
109 dry_a_towel(obj, -1, drying_feedback);
110 return 1;
111 case 1:
112 if (!ublindf) {
113 old = u.ucreamed;
114 u.ucreamed += rn1(10, 3);
115 pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
116 (old ? "has more" : "now has"));
117 make_blinded(Blinded + (long) u.ucreamed - old, TRUE);
118 } else {
119 const char *what;
121 what = (ublindf->otyp == LENSES)
122 ? "lenses"
123 : (obj->otyp == ublindf->otyp) ? "other towel"
124 : "blindfold";
125 if (ublindf->cursed) {
126 You("push your %s %s.", what,
127 rn2(2) ? "cock-eyed" : "crooked");
128 } else {
129 struct obj *saved_ublindf = ublindf;
130 You("push your %s off.", what);
131 Blindf_off(ublindf);
132 dropx(saved_ublindf);
135 if (is_wet_towel(obj))
136 dry_a_towel(obj, -1, drying_feedback);
137 return 1;
138 case 0:
139 break;
143 if (Glib) {
144 Glib = 0;
145 You("wipe off your %s.", makeplural(body_part(HAND)));
146 if (is_wet_towel(obj))
147 dry_a_towel(obj, -1, drying_feedback);
148 return 1;
149 } else if (u.ucreamed) {
150 Blinded -= u.ucreamed;
151 u.ucreamed = 0;
152 if (!Blinded) {
153 pline("You've got the glop off.");
154 if (!gulp_blnd_check()) {
155 Blinded = 1;
156 make_blinded(0L, TRUE);
158 } else {
159 Your("%s feels clean now.", body_part(FACE));
161 if (is_wet_towel(obj))
162 dry_a_towel(obj, -1, drying_feedback);
163 return 1;
166 Your("%s and %s are already clean.", body_part(FACE),
167 makeplural(body_part(HAND)));
169 return 0;
172 /* maybe give a stethoscope message based on floor objects */
173 STATIC_OVL boolean
174 its_dead(rx, ry, resp)
175 int rx, ry, *resp;
177 char buf[BUFSZ];
178 boolean more_corpses;
179 struct permonst *mptr;
180 struct obj *corpse = sobj_at(CORPSE, rx, ry),
181 *statue = sobj_at(STATUE, rx, ry);
183 if (!can_reach_floor(TRUE)) { /* levitation or unskilled riding */
184 corpse = 0; /* can't reach corpse on floor */
185 /* you can't reach tiny statues (even though you can fight
186 tiny monsters while levitating--consistency, what's that?) */
187 while (statue && mons[statue->corpsenm].msize == MZ_TINY)
188 statue = nxtobj(statue, STATUE, TRUE);
190 /* when both corpse and statue are present, pick the uppermost one */
191 if (corpse && statue) {
192 if (nxtobj(statue, CORPSE, TRUE) == corpse)
193 corpse = 0; /* corpse follows statue; ignore it */
194 else
195 statue = 0; /* corpse precedes statue; ignore statue */
197 more_corpses = (corpse && nxtobj(corpse, CORPSE, TRUE));
199 /* additional stethoscope messages from jyoung@apanix.apana.org.au */
200 if (!corpse && !statue) {
201 ; /* nothing to do */
203 } else if (Hallucination) {
204 if (!corpse) {
205 /* it's a statue */
206 Strcpy(buf, "You're both stoned");
207 } else if (corpse->quan == 1L && !more_corpses) {
208 int gndr = 2; /* neuter: "it" */
209 struct monst *mtmp = get_mtraits(corpse, FALSE);
211 /* (most corpses don't retain the monster's sex, so
212 we're usually forced to use generic pronoun here) */
213 if (mtmp) {
214 mptr = &mons[mtmp->mnum];
215 /* can't use mhe() here; it calls pronoun_gender() which
216 expects monster to be on the map (visibility check) */
217 if ((humanoid(mptr) || (mptr->geno & G_UNIQ)
218 || type_is_pname(mptr)) && !is_neuter(mptr))
219 gndr = (int) mtmp->female;
220 } else {
221 mptr = &mons[corpse->corpsenm];
222 if (is_female(mptr))
223 gndr = 1;
224 else if (is_male(mptr))
225 gndr = 0;
227 Sprintf(buf, "%s's dead", genders[gndr].he); /* "he"/"she"/"it" */
228 buf[0] = highc(buf[0]);
229 } else { /* plural */
230 Strcpy(buf, "They're dead");
232 /* variations on "He's dead, Jim." (Star Trek's Dr McCoy) */
233 You_hear("a voice say, \"%s, Jim.\"", buf);
234 *resp = 1;
235 return TRUE;
237 } else if (corpse) {
238 boolean here = (rx == u.ux && ry == u.uy),
239 one = (corpse->quan == 1L && !more_corpses), reviver = FALSE;
240 int visglyph, corpseglyph;
242 visglyph = glyph_at(rx, ry);
243 corpseglyph = obj_to_glyph(corpse);
245 if (Blind && (visglyph != corpseglyph))
246 map_object(corpse, TRUE);
248 if (Role_if(PM_HEALER)) {
249 /* ok to reset `corpse' here; we're done with it */
250 do {
251 if (obj_has_timer(corpse, REVIVE_MON))
252 reviver = TRUE;
253 else
254 corpse = nxtobj(corpse, CORPSE, TRUE);
255 } while (corpse && !reviver);
257 You("determine that %s unfortunate being%s %s%s dead.",
258 one ? (here ? "this" : "that") : (here ? "these" : "those"),
259 one ? "" : "s", one ? "is" : "are", reviver ? " mostly" : "");
260 return TRUE;
262 } else { /* statue */
263 const char *what, *how;
265 mptr = &mons[statue->corpsenm];
266 if (Blind) { /* ignore statue->dknown; it'll always be set */
267 Sprintf(buf, "%s %s",
268 (rx == u.ux && ry == u.uy) ? "This" : "That",
269 humanoid(mptr) ? "person" : "creature");
270 what = buf;
271 } else {
272 what = mptr->mname;
273 if (!type_is_pname(mptr))
274 what = The(what);
276 how = "fine";
277 if (Role_if(PM_HEALER)) {
278 struct trap *ttmp = t_at(rx, ry);
280 if (ttmp && ttmp->ttyp == STATUE_TRAP)
281 how = "extraordinary";
282 else if (Has_contents(statue))
283 how = "remarkable";
286 pline("%s is in %s health for a statue.", what, how);
287 return TRUE;
289 return FALSE; /* no corpse or statue */
292 static const char hollow_str[] = "a hollow sound. This must be a secret %s!";
294 /* Strictly speaking it makes no sense for usage of a stethoscope to
295 not take any time; however, unless it did, the stethoscope would be
296 almost useless. As a compromise, one use per turn is free, another
297 uses up the turn; this makes curse status have a tangible effect. */
298 STATIC_OVL int
299 use_stethoscope(obj)
300 register struct obj *obj;
302 struct monst *mtmp;
303 struct rm *lev;
304 int rx, ry, res;
305 boolean interference = (u.uswallow && is_whirly(u.ustuck->data)
306 && !rn2(Role_if(PM_HEALER) ? 10 : 3));
308 if (nohands(youmonst.data)) {
309 You("have no hands!"); /* not `body_part(HAND)' */
310 return 0;
311 } else if (Deaf) {
312 You_cant("hear anything!");
313 return 0;
314 } else if (!freehand()) {
315 You("have no free %s.", body_part(HAND));
316 return 0;
318 if (!getdir((char *) 0))
319 return 0;
321 res = (moves == context.stethoscope_move)
322 && (youmonst.movement == context.stethoscope_movement);
323 context.stethoscope_move = moves;
324 context.stethoscope_movement = youmonst.movement;
326 bhitpos.x = u.ux, bhitpos.y = u.uy; /* tentative, reset below */
327 notonhead = u.uswallow;
328 if (u.usteed && u.dz > 0) {
329 if (interference) {
330 pline("%s interferes.", Monnam(u.ustuck));
331 mstatusline(u.ustuck);
332 } else
333 mstatusline(u.usteed);
334 return res;
335 } else if (u.uswallow && (u.dx || u.dy || u.dz)) {
336 mstatusline(u.ustuck);
337 return res;
338 } else if (u.uswallow && interference) {
339 pline("%s interferes.", Monnam(u.ustuck));
340 mstatusline(u.ustuck);
341 return res;
342 } else if (u.dz) {
343 if (Underwater)
344 You_hear("faint splashing.");
345 else if (u.dz < 0 || !can_reach_floor(TRUE))
346 cant_reach_floor(u.ux, u.uy, (u.dz < 0), TRUE);
347 else if (its_dead(u.ux, u.uy, &res))
348 ; /* message already given */
349 else if (Is_stronghold(&u.uz))
350 You_hear("the crackling of hellfire.");
351 else
352 pline_The("%s seems healthy enough.", surface(u.ux, u.uy));
353 return res;
354 } else if (obj->cursed && !rn2(2)) {
355 You_hear("your heart beat.");
356 return res;
358 if (Stunned || (Confusion && !rn2(5)))
359 confdir();
360 if (!u.dx && !u.dy) {
361 ustatusline();
362 return res;
364 rx = u.ux + u.dx;
365 ry = u.uy + u.dy;
366 if (!isok(rx, ry)) {
367 You_hear("a faint typing noise.");
368 return 0;
370 if ((mtmp = m_at(rx, ry)) != 0) {
371 const char *mnm = x_monnam(mtmp, ARTICLE_A, (const char *) 0,
372 SUPPRESS_IT | SUPPRESS_INVISIBLE, FALSE);
374 /* bhitpos needed by mstatusline() iff mtmp is a long worm */
375 bhitpos.x = rx, bhitpos.y = ry;
376 notonhead = (mtmp->mx != rx || mtmp->my != ry);
378 if (mtmp->mundetected) {
379 if (!canspotmon(mtmp))
380 There("is %s hidden there.", mnm);
381 mtmp->mundetected = 0;
382 newsym(mtmp->mx, mtmp->my);
383 } else if (mtmp->mappearance) {
384 const char *what = "thing";
386 switch (mtmp->m_ap_type) {
387 case M_AP_OBJECT:
388 what = simple_typename(mtmp->mappearance);
389 break;
390 case M_AP_MONSTER: /* ignore Hallucination here */
391 what = mons[mtmp->mappearance].mname;
392 break;
393 case M_AP_FURNITURE:
394 what = defsyms[mtmp->mappearance].explanation;
395 break;
397 seemimic(mtmp);
398 pline("That %s is really %s.", what, mnm);
399 } else if (flags.verbose && !canspotmon(mtmp)) {
400 There("is %s there.", mnm);
403 mstatusline(mtmp);
404 if (!canspotmon(mtmp))
405 map_invisible(rx, ry);
406 return res;
408 if (glyph_is_invisible(levl[rx][ry].glyph)) {
409 unmap_object(rx, ry);
410 newsym(rx, ry);
411 pline_The("invisible monster must have moved.");
414 lev = &levl[rx][ry];
415 switch (lev->typ) {
416 case SDOOR:
417 You_hear(hollow_str, "door");
418 cvt_sdoor_to_door(lev); /* ->typ = DOOR */
419 feel_newsym(rx, ry);
420 return res;
421 case SCORR:
422 You_hear(hollow_str, "passage");
423 lev->typ = CORR;
424 unblock_point(rx, ry);
425 feel_newsym(rx, ry);
426 return res;
429 if (!its_dead(rx, ry, &res))
430 You("hear nothing special."); /* not You_hear() */
431 return res;
434 static const char whistle_str[] = "produce a %s whistling sound.";
436 STATIC_OVL void
437 use_whistle(obj)
438 struct obj *obj;
440 if (!can_blow(&youmonst)) {
441 You("are incapable of using the whistle.");
442 } else if (Underwater) {
443 You("blow bubbles through %s.", yname(obj));
444 } else {
445 You(whistle_str, obj->cursed ? "shrill" : "high");
446 wake_nearby();
450 STATIC_OVL void
451 use_magic_whistle(obj)
452 struct obj *obj;
454 register struct monst *mtmp, *nextmon;
456 if (!can_blow(&youmonst)) {
457 You("are incapable of using the whistle.");
458 } else if (obj->cursed && !rn2(2)) {
459 You("produce a %shigh-pitched humming noise.",
460 Underwater ? "very " : "");
461 wake_nearby();
462 } else {
463 int pet_cnt = 0, omx, omy;
465 /* it's magic! it works underwater too (at a higher pitch) */
466 You(whistle_str,
467 Hallucination ? "normal" : Underwater ? "strange, high-pitched"
468 : "strange");
469 for (mtmp = fmon; mtmp; mtmp = nextmon) {
470 nextmon = mtmp->nmon; /* trap might kill mon */
471 if (DEADMONSTER(mtmp))
472 continue;
473 /* steed is already at your location, so not affected;
474 this avoids trap issues if you're on a trap location */
475 if (mtmp == u.usteed)
476 continue;
477 if (mtmp->mtame) {
478 if (mtmp->mtrapped) {
479 /* no longer in previous trap (affects mintrap) */
480 mtmp->mtrapped = 0;
481 fill_pit(mtmp->mx, mtmp->my);
483 /* mimic must be revealed before we know whether it
484 actually moves because line-of-sight may change */
485 if (mtmp->m_ap_type)
486 seemimic(mtmp);
487 omx = mtmp->mx, omy = mtmp->my;
488 mnexto(mtmp);
489 if (mtmp->mx != omx || mtmp->my != omy) {
490 mtmp->mundetected = 0; /* reveal non-mimic hider */
491 if (canspotmon(mtmp))
492 ++pet_cnt;
493 if (mintrap(mtmp) == 2)
494 change_luck(-1);
498 if (pet_cnt > 0)
499 makeknown(obj->otyp);
503 boolean
504 um_dist(x, y, n)
505 xchar x, y, n;
507 return (boolean) (abs(u.ux - x) > n || abs(u.uy - y) > n);
511 number_leashed()
513 int i = 0;
514 struct obj *obj;
516 for (obj = invent; obj; obj = obj->nobj)
517 if (obj->otyp == LEASH && obj->leashmon != 0)
518 i++;
519 return i;
522 /* otmp is about to be destroyed or stolen */
523 void
524 o_unleash(otmp)
525 register struct obj *otmp;
527 register struct monst *mtmp;
529 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
530 if (mtmp->m_id == (unsigned) otmp->leashmon)
531 mtmp->mleashed = 0;
532 otmp->leashmon = 0;
535 /* mtmp is about to die, or become untame */
536 void
537 m_unleash(mtmp, feedback)
538 register struct monst *mtmp;
539 boolean feedback;
541 register struct obj *otmp;
543 if (feedback) {
544 if (canseemon(mtmp))
545 pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp));
546 else
547 Your("leash falls slack.");
549 for (otmp = invent; otmp; otmp = otmp->nobj)
550 if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id)
551 otmp->leashmon = 0;
552 mtmp->mleashed = 0;
555 /* player is about to die (for bones) */
556 void
557 unleash_all()
559 register struct obj *otmp;
560 register struct monst *mtmp;
562 for (otmp = invent; otmp; otmp = otmp->nobj)
563 if (otmp->otyp == LEASH)
564 otmp->leashmon = 0;
565 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
566 mtmp->mleashed = 0;
569 #define MAXLEASHED 2
571 static boolean
572 leashable(mtmp)
573 struct monst *mtmp;
575 return (boolean) (mtmp->mnum != PM_LONG_WORM);
578 /* ARGSUSED */
579 STATIC_OVL void
580 use_leash(obj)
581 struct obj *obj;
583 coord cc;
584 register struct monst *mtmp;
585 int spotmon;
587 if (!obj->leashmon && number_leashed() >= MAXLEASHED) {
588 You("cannot leash any more pets.");
589 return;
592 if (!get_adjacent_loc((char *) 0, (char *) 0, u.ux, u.uy, &cc))
593 return;
595 if ((cc.x == u.ux) && (cc.y == u.uy)) {
596 if (u.usteed && u.dz > 0) {
597 mtmp = u.usteed;
598 spotmon = 1;
599 goto got_target;
601 pline("Leash yourself? Very funny...");
602 return;
605 if (!(mtmp = m_at(cc.x, cc.y))) {
606 There("is no creature there.");
607 return;
610 spotmon = canspotmon(mtmp);
611 got_target:
613 if (!mtmp->mtame) {
614 if (!spotmon)
615 There("is no creature there.");
616 else
617 pline("%s %s leashed!", Monnam(mtmp),
618 (!obj->leashmon) ? "cannot be" : "is not");
619 return;
621 if (!obj->leashmon) {
622 if (mtmp->mleashed) {
623 pline("This %s is already leashed.",
624 spotmon ? l_monnam(mtmp) : "monster");
625 return;
627 if (!leashable(mtmp)) {
628 pline("The leash won't fit onto %s%s.", spotmon ? "your " : "",
629 l_monnam(mtmp));
630 return;
633 You("slip the leash around %s%s.", spotmon ? "your " : "",
634 l_monnam(mtmp));
635 mtmp->mleashed = 1;
636 obj->leashmon = (int) mtmp->m_id;
637 mtmp->msleeping = 0;
638 return;
640 if (obj->leashmon != (int) mtmp->m_id) {
641 pline("This leash is not attached to that creature.");
642 return;
643 } else {
644 if (obj->cursed) {
645 pline_The("leash would not come off!");
646 obj->bknown = TRUE;
647 return;
649 mtmp->mleashed = 0;
650 obj->leashmon = 0;
651 You("remove the leash from %s%s.", spotmon ? "your " : "",
652 l_monnam(mtmp));
654 return;
657 /* assuming mtmp->mleashed has been checked */
658 struct obj *
659 get_mleash(mtmp)
660 struct monst *mtmp;
662 struct obj *otmp;
664 otmp = invent;
665 while (otmp) {
666 if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id)
667 return otmp;
668 otmp = otmp->nobj;
670 return (struct obj *) 0;
673 boolean
674 next_to_u()
676 register struct monst *mtmp;
677 register struct obj *otmp;
679 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
680 if (DEADMONSTER(mtmp))
681 continue;
682 if (mtmp->mleashed) {
683 if (distu(mtmp->mx, mtmp->my) > 2)
684 mnexto(mtmp);
685 if (distu(mtmp->mx, mtmp->my) > 2) {
686 for (otmp = invent; otmp; otmp = otmp->nobj)
687 if (otmp->otyp == LEASH
688 && otmp->leashmon == (int) mtmp->m_id) {
689 if (otmp->cursed)
690 return FALSE;
691 You_feel("%s leash go slack.",
692 (number_leashed() > 1) ? "a" : "the");
693 mtmp->mleashed = 0;
694 otmp->leashmon = 0;
699 /* no pack mules for the Amulet */
700 if (u.usteed && mon_has_amulet(u.usteed))
701 return FALSE;
702 return TRUE;
705 void
706 check_leash(x, y)
707 register xchar x, y;
709 register struct obj *otmp;
710 register struct monst *mtmp;
712 for (otmp = invent; otmp; otmp = otmp->nobj) {
713 if (otmp->otyp != LEASH || otmp->leashmon == 0)
714 continue;
715 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
716 if (DEADMONSTER(mtmp))
717 continue;
718 if ((int) mtmp->m_id == otmp->leashmon)
719 break;
721 if (!mtmp) {
722 impossible("leash in use isn't attached to anything?");
723 otmp->leashmon = 0;
724 continue;
726 if (dist2(u.ux, u.uy, mtmp->mx, mtmp->my)
727 > dist2(x, y, mtmp->mx, mtmp->my)) {
728 if (!um_dist(mtmp->mx, mtmp->my, 3)) {
729 ; /* still close enough */
730 } else if (otmp->cursed && !breathless(mtmp->data)) {
731 if (um_dist(mtmp->mx, mtmp->my, 5)
732 || (mtmp->mhp -= rnd(2)) <= 0) {
733 long save_pacifism = u.uconduct.killer;
735 Your("leash chokes %s to death!", mon_nam(mtmp));
736 /* hero might not have intended to kill pet, but
737 that's the result of his actions; gain experience,
738 lose pacifism, take alignment and luck hit, make
739 corpse less likely to remain tame after revival */
740 xkilled(mtmp, XKILL_NOMSG);
741 /* life-saving doesn't ordinarily reset this */
742 if (mtmp->mhp > 0)
743 u.uconduct.killer = save_pacifism;
744 } else {
745 pline("%s is choked by the leash!", Monnam(mtmp));
746 /* tameness eventually drops to 1 here (never 0) */
747 if (mtmp->mtame && rn2(mtmp->mtame))
748 mtmp->mtame--;
750 } else {
751 if (um_dist(mtmp->mx, mtmp->my, 5)) {
752 pline("%s leash snaps loose!", s_suffix(Monnam(mtmp)));
753 m_unleash(mtmp, FALSE);
754 } else {
755 You("pull on the leash.");
756 if (mtmp->data->msound != MS_SILENT)
757 switch (rn2(3)) {
758 case 0:
759 growl(mtmp);
760 break;
761 case 1:
762 yelp(mtmp);
763 break;
764 default:
765 whimper(mtmp);
766 break;
774 const char *
775 beautiful()
777 return ((ACURR(A_CHA) > 14)
778 ? ((poly_gender() == 1)
779 ? "beautiful"
780 : "handsome")
781 : "ugly");
784 static const char look_str[] = "look %s.";
786 STATIC_OVL int
787 use_mirror(obj)
788 struct obj *obj;
790 const char *mirror, *uvisage;
791 struct monst *mtmp;
792 unsigned how_seen;
793 char mlet;
794 boolean vis, invis_mirror, useeit, monable;
796 if (!getdir((char *) 0))
797 return 0;
798 invis_mirror = Invis;
799 useeit = !Blind && (!invis_mirror || See_invisible);
800 uvisage = beautiful();
801 mirror = simpleonames(obj); /* "mirror" or "looking glass" */
802 if (obj->cursed && !rn2(2)) {
803 if (!Blind)
804 pline_The("%s fogs up and doesn't reflect!", mirror);
805 return 1;
807 if (!u.dx && !u.dy && !u.dz) {
808 if (!useeit) {
809 You_cant("see your %s %s.", uvisage, body_part(FACE));
810 } else {
811 if (u.umonnum == PM_FLOATING_EYE) {
812 if (Free_action) {
813 You("stiffen momentarily under your gaze.");
814 } else {
815 if (Hallucination)
816 pline("Yow! The %s stares back!", mirror);
817 else
818 pline("Yikes! You've frozen yourself!");
819 if (!Hallucination || !rn2(4)) {
820 nomul(-rnd(MAXULEV + 6 - u.ulevel));
821 multi_reason = "gazing into a mirror";
823 nomovemsg = 0; /* default, "you can move again" */
825 } else if (youmonst.data->mlet == S_VAMPIRE)
826 You("don't have a reflection.");
827 else if (u.umonnum == PM_UMBER_HULK) {
828 pline("Huh? That doesn't look like you!");
829 make_confused(HConfusion + d(3, 4), FALSE);
830 } else if (Hallucination)
831 You(look_str, hcolor((char *) 0));
832 else if (Sick)
833 You(look_str, "peaked");
834 else if (u.uhs >= WEAK)
835 You(look_str, "undernourished");
836 else
837 You("look as %s as ever.", uvisage);
839 return 1;
841 if (u.uswallow) {
842 if (useeit)
843 You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
844 mbodypart(u.ustuck, STOMACH));
845 return 1;
847 if (Underwater) {
848 if (useeit)
849 You(Hallucination ? "give the fish a chance to fix their makeup."
850 : "reflect the murky water.");
851 return 1;
853 if (u.dz) {
854 if (useeit)
855 You("reflect the %s.",
856 (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy));
857 return 1;
859 mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM,
860 (int FDECL((*), (MONST_P, OBJ_P))) 0,
861 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
862 if (!mtmp || !haseyes(mtmp->data) || notonhead)
863 return 1;
865 /* couldsee(mtmp->mx, mtmp->my) is implied by the fact that bhit()
866 targetted it, so we can ignore possibility of X-ray vision */
867 vis = canseemon(mtmp);
868 /* ways to directly see monster (excludes X-ray vision, telepathy,
869 extended detection, type-specific warning) */
870 #define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS)
871 how_seen = vis ? howmonseen(mtmp) : 0;
872 /* whether monster is able to use its vision-based capabilities */
873 monable = !mtmp->mcan && (!mtmp->minvis || perceives(mtmp->data));
874 mlet = mtmp->data->mlet;
875 if (mtmp->msleeping) {
876 if (vis)
877 pline("%s is too tired to look at your %s.", Monnam(mtmp),
878 mirror);
879 } else if (!mtmp->mcansee) {
880 if (vis)
881 pline("%s can't see anything right now.", Monnam(mtmp));
882 } else if (invis_mirror && !perceives(mtmp->data)) {
883 if (vis)
884 pline("%s fails to notice your %s.", Monnam(mtmp), mirror);
885 /* infravision doesn't produce an image in the mirror */
886 } else if ((how_seen & SEENMON) == MONSEEN_INFRAVIS) {
887 if (vis) /* (redundant) */
888 pline("%s is too far away to see %sself in the dark.",
889 Monnam(mtmp), mhim(mtmp));
890 /* some monsters do special things */
891 } else if (mlet == S_VAMPIRE || mlet == S_GHOST || is_vampshifter(mtmp)) {
892 if (vis)
893 pline("%s doesn't have a reflection.", Monnam(mtmp));
894 } else if (monable && mtmp->data == &mons[PM_MEDUSA]) {
895 if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
896 return 1;
897 if (vis)
898 pline("%s is turned to stone!", Monnam(mtmp));
899 stoned = TRUE;
900 killed(mtmp);
901 } else if (monable && mtmp->data == &mons[PM_FLOATING_EYE]) {
902 int tmp = d((int) mtmp->m_lev, (int) mtmp->data->mattk[0].damd);
903 if (!rn2(4))
904 tmp = 120;
905 if (vis)
906 pline("%s is frozen by its reflection.", Monnam(mtmp));
907 else
908 You_hear("%s stop moving.", something);
909 paralyze_monst(mtmp, (int) mtmp->mfrozen + tmp);
910 } else if (monable && mtmp->data == &mons[PM_UMBER_HULK]) {
911 if (vis)
912 pline("%s confuses itself!", Monnam(mtmp));
913 mtmp->mconf = 1;
914 } else if (monable && (mlet == S_NYMPH || mtmp->data == &mons[PM_SUCCUBUS]
915 || mtmp->data == &mons[PM_INCUBUS])) {
916 if (vis) {
917 char buf[BUFSZ]; /* "She" or "He" */
919 pline("%s admires %sself in your %s.", Monnam(mtmp), mhim(mtmp),
920 mirror);
921 pline("%s takes it!", upstart(strcpy(buf, mhe(mtmp))));
922 } else
923 pline("It steals your %s!", mirror);
924 setnotworn(obj); /* in case mirror was wielded */
925 freeinv(obj);
926 (void) mpickobj(mtmp, obj);
927 if (!tele_restrict(mtmp))
928 (void) rloc(mtmp, TRUE);
929 } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data)
930 && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
931 if (vis)
932 pline("%s is frightened by its reflection.", Monnam(mtmp));
933 monflee(mtmp, d(2, 4), FALSE, FALSE);
934 } else if (!Blind) {
935 if (mtmp->minvis && !See_invisible)
937 else if ((mtmp->minvis && !perceives(mtmp->data))
938 /* redundant: can't get here if these are true */
939 || !haseyes(mtmp->data) || notonhead || !mtmp->mcansee)
940 pline("%s doesn't seem to notice %s reflection.", Monnam(mtmp),
941 mhis(mtmp));
942 else
943 pline("%s ignores %s reflection.", Monnam(mtmp), mhis(mtmp));
945 return 1;
948 STATIC_OVL void
949 use_bell(optr)
950 struct obj **optr;
952 register struct obj *obj = *optr;
953 struct monst *mtmp;
954 boolean wakem = FALSE, learno = FALSE,
955 ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe),
956 invoking =
957 (obj->otyp == BELL_OF_OPENING && invocation_pos(u.ux, u.uy)
958 && !On_stairs(u.ux, u.uy));
960 You("ring %s.", the(xname(obj)));
962 if (Underwater || (u.uswallow && ordinary)) {
963 #ifdef AMIGA
964 amii_speaker(obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME);
965 #endif
966 pline("But the sound is muffled.");
968 } else if (invoking && ordinary) {
969 /* needs to be recharged... */
970 pline("But it makes no sound.");
971 learno = TRUE; /* help player figure out why */
973 } else if (ordinary) {
974 #ifdef AMIGA
975 amii_speaker(obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME);
976 #endif
977 if (obj->cursed && !rn2(4)
978 /* note: once any of them are gone, we stop all of them */
979 && !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE)
980 && !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE)
981 && !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE)
982 && (mtmp = makemon(mkclass(S_NYMPH, 0), u.ux, u.uy, NO_MINVENT))
983 != 0) {
984 You("summon %s!", a_monnam(mtmp));
985 if (!obj_resists(obj, 93, 100)) {
986 pline("%s shattered!", Tobjnam(obj, "have"));
987 useup(obj);
988 *optr = 0;
989 } else
990 switch (rn2(3)) {
991 default:
992 break;
993 case 1:
994 mon_adjust_speed(mtmp, 2, (struct obj *) 0);
995 break;
996 case 2: /* no explanation; it just happens... */
997 nomovemsg = "";
998 multi_reason = NULL;
999 nomul(-rnd(2));
1000 break;
1003 wakem = TRUE;
1005 } else {
1006 /* charged Bell of Opening */
1007 consume_obj_charge(obj, TRUE);
1009 if (u.uswallow) {
1010 if (!obj->cursed)
1011 (void) openit();
1012 else
1013 pline1(nothing_happens);
1015 } else if (obj->cursed) {
1016 coord mm;
1018 mm.x = u.ux;
1019 mm.y = u.uy;
1020 mkundead(&mm, FALSE, NO_MINVENT);
1021 wakem = TRUE;
1023 } else if (invoking) {
1024 pline("%s an unsettling shrill sound...", Tobjnam(obj, "issue"));
1025 #ifdef AMIGA
1026 amii_speaker(obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME);
1027 #endif
1028 obj->age = moves;
1029 learno = TRUE;
1030 wakem = TRUE;
1032 } else if (obj->blessed) {
1033 int res = 0;
1035 #ifdef AMIGA
1036 amii_speaker(obj, "ahahahDhEhCw", AMII_SOFT_VOLUME);
1037 #endif
1038 if (uchain) {
1039 unpunish();
1040 res = 1;
1041 } else if (u.utrap && u.utraptype == TT_BURIEDBALL) {
1042 buried_ball_to_freedom();
1043 res = 1;
1045 res += openit();
1046 switch (res) {
1047 case 0:
1048 pline1(nothing_happens);
1049 break;
1050 case 1:
1051 pline("%s opens...", Something);
1052 learno = TRUE;
1053 break;
1054 default:
1055 pline("Things open around you...");
1056 learno = TRUE;
1057 break;
1060 } else { /* uncursed */
1061 #ifdef AMIGA
1062 amii_speaker(obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME);
1063 #endif
1064 if (findit() != 0)
1065 learno = TRUE;
1066 else
1067 pline1(nothing_happens);
1070 } /* charged BofO */
1072 if (learno) {
1073 makeknown(BELL_OF_OPENING);
1074 obj->known = 1;
1076 if (wakem)
1077 wake_nearby();
1080 STATIC_OVL void
1081 use_candelabrum(obj)
1082 register struct obj *obj;
1084 const char *s = (obj->spe != 1) ? "candles" : "candle";
1086 if (obj->lamplit) {
1087 You("snuff the %s.", s);
1088 end_burn(obj, TRUE);
1089 return;
1091 if (obj->spe <= 0) {
1092 pline("This %s has no %s.", xname(obj), s);
1093 return;
1095 if (Underwater) {
1096 You("cannot make fire under water.");
1097 return;
1099 if (u.uswallow || obj->cursed) {
1100 if (!Blind)
1101 pline_The("%s %s for a moment, then %s.", s, vtense(s, "flicker"),
1102 vtense(s, "die"));
1103 return;
1105 if (obj->spe < 7) {
1106 There("%s only %d %s in %s.", vtense(s, "are"), obj->spe, s,
1107 the(xname(obj)));
1108 if (!Blind)
1109 pline("%s lit. %s dimly.", obj->spe == 1 ? "It is" : "They are",
1110 Tobjnam(obj, "shine"));
1111 } else {
1112 pline("%s's %s burn%s", The(xname(obj)), s,
1113 (Blind ? "." : " brightly!"));
1115 if (!invocation_pos(u.ux, u.uy) || On_stairs(u.ux, u.uy)) {
1116 pline_The("%s %s being rapidly consumed!", s, vtense(s, "are"));
1117 /* this used to be obj->age /= 2, rounding down; an age of
1118 1 would yield 0, confusing begin_burn() and producing an
1119 unlightable, unrefillable candelabrum; round up instead */
1120 obj->age = (obj->age + 1L) / 2L;
1121 } else {
1122 if (obj->spe == 7) {
1123 if (Blind)
1124 pline("%s a strange warmth!", Tobjnam(obj, "radiate"));
1125 else
1126 pline("%s with a strange light!", Tobjnam(obj, "glow"));
1128 obj->known = 1;
1130 begin_burn(obj, FALSE);
1133 STATIC_OVL void
1134 use_candle(optr)
1135 struct obj **optr;
1137 register struct obj *obj = *optr;
1138 register struct obj *otmp;
1139 const char *s = (obj->quan != 1) ? "candles" : "candle";
1140 char qbuf[QBUFSZ], qsfx[QBUFSZ], *q;
1142 if (u.uswallow) {
1143 You(no_elbow_room);
1144 return;
1147 otmp = carrying(CANDELABRUM_OF_INVOCATION);
1148 if (!otmp || otmp->spe == 7) {
1149 use_lamp(obj);
1150 return;
1153 /* first, minimal candelabrum suffix for formatting candles */
1154 Sprintf(qsfx, " to\033%s?", thesimpleoname(otmp));
1155 /* next, format the candles as a prefix for the candelabrum */
1156 (void) safe_qbuf(qbuf, "Attach ", qsfx, obj, yname, thesimpleoname, s);
1157 /* strip temporary candelabrum suffix */
1158 if ((q = strstri(qbuf, " to\033")) != 0)
1159 Strcpy(q, " to ");
1160 /* last, format final "attach candles to candelabrum?" query */
1161 if (yn(safe_qbuf(qbuf, qbuf, "?", otmp, yname, thesimpleoname, "it"))
1162 == 'n') {
1163 use_lamp(obj);
1164 return;
1165 } else {
1166 if ((long) otmp->spe + obj->quan > 7L) {
1167 obj = splitobj(obj, 7L - (long) otmp->spe);
1168 /* avoid a grammatical error if obj->quan gets
1169 reduced to 1 candle from more than one */
1170 s = (obj->quan != 1) ? "candles" : "candle";
1171 } else
1172 *optr = 0;
1173 You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s,
1174 the(xname(otmp)));
1175 if (!otmp->spe || otmp->age > obj->age)
1176 otmp->age = obj->age;
1177 otmp->spe += (int) obj->quan;
1178 if (otmp->lamplit && !obj->lamplit)
1179 pline_The("new %s magically %s!", s, vtense(s, "ignite"));
1180 else if (!otmp->lamplit && obj->lamplit)
1181 pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
1182 if (obj->unpaid)
1183 verbalize("You %s %s, you bought %s!",
1184 otmp->lamplit ? "burn" : "use",
1185 (obj->quan > 1L) ? "them" : "it",
1186 (obj->quan > 1L) ? "them" : "it");
1187 if (obj->quan < 7L && otmp->spe == 7)
1188 pline("%s now has seven%s candles attached.", The(xname(otmp)),
1189 otmp->lamplit ? " lit" : "");
1190 /* candelabrum's light range might increase */
1191 if (otmp->lamplit)
1192 obj_merge_light_sources(otmp, otmp);
1193 /* candles are no longer a separate light source */
1194 if (obj->lamplit)
1195 end_burn(obj, TRUE);
1196 /* candles are now gone */
1197 useupall(obj);
1201 /* call in drop, throw, and put in box, etc. */
1202 boolean
1203 snuff_candle(otmp)
1204 struct obj *otmp;
1206 boolean candle = Is_candle(otmp);
1208 if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION)
1209 && otmp->lamplit) {
1210 char buf[BUFSZ];
1211 xchar x, y;
1212 boolean many = candle ? (otmp->quan > 1L) : (otmp->spe > 1);
1214 (void) get_obj_location(otmp, &x, &y, 0);
1215 if (otmp->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1216 pline("%s%scandle%s flame%s extinguished.", Shk_Your(buf, otmp),
1217 (candle ? "" : "candelabrum's "), (many ? "s'" : "'s"),
1218 (many ? "s are" : " is"));
1219 end_burn(otmp, TRUE);
1220 return TRUE;
1222 return FALSE;
1225 /* called when lit lamp is hit by water or put into a container or
1226 you've been swallowed by a monster; obj might be in transit while
1227 being thrown or dropped so don't assume that its location is valid */
1228 boolean
1229 snuff_lit(obj)
1230 struct obj *obj;
1232 xchar x, y;
1234 if (obj->lamplit) {
1235 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1236 || obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) {
1237 (void) get_obj_location(obj, &x, &y, 0);
1238 if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1239 pline("%s %s out!", Yname2(obj), otense(obj, "go"));
1240 end_burn(obj, TRUE);
1241 return TRUE;
1243 if (snuff_candle(obj))
1244 return TRUE;
1246 return FALSE;
1249 /* Called when potentially lightable object is affected by fire_damage().
1250 Return TRUE if object was lit and FALSE otherwise --ALI */
1251 boolean
1252 catch_lit(obj)
1253 struct obj *obj;
1255 xchar x, y;
1257 if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) {
1258 if ((obj->otyp == MAGIC_LAMP
1259 || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0)
1260 return FALSE;
1261 else if (obj->otyp != MAGIC_LAMP && obj->age == 0)
1262 return FALSE;
1263 if (!get_obj_location(obj, &x, &y, 0))
1264 return FALSE;
1265 if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed)
1266 return FALSE;
1267 if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1268 || obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2))
1269 return FALSE;
1270 if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1271 pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
1272 if (obj->otyp == POT_OIL)
1273 makeknown(obj->otyp);
1274 if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) {
1275 /* if it catches while you have it, then it's your tough luck */
1276 check_unpaid(obj);
1277 verbalize("That's in addition to the cost of %s %s, of course.",
1278 yname(obj), obj->quan == 1L ? "itself" : "themselves");
1279 bill_dummy_object(obj);
1281 begin_burn(obj, FALSE);
1282 return TRUE;
1284 return FALSE;
1287 STATIC_OVL void
1288 use_lamp(obj)
1289 struct obj *obj;
1291 char buf[BUFSZ];
1293 if (obj->lamplit) {
1294 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1295 || obj->otyp == BRASS_LANTERN)
1296 pline("%slamp is now off.", Shk_Your(buf, obj));
1297 else
1298 You("snuff out %s.", yname(obj));
1299 end_burn(obj, TRUE);
1300 return;
1302 if (Underwater) {
1303 pline(!Is_candle(obj) ? "This is not a diving lamp"
1304 : "Sorry, fire and water don't mix.");
1305 return;
1307 /* magic lamps with an spe == 0 (wished for) cannot be lit */
1308 if ((!Is_candle(obj) && obj->age == 0)
1309 || (obj->otyp == MAGIC_LAMP && obj->spe == 0)) {
1310 if (obj->otyp == BRASS_LANTERN)
1311 Your("lamp has run out of power.");
1312 else
1313 pline("This %s has no oil.", xname(obj));
1314 return;
1316 if (obj->cursed && !rn2(2)) {
1317 if (!Blind)
1318 pline("%s for a moment, then %s.", Tobjnam(obj, "flicker"),
1319 otense(obj, "die"));
1320 } else {
1321 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1322 || obj->otyp == BRASS_LANTERN) {
1323 check_unpaid(obj);
1324 pline("%slamp is now on.", Shk_Your(buf, obj));
1325 } else { /* candle(s) */
1326 pline("%s flame%s %s%s", s_suffix(Yname2(obj)), plur(obj->quan),
1327 otense(obj, "burn"), Blind ? "." : " brightly!");
1328 if (obj->unpaid && costly_spot(u.ux, u.uy)
1329 && obj->age == 20L * (long) objects[obj->otyp].oc_cost) {
1330 const char *ithem = (obj->quan > 1L) ? "them" : "it";
1332 verbalize("You burn %s, you bought %s!", ithem, ithem);
1333 bill_dummy_object(obj);
1336 begin_burn(obj, FALSE);
1340 STATIC_OVL void
1341 light_cocktail(obj)
1342 struct obj *obj; /* obj is a potion of oil */
1344 char buf[BUFSZ];
1345 boolean split1off;
1347 if (u.uswallow) {
1348 You(no_elbow_room);
1349 return;
1352 if (obj->lamplit) {
1353 You("snuff the lit potion.");
1354 end_burn(obj, TRUE);
1356 * Free & add to re-merge potion. This will average the
1357 * age of the potions. Not exactly the best solution,
1358 * but its easy.
1360 freeinv(obj);
1361 (void) addinv(obj);
1362 return;
1363 } else if (Underwater) {
1364 There("is not enough oxygen to sustain a fire.");
1365 return;
1368 split1off = (obj->quan > 1L);
1369 if (split1off)
1370 obj = splitobj(obj, 1L);
1372 You("light %spotion.%s", shk_your(buf, obj),
1373 Blind ? "" : " It gives off a dim light.");
1375 if (obj->unpaid && costly_spot(u.ux, u.uy)) {
1376 /* Normally, we shouldn't both partially and fully charge
1377 * for an item, but (Yendorian Fuel) Taxes are inevitable...
1379 check_unpaid(obj);
1380 verbalize("That's in addition to the cost of the potion, of course.");
1381 bill_dummy_object(obj);
1383 makeknown(obj->otyp);
1385 begin_burn(obj, FALSE); /* after shop billing */
1386 if (split1off) {
1387 obj_extract_self(obj); /* free from inv */
1388 obj->nomerge = 1;
1389 obj = hold_another_object(obj, "You drop %s!", doname(obj),
1390 (const char *) 0);
1391 if (obj)
1392 obj->nomerge = 0;
1396 static NEARDATA const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 };
1399 dorub()
1401 struct obj *obj = getobj(cuddly, "rub");
1403 if (obj && obj->oclass == GEM_CLASS) {
1404 if (is_graystone(obj)) {
1405 use_stone(obj);
1406 return 1;
1407 } else {
1408 pline("Sorry, I don't know how to use that.");
1409 return 0;
1413 if (!obj || !wield_tool(obj, "rub"))
1414 return 0;
1416 /* now uwep is obj */
1417 if (uwep->otyp == MAGIC_LAMP) {
1418 if (uwep->spe > 0 && !rn2(3)) {
1419 check_unpaid_usage(uwep, TRUE); /* unusual item use */
1420 /* bones preparation: perform the lamp transformation
1421 before releasing the djinni in case the latter turns out
1422 to be fatal (a hostile djinni has no chance to attack yet,
1423 but an indebted one who grants a wish might bestow an
1424 artifact which blasts the hero with lethal results) */
1425 uwep->otyp = OIL_LAMP;
1426 uwep->spe = 0; /* for safety */
1427 uwep->age = rn1(500, 1000);
1428 if (uwep->lamplit)
1429 begin_burn(uwep, TRUE);
1430 djinni_from_bottle(uwep);
1431 makeknown(MAGIC_LAMP);
1432 update_inventory();
1433 } else if (rn2(2)) {
1434 You("%s smoke.", !Blind ? "see a puff of" : "smell");
1435 } else
1436 pline1(nothing_happens);
1437 } else if (obj->otyp == BRASS_LANTERN) {
1438 /* message from Adventure */
1439 pline("Rubbing the electric lamp is not particularly rewarding.");
1440 pline("Anyway, nothing exciting happens.");
1441 } else
1442 pline1(nothing_happens);
1443 return 1;
1447 dojump()
1449 /* Physical jump */
1450 return jump(0);
1453 boolean
1454 is_valid_jump_pos(x, y, magic, showmsg)
1455 int x, y, magic;
1456 boolean showmsg;
1458 if (!magic && !(HJumping & ~INTRINSIC) && !EJumping && distu(x, y) != 5) {
1459 /* The Knight jumping restriction still applies when riding a
1460 * horse. After all, what shape is the knight piece in chess?
1462 if (showmsg)
1463 pline("Illegal move!");
1464 return FALSE;
1465 } else if (distu(x, y) > (magic ? 6 + magic * 3 : 9)) {
1466 if (showmsg)
1467 pline("Too far!");
1468 return FALSE;
1469 } else if (!cansee(x, y)) {
1470 if (showmsg)
1471 You("cannot see where to land!");
1472 return FALSE;
1473 } else if (!isok(x, y)) {
1474 if (showmsg)
1475 You("cannot jump there!");
1476 return FALSE;
1478 return TRUE;
1481 static int jumping_is_magic;
1483 void
1484 display_jump_positions(state)
1485 int state;
1487 if (state == 0) {
1488 tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
1489 } else if (state == 1) {
1490 int x, y, dx, dy;
1492 for (dx = -4; dx <= 4; dx++)
1493 for (dy = -4; dy <= 4; dy++) {
1494 x = dx + (int) u.ux;
1495 y = dy + (int) u.uy;
1496 if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
1497 && is_valid_jump_pos(x, y, jumping_is_magic, FALSE))
1498 tmp_at(x, y);
1500 } else {
1501 tmp_at(DISP_END, 0);
1506 jump(magic)
1507 int magic; /* 0=Physical, otherwise skill level */
1509 coord cc;
1511 /* attempt "jumping" spell if hero has no innate jumping ability */
1512 if (!magic && !Jumping) {
1513 int sp_no;
1515 for (sp_no = 0; sp_no < MAXSPELL; ++sp_no)
1516 if (spl_book[sp_no].sp_id == NO_SPELL)
1517 break;
1518 else if (spl_book[sp_no].sp_id == SPE_JUMPING)
1519 return spelleffects(sp_no, FALSE);
1522 if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) {
1523 /* normally (nolimbs || slithy) implies !Jumping,
1524 but that isn't necessarily the case for knights */
1525 You_cant("jump; you have no legs!");
1526 return 0;
1527 } else if (!magic && !Jumping) {
1528 You_cant("jump very far.");
1529 return 0;
1530 /* if steed is immobile, can't do physical jump but can do spell one */
1531 } else if (!magic && u.usteed && stucksteed(FALSE)) {
1532 /* stucksteed gave "<steed> won't move" message */
1533 return 0;
1534 } else if (u.uswallow) {
1535 if (magic) {
1536 You("bounce around a little.");
1537 return 1;
1539 pline("You've got to be kidding!");
1540 return 0;
1541 } else if (u.uinwater) {
1542 if (magic) {
1543 You("swish around a little.");
1544 return 1;
1546 pline("This calls for swimming, not jumping!");
1547 return 0;
1548 } else if (u.ustuck) {
1549 if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) {
1550 You("pull free from %s.", mon_nam(u.ustuck));
1551 u.ustuck = 0;
1552 return 1;
1554 if (magic) {
1555 You("writhe a little in the grasp of %s!", mon_nam(u.ustuck));
1556 return 1;
1558 You("cannot escape from %s!", mon_nam(u.ustuck));
1559 return 0;
1560 } else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
1561 if (magic) {
1562 You("flail around a little.");
1563 return 1;
1565 You("don't have enough traction to jump.");
1566 return 0;
1567 } else if (!magic && near_capacity() > UNENCUMBERED) {
1568 You("are carrying too much to jump!");
1569 return 0;
1570 } else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) {
1571 You("lack the strength to jump!");
1572 return 0;
1573 } else if (!magic && Wounded_legs) {
1574 long wl = (Wounded_legs & BOTH_SIDES);
1575 const char *bp = body_part(LEG);
1577 if (wl == BOTH_SIDES)
1578 bp = makeplural(bp);
1579 if (u.usteed)
1580 pline("%s is in no shape for jumping.", Monnam(u.usteed));
1581 else
1582 Your("%s%s %s in no shape for jumping.",
1583 (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right "
1584 : "",
1585 bp, (wl == BOTH_SIDES) ? "are" : "is");
1586 return 0;
1587 } else if (u.usteed && u.utrap) {
1588 pline("%s is stuck in a trap.", Monnam(u.usteed));
1589 return 0;
1592 pline("Where do you want to jump?");
1593 cc.x = u.ux;
1594 cc.y = u.uy;
1595 jumping_is_magic = magic;
1596 getpos_sethilite(display_jump_positions);
1597 if (getpos(&cc, TRUE, "the desired position") < 0)
1598 return 0; /* user pressed ESC */
1599 if (!is_valid_jump_pos(cc.x, cc.y, magic, TRUE)) {
1600 return 0;
1601 } else {
1602 coord uc;
1603 int range, temp;
1605 if (u.utrap)
1606 switch (u.utraptype) {
1607 case TT_BEARTRAP: {
1608 long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
1610 You("rip yourself free of the bear trap! Ouch!");
1611 losehp(Maybe_Half_Phys(rnd(10)), "jumping out of a bear trap",
1612 KILLED_BY);
1613 set_wounded_legs(side, rn1(1000, 500));
1614 break;
1616 case TT_PIT:
1617 You("leap from the pit!");
1618 break;
1619 case TT_WEB:
1620 You("tear the web apart as you pull yourself free!");
1621 deltrap(t_at(u.ux, u.uy));
1622 break;
1623 case TT_LAVA:
1624 You("pull yourself above the %s!", hliquid("lava"));
1625 u.utrap = 0;
1626 return 1;
1627 case TT_BURIEDBALL:
1628 case TT_INFLOOR:
1629 You("strain your %s, but you're still %s.",
1630 makeplural(body_part(LEG)),
1631 (u.utraptype == TT_INFLOOR)
1632 ? "stuck in the floor"
1633 : "attached to the buried ball");
1634 set_wounded_legs(LEFT_SIDE, rn1(10, 11));
1635 set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
1636 return 1;
1640 * Check the path from uc to cc, calling hurtle_step at each
1641 * location. The final position actually reached will be
1642 * in cc.
1644 uc.x = u.ux;
1645 uc.y = u.uy;
1646 /* calculate max(abs(dx), abs(dy)) as the range */
1647 range = cc.x - uc.x;
1648 if (range < 0)
1649 range = -range;
1650 temp = cc.y - uc.y;
1651 if (temp < 0)
1652 temp = -temp;
1653 if (range < temp)
1654 range = temp;
1655 (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range);
1656 /* hurtle_step results in (u.ux, u.uy) == (cc.x, cc.y) and usually
1657 * moves the ball if punished, but does not handle all the effects
1658 * of landing on the final position.
1660 teleds(cc.x, cc.y, FALSE);
1661 sokoban_guilt();
1662 nomul(-1);
1663 multi_reason = "jumping around";
1664 nomovemsg = "";
1665 morehungry(rnd(25));
1666 return 1;
1670 boolean
1671 tinnable(corpse)
1672 struct obj *corpse;
1674 if (corpse->oeaten)
1675 return 0;
1676 if (!mons[corpse->corpsenm].cnutrit)
1677 return 0;
1678 return 1;
1681 STATIC_OVL void
1682 use_tinning_kit(obj)
1683 struct obj *obj;
1685 struct obj *corpse, *can;
1687 /* This takes only 1 move. If this is to be changed to take many
1688 * moves, we've got to deal with decaying corpses...
1690 if (obj->spe <= 0) {
1691 You("seem to be out of tins.");
1692 return;
1694 if (!(corpse = floorfood("tin", 2)))
1695 return;
1696 if (corpse->oeaten) {
1697 You("cannot tin %s which is partly eaten.", something);
1698 return;
1700 if (touch_petrifies(&mons[corpse->corpsenm]) && !Stone_resistance
1701 && !uarmg) {
1702 char kbuf[BUFSZ];
1704 if (poly_when_stoned(youmonst.data))
1705 You("tin %s without wearing gloves.",
1706 an(mons[corpse->corpsenm].mname));
1707 else {
1708 pline("Tinning %s without wearing gloves is a fatal mistake...",
1709 an(mons[corpse->corpsenm].mname));
1710 Sprintf(kbuf, "trying to tin %s without gloves",
1711 an(mons[corpse->corpsenm].mname));
1713 instapetrify(kbuf);
1715 if (is_rider(&mons[corpse->corpsenm])) {
1716 if (revive_corpse(corpse))
1717 verbalize("Yes... But War does not preserve its enemies...");
1718 else
1719 pline_The("corpse evades your grasp.");
1720 return;
1722 if (mons[corpse->corpsenm].cnutrit == 0) {
1723 pline("That's too insubstantial to tin.");
1724 return;
1726 consume_obj_charge(obj, TRUE);
1728 if ((can = mksobj(TIN, FALSE, FALSE)) != 0) {
1729 static const char you_buy_it[] = "You tin it, you bought it!";
1731 can->corpsenm = corpse->corpsenm;
1732 can->cursed = obj->cursed;
1733 can->blessed = obj->blessed;
1734 can->owt = weight(can);
1735 can->known = 1;
1736 /* Mark tinned tins. No spinach allowed... */
1737 set_tin_variety(can, HOMEMADE_TIN);
1738 if (carried(corpse)) {
1739 if (corpse->unpaid)
1740 verbalize(you_buy_it);
1741 useup(corpse);
1742 } else {
1743 if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
1744 verbalize(you_buy_it);
1745 useupf(corpse, 1L);
1747 can = hold_another_object(can, "You make, but cannot pick up, %s.",
1748 doname(can), (const char *) 0);
1749 } else
1750 impossible("Tinning failed.");
1753 void
1754 use_unicorn_horn(obj)
1755 struct obj *obj;
1757 #define PROP_COUNT 7 /* number of properties we're dealing with */
1758 #define ATTR_COUNT (A_MAX * 3) /* number of attribute points we might fix */
1759 int idx, val, val_limit, trouble_count, unfixable_trbl, did_prop,
1760 did_attr;
1761 int trouble_list[PROP_COUNT + ATTR_COUNT];
1763 if (obj && obj->cursed) {
1764 long lcount = (long) rn1(90, 10);
1766 switch (rn2(13) / 2) { /* case 6 is half as likely as the others */
1767 case 0:
1768 make_sick((Sick & TIMEOUT) ? (Sick & TIMEOUT) / 3L + 1L
1769 : (long) rn1(ACURR(A_CON), 20),
1770 xname(obj), TRUE, SICK_NONVOMITABLE);
1771 break;
1772 case 1:
1773 make_blinded((Blinded & TIMEOUT) + lcount, TRUE);
1774 break;
1775 case 2:
1776 if (!Confusion)
1777 You("suddenly feel %s.",
1778 Hallucination ? "trippy" : "confused");
1779 make_confused((HConfusion & TIMEOUT) + lcount, TRUE);
1780 break;
1781 case 3:
1782 make_stunned((HStun & TIMEOUT) + lcount, TRUE);
1783 break;
1784 case 4:
1785 (void) adjattrib(rn2(A_MAX), -1, FALSE);
1786 break;
1787 case 5:
1788 (void) make_hallucinated((HHallucination & TIMEOUT) + lcount,
1789 TRUE, 0L);
1790 break;
1791 case 6:
1792 if (Deaf) /* make_deaf() won't give feedback when already deaf */
1793 pline("Nothing seems to happen.");
1794 make_deaf((HDeaf & TIMEOUT) + lcount, TRUE);
1795 context.botl = TRUE;
1796 break;
1798 return;
1802 * Entries in the trouble list use a very simple encoding scheme.
1804 #define prop2trbl(X) ((X) + A_MAX)
1805 #define attr2trbl(Y) (Y)
1806 #define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X)
1807 #define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y)
1808 #define TimedTrouble(P) (((P) && !((P) & ~TIMEOUT)) ? ((P) & TIMEOUT) : 0L)
1810 trouble_count = unfixable_trbl = did_prop = did_attr = 0;
1812 /* collect property troubles */
1813 if (TimedTrouble(Sick))
1814 prop_trouble(SICK);
1815 if (TimedTrouble(Blinded) > (long) u.ucreamed
1816 && !(u.uswallow
1817 && attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND)))
1818 prop_trouble(BLINDED);
1819 if (TimedTrouble(HHallucination))
1820 prop_trouble(HALLUC);
1821 if (TimedTrouble(Vomiting))
1822 prop_trouble(VOMITING);
1823 if (TimedTrouble(HConfusion))
1824 prop_trouble(CONFUSION);
1825 if (TimedTrouble(HStun))
1826 prop_trouble(STUNNED);
1827 if (TimedTrouble(HDeaf))
1828 prop_trouble(DEAF);
1830 unfixable_trbl = unfixable_trouble_count(TRUE);
1832 /* collect attribute troubles */
1833 for (idx = 0; idx < A_MAX; idx++) {
1834 if (ABASE(idx) >= AMAX(idx))
1835 continue;
1836 val_limit = AMAX(idx);
1837 /* don't recover strength lost from hunger */
1838 if (idx == A_STR && u.uhs >= WEAK)
1839 val_limit--;
1840 if (Fixed_abil) {
1841 /* potion/spell of restore ability override sustain ability
1842 intrinsic but unicorn horn usage doesn't */
1843 unfixable_trbl += val_limit - ABASE(idx);
1844 continue;
1846 /* don't recover more than 3 points worth of any attribute */
1847 if (val_limit > ABASE(idx) + 3)
1848 val_limit = ABASE(idx) + 3;
1850 for (val = ABASE(idx); val < val_limit; val++)
1851 attr_trouble(idx);
1852 /* keep track of unfixed trouble, for message adjustment below */
1853 unfixable_trbl += (AMAX(idx) - val_limit);
1856 if (trouble_count == 0) {
1857 pline1(nothing_happens);
1858 return;
1859 } else if (trouble_count > 1) { /* shuffle */
1860 int i, j, k;
1862 for (i = trouble_count - 1; i > 0; i--)
1863 if ((j = rn2(i + 1)) != i) {
1864 k = trouble_list[j];
1865 trouble_list[j] = trouble_list[i];
1866 trouble_list[i] = k;
1871 * Chances for number of troubles to be fixed
1872 * 0 1 2 3 4 5 6 7
1873 * blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8%
1874 * uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0
1876 val_limit = rn2(d(2, (obj && obj->blessed) ? 4 : 2));
1877 if (val_limit > trouble_count)
1878 val_limit = trouble_count;
1880 /* fix [some of] the troubles */
1881 for (val = 0; val < val_limit; val++) {
1882 idx = trouble_list[val];
1884 switch (idx) {
1885 case prop2trbl(SICK):
1886 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
1887 did_prop++;
1888 break;
1889 case prop2trbl(BLINDED):
1890 make_blinded((long) u.ucreamed, TRUE);
1891 did_prop++;
1892 break;
1893 case prop2trbl(HALLUC):
1894 (void) make_hallucinated(0L, TRUE, 0L);
1895 did_prop++;
1896 break;
1897 case prop2trbl(VOMITING):
1898 make_vomiting(0L, TRUE);
1899 did_prop++;
1900 break;
1901 case prop2trbl(CONFUSION):
1902 make_confused(0L, TRUE);
1903 did_prop++;
1904 break;
1905 case prop2trbl(STUNNED):
1906 make_stunned(0L, TRUE);
1907 did_prop++;
1908 break;
1909 case prop2trbl(DEAF):
1910 make_deaf(0L, TRUE);
1911 did_prop++;
1912 break;
1913 default:
1914 if (idx >= 0 && idx < A_MAX) {
1915 ABASE(idx) += 1;
1916 did_attr++;
1917 } else
1918 panic("use_unicorn_horn: bad trouble? (%d)", idx);
1919 break;
1923 if (did_attr)
1924 pline("This makes you feel %s!",
1925 (did_prop + did_attr) == (trouble_count + unfixable_trbl)
1926 ? "great"
1927 : "better");
1928 else if (!did_prop)
1929 pline("Nothing seems to happen.");
1931 context.botl = (did_attr || did_prop);
1932 #undef PROP_COUNT
1933 #undef ATTR_COUNT
1934 #undef prop2trbl
1935 #undef attr2trbl
1936 #undef prop_trouble
1937 #undef attr_trouble
1938 #undef TimedTrouble
1942 * Timer callback routine: turn figurine into monster
1944 void
1945 fig_transform(arg, timeout)
1946 anything *arg;
1947 long timeout;
1949 struct obj *figurine = arg->a_obj;
1950 struct monst *mtmp;
1951 coord cc;
1952 boolean cansee_spot, silent, okay_spot;
1953 boolean redraw = FALSE;
1954 boolean suppress_see = FALSE;
1955 char monnambuf[BUFSZ], carriedby[BUFSZ];
1957 if (!figurine) {
1958 debugpline0("null figurine in fig_transform()");
1959 return;
1961 silent = (timeout != monstermoves); /* happened while away */
1962 okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0);
1963 if (figurine->where == OBJ_INVENT || figurine->where == OBJ_MINVENT)
1964 okay_spot = enexto(&cc, cc.x, cc.y, &mons[figurine->corpsenm]);
1965 if (!okay_spot || !figurine_location_checks(figurine, &cc, TRUE)) {
1966 /* reset the timer to try again later */
1967 (void) start_timer((long) rnd(5000), TIMER_OBJECT, FIG_TRANSFORM,
1968 obj_to_any(figurine));
1969 return;
1972 cansee_spot = cansee(cc.x, cc.y);
1973 mtmp = make_familiar(figurine, cc.x, cc.y, TRUE);
1974 if (mtmp) {
1975 char and_vanish[BUFSZ];
1976 struct obj *mshelter = level.objects[mtmp->mx][mtmp->my];
1978 Sprintf(monnambuf, "%s", an(m_monnam(mtmp)));
1979 and_vanish[0] = '\0';
1980 if ((mtmp->minvis && !See_invisible)
1981 || (mtmp->data->mlet == S_MIMIC
1982 && mtmp->m_ap_type != M_AP_NOTHING))
1983 suppress_see = TRUE;
1985 if (mtmp->mundetected) {
1986 if (hides_under(mtmp->data) && mshelter) {
1987 Sprintf(and_vanish, " and %s under %s",
1988 locomotion(mtmp->data, "crawl"), doname(mshelter));
1989 } else if (mtmp->data->mlet == S_MIMIC
1990 || mtmp->data->mlet == S_EEL) {
1991 suppress_see = TRUE;
1992 } else
1993 Strcpy(and_vanish, " and vanish");
1996 switch (figurine->where) {
1997 case OBJ_INVENT:
1998 if (Blind || suppress_see)
1999 You_feel("%s %s from your pack!", something,
2000 locomotion(mtmp->data, "drop"));
2001 else
2002 You_see("%s %s out of your pack%s!", monnambuf,
2003 locomotion(mtmp->data, "drop"), and_vanish);
2004 break;
2006 case OBJ_FLOOR:
2007 if (cansee_spot && !silent) {
2008 if (suppress_see)
2009 pline("%s suddenly vanishes!", an(xname(figurine)));
2010 else
2011 You_see("a figurine transform into %s%s!", monnambuf,
2012 and_vanish);
2013 redraw = TRUE; /* update figurine's map location */
2015 break;
2017 case OBJ_MINVENT:
2018 if (cansee_spot && !silent && !suppress_see) {
2019 struct monst *mon;
2021 mon = figurine->ocarry;
2022 /* figurine carrying monster might be invisible */
2023 if (canseemon(figurine->ocarry)
2024 && (!mon->wormno || cansee(mon->mx, mon->my)))
2025 Sprintf(carriedby, "%s pack", s_suffix(a_monnam(mon)));
2026 else if (is_pool(mon->mx, mon->my))
2027 Strcpy(carriedby, "empty water");
2028 else
2029 Strcpy(carriedby, "thin air");
2030 You_see("%s %s out of %s%s!", monnambuf,
2031 locomotion(mtmp->data, "drop"), carriedby,
2032 and_vanish);
2034 break;
2035 #if 0
2036 case OBJ_MIGRATING:
2037 break;
2038 #endif
2040 default:
2041 impossible("figurine came to life where? (%d)",
2042 (int) figurine->where);
2043 break;
2046 /* free figurine now */
2047 if (carried(figurine)) {
2048 useup(figurine);
2049 } else {
2050 obj_extract_self(figurine);
2051 obfree(figurine, (struct obj *) 0);
2053 if (redraw)
2054 newsym(cc.x, cc.y);
2057 STATIC_OVL boolean
2058 figurine_location_checks(obj, cc, quietly)
2059 struct obj *obj;
2060 coord *cc;
2061 boolean quietly;
2063 xchar x, y;
2065 if (carried(obj) && u.uswallow) {
2066 if (!quietly)
2067 You("don't have enough room in here.");
2068 return FALSE;
2070 x = cc ? cc->x : u.ux;
2071 y = cc ? cc->y : u.uy;
2072 if (!isok(x, y)) {
2073 if (!quietly)
2074 You("cannot put the figurine there.");
2075 return FALSE;
2077 if (IS_ROCK(levl[x][y].typ)
2078 && !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x, y))) {
2079 if (!quietly)
2080 You("cannot place a figurine in %s!",
2081 IS_TREE(levl[x][y].typ) ? "a tree" : "solid rock");
2082 return FALSE;
2084 if (sobj_at(BOULDER, x, y) && !passes_walls(&mons[obj->corpsenm])
2085 && !throws_rocks(&mons[obj->corpsenm])) {
2086 if (!quietly)
2087 You("cannot fit the figurine on the boulder.");
2088 return FALSE;
2090 return TRUE;
2093 STATIC_OVL void
2094 use_figurine(optr)
2095 struct obj **optr;
2097 register struct obj *obj = *optr;
2098 xchar x, y;
2099 coord cc;
2101 if (u.uswallow) {
2102 /* can't activate a figurine while swallowed */
2103 if (!figurine_location_checks(obj, (coord *) 0, FALSE))
2104 return;
2106 if (!getdir((char *) 0)) {
2107 context.move = multi = 0;
2108 return;
2110 x = u.ux + u.dx;
2111 y = u.uy + u.dy;
2112 cc.x = x;
2113 cc.y = y;
2114 /* Passing FALSE arg here will result in messages displayed */
2115 if (!figurine_location_checks(obj, &cc, FALSE))
2116 return;
2117 You("%s and it transforms.",
2118 (u.dx || u.dy) ? "set the figurine beside you"
2119 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
2120 || is_pool(cc.x, cc.y))
2121 ? "release the figurine"
2122 : (u.dz < 0 ? "toss the figurine into the air"
2123 : "set the figurine on the ground"));
2124 (void) make_familiar(obj, cc.x, cc.y, FALSE);
2125 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
2126 useup(obj);
2127 *optr = 0;
2130 static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 };
2132 STATIC_OVL void
2133 use_grease(obj)
2134 struct obj *obj;
2136 struct obj *otmp;
2138 if (Glib) {
2139 pline("%s from your %s.", Tobjnam(obj, "slip"),
2140 makeplural(body_part(FINGER)));
2141 dropx(obj);
2142 return;
2145 if (obj->spe > 0) {
2146 if ((obj->cursed || Fumbling) && !rn2(2)) {
2147 consume_obj_charge(obj, TRUE);
2149 pline("%s from your %s.", Tobjnam(obj, "slip"),
2150 makeplural(body_part(FINGER)));
2151 dropx(obj);
2152 return;
2154 otmp = getobj(lubricables, "grease");
2155 if (!otmp)
2156 return;
2157 if (inaccessible_equipment(otmp, "grease", FALSE))
2158 return;
2159 consume_obj_charge(obj, TRUE);
2161 if (otmp != &zeroobj) {
2162 You("cover %s with a thick layer of grease.", yname(otmp));
2163 otmp->greased = 1;
2164 if (obj->cursed && !nohands(youmonst.data)) {
2165 incr_itimeout(&Glib, rnd(15));
2166 pline("Some of the grease gets all over your %s.",
2167 makeplural(body_part(HAND)));
2169 } else {
2170 incr_itimeout(&Glib, rnd(15));
2171 You("coat your %s with grease.", makeplural(body_part(FINGER)));
2173 } else {
2174 if (obj->known)
2175 pline("%s empty.", Tobjnam(obj, "are"));
2176 else
2177 pline("%s to be empty.", Tobjnam(obj, "seem"));
2179 update_inventory();
2182 /* touchstones - by Ken Arnold */
2183 STATIC_OVL void
2184 use_stone(tstone)
2185 struct obj *tstone;
2187 struct obj *obj;
2188 boolean do_scratch;
2189 const char *streak_color, *choices;
2190 char stonebuf[QBUFSZ];
2191 static const char scritch[] = "\"scritch, scritch\"";
2192 static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 };
2193 static const char coins_gems[3] = { COIN_CLASS, GEM_CLASS, 0 };
2195 /* in case it was acquired while blinded */
2196 if (!Blind)
2197 tstone->dknown = 1;
2198 /* when the touchstone is fully known, don't bother listing extra
2199 junk as likely candidates for rubbing */
2200 choices = (tstone->otyp == TOUCHSTONE && tstone->dknown
2201 && objects[TOUCHSTONE].oc_name_known)
2202 ? coins_gems
2203 : allowall;
2204 Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan));
2205 if ((obj = getobj(choices, stonebuf)) == 0)
2206 return;
2208 if (obj == tstone && obj->quan == 1L) {
2209 You_cant("rub %s on itself.", the(xname(obj)));
2210 return;
2213 if (tstone->otyp == TOUCHSTONE && tstone->cursed
2214 && obj->oclass == GEM_CLASS && !is_graystone(obj)
2215 && !obj_resists(obj, 80, 100)) {
2216 if (Blind)
2217 pline("You feel something shatter.");
2218 else if (Hallucination)
2219 pline("Oh, wow, look at the pretty shards.");
2220 else
2221 pline("A sharp crack shatters %s%s.",
2222 (obj->quan > 1L) ? "one of " : "", the(xname(obj)));
2223 useup(obj);
2224 return;
2227 if (Blind) {
2228 pline(scritch);
2229 return;
2230 } else if (Hallucination) {
2231 pline("Oh wow, man: Fractals!");
2232 return;
2235 do_scratch = FALSE;
2236 streak_color = 0;
2238 switch (obj->oclass) {
2239 case GEM_CLASS: /* these have class-specific handling below */
2240 case RING_CLASS:
2241 if (tstone->otyp != TOUCHSTONE) {
2242 do_scratch = TRUE;
2243 } else if (obj->oclass == GEM_CLASS
2244 && (tstone->blessed
2245 || (!tstone->cursed && (Role_if(PM_ARCHEOLOGIST)
2246 || Race_if(PM_GNOME))))) {
2247 makeknown(TOUCHSTONE);
2248 makeknown(obj->otyp);
2249 prinv((char *) 0, obj, 0L);
2250 return;
2251 } else {
2252 /* either a ring or the touchstone was not effective */
2253 if (objects[obj->otyp].oc_material == GLASS) {
2254 do_scratch = TRUE;
2255 break;
2258 streak_color = c_obj_colors[objects[obj->otyp].oc_color];
2259 break; /* gem or ring */
2261 default:
2262 switch (objects[obj->otyp].oc_material) {
2263 case CLOTH:
2264 pline("%s a little more polished now.", Tobjnam(tstone, "look"));
2265 return;
2266 case LIQUID:
2267 if (!obj->known) /* note: not "whetstone" */
2268 You("must think this is a wetstone, do you?");
2269 else
2270 pline("%s a little wetter now.", Tobjnam(tstone, "are"));
2271 return;
2272 case WAX:
2273 streak_color = "waxy";
2274 break; /* okay even if not touchstone */
2275 case WOOD:
2276 streak_color = "wooden";
2277 break; /* okay even if not touchstone */
2278 case GOLD:
2279 do_scratch = TRUE; /* scratching and streaks */
2280 streak_color = "golden";
2281 break;
2282 case SILVER:
2283 do_scratch = TRUE; /* scratching and streaks */
2284 streak_color = "silvery";
2285 break;
2286 default:
2287 /* Objects passing the is_flimsy() test will not
2288 scratch a stone. They will leave streaks on
2289 non-touchstones and touchstones alike. */
2290 if (is_flimsy(obj))
2291 streak_color = c_obj_colors[objects[obj->otyp].oc_color];
2292 else
2293 do_scratch = (tstone->otyp != TOUCHSTONE);
2294 break;
2296 break; /* default oclass */
2299 Sprintf(stonebuf, "stone%s", plur(tstone->quan));
2300 if (do_scratch)
2301 You("make %s%sscratch marks on the %s.",
2302 streak_color ? streak_color : (const char *) "",
2303 streak_color ? " " : "", stonebuf);
2304 else if (streak_color)
2305 You_see("%s streaks on the %s.", streak_color, stonebuf);
2306 else
2307 pline(scritch);
2308 return;
2311 static struct trapinfo {
2312 struct obj *tobj;
2313 xchar tx, ty;
2314 int time_needed;
2315 boolean force_bungle;
2316 } trapinfo;
2318 void
2319 reset_trapset()
2321 trapinfo.tobj = 0;
2322 trapinfo.force_bungle = 0;
2325 /* Place a landmine/bear trap. Helge Hafting */
2326 STATIC_OVL void
2327 use_trap(otmp)
2328 struct obj *otmp;
2330 int ttyp, tmp;
2331 const char *what = (char *) 0;
2332 char buf[BUFSZ];
2333 int levtyp = levl[u.ux][u.uy].typ;
2334 const char *occutext = "setting the trap";
2336 if (nohands(youmonst.data))
2337 what = "without hands";
2338 else if (Stunned)
2339 what = "while stunned";
2340 else if (u.uswallow)
2341 what =
2342 is_animal(u.ustuck->data) ? "while swallowed" : "while engulfed";
2343 else if (Underwater)
2344 what = "underwater";
2345 else if (Levitation)
2346 what = "while levitating";
2347 else if (is_pool(u.ux, u.uy))
2348 what = "in water";
2349 else if (is_lava(u.ux, u.uy))
2350 what = "in lava";
2351 else if (On_stairs(u.ux, u.uy))
2352 what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder"
2353 : "on the stairs";
2354 else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp)
2355 || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
2356 what = "here";
2357 else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
2358 what = (levtyp == AIR)
2359 ? "in midair"
2360 : (levtyp == CLOUD)
2361 ? "in a cloud"
2362 : "in this place"; /* Air/Water Plane catch-all */
2363 if (what) {
2364 You_cant("set a trap %s!", what);
2365 reset_trapset();
2366 return;
2368 ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
2369 if (otmp == trapinfo.tobj && u.ux == trapinfo.tx && u.uy == trapinfo.ty) {
2370 You("resume setting %s%s.", shk_your(buf, otmp),
2371 defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
2372 set_occupation(set_trap, occutext, 0);
2373 return;
2375 trapinfo.tobj = otmp;
2376 trapinfo.tx = u.ux, trapinfo.ty = u.uy;
2377 tmp = ACURR(A_DEX);
2378 trapinfo.time_needed =
2379 (tmp > 17) ? 2 : (tmp > 12) ? 3 : (tmp > 7) ? 4 : 5;
2380 if (Blind)
2381 trapinfo.time_needed *= 2;
2382 tmp = ACURR(A_STR);
2383 if (ttyp == BEAR_TRAP && tmp < 18)
2384 trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4;
2385 /*[fumbling and/or confusion and/or cursed object check(s)
2386 should be incorporated here instead of in set_trap]*/
2387 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
2388 boolean chance;
2390 if (Fumbling || otmp->cursed)
2391 chance = (rnl(10) > 3);
2392 else
2393 chance = (rnl(10) > 5);
2394 You("aren't very skilled at reaching from %s.", mon_nam(u.usteed));
2395 Sprintf(buf, "Continue your attempt to set %s?",
2396 the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
2397 if (yn(buf) == 'y') {
2398 if (chance) {
2399 switch (ttyp) {
2400 case LANDMINE: /* set it off */
2401 trapinfo.time_needed = 0;
2402 trapinfo.force_bungle = TRUE;
2403 break;
2404 case BEAR_TRAP: /* drop it without arming it */
2405 reset_trapset();
2406 You("drop %s!",
2407 the(defsyms[trap_to_defsym(what_trap(ttyp))]
2408 .explanation));
2409 dropx(otmp);
2410 return;
2413 } else {
2414 reset_trapset();
2415 return;
2418 You("begin setting %s%s.", shk_your(buf, otmp),
2419 defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
2420 set_occupation(set_trap, occutext, 0);
2421 return;
2424 STATIC_PTR
2426 set_trap()
2428 struct obj *otmp = trapinfo.tobj;
2429 struct trap *ttmp;
2430 int ttyp;
2432 if (!otmp || !carried(otmp) || u.ux != trapinfo.tx
2433 || u.uy != trapinfo.ty) {
2434 /* ?? */
2435 reset_trapset();
2436 return 0;
2439 if (--trapinfo.time_needed > 0)
2440 return 1; /* still busy */
2442 ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
2443 ttmp = maketrap(u.ux, u.uy, ttyp);
2444 if (ttmp) {
2445 ttmp->madeby_u = 1;
2446 feeltrap(ttmp);
2447 if (*in_rooms(u.ux, u.uy, SHOPBASE)) {
2448 add_damage(u.ux, u.uy, 0L); /* schedule removal */
2450 if (!trapinfo.force_bungle)
2451 You("finish arming %s.",
2452 the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
2453 if (((otmp->cursed || Fumbling) && (rnl(10) > 5))
2454 || trapinfo.force_bungle)
2455 dotrap(ttmp,
2456 (unsigned) (trapinfo.force_bungle ? FORCEBUNGLE : 0));
2457 } else {
2458 /* this shouldn't happen */
2459 Your("trap setting attempt fails.");
2461 useup(otmp);
2462 reset_trapset();
2463 return 0;
2466 STATIC_OVL int
2467 use_whip(obj)
2468 struct obj *obj;
2470 char buf[BUFSZ];
2471 struct monst *mtmp;
2472 struct obj *otmp;
2473 int rx, ry, proficient, res = 0;
2474 const char *msg_slipsfree = "The bullwhip slips free.";
2475 const char *msg_snap = "Snap!";
2477 if (obj != uwep) {
2478 if (!wield_tool(obj, "lash"))
2479 return 0;
2480 else
2481 res = 1;
2483 if (!getdir((char *) 0))
2484 return res;
2486 if (u.uswallow) {
2487 mtmp = u.ustuck;
2488 rx = mtmp->mx;
2489 ry = mtmp->my;
2490 } else {
2491 if (Stunned || (Confusion && !rn2(5)))
2492 confdir();
2493 rx = u.ux + u.dx;
2494 ry = u.uy + u.dy;
2495 if (!isok(rx, ry)) {
2496 You("miss.");
2497 return res;
2499 mtmp = m_at(rx, ry);
2502 /* fake some proficiency checks */
2503 proficient = 0;
2504 if (Role_if(PM_ARCHEOLOGIST))
2505 ++proficient;
2506 if (ACURR(A_DEX) < 6)
2507 proficient--;
2508 else if (ACURR(A_DEX) >= 14)
2509 proficient += (ACURR(A_DEX) - 14);
2510 if (Fumbling)
2511 --proficient;
2512 if (proficient > 3)
2513 proficient = 3;
2514 if (proficient < 0)
2515 proficient = 0;
2517 if (u.uswallow && attack(u.ustuck)) {
2518 There("is not enough room to flick your bullwhip.");
2520 } else if (Underwater) {
2521 There("is too much resistance to flick your bullwhip.");
2523 } else if (u.dz < 0) {
2524 You("flick a bug off of the %s.", ceiling(u.ux, u.uy));
2526 } else if ((!u.dx && !u.dy) || (u.dz > 0)) {
2527 int dam;
2529 /* Sometimes you hit your steed by mistake */
2530 if (u.usteed && !rn2(proficient + 2)) {
2531 You("whip %s!", mon_nam(u.usteed));
2532 kick_steed();
2533 return 1;
2535 if (Levitation || u.usteed) {
2536 /* Have a shot at snaring something on the floor */
2537 otmp = level.objects[u.ux][u.uy];
2538 if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) {
2539 pline("Why beat a dead horse?");
2540 return 1;
2542 if (otmp && proficient) {
2543 You("wrap your bullwhip around %s on the %s.",
2544 an(singular(otmp, xname)), surface(u.ux, u.uy));
2545 if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1)
2546 pline1(msg_slipsfree);
2547 return 1;
2550 dam = rnd(2) + dbon() + obj->spe;
2551 if (dam <= 0)
2552 dam = 1;
2553 You("hit your %s with your bullwhip.", body_part(FOOT));
2554 Sprintf(buf, "killed %sself with %s bullwhip", uhim(), uhis());
2555 losehp(Maybe_Half_Phys(dam), buf, NO_KILLER_PREFIX);
2556 context.botl = 1;
2557 return 1;
2559 } else if ((Fumbling || Glib) && !rn2(5)) {
2560 pline_The("bullwhip slips out of your %s.", body_part(HAND));
2561 dropx(obj);
2563 } else if (u.utrap && u.utraptype == TT_PIT) {
2565 * Assumptions:
2567 * if you're in a pit
2568 * - you are attempting to get out of the pit
2569 * or, if you are applying it towards a small monster
2570 * - then it is assumed that you are trying to hit it
2571 * else if the monster is wielding a weapon
2572 * - you are attempting to disarm a monster
2573 * else
2574 * - you are attempting to hit the monster.
2576 * if you're confused (and thus off the mark)
2577 * - you only end up hitting.
2580 const char *wrapped_what = (char *) 0;
2582 if (mtmp) {
2583 if (bigmonst(mtmp->data)) {
2584 wrapped_what = strcpy(buf, mon_nam(mtmp));
2585 } else if (proficient) {
2586 if (attack(mtmp))
2587 return 1;
2588 else
2589 pline1(msg_snap);
2592 if (!wrapped_what) {
2593 if (IS_FURNITURE(levl[rx][ry].typ))
2594 wrapped_what = something;
2595 else if (sobj_at(BOULDER, rx, ry))
2596 wrapped_what = "a boulder";
2598 if (wrapped_what) {
2599 coord cc;
2601 cc.x = rx;
2602 cc.y = ry;
2603 You("wrap your bullwhip around %s.", wrapped_what);
2604 if (proficient && rn2(proficient + 2)) {
2605 if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
2606 You("yank yourself out of the pit!");
2607 teleds(cc.x, cc.y, TRUE);
2608 u.utrap = 0;
2609 vision_full_recalc = 1;
2611 } else {
2612 pline1(msg_slipsfree);
2614 if (mtmp)
2615 wakeup(mtmp);
2616 } else
2617 pline1(msg_snap);
2619 } else if (mtmp) {
2620 if (!canspotmon(mtmp) && !glyph_is_invisible(levl[rx][ry].glyph)) {
2621 pline("A monster is there that you couldn't see.");
2622 map_invisible(rx, ry);
2624 otmp = MON_WEP(mtmp); /* can be null */
2625 if (otmp) {
2626 char onambuf[BUFSZ];
2627 const char *mon_hand;
2628 boolean gotit = proficient && (!Fumbling || !rn2(10));
2630 Strcpy(onambuf, cxname(otmp));
2631 if (gotit) {
2632 mon_hand = mbodypart(mtmp, HAND);
2633 if (bimanual(otmp))
2634 mon_hand = makeplural(mon_hand);
2635 } else
2636 mon_hand = 0; /* lint suppression */
2638 You("wrap your bullwhip around %s.", yname(otmp));
2639 if (gotit && mwelded(otmp)) {
2640 pline("%s welded to %s %s%c",
2641 (otmp->quan == 1L) ? "It is" : "They are", mhis(mtmp),
2642 mon_hand, !otmp->bknown ? '!' : '.');
2643 otmp->bknown = 1;
2644 gotit = FALSE; /* can't pull it free */
2646 if (gotit) {
2647 obj_extract_self(otmp);
2648 possibly_unwield(mtmp, FALSE);
2649 setmnotwielded(mtmp, otmp);
2651 switch (rn2(proficient + 1)) {
2652 case 2:
2653 /* to floor near you */
2654 You("yank %s to the %s!", yname(otmp),
2655 surface(u.ux, u.uy));
2656 place_object(otmp, u.ux, u.uy);
2657 stackobj(otmp);
2658 break;
2659 case 3:
2660 #if 0
2661 /* right to you */
2662 if (!rn2(25)) {
2663 /* proficient with whip, but maybe not
2664 so proficient at catching weapons */
2665 int hitu, hitvalu;
2667 hitvalu = 8 + otmp->spe;
2668 hitu = thitu(hitvalu,
2669 dmgval(otmp, &youmonst),
2670 otmp, (char *)0);
2671 if (hitu) {
2672 pline_The("%s hits you as you try to snatch it!",
2673 the(onambuf));
2675 place_object(otmp, u.ux, u.uy);
2676 stackobj(otmp);
2677 break;
2679 #endif /* 0 */
2680 /* right into your inventory */
2681 You("snatch %s!", yname(otmp));
2682 if (otmp->otyp == CORPSE
2683 && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg
2684 && !Stone_resistance
2685 && !(poly_when_stoned(youmonst.data)
2686 && polymon(PM_STONE_GOLEM))) {
2687 char kbuf[BUFSZ];
2689 Sprintf(kbuf, "%s corpse",
2690 an(mons[otmp->corpsenm].mname));
2691 pline("Snatching %s is a fatal mistake.", kbuf);
2692 instapetrify(kbuf);
2694 otmp = hold_another_object(
2695 otmp, "You drop %s!", doname(otmp), (const char *) 0);
2696 break;
2697 default:
2698 /* to floor beneath mon */
2699 You("yank %s from %s %s!", the(onambuf),
2700 s_suffix(mon_nam(mtmp)), mon_hand);
2701 obj_no_longer_held(otmp);
2702 place_object(otmp, mtmp->mx, mtmp->my);
2703 stackobj(otmp);
2704 break;
2706 } else {
2707 pline1(msg_slipsfree);
2709 wakeup(mtmp);
2710 } else {
2711 if (mtmp->m_ap_type && !Protection_from_shape_changers
2712 && !sensemon(mtmp))
2713 stumble_onto_mimic(mtmp);
2714 else
2715 You("flick your bullwhip towards %s.", mon_nam(mtmp));
2716 if (proficient) {
2717 if (attack(mtmp))
2718 return 1;
2719 else
2720 pline1(msg_snap);
2724 } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
2725 /* it must be air -- water checked above */
2726 You("snap your whip through thin air.");
2728 } else {
2729 pline1(msg_snap);
2731 return 1;
2734 static const char
2735 not_enough_room[] = "There's not enough room here to use that.",
2736 where_to_hit[] = "Where do you want to hit?",
2737 cant_see_spot[] = "won't hit anything if you can't see that spot.",
2738 cant_reach[] = "can't reach that spot from here.";
2740 /* find pos of monster in range, if only one monster */
2741 boolean
2742 find_poleable_mon(pos, min_range, max_range)
2743 coord *pos;
2744 int min_range, max_range;
2746 struct monst *mtmp;
2747 struct monst *selmon = (struct monst *) 0;
2749 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
2750 if (mtmp && !DEADMONSTER(mtmp) && !mtmp->mtame
2751 && cansee(mtmp->mx, mtmp->my)
2752 && distu(mtmp->mx, mtmp->my) <= max_range
2753 && distu(mtmp->mx, mtmp->my) >= min_range) {
2754 if (selmon)
2755 return FALSE;
2756 selmon = mtmp;
2758 if (!selmon)
2759 return FALSE;
2760 pos->x = selmon->mx;
2761 pos->y = selmon->my;
2762 return TRUE;
2765 static int polearm_range_min = -1;
2766 static int polearm_range_max = -1;
2768 void
2769 display_polearm_positions(state)
2770 int state;
2772 if (state == 0) {
2773 tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
2774 } else if (state == 1) {
2775 int x, y, dx, dy;
2777 for (dx = -4; dx <= 4; dx++)
2778 for (dy = -4; dy <= 4; dy++) {
2779 x = dx + (int) u.ux;
2780 y = dy + (int) u.uy;
2781 if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
2782 && distu(x, y) >= polearm_range_min
2783 && distu(x, y) <= polearm_range_max) {
2784 tmp_at(x, y);
2787 } else {
2788 tmp_at(DISP_END, 0);
2792 /* Distance attacks by pole-weapons */
2793 STATIC_OVL int
2794 use_pole(obj)
2795 struct obj *obj;
2797 int res = 0, typ, max_range, min_range, glyph;
2798 coord cc;
2799 struct monst *mtmp;
2800 struct monst *hitm = context.polearm.hitmon;
2802 /* Are you allowed to use the pole? */
2803 if (u.uswallow) {
2804 pline(not_enough_room);
2805 return 0;
2807 if (obj != uwep) {
2808 if (!wield_tool(obj, "swing"))
2809 return 0;
2810 else
2811 res = 1;
2813 /* assert(obj == uwep); */
2816 * Calculate allowable range (pole's reach is always 2 steps):
2817 * unskilled and basic: orthogonal direction, 4..4;
2818 * skilled: as basic, plus knight's jump position, 4..5;
2819 * expert: as skilled, plus diagonal, 4..8.
2820 * ...9...
2821 * .85458.
2822 * .52125.
2823 * 9410149
2824 * .52125.
2825 * .85458.
2826 * ...9...
2827 * (Note: no roles in nethack can become expert or better
2828 * for polearm skill; Yeoman in slash'em can become expert.)
2830 min_range = 4;
2831 typ = uwep_skill_type();
2832 if (typ == P_NONE || P_SKILL(typ) <= P_BASIC)
2833 max_range = 4;
2834 else if (P_SKILL(typ) == P_SKILLED)
2835 max_range = 5;
2836 else
2837 max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */
2839 polearm_range_min = min_range;
2840 polearm_range_max = max_range;
2842 /* Prompt for a location */
2843 pline(where_to_hit);
2844 cc.x = u.ux;
2845 cc.y = u.uy;
2846 if (!find_poleable_mon(&cc, min_range, max_range) && hitm
2847 && !DEADMONSTER(hitm) && cansee(hitm->mx, hitm->my)
2848 && distu(hitm->mx, hitm->my) <= max_range
2849 && distu(hitm->mx, hitm->my) >= min_range) {
2850 cc.x = hitm->mx;
2851 cc.y = hitm->my;
2853 getpos_sethilite(display_polearm_positions);
2854 if (getpos(&cc, TRUE, "the spot to hit") < 0)
2855 return res; /* ESC; uses turn iff polearm became wielded */
2857 glyph = glyph_at(cc.x, cc.y);
2858 if (distu(cc.x, cc.y) > max_range) {
2859 pline("Too far!");
2860 return res;
2861 } else if (distu(cc.x, cc.y) < min_range) {
2862 pline("Too close!");
2863 return res;
2864 } else if (!cansee(cc.x, cc.y) && !glyph_is_monster(glyph)
2865 && !glyph_is_invisible(glyph) && !glyph_is_statue(glyph)) {
2866 You(cant_see_spot);
2867 return res;
2868 } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
2869 You(cant_reach);
2870 return res;
2873 context.polearm.hitmon = NULL;
2874 /* Attack the monster there */
2875 bhitpos = cc;
2876 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *) 0) {
2877 if (attack_checks(mtmp, uwep))
2878 return res;
2879 if (overexertion())
2880 return 1; /* burn nutrition; maybe pass out */
2881 context.polearm.hitmon = mtmp;
2882 check_caitiff(mtmp);
2883 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
2884 (void) thitmonst(mtmp, uwep);
2885 } else if (glyph_is_statue(glyph) /* might be hallucinatory */
2886 && sobj_at(STATUE, bhitpos.x, bhitpos.y)) {
2887 struct trap *t = t_at(bhitpos.x, bhitpos.y);
2889 if (t && t->ttyp == STATUE_TRAP
2890 && activate_statue_trap(t, t->tx, t->ty, FALSE)) {
2891 ; /* feedback has been give by animate_statue() */
2892 } else {
2893 /* Since statues look like monsters now, we say something
2894 different from "you miss" or "there's nobody there".
2895 Note: we only do this when a statue is displayed here,
2896 because the player is probably attempting to attack it;
2897 other statues obscured by anything are just ignored. */
2898 pline("Thump! Your blow bounces harmlessly off the statue.");
2899 wake_nearto(bhitpos.x, bhitpos.y, 25);
2901 } else {
2902 /* no monster here and no statue seen or remembered here */
2903 if (glyph_is_invisible(glyph)) {
2904 /* now you know that nothing is there... */
2905 unmap_object(bhitpos.x, bhitpos.y);
2906 newsym(bhitpos.x, bhitpos.y);
2908 You("miss; there is no one there to hit.");
2910 u_wipe_engr(2); /* same as for melee or throwing */
2911 return 1;
2914 STATIC_OVL int
2915 use_cream_pie(obj)
2916 struct obj *obj;
2918 boolean wasblind = Blind;
2919 boolean wascreamed = u.ucreamed;
2920 boolean several = FALSE;
2922 if (obj->quan > 1L) {
2923 several = TRUE;
2924 obj = splitobj(obj, 1L);
2926 if (Hallucination)
2927 You("give yourself a facial.");
2928 else
2929 pline("You immerse your %s in %s%s.", body_part(FACE),
2930 several ? "one of " : "",
2931 several ? makeplural(the(xname(obj))) : the(xname(obj)));
2932 if (can_blnd((struct monst *) 0, &youmonst, AT_WEAP, obj)) {
2933 int blindinc = rnd(25);
2934 u.ucreamed += blindinc;
2935 make_blinded(Blinded + (long) blindinc, FALSE);
2936 if (!Blind || (Blind && wasblind))
2937 pline("There's %ssticky goop all over your %s.",
2938 wascreamed ? "more " : "", body_part(FACE));
2939 else /* Blind && !wasblind */
2940 You_cant("see through all the sticky goop on your %s.",
2941 body_part(FACE));
2944 setnotworn(obj);
2945 /* useup() is appropriate, but we want costly_alteration()'s message */
2946 costly_alteration(obj, COST_SPLAT);
2947 obj_extract_self(obj);
2948 delobj(obj);
2949 return 0;
2952 STATIC_OVL int
2953 use_grapple(obj)
2954 struct obj *obj;
2956 int res = 0, typ, max_range = 4, tohit;
2957 boolean save_confirm;
2958 coord cc;
2959 struct monst *mtmp;
2960 struct obj *otmp;
2962 /* Are you allowed to use the hook? */
2963 if (u.uswallow) {
2964 pline(not_enough_room);
2965 return 0;
2967 if (obj != uwep) {
2968 if (!wield_tool(obj, "cast"))
2969 return 0;
2970 else
2971 res = 1;
2973 /* assert(obj == uwep); */
2975 /* Prompt for a location */
2976 pline(where_to_hit);
2977 cc.x = u.ux;
2978 cc.y = u.uy;
2979 if (getpos(&cc, TRUE, "the spot to hit") < 0)
2980 return res; /* ESC; uses turn iff grapnel became wielded */
2982 /* Calculate range; unlike use_pole(), there's no minimum for range */
2983 typ = uwep_skill_type();
2984 if (typ == P_NONE || P_SKILL(typ) <= P_BASIC)
2985 max_range = 4;
2986 else if (P_SKILL(typ) == P_SKILLED)
2987 max_range = 5;
2988 else
2989 max_range = 8;
2990 if (distu(cc.x, cc.y) > max_range) {
2991 pline("Too far!");
2992 return res;
2993 } else if (!cansee(cc.x, cc.y)) {
2994 You(cant_see_spot);
2995 return res;
2996 } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
2997 You(cant_reach);
2998 return res;
3001 /* What do you want to hit? */
3002 tohit = rn2(5);
3003 if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) {
3004 winid tmpwin = create_nhwindow(NHW_MENU);
3005 anything any;
3006 char buf[BUFSZ];
3007 menu_item *selected;
3009 any = zeroany; /* set all bits to zero */
3010 any.a_int = 1; /* use index+1 (cant use 0) as identifier */
3011 start_menu(tmpwin);
3012 any.a_int++;
3013 Sprintf(buf, "an object on the %s", surface(cc.x, cc.y));
3014 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3015 MENU_UNSELECTED);
3016 any.a_int++;
3017 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "a monster",
3018 MENU_UNSELECTED);
3019 any.a_int++;
3020 Sprintf(buf, "the %s", surface(cc.x, cc.y));
3021 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3022 MENU_UNSELECTED);
3023 end_menu(tmpwin, "Aim for what?");
3024 tohit = rn2(4);
3025 if (select_menu(tmpwin, PICK_ONE, &selected) > 0
3026 && rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2))
3027 tohit = selected[0].item.a_int - 1;
3028 free((genericptr_t) selected);
3029 destroy_nhwindow(tmpwin);
3032 /* possibly scuff engraving at your feet;
3033 any engraving at the target location is unaffected */
3034 if (tohit == 2 || !rn2(2))
3035 u_wipe_engr(rnd(2));
3037 /* What did you hit? */
3038 switch (tohit) {
3039 case 0: /* Trap */
3040 /* FIXME -- untrap needs to deal with non-adjacent traps */
3041 break;
3042 case 1: /* Object */
3043 if ((otmp = level.objects[cc.x][cc.y]) != 0) {
3044 You("snag an object from the %s!", surface(cc.x, cc.y));
3045 (void) pickup_object(otmp, 1L, FALSE);
3046 /* If pickup fails, leave it alone */
3047 newsym(cc.x, cc.y);
3048 return 1;
3050 break;
3051 case 2: /* Monster */
3052 bhitpos = cc;
3053 if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *) 0)
3054 break;
3055 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
3056 save_confirm = flags.confirm;
3057 if (verysmall(mtmp->data) && !rn2(4)
3058 && enexto(&cc, u.ux, u.uy, (struct permonst *) 0)) {
3059 flags.confirm = FALSE;
3060 (void) attack_checks(mtmp, uwep);
3061 flags.confirm = save_confirm;
3062 check_caitiff(mtmp); /* despite fact there's no damage */
3063 You("pull in %s!", mon_nam(mtmp));
3064 mtmp->mundetected = 0;
3065 rloc_to(mtmp, cc.x, cc.y);
3066 return 1;
3067 } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data))
3068 || rn2(4)) {
3069 flags.confirm = FALSE;
3070 (void) attack_checks(mtmp, uwep);
3071 flags.confirm = save_confirm;
3072 check_caitiff(mtmp);
3073 (void) thitmonst(mtmp, uwep);
3074 return 1;
3076 /* FALL THROUGH */
3077 case 3: /* Surface */
3078 if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y))
3079 pline_The("hook slices through the %s.", surface(cc.x, cc.y));
3080 else {
3081 You("are yanked toward the %s!", surface(cc.x, cc.y));
3082 hurtle(sgn(cc.x - u.ux), sgn(cc.y - u.uy), 1, FALSE);
3083 spoteffects(TRUE);
3085 return 1;
3086 default: /* Yourself (oops!) */
3087 if (P_SKILL(typ) <= P_BASIC) {
3088 You("hook yourself!");
3089 losehp(Maybe_Half_Phys(rn1(10, 10)), "a grappling hook",
3090 KILLED_BY);
3091 return 1;
3093 break;
3095 pline1(nothing_happens);
3096 return 1;
3099 #define BY_OBJECT ((struct monst *) 0)
3101 /* return 1 if the wand is broken, hence some time elapsed */
3102 STATIC_OVL int
3103 do_break_wand(obj)
3104 struct obj *obj;
3106 static const char nothing_else_happens[] = "But nothing else happens...";
3107 register int i, x, y;
3108 register struct monst *mon;
3109 int dmg, damage;
3110 boolean affects_objects;
3111 boolean shop_damage = FALSE;
3112 boolean fillmsg = FALSE;
3113 int expltype = EXPL_MAGICAL;
3114 char confirm[QBUFSZ], buf[BUFSZ];
3115 boolean is_fragile = (!strcmp(OBJ_DESCR(objects[obj->otyp]), "balsa"));
3117 if (!paranoid_query(ParanoidBreakwand,
3118 safe_qbuf(confirm,
3119 "Are you really sure you want to break ",
3120 "?", obj, yname, ysimple_name, "the wand")))
3121 return 0;
3123 if (nohands(youmonst.data)) {
3124 You_cant("break %s without hands!", yname(obj));
3125 return 0;
3126 } else if (ACURR(A_STR) < (is_fragile ? 5 : 10)) {
3127 You("don't have the strength to break %s!", yname(obj));
3128 return 0;
3130 pline("Raising %s high above your %s, you break it in two!", yname(obj),
3131 body_part(HEAD));
3133 /* [ALI] Do this first so that wand is removed from bill. Otherwise,
3134 * the freeinv() below also hides it from setpaid() which causes problems.
3136 if (obj->unpaid) {
3137 check_unpaid(obj); /* Extra charge for use */
3138 costly_alteration(obj, COST_DSTROY);
3141 current_wand = obj; /* destroy_item might reset this */
3142 freeinv(obj); /* hide it from destroy_item instead... */
3143 setnotworn(obj); /* so we need to do this ourselves */
3145 if (!zappable(obj)) {
3146 pline(nothing_else_happens);
3147 goto discard_broken_wand;
3149 /* successful call to zappable() consumes a charge; put it back */
3150 obj->spe++;
3151 /* might have "wrested" a final charge, taking it from 0 to -1;
3152 if so, we just brought it back up to 0, which wouldn't do much
3153 below so give it 1..3 charges now, usually making it stronger
3154 than an ordinary last charge (the wand is already gone from
3155 inventory, so perm_invent can't accidentally reveal this) */
3156 if (!obj->spe)
3157 obj->spe = rnd(3);
3159 obj->ox = u.ux;
3160 obj->oy = u.uy;
3161 dmg = obj->spe * 4;
3162 affects_objects = FALSE;
3164 switch (obj->otyp) {
3165 case WAN_WISHING:
3166 case WAN_NOTHING:
3167 case WAN_LOCKING:
3168 case WAN_PROBING:
3169 case WAN_ENLIGHTENMENT:
3170 case WAN_OPENING:
3171 case WAN_SECRET_DOOR_DETECTION:
3172 pline(nothing_else_happens);
3173 goto discard_broken_wand;
3174 case WAN_DEATH:
3175 case WAN_LIGHTNING:
3176 dmg *= 4;
3177 goto wanexpl;
3178 case WAN_FIRE:
3179 expltype = EXPL_FIERY;
3180 case WAN_COLD:
3181 if (expltype == EXPL_MAGICAL)
3182 expltype = EXPL_FROSTY;
3183 dmg *= 2;
3184 case WAN_MAGIC_MISSILE:
3185 wanexpl:
3186 explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype);
3187 makeknown(obj->otyp); /* explode describes the effect */
3188 goto discard_broken_wand;
3189 case WAN_STRIKING:
3190 /* we want this before the explosion instead of at the very end */
3191 pline("A wall of force smashes down around you!");
3192 dmg = d(1 + obj->spe, 6); /* normally 2d12 */
3193 /*FALLTHRU*/
3194 case WAN_CANCELLATION:
3195 case WAN_POLYMORPH:
3196 case WAN_TELEPORTATION:
3197 case WAN_UNDEAD_TURNING:
3198 affects_objects = TRUE;
3199 break;
3200 default:
3201 break;
3204 /* magical explosion and its visual effect occur before specific effects
3206 /* [TODO? This really ought to prevent the explosion from being
3207 fatal so that we never leave a bones file where none of the
3208 surrounding targets (or underlying objects) got affected yet.] */
3209 explode(obj->ox, obj->oy, -(obj->otyp), rnd(dmg), WAND_CLASS,
3210 EXPL_MAGICAL);
3212 /* prepare for potential feedback from polymorph... */
3213 zapsetup();
3215 /* this makes it hit us last, so that we can see the action first */
3216 for (i = 0; i <= 8; i++) {
3217 bhitpos.x = x = obj->ox + xdir[i];
3218 bhitpos.y = y = obj->oy + ydir[i];
3219 if (!isok(x, y))
3220 continue;
3222 if (obj->otyp == WAN_DIGGING) {
3223 schar typ;
3225 if (dig_check(BY_OBJECT, FALSE, x, y)) {
3226 if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) {
3227 /* normally, pits and holes don't anger guards, but they
3228 * do if it's a wall or door that's being dug */
3229 watch_dig((struct monst *) 0, x, y, TRUE);
3230 if (*in_rooms(x, y, SHOPBASE))
3231 shop_damage = TRUE;
3234 * Let liquid flow into the newly created pits.
3235 * Adjust corresponding code in music.c for
3236 * drum of earthquake if you alter this sequence.
3238 typ = fillholetyp(x, y, FALSE);
3239 if (typ != ROOM) {
3240 levl[x][y].typ = typ;
3241 liquid_flow(x, y, typ, t_at(x, y),
3242 fillmsg
3243 ? (char *) 0
3244 : "Some holes are quickly filled with %s!");
3245 fillmsg = TRUE;
3246 } else
3247 digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3
3248 || (!Can_dig_down(&u.uz)
3249 && !levl[x][y].candig))
3250 ? PIT
3251 : HOLE);
3253 continue;
3254 } else if (obj->otyp == WAN_CREATE_MONSTER) {
3255 /* u.ux,u.uy creates it near you--x,y might create it in rock */
3256 (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS);
3257 continue;
3258 } else if (x != u.ux || y != u.uy) {
3260 * Wand breakage is targetting a square adjacent to the hero,
3261 * which might contain a monster or a pile of objects or both.
3262 * Handle objects last; avoids having undead turning raise an
3263 * undead's corpse and then attack resulting undead monster.
3264 * obj->bypass in bhitm() prevents the polymorphing of items
3265 * dropped due to monster's polymorph and prevents undead
3266 * turning that kills an undead from raising resulting corpse.
3268 if ((mon = m_at(x, y)) != 0) {
3269 (void) bhitm(mon, obj);
3270 /* if (context.botl) bot(); */
3272 if (affects_objects && level.objects[x][y]) {
3273 (void) bhitpile(obj, bhito, x, y, 0);
3274 if (context.botl)
3275 bot(); /* potion effects */
3277 } else {
3279 * Wand breakage is targetting the hero. Using xdir[]+ydir[]
3280 * deltas for location selection causes this case to happen
3281 * after all the surrounding squares have been handled.
3282 * Process objects first, in case damage is fatal and leaves
3283 * bones, or teleportation sends one or more of the objects to
3284 * same destination as hero (lookhere/autopickup); also avoids
3285 * the polymorphing of gear dropped due to hero's transformation.
3286 * (Unlike with monsters being hit by zaps, we can't rely on use
3287 * of obj->bypass in the zap code to accomplish that last case
3288 * since it's also used by retouch_equipment() for polyself.)
3290 if (affects_objects && level.objects[x][y]) {
3291 (void) bhitpile(obj, bhito, x, y, 0);
3292 if (context.botl)
3293 bot(); /* potion effects */
3295 damage = zapyourself(obj, FALSE);
3296 if (damage) {
3297 Sprintf(buf, "killed %sself by breaking a wand", uhim());
3298 losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX);
3300 if (context.botl)
3301 bot(); /* blindness */
3305 /* potentially give post zap/break feedback */
3306 zapwrapup();
3308 /* Note: if player fell thru, this call is a no-op.
3309 Damage is handled in digactualhole in that case */
3310 if (shop_damage)
3311 pay_for_damage("dig into", FALSE);
3313 if (obj->otyp == WAN_LIGHT)
3314 litroom(TRUE, obj); /* only needs to be done once */
3316 discard_broken_wand:
3317 obj = current_wand; /* [see dozap() and destroy_item()] */
3318 current_wand = 0;
3319 if (obj)
3320 delobj(obj);
3321 nomul(0);
3322 return 1;
3325 STATIC_OVL void
3326 add_class(cl, class)
3327 char *cl;
3328 char class;
3330 char tmp[2];
3332 tmp[0] = class;
3333 tmp[1] = '\0';
3334 Strcat(cl, tmp);
3337 static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
3339 /* augment tools[] if various items are carried */
3340 STATIC_OVL void
3341 setapplyclasses(class_list)
3342 char class_list[];
3344 register struct obj *otmp;
3345 int otyp;
3346 boolean knowoil, knowtouchstone, addpotions, addstones, addfood;
3348 knowoil = objects[POT_OIL].oc_name_known;
3349 knowtouchstone = objects[TOUCHSTONE].oc_name_known;
3350 addpotions = addstones = addfood = FALSE;
3351 for (otmp = invent; otmp; otmp = otmp->nobj) {
3352 otyp = otmp->otyp;
3353 if (otyp == POT_OIL
3354 || (otmp->oclass == POTION_CLASS
3355 && (!otmp->dknown
3356 || (!knowoil && !objects[otyp].oc_name_known))))
3357 addpotions = TRUE;
3358 if (otyp == TOUCHSTONE
3359 || (is_graystone(otmp)
3360 && (!otmp->dknown
3361 || (!knowtouchstone && !objects[otyp].oc_name_known))))
3362 addstones = TRUE;
3363 if (otyp == CREAM_PIE || otyp == EUCALYPTUS_LEAF)
3364 addfood = TRUE;
3367 class_list[0] = '\0';
3368 if (addpotions || addstones)
3369 add_class(class_list, ALL_CLASSES);
3370 Strcat(class_list, tools);
3371 if (addpotions)
3372 add_class(class_list, POTION_CLASS);
3373 if (addstones)
3374 add_class(class_list, GEM_CLASS);
3375 if (addfood)
3376 add_class(class_list, FOOD_CLASS);
3379 /* the 'a' command */
3381 doapply()
3383 struct obj *obj;
3384 register int res = 1;
3385 char class_list[MAXOCLASSES + 2];
3387 if (check_capacity((char *) 0))
3388 return 0;
3390 setapplyclasses(class_list); /* tools[] */
3391 obj = getobj(class_list, "use or apply");
3392 if (!obj)
3393 return 0;
3395 if (!retouch_object(&obj, FALSE))
3396 return 1; /* evading your grasp costs a turn; just be
3397 grateful that you don't drop it as well */
3399 if (obj->oclass == WAND_CLASS)
3400 return do_break_wand(obj);
3402 switch (obj->otyp) {
3403 case BLINDFOLD:
3404 case LENSES:
3405 if (obj == ublindf) {
3406 if (!cursed(obj))
3407 Blindf_off(obj);
3408 } else if (!ublindf) {
3409 Blindf_on(obj);
3410 } else {
3411 You("are already %s.", ublindf->otyp == TOWEL
3412 ? "covered by a towel"
3413 : ublindf->otyp == BLINDFOLD
3414 ? "wearing a blindfold"
3415 : "wearing lenses");
3417 break;
3418 case CREAM_PIE:
3419 res = use_cream_pie(obj);
3420 break;
3421 case BULLWHIP:
3422 res = use_whip(obj);
3423 break;
3424 case GRAPPLING_HOOK:
3425 res = use_grapple(obj);
3426 break;
3427 case LARGE_BOX:
3428 case CHEST:
3429 case ICE_BOX:
3430 case SACK:
3431 case BAG_OF_HOLDING:
3432 case OILSKIN_SACK:
3433 res = use_container(&obj, 1, FALSE);
3434 break;
3435 case BAG_OF_TRICKS:
3436 (void) bagotricks(obj, FALSE, (int *) 0);
3437 break;
3438 case CAN_OF_GREASE:
3439 use_grease(obj);
3440 break;
3441 case LOCK_PICK:
3442 case CREDIT_CARD:
3443 case SKELETON_KEY:
3444 res = (pick_lock(obj) != 0);
3445 break;
3446 case PICK_AXE:
3447 case DWARVISH_MATTOCK:
3448 res = use_pick_axe(obj);
3449 break;
3450 case TINNING_KIT:
3451 use_tinning_kit(obj);
3452 break;
3453 case LEASH:
3454 use_leash(obj);
3455 break;
3456 case SADDLE:
3457 res = use_saddle(obj);
3458 break;
3459 case MAGIC_WHISTLE:
3460 use_magic_whistle(obj);
3461 break;
3462 case TIN_WHISTLE:
3463 use_whistle(obj);
3464 break;
3465 case EUCALYPTUS_LEAF:
3466 /* MRKR: Every Australian knows that a gum leaf makes an excellent
3467 * whistle, especially if your pet is a tame kangaroo named Skippy.
3469 if (obj->blessed) {
3470 use_magic_whistle(obj);
3471 /* sometimes the blessing will be worn off */
3472 if (!rn2(49)) {
3473 if (!Blind) {
3474 pline("%s %s.", Yobjnam2(obj, "glow"), hcolor("brown"));
3475 obj->bknown = 1;
3477 unbless(obj);
3479 } else {
3480 use_whistle(obj);
3482 break;
3483 case STETHOSCOPE:
3484 res = use_stethoscope(obj);
3485 break;
3486 case MIRROR:
3487 res = use_mirror(obj);
3488 break;
3489 case BELL:
3490 case BELL_OF_OPENING:
3491 use_bell(&obj);
3492 break;
3493 case CANDELABRUM_OF_INVOCATION:
3494 use_candelabrum(obj);
3495 break;
3496 case WAX_CANDLE:
3497 case TALLOW_CANDLE:
3498 use_candle(&obj);
3499 break;
3500 case OIL_LAMP:
3501 case MAGIC_LAMP:
3502 case BRASS_LANTERN:
3503 use_lamp(obj);
3504 break;
3505 case POT_OIL:
3506 light_cocktail(obj);
3507 break;
3508 case EXPENSIVE_CAMERA:
3509 res = use_camera(obj);
3510 break;
3511 case TOWEL:
3512 res = use_towel(obj);
3513 break;
3514 case CRYSTAL_BALL:
3515 use_crystal_ball(&obj);
3516 break;
3517 case MAGIC_MARKER:
3518 res = dowrite(obj);
3519 break;
3520 case TIN_OPENER:
3521 res = use_tin_opener(obj);
3522 break;
3523 case FIGURINE:
3524 use_figurine(&obj);
3525 break;
3526 case UNICORN_HORN:
3527 use_unicorn_horn(obj);
3528 break;
3529 case WOODEN_FLUTE:
3530 case MAGIC_FLUTE:
3531 case TOOLED_HORN:
3532 case FROST_HORN:
3533 case FIRE_HORN:
3534 case WOODEN_HARP:
3535 case MAGIC_HARP:
3536 case BUGLE:
3537 case LEATHER_DRUM:
3538 case DRUM_OF_EARTHQUAKE:
3539 res = do_play_instrument(obj);
3540 break;
3541 case HORN_OF_PLENTY: /* not a musical instrument */
3542 (void) hornoplenty(obj, FALSE);
3543 break;
3544 case LAND_MINE:
3545 case BEARTRAP:
3546 use_trap(obj);
3547 break;
3548 case FLINT:
3549 case LUCKSTONE:
3550 case LOADSTONE:
3551 case TOUCHSTONE:
3552 use_stone(obj);
3553 break;
3554 default:
3555 /* Pole-weapons can strike at a distance */
3556 if (is_pole(obj)) {
3557 res = use_pole(obj);
3558 break;
3559 } else if (is_pick(obj) || is_axe(obj)) {
3560 res = use_pick_axe(obj);
3561 break;
3563 pline("Sorry, I don't know how to use that.");
3564 nomul(0);
3565 return 0;
3567 if (res && obj && obj->oartifact)
3568 arti_speak(obj);
3569 nomul(0);
3570 return res;
3573 /* Keep track of unfixable troubles for purposes of messages saying you feel
3574 * great.
3577 unfixable_trouble_count(is_horn)
3578 boolean is_horn;
3580 int unfixable_trbl = 0;
3582 if (Stoned)
3583 unfixable_trbl++;
3584 if (Strangled)
3585 unfixable_trbl++;
3586 if (Wounded_legs && !u.usteed)
3587 unfixable_trbl++;
3588 if (Slimed)
3589 unfixable_trbl++;
3590 /* lycanthropy is undesirable, but it doesn't actually make you feel bad */
3592 if (!is_horn || (Confusion & ~TIMEOUT))
3593 unfixable_trbl++;
3594 if (!is_horn || (Sick & ~TIMEOUT))
3595 unfixable_trbl++;
3596 if (!is_horn || (HHallucination & ~TIMEOUT))
3597 unfixable_trbl++;
3598 if (!is_horn || (Vomiting & ~TIMEOUT))
3599 unfixable_trbl++;
3600 if (!is_horn || (HStun & ~TIMEOUT))
3601 unfixable_trbl++;
3602 if (!is_horn || (HDeaf & ~TIMEOUT))
3603 unfixable_trbl++;
3605 return unfixable_trbl;
3608 /*apply.c*/