Allow changing max name len via hints file
[aNetHack.git] / src / apply.c
blobe74160b9e6779c923f24b689ff1fa53ca1def017
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_PTR boolean FDECL(check_jump, (genericptr_t, int, int));
40 STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P));
41 STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int));
43 #ifdef AMIGA
44 void FDECL(amii_speaker, (struct obj *, char *, int));
45 #endif
47 static const char no_elbow_room[] =
48 "don't have enough elbow-room to maneuver.";
50 STATIC_OVL int
51 use_camera(obj)
52 struct obj *obj;
54 struct monst *mtmp;
56 if (Underwater) {
57 pline("Using your camera underwater would void the warranty.");
58 return 0;
60 if (!getdir((char *) 0))
61 return 0;
63 if (obj->spe <= 0) {
64 pline1(nothing_happens);
65 return 1;
67 consume_obj_charge(obj, TRUE);
69 if (obj->cursed && !rn2(2)) {
70 (void) zapyourself(obj, TRUE);
71 } else if (u.uswallow) {
72 You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)),
73 mbodypart(u.ustuck, STOMACH));
74 } else if (u.dz) {
75 You("take a picture of the %s.",
76 (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy));
77 } else if (!u.dx && !u.dy) {
78 (void) zapyourself(obj, TRUE);
79 } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
80 (int FDECL((*), (MONST_P, OBJ_P))) 0,
81 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj)) != 0) {
82 obj->ox = u.ux, obj->oy = u.uy;
83 (void) flash_hits_mon(mtmp, obj);
85 return 1;
88 STATIC_OVL int
89 use_towel(obj)
90 struct obj *obj;
92 boolean drying_feedback = (obj == uwep);
94 if (!freehand()) {
95 You("have no free %s!", body_part(HAND));
96 return 0;
97 } else if (obj == ublindf) {
98 You("cannot use it while you're wearing it!");
99 return 0;
100 } else if (obj->cursed) {
101 long old;
103 switch (rn2(3)) {
104 case 2:
105 old = Glib;
106 incr_itimeout(&Glib, rn1(10, 3));
107 Your("%s %s!", makeplural(body_part(HAND)),
108 (old ? "are filthier than ever" : "get slimy"));
109 if (is_wet_towel(obj))
110 dry_a_towel(obj, -1, drying_feedback);
111 return 1;
112 case 1:
113 if (!ublindf) {
114 old = u.ucreamed;
115 u.ucreamed += rn1(10, 3);
116 pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
117 (old ? "has more" : "now has"));
118 make_blinded(Blinded + (long) u.ucreamed - old, TRUE);
119 } else {
120 const char *what;
122 what = (ublindf->otyp == LENSES)
123 ? "lenses"
124 : (obj->otyp == ublindf->otyp) ? "other towel"
125 : "blindfold";
126 if (ublindf->cursed) {
127 You("push your %s %s.", what,
128 rn2(2) ? "cock-eyed" : "crooked");
129 } else {
130 struct obj *saved_ublindf = ublindf;
131 You("push your %s off.", what);
132 Blindf_off(ublindf);
133 dropx(saved_ublindf);
136 if (is_wet_towel(obj))
137 dry_a_towel(obj, -1, drying_feedback);
138 return 1;
139 case 0:
140 break;
144 if (Glib) {
145 Glib = 0;
146 You("wipe off your %s.", makeplural(body_part(HAND)));
147 if (is_wet_towel(obj))
148 dry_a_towel(obj, -1, drying_feedback);
149 return 1;
150 } else if (u.ucreamed) {
151 Blinded -= u.ucreamed;
152 u.ucreamed = 0;
153 if (!Blinded) {
154 pline("You've got the glop off.");
155 if (!gulp_blnd_check()) {
156 Blinded = 1;
157 make_blinded(0L, TRUE);
159 } else {
160 Your("%s feels clean now.", body_part(FACE));
162 if (is_wet_towel(obj))
163 dry_a_towel(obj, -1, drying_feedback);
164 return 1;
167 Your("%s and %s are already clean.", body_part(FACE),
168 makeplural(body_part(HAND)));
170 return 0;
173 /* maybe give a stethoscope message based on floor objects */
174 STATIC_OVL boolean
175 its_dead(rx, ry, resp)
176 int rx, ry, *resp;
178 char buf[BUFSZ];
179 boolean more_corpses;
180 struct permonst *mptr;
181 struct obj *corpse = sobj_at(CORPSE, rx, ry),
182 *statue = sobj_at(STATUE, rx, ry);
184 if (!can_reach_floor(TRUE)) { /* levitation or unskilled riding */
185 corpse = 0; /* can't reach corpse on floor */
186 /* you can't reach tiny statues (even though you can fight
187 tiny monsters while levitating--consistency, what's that?) */
188 while (statue && mons[statue->corpsenm].msize == MZ_TINY)
189 statue = nxtobj(statue, STATUE, TRUE);
191 /* when both corpse and statue are present, pick the uppermost one */
192 if (corpse && statue) {
193 if (nxtobj(statue, CORPSE, TRUE) == corpse)
194 corpse = 0; /* corpse follows statue; ignore it */
195 else
196 statue = 0; /* corpse precedes statue; ignore statue */
198 more_corpses = (corpse && nxtobj(corpse, CORPSE, TRUE));
200 /* additional stethoscope messages from jyoung@apanix.apana.org.au */
201 if (!corpse && !statue) {
202 ; /* nothing to do */
204 } else if (Hallucination) {
205 if (!corpse) {
206 /* it's a statue */
207 Strcpy(buf, "You're both stoned");
208 } else if (corpse->quan == 1L && !more_corpses) {
209 int gndr = 2; /* neuter: "it" */
210 struct monst *mtmp = get_mtraits(corpse, FALSE);
212 /* (most corpses don't retain the monster's sex, so
213 we're usually forced to use generic pronoun here) */
214 if (mtmp) {
215 mptr = &mons[mtmp->mnum];
216 /* can't use mhe() here; it calls pronoun_gender() which
217 expects monster to be on the map (visibility check) */
218 if ((humanoid(mptr) || (mptr->geno & G_UNIQ)
219 || type_is_pname(mptr)) && !is_neuter(mptr))
220 gndr = (int) mtmp->female;
221 } else {
222 mptr = &mons[corpse->corpsenm];
223 if (is_female(mptr))
224 gndr = 1;
225 else if (is_male(mptr))
226 gndr = 0;
228 Sprintf(buf, "%s's dead", genders[gndr].he); /* "he"/"she"/"it" */
229 buf[0] = highc(buf[0]);
230 } else { /* plural */
231 Strcpy(buf, "They're dead");
233 /* variations on "He's dead, Jim." (Star Trek's Dr McCoy) */
234 You_hear("a voice say, \"%s, Jim.\"", buf);
235 *resp = 1;
236 return TRUE;
238 } else if (corpse) {
239 boolean here = (rx == u.ux && ry == u.uy),
240 one = (corpse->quan == 1L && !more_corpses), reviver = FALSE;
241 int visglyph, corpseglyph;
243 visglyph = glyph_at(rx, ry);
244 corpseglyph = obj_to_glyph(corpse);
246 if (Blind && (visglyph != corpseglyph))
247 map_object(corpse, TRUE);
249 if (Role_if(PM_HEALER)) {
250 /* ok to reset `corpse' here; we're done with it */
251 do {
252 if (obj_has_timer(corpse, REVIVE_MON))
253 reviver = TRUE;
254 else
255 corpse = nxtobj(corpse, CORPSE, TRUE);
256 } while (corpse && !reviver);
258 You("determine that %s unfortunate being%s %s%s dead.",
259 one ? (here ? "this" : "that") : (here ? "these" : "those"),
260 one ? "" : "s", one ? "is" : "are", reviver ? " mostly" : "");
261 return TRUE;
263 } else { /* statue */
264 const char *what, *how;
266 mptr = &mons[statue->corpsenm];
267 if (Blind) { /* ignore statue->dknown; it'll always be set */
268 Sprintf(buf, "%s %s",
269 (rx == u.ux && ry == u.uy) ? "This" : "That",
270 humanoid(mptr) ? "person" : "creature");
271 what = buf;
272 } else {
273 what = mptr->mname;
274 if (!type_is_pname(mptr))
275 what = The(what);
277 how = "fine";
278 if (Role_if(PM_HEALER)) {
279 struct trap *ttmp = t_at(rx, ry);
281 if (ttmp && ttmp->ttyp == STATUE_TRAP)
282 how = "extraordinary";
283 else if (Has_contents(statue))
284 how = "remarkable";
287 pline("%s is in %s health for a statue.", what, how);
288 return TRUE;
290 return FALSE; /* no corpse or statue */
293 static const char hollow_str[] = "a hollow sound. This must be a secret %s!";
295 /* Strictly speaking it makes no sense for usage of a stethoscope to
296 not take any time; however, unless it did, the stethoscope would be
297 almost useless. As a compromise, one use per turn is free, another
298 uses up the turn; this makes curse status have a tangible effect. */
299 STATIC_OVL int
300 use_stethoscope(obj)
301 register struct obj *obj;
303 struct monst *mtmp;
304 struct rm *lev;
305 int rx, ry, res;
306 boolean interference = (u.uswallow && is_whirly(u.ustuck->data)
307 && !rn2(Role_if(PM_HEALER) ? 10 : 3));
309 if (nohands(youmonst.data)) {
310 You("have no hands!"); /* not `body_part(HAND)' */
311 return 0;
312 } else if (Deaf) {
313 You_cant("hear anything!");
314 return 0;
315 } else if (!freehand()) {
316 You("have no free %s.", body_part(HAND));
317 return 0;
319 if (!getdir((char *) 0))
320 return 0;
322 res = (moves == context.stethoscope_move)
323 && (youmonst.movement == context.stethoscope_movement);
324 context.stethoscope_move = moves;
325 context.stethoscope_movement = youmonst.movement;
327 bhitpos.x = u.ux, bhitpos.y = u.uy; /* tentative, reset below */
328 notonhead = u.uswallow;
329 if (u.usteed && u.dz > 0) {
330 if (interference) {
331 pline("%s interferes.", Monnam(u.ustuck));
332 mstatusline(u.ustuck);
333 } else
334 mstatusline(u.usteed);
335 return res;
336 } else if (u.uswallow && (u.dx || u.dy || u.dz)) {
337 mstatusline(u.ustuck);
338 return res;
339 } else if (u.uswallow && interference) {
340 pline("%s interferes.", Monnam(u.ustuck));
341 mstatusline(u.ustuck);
342 return res;
343 } else if (u.dz) {
344 if (Underwater)
345 You_hear("faint splashing.");
346 else if (u.dz < 0 || !can_reach_floor(TRUE))
347 cant_reach_floor(u.ux, u.uy, (u.dz < 0), TRUE);
348 else if (its_dead(u.ux, u.uy, &res))
349 ; /* message already given */
350 else if (Is_stronghold(&u.uz))
351 You_hear("the crackling of hellfire.");
352 else
353 pline_The("%s seems healthy enough.", surface(u.ux, u.uy));
354 return res;
355 } else if (obj->cursed && !rn2(2)) {
356 You_hear("your heart beat.");
357 return res;
359 if (Stunned || (Confusion && !rn2(5)))
360 confdir();
361 if (!u.dx && !u.dy) {
362 ustatusline();
363 return res;
365 rx = u.ux + u.dx;
366 ry = u.uy + u.dy;
367 if (!isok(rx, ry)) {
368 You_hear("a faint typing noise.");
369 return 0;
371 if ((mtmp = m_at(rx, ry)) != 0) {
372 const char *mnm = x_monnam(mtmp, ARTICLE_A, (const char *) 0,
373 SUPPRESS_IT | SUPPRESS_INVISIBLE, FALSE);
375 /* bhitpos needed by mstatusline() iff mtmp is a long worm */
376 bhitpos.x = rx, bhitpos.y = ry;
377 notonhead = (mtmp->mx != rx || mtmp->my != ry);
379 if (mtmp->mundetected) {
380 if (!canspotmon(mtmp))
381 There("is %s hidden there.", mnm);
382 mtmp->mundetected = 0;
383 newsym(mtmp->mx, mtmp->my);
384 } else if (mtmp->mappearance) {
385 const char *what = "thing";
387 switch (mtmp->m_ap_type) {
388 case M_AP_OBJECT:
389 what = simple_typename(mtmp->mappearance);
390 break;
391 case M_AP_MONSTER: /* ignore Hallucination here */
392 what = mons[mtmp->mappearance].mname;
393 break;
394 case M_AP_FURNITURE:
395 what = defsyms[mtmp->mappearance].explanation;
396 break;
398 seemimic(mtmp);
399 pline("That %s is really %s.", what, mnm);
400 } else if (flags.verbose && !canspotmon(mtmp)) {
401 There("is %s there.", mnm);
404 mstatusline(mtmp);
405 if (!canspotmon(mtmp))
406 map_invisible(rx, ry);
407 return res;
409 if (glyph_is_invisible(levl[rx][ry].glyph)) {
410 unmap_object(rx, ry);
411 newsym(rx, ry);
412 pline_The("invisible monster must have moved.");
415 lev = &levl[rx][ry];
416 switch (lev->typ) {
417 case SDOOR:
418 You_hear(hollow_str, "door");
419 cvt_sdoor_to_door(lev); /* ->typ = DOOR */
420 feel_newsym(rx, ry);
421 return res;
422 case SCORR:
423 You_hear(hollow_str, "passage");
424 lev->typ = CORR;
425 unblock_point(rx, ry);
426 feel_newsym(rx, ry);
427 return res;
430 if (!its_dead(rx, ry, &res))
431 You("hear nothing special."); /* not You_hear() */
432 return res;
435 static const char whistle_str[] = "produce a %s whistling sound.";
437 STATIC_OVL void
438 use_whistle(obj)
439 struct obj *obj;
441 if (!can_blow(&youmonst)) {
442 You("are incapable of using the whistle.");
443 } else if (Underwater) {
444 You("blow bubbles through %s.", yname(obj));
445 } else {
446 You(whistle_str, obj->cursed ? "shrill" : "high");
447 wake_nearby();
451 STATIC_OVL void
452 use_magic_whistle(obj)
453 struct obj *obj;
455 register struct monst *mtmp, *nextmon;
457 if (!can_blow(&youmonst)) {
458 You("are incapable of using the whistle.");
459 } else if (obj->cursed && !rn2(2)) {
460 You("produce a %shigh-pitched humming noise.",
461 Underwater ? "very " : "");
462 wake_nearby();
463 } else {
464 int pet_cnt = 0, omx, omy;
466 /* it's magic! it works underwater too (at a higher pitch) */
467 You(whistle_str,
468 Hallucination ? "normal" : Underwater ? "strange, high-pitched"
469 : "strange");
470 for (mtmp = fmon; mtmp; mtmp = nextmon) {
471 nextmon = mtmp->nmon; /* trap might kill mon */
472 if (DEADMONSTER(mtmp))
473 continue;
474 /* steed is already at your location, so not affected;
475 this avoids trap issues if you're on a trap location */
476 if (mtmp == u.usteed)
477 continue;
478 if (mtmp->mtame) {
479 if (mtmp->mtrapped) {
480 /* no longer in previous trap (affects mintrap) */
481 mtmp->mtrapped = 0;
482 fill_pit(mtmp->mx, mtmp->my);
484 /* mimic must be revealed before we know whether it
485 actually moves because line-of-sight may change */
486 if (mtmp->m_ap_type)
487 seemimic(mtmp);
488 omx = mtmp->mx, omy = mtmp->my;
489 mnexto(mtmp);
490 if (mtmp->mx != omx || mtmp->my != omy) {
491 mtmp->mundetected = 0; /* reveal non-mimic hider */
492 if (canspotmon(mtmp))
493 ++pet_cnt;
494 if (mintrap(mtmp) == 2)
495 change_luck(-1);
499 if (pet_cnt > 0)
500 makeknown(obj->otyp);
504 boolean
505 um_dist(x, y, n)
506 xchar x, y, n;
508 return (boolean) (abs(u.ux - x) > n || abs(u.uy - y) > n);
512 number_leashed()
514 int i = 0;
515 struct obj *obj;
517 for (obj = invent; obj; obj = obj->nobj)
518 if (obj->otyp == LEASH && obj->leashmon != 0)
519 i++;
520 return i;
523 /* otmp is about to be destroyed or stolen */
524 void
525 o_unleash(otmp)
526 register struct obj *otmp;
528 register struct monst *mtmp;
530 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
531 if (mtmp->m_id == (unsigned) otmp->leashmon)
532 mtmp->mleashed = 0;
533 otmp->leashmon = 0;
536 /* mtmp is about to die, or become untame */
537 void
538 m_unleash(mtmp, feedback)
539 register struct monst *mtmp;
540 boolean feedback;
542 register struct obj *otmp;
544 if (feedback) {
545 if (canseemon(mtmp))
546 pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp));
547 else
548 Your("leash falls slack.");
550 for (otmp = invent; otmp; otmp = otmp->nobj)
551 if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id)
552 otmp->leashmon = 0;
553 mtmp->mleashed = 0;
556 /* player is about to die (for bones) */
557 void
558 unleash_all()
560 register struct obj *otmp;
561 register struct monst *mtmp;
563 for (otmp = invent; otmp; otmp = otmp->nobj)
564 if (otmp->otyp == LEASH)
565 otmp->leashmon = 0;
566 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
567 mtmp->mleashed = 0;
570 #define MAXLEASHED 2
572 static boolean
573 leashable(mtmp)
574 struct monst *mtmp;
576 return (boolean) (mtmp->mnum != PM_LONG_WORM);
579 /* ARGSUSED */
580 STATIC_OVL void
581 use_leash(obj)
582 struct obj *obj;
584 coord cc;
585 register struct monst *mtmp;
586 int spotmon;
588 if (!obj->leashmon && number_leashed() >= MAXLEASHED) {
589 You("cannot leash any more pets.");
590 return;
593 if (!get_adjacent_loc((char *) 0, (char *) 0, u.ux, u.uy, &cc))
594 return;
596 if ((cc.x == u.ux) && (cc.y == u.uy)) {
597 if (u.usteed && u.dz > 0) {
598 mtmp = u.usteed;
599 spotmon = 1;
600 goto got_target;
602 pline("Leash yourself? Very funny...");
603 return;
606 if (!(mtmp = m_at(cc.x, cc.y))) {
607 There("is no creature there.");
608 return;
611 spotmon = canspotmon(mtmp);
612 got_target:
614 if (!mtmp->mtame) {
615 if (!spotmon)
616 There("is no creature there.");
617 else
618 pline("%s %s leashed!", Monnam(mtmp),
619 (!obj->leashmon) ? "cannot be" : "is not");
620 return;
622 if (!obj->leashmon) {
623 if (mtmp->mleashed) {
624 pline("This %s is already leashed.",
625 spotmon ? l_monnam(mtmp) : "monster");
626 return;
628 if (!leashable(mtmp)) {
629 pline("The leash won't fit onto %s%s.", spotmon ? "your " : "",
630 l_monnam(mtmp));
631 return;
634 You("slip the leash around %s%s.", spotmon ? "your " : "",
635 l_monnam(mtmp));
636 mtmp->mleashed = 1;
637 obj->leashmon = (int) mtmp->m_id;
638 mtmp->msleeping = 0;
639 return;
641 if (obj->leashmon != (int) mtmp->m_id) {
642 pline("This leash is not attached to that creature.");
643 return;
644 } else {
645 if (obj->cursed) {
646 pline_The("leash would not come off!");
647 obj->bknown = TRUE;
648 return;
650 mtmp->mleashed = 0;
651 obj->leashmon = 0;
652 You("remove the leash from %s%s.", spotmon ? "your " : "",
653 l_monnam(mtmp));
655 return;
658 /* assuming mtmp->mleashed has been checked */
659 struct obj *
660 get_mleash(mtmp)
661 struct monst *mtmp;
663 struct obj *otmp;
665 otmp = invent;
666 while (otmp) {
667 if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id)
668 return otmp;
669 otmp = otmp->nobj;
671 return (struct obj *) 0;
674 boolean
675 next_to_u()
677 register struct monst *mtmp;
678 register struct obj *otmp;
680 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
681 if (DEADMONSTER(mtmp))
682 continue;
683 if (mtmp->mleashed) {
684 if (distu(mtmp->mx, mtmp->my) > 2)
685 mnexto(mtmp);
686 if (distu(mtmp->mx, mtmp->my) > 2) {
687 for (otmp = invent; otmp; otmp = otmp->nobj)
688 if (otmp->otyp == LEASH
689 && otmp->leashmon == (int) mtmp->m_id) {
690 if (otmp->cursed)
691 return FALSE;
692 You_feel("%s leash go slack.",
693 (number_leashed() > 1) ? "a" : "the");
694 mtmp->mleashed = 0;
695 otmp->leashmon = 0;
700 /* no pack mules for the Amulet */
701 if (u.usteed && mon_has_amulet(u.usteed))
702 return FALSE;
703 return TRUE;
706 void
707 check_leash(x, y)
708 register xchar x, y;
710 register struct obj *otmp;
711 register struct monst *mtmp;
713 for (otmp = invent; otmp; otmp = otmp->nobj) {
714 if (otmp->otyp != LEASH || otmp->leashmon == 0)
715 continue;
716 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
717 if (DEADMONSTER(mtmp))
718 continue;
719 if ((int) mtmp->m_id == otmp->leashmon)
720 break;
722 if (!mtmp) {
723 impossible("leash in use isn't attached to anything?");
724 otmp->leashmon = 0;
725 continue;
727 if (dist2(u.ux, u.uy, mtmp->mx, mtmp->my)
728 > dist2(x, y, mtmp->mx, mtmp->my)) {
729 if (!um_dist(mtmp->mx, mtmp->my, 3)) {
730 ; /* still close enough */
731 } else if (otmp->cursed && !breathless(mtmp->data)) {
732 if (um_dist(mtmp->mx, mtmp->my, 5)
733 || (mtmp->mhp -= rnd(2)) <= 0) {
734 long save_pacifism = u.uconduct.killer;
736 Your("leash chokes %s to death!", mon_nam(mtmp));
737 /* hero might not have intended to kill pet, but
738 that's the result of his actions; gain experience,
739 lose pacifism, take alignment and luck hit, make
740 corpse less likely to remain tame after revival */
741 xkilled(mtmp, XKILL_NOMSG);
742 /* life-saving doesn't ordinarily reset this */
743 if (mtmp->mhp > 0)
744 u.uconduct.killer = save_pacifism;
745 } else {
746 pline("%s is choked by the leash!", Monnam(mtmp));
747 /* tameness eventually drops to 1 here (never 0) */
748 if (mtmp->mtame && rn2(mtmp->mtame))
749 mtmp->mtame--;
751 } else {
752 if (um_dist(mtmp->mx, mtmp->my, 5)) {
753 pline("%s leash snaps loose!", s_suffix(Monnam(mtmp)));
754 m_unleash(mtmp, FALSE);
755 } else {
756 You("pull on the leash.");
757 if (mtmp->data->msound != MS_SILENT)
758 switch (rn2(3)) {
759 case 0:
760 growl(mtmp);
761 break;
762 case 1:
763 yelp(mtmp);
764 break;
765 default:
766 whimper(mtmp);
767 break;
775 const char *
776 beautiful()
778 return ((ACURR(A_CHA) > 14)
779 ? ((poly_gender() == 1)
780 ? "beautiful"
781 : "handsome")
782 : "ugly");
785 static const char look_str[] = "look %s.";
787 STATIC_OVL int
788 use_mirror(obj)
789 struct obj *obj;
791 const char *mirror, *uvisage;
792 struct monst *mtmp;
793 unsigned how_seen;
794 char mlet;
795 boolean vis, invis_mirror, useeit, monable;
797 if (!getdir((char *) 0))
798 return 0;
799 invis_mirror = Invis;
800 useeit = !Blind && (!invis_mirror || See_invisible);
801 uvisage = beautiful();
802 mirror = simpleonames(obj); /* "mirror" or "looking glass" */
803 if (obj->cursed && !rn2(2)) {
804 if (!Blind)
805 pline_The("%s fogs up and doesn't reflect!", mirror);
806 return 1;
808 if (!u.dx && !u.dy && !u.dz) {
809 if (!useeit) {
810 You_cant("see your %s %s.", uvisage, body_part(FACE));
811 } else {
812 if (u.umonnum == PM_FLOATING_EYE) {
813 if (Free_action) {
814 You("stiffen momentarily under your gaze.");
815 } else {
816 if (Hallucination)
817 pline("Yow! The %s stares back!", mirror);
818 else
819 pline("Yikes! You've frozen yourself!");
820 if (!Hallucination || !rn2(4)) {
821 nomul(-rnd(MAXULEV + 6 - u.ulevel));
822 multi_reason = "gazing into a mirror";
824 nomovemsg = 0; /* default, "you can move again" */
826 } else if (youmonst.data->mlet == S_VAMPIRE)
827 You("don't have a reflection.");
828 else if (u.umonnum == PM_UMBER_HULK) {
829 pline("Huh? That doesn't look like you!");
830 make_confused(HConfusion + d(3, 4), FALSE);
831 } else if (Hallucination)
832 You(look_str, hcolor((char *) 0));
833 else if (Sick)
834 You(look_str, "peaked");
835 else if (u.uhs >= WEAK)
836 You(look_str, "undernourished");
837 else
838 You("look as %s as ever.", uvisage);
840 return 1;
842 if (u.uswallow) {
843 if (useeit)
844 You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
845 mbodypart(u.ustuck, STOMACH));
846 return 1;
848 if (Underwater) {
849 if (useeit)
850 You(Hallucination ? "give the fish a chance to fix their makeup."
851 : "reflect the murky water.");
852 return 1;
854 if (u.dz) {
855 if (useeit)
856 You("reflect the %s.",
857 (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy));
858 return 1;
860 mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM,
861 (int FDECL((*), (MONST_P, OBJ_P))) 0,
862 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
863 if (!mtmp || !haseyes(mtmp->data) || notonhead)
864 return 1;
866 /* couldsee(mtmp->mx, mtmp->my) is implied by the fact that bhit()
867 targetted it, so we can ignore possibility of X-ray vision */
868 vis = canseemon(mtmp);
869 /* ways to directly see monster (excludes X-ray vision, telepathy,
870 extended detection, type-specific warning) */
871 #define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS)
872 how_seen = vis ? howmonseen(mtmp) : 0;
873 /* whether monster is able to use its vision-based capabilities */
874 monable = !mtmp->mcan && (!mtmp->minvis || perceives(mtmp->data));
875 mlet = mtmp->data->mlet;
876 if (mtmp->msleeping) {
877 if (vis)
878 pline("%s is too tired to look at your %s.", Monnam(mtmp),
879 mirror);
880 } else if (!mtmp->mcansee) {
881 if (vis)
882 pline("%s can't see anything right now.", Monnam(mtmp));
883 } else if (invis_mirror && !perceives(mtmp->data)) {
884 if (vis)
885 pline("%s fails to notice your %s.", Monnam(mtmp), mirror);
886 /* infravision doesn't produce an image in the mirror */
887 } else if ((how_seen & SEENMON) == MONSEEN_INFRAVIS) {
888 if (vis) /* (redundant) */
889 pline("%s is too far away to see %sself in the dark.",
890 Monnam(mtmp), mhim(mtmp));
891 /* some monsters do special things */
892 } else if (mlet == S_VAMPIRE || mlet == S_GHOST || is_vampshifter(mtmp)) {
893 if (vis)
894 pline("%s doesn't have a reflection.", Monnam(mtmp));
895 } else if (monable && mtmp->data == &mons[PM_MEDUSA]) {
896 if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
897 return 1;
898 if (vis)
899 pline("%s is turned to stone!", Monnam(mtmp));
900 stoned = TRUE;
901 killed(mtmp);
902 } else if (monable && mtmp->data == &mons[PM_FLOATING_EYE]) {
903 int tmp = d((int) mtmp->m_lev, (int) mtmp->data->mattk[0].damd);
904 if (!rn2(4))
905 tmp = 120;
906 if (vis)
907 pline("%s is frozen by its reflection.", Monnam(mtmp));
908 else
909 You_hear("%s stop moving.", something);
910 paralyze_monst(mtmp, (int) mtmp->mfrozen + tmp);
911 } else if (monable && mtmp->data == &mons[PM_UMBER_HULK]) {
912 if (vis)
913 pline("%s confuses itself!", Monnam(mtmp));
914 mtmp->mconf = 1;
915 } else if (monable && (mlet == S_NYMPH || mtmp->data == &mons[PM_SUCCUBUS]
916 || mtmp->data == &mons[PM_INCUBUS])) {
917 if (vis) {
918 char buf[BUFSZ]; /* "She" or "He" */
920 pline("%s admires %sself in your %s.", Monnam(mtmp), mhim(mtmp),
921 mirror);
922 pline("%s takes it!", upstart(strcpy(buf, mhe(mtmp))));
923 } else
924 pline("It steals your %s!", mirror);
925 setnotworn(obj); /* in case mirror was wielded */
926 freeinv(obj);
927 (void) mpickobj(mtmp, obj);
928 if (!tele_restrict(mtmp))
929 (void) rloc(mtmp, TRUE);
930 } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data)
931 && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
932 if (vis)
933 pline("%s is frightened by its reflection.", Monnam(mtmp));
934 monflee(mtmp, d(2, 4), FALSE, FALSE);
935 } else if (!Blind) {
936 if (mtmp->minvis && !See_invisible)
938 else if ((mtmp->minvis && !perceives(mtmp->data))
939 /* redundant: can't get here if these are true */
940 || !haseyes(mtmp->data) || notonhead || !mtmp->mcansee)
941 pline("%s doesn't seem to notice %s reflection.", Monnam(mtmp),
942 mhis(mtmp));
943 else
944 pline("%s ignores %s reflection.", Monnam(mtmp), mhis(mtmp));
946 return 1;
949 STATIC_OVL void
950 use_bell(optr)
951 struct obj **optr;
953 register struct obj *obj = *optr;
954 struct monst *mtmp;
955 boolean wakem = FALSE, learno = FALSE,
956 ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe),
957 invoking =
958 (obj->otyp == BELL_OF_OPENING && invocation_pos(u.ux, u.uy)
959 && !On_stairs(u.ux, u.uy));
961 You("ring %s.", the(xname(obj)));
963 if (Underwater || (u.uswallow && ordinary)) {
964 #ifdef AMIGA
965 amii_speaker(obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME);
966 #endif
967 pline("But the sound is muffled.");
969 } else if (invoking && ordinary) {
970 /* needs to be recharged... */
971 pline("But it makes no sound.");
972 learno = TRUE; /* help player figure out why */
974 } else if (ordinary) {
975 #ifdef AMIGA
976 amii_speaker(obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME);
977 #endif
978 if (obj->cursed && !rn2(4)
979 /* note: once any of them are gone, we stop all of them */
980 && !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE)
981 && !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE)
982 && !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE)
983 && (mtmp = makemon(mkclass(S_NYMPH, 0), u.ux, u.uy, NO_MINVENT))
984 != 0) {
985 You("summon %s!", a_monnam(mtmp));
986 if (!obj_resists(obj, 93, 100)) {
987 pline("%s shattered!", Tobjnam(obj, "have"));
988 useup(obj);
989 *optr = 0;
990 } else
991 switch (rn2(3)) {
992 default:
993 break;
994 case 1:
995 mon_adjust_speed(mtmp, 2, (struct obj *) 0);
996 break;
997 case 2: /* no explanation; it just happens... */
998 nomovemsg = "";
999 multi_reason = NULL;
1000 nomul(-rnd(2));
1001 break;
1004 wakem = TRUE;
1006 } else {
1007 /* charged Bell of Opening */
1008 consume_obj_charge(obj, TRUE);
1010 if (u.uswallow) {
1011 if (!obj->cursed)
1012 (void) openit();
1013 else
1014 pline1(nothing_happens);
1016 } else if (obj->cursed) {
1017 coord mm;
1019 mm.x = u.ux;
1020 mm.y = u.uy;
1021 mkundead(&mm, FALSE, NO_MINVENT);
1022 wakem = TRUE;
1024 } else if (invoking) {
1025 pline("%s an unsettling shrill sound...", Tobjnam(obj, "issue"));
1026 #ifdef AMIGA
1027 amii_speaker(obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME);
1028 #endif
1029 obj->age = moves;
1030 learno = TRUE;
1031 wakem = TRUE;
1033 } else if (obj->blessed) {
1034 int res = 0;
1036 #ifdef AMIGA
1037 amii_speaker(obj, "ahahahDhEhCw", AMII_SOFT_VOLUME);
1038 #endif
1039 if (uchain) {
1040 unpunish();
1041 res = 1;
1042 } else if (u.utrap && u.utraptype == TT_BURIEDBALL) {
1043 buried_ball_to_freedom();
1044 res = 1;
1046 res += openit();
1047 switch (res) {
1048 case 0:
1049 pline1(nothing_happens);
1050 break;
1051 case 1:
1052 pline("%s opens...", Something);
1053 learno = TRUE;
1054 break;
1055 default:
1056 pline("Things open around you...");
1057 learno = TRUE;
1058 break;
1061 } else { /* uncursed */
1062 #ifdef AMIGA
1063 amii_speaker(obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME);
1064 #endif
1065 if (findit() != 0)
1066 learno = TRUE;
1067 else
1068 pline1(nothing_happens);
1071 } /* charged BofO */
1073 if (learno) {
1074 makeknown(BELL_OF_OPENING);
1075 obj->known = 1;
1077 if (wakem)
1078 wake_nearby();
1081 STATIC_OVL void
1082 use_candelabrum(obj)
1083 register struct obj *obj;
1085 const char *s = (obj->spe != 1) ? "candles" : "candle";
1087 if (obj->lamplit) {
1088 You("snuff the %s.", s);
1089 end_burn(obj, TRUE);
1090 return;
1092 if (obj->spe <= 0) {
1093 pline("This %s has no %s.", xname(obj), s);
1094 return;
1096 if (Underwater) {
1097 You("cannot make fire under water.");
1098 return;
1100 if (u.uswallow || obj->cursed) {
1101 if (!Blind)
1102 pline_The("%s %s for a moment, then %s.", s, vtense(s, "flicker"),
1103 vtense(s, "die"));
1104 return;
1106 if (obj->spe < 7) {
1107 There("%s only %d %s in %s.", vtense(s, "are"), obj->spe, s,
1108 the(xname(obj)));
1109 if (!Blind)
1110 pline("%s lit. %s dimly.", obj->spe == 1 ? "It is" : "They are",
1111 Tobjnam(obj, "shine"));
1112 } else {
1113 pline("%s's %s burn%s", The(xname(obj)), s,
1114 (Blind ? "." : " brightly!"));
1116 if (!invocation_pos(u.ux, u.uy) || On_stairs(u.ux, u.uy)) {
1117 pline_The("%s %s being rapidly consumed!", s, vtense(s, "are"));
1118 /* this used to be obj->age /= 2, rounding down; an age of
1119 1 would yield 0, confusing begin_burn() and producing an
1120 unlightable, unrefillable candelabrum; round up instead */
1121 obj->age = (obj->age + 1L) / 2L;
1122 } else {
1123 if (obj->spe == 7) {
1124 if (Blind)
1125 pline("%s a strange warmth!", Tobjnam(obj, "radiate"));
1126 else
1127 pline("%s with a strange light!", Tobjnam(obj, "glow"));
1129 obj->known = 1;
1131 begin_burn(obj, FALSE);
1134 STATIC_OVL void
1135 use_candle(optr)
1136 struct obj **optr;
1138 register struct obj *obj = *optr;
1139 register struct obj *otmp;
1140 const char *s = (obj->quan != 1) ? "candles" : "candle";
1141 char qbuf[QBUFSZ], qsfx[QBUFSZ], *q;
1143 if (u.uswallow) {
1144 You(no_elbow_room);
1145 return;
1148 otmp = carrying(CANDELABRUM_OF_INVOCATION);
1149 if (!otmp || otmp->spe == 7) {
1150 use_lamp(obj);
1151 return;
1154 /* first, minimal candelabrum suffix for formatting candles */
1155 Sprintf(qsfx, " to\033%s?", thesimpleoname(otmp));
1156 /* next, format the candles as a prefix for the candelabrum */
1157 (void) safe_qbuf(qbuf, "Attach ", qsfx, obj, yname, thesimpleoname, s);
1158 /* strip temporary candelabrum suffix */
1159 if ((q = strstri(qbuf, " to\033")) != 0)
1160 Strcpy(q, " to ");
1161 /* last, format final "attach candles to candelabrum?" query */
1162 if (yn(safe_qbuf(qbuf, qbuf, "?", otmp, yname, thesimpleoname, "it"))
1163 == 'n') {
1164 use_lamp(obj);
1165 return;
1166 } else {
1167 if ((long) otmp->spe + obj->quan > 7L) {
1168 obj = splitobj(obj, 7L - (long) otmp->spe);
1169 /* avoid a grammatical error if obj->quan gets
1170 reduced to 1 candle from more than one */
1171 s = (obj->quan != 1) ? "candles" : "candle";
1172 } else
1173 *optr = 0;
1174 You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s,
1175 the(xname(otmp)));
1176 if (!otmp->spe || otmp->age > obj->age)
1177 otmp->age = obj->age;
1178 otmp->spe += (int) obj->quan;
1179 if (otmp->lamplit && !obj->lamplit)
1180 pline_The("new %s magically %s!", s, vtense(s, "ignite"));
1181 else if (!otmp->lamplit && obj->lamplit)
1182 pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
1183 if (obj->unpaid)
1184 verbalize("You %s %s, you bought %s!",
1185 otmp->lamplit ? "burn" : "use",
1186 (obj->quan > 1L) ? "them" : "it",
1187 (obj->quan > 1L) ? "them" : "it");
1188 if (obj->quan < 7L && otmp->spe == 7)
1189 pline("%s now has seven%s candles attached.", The(xname(otmp)),
1190 otmp->lamplit ? " lit" : "");
1191 /* candelabrum's light range might increase */
1192 if (otmp->lamplit)
1193 obj_merge_light_sources(otmp, otmp);
1194 /* candles are no longer a separate light source */
1195 if (obj->lamplit)
1196 end_burn(obj, TRUE);
1197 /* candles are now gone */
1198 useupall(obj);
1202 /* call in drop, throw, and put in box, etc. */
1203 boolean
1204 snuff_candle(otmp)
1205 struct obj *otmp;
1207 boolean candle = Is_candle(otmp);
1209 if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION)
1210 && otmp->lamplit) {
1211 char buf[BUFSZ];
1212 xchar x, y;
1213 boolean many = candle ? (otmp->quan > 1L) : (otmp->spe > 1);
1215 (void) get_obj_location(otmp, &x, &y, 0);
1216 if (otmp->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1217 pline("%s%scandle%s flame%s extinguished.", Shk_Your(buf, otmp),
1218 (candle ? "" : "candelabrum's "), (many ? "s'" : "'s"),
1219 (many ? "s are" : " is"));
1220 end_burn(otmp, TRUE);
1221 return TRUE;
1223 return FALSE;
1226 /* called when lit lamp is hit by water or put into a container or
1227 you've been swallowed by a monster; obj might be in transit while
1228 being thrown or dropped so don't assume that its location is valid */
1229 boolean
1230 snuff_lit(obj)
1231 struct obj *obj;
1233 xchar x, y;
1235 if (obj->lamplit) {
1236 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1237 || obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) {
1238 (void) get_obj_location(obj, &x, &y, 0);
1239 if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1240 pline("%s %s out!", Yname2(obj), otense(obj, "go"));
1241 end_burn(obj, TRUE);
1242 return TRUE;
1244 if (snuff_candle(obj))
1245 return TRUE;
1247 return FALSE;
1250 /* Called when potentially lightable object is affected by fire_damage().
1251 Return TRUE if object was lit and FALSE otherwise --ALI */
1252 boolean
1253 catch_lit(obj)
1254 struct obj *obj;
1256 xchar x, y;
1258 if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) {
1259 if ((obj->otyp == MAGIC_LAMP
1260 || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0)
1261 return FALSE;
1262 else if (obj->otyp != MAGIC_LAMP && obj->age == 0)
1263 return FALSE;
1264 if (!get_obj_location(obj, &x, &y, 0))
1265 return FALSE;
1266 if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed)
1267 return FALSE;
1268 if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1269 || obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2))
1270 return FALSE;
1271 if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
1272 pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
1273 if (obj->otyp == POT_OIL)
1274 makeknown(obj->otyp);
1275 if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) {
1276 /* if it catches while you have it, then it's your tough luck */
1277 check_unpaid(obj);
1278 verbalize("That's in addition to the cost of %s %s, of course.",
1279 yname(obj), obj->quan == 1L ? "itself" : "themselves");
1280 bill_dummy_object(obj);
1282 begin_burn(obj, FALSE);
1283 return TRUE;
1285 return FALSE;
1288 STATIC_OVL void
1289 use_lamp(obj)
1290 struct obj *obj;
1292 char buf[BUFSZ];
1294 if (obj->lamplit) {
1295 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1296 || obj->otyp == BRASS_LANTERN)
1297 pline("%slamp is now off.", Shk_Your(buf, obj));
1298 else
1299 You("snuff out %s.", yname(obj));
1300 end_burn(obj, TRUE);
1301 return;
1303 if (Underwater) {
1304 pline(!Is_candle(obj) ? "This is not a diving lamp"
1305 : "Sorry, fire and water don't mix.");
1306 return;
1308 /* magic lamps with an spe == 0 (wished for) cannot be lit */
1309 if ((!Is_candle(obj) && obj->age == 0)
1310 || (obj->otyp == MAGIC_LAMP && obj->spe == 0)) {
1311 if (obj->otyp == BRASS_LANTERN)
1312 Your("lamp has run out of power.");
1313 else
1314 pline("This %s has no oil.", xname(obj));
1315 return;
1317 if (obj->cursed && !rn2(2)) {
1318 if (!Blind)
1319 pline("%s for a moment, then %s.", Tobjnam(obj, "flicker"),
1320 otense(obj, "die"));
1321 } else {
1322 if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
1323 || obj->otyp == BRASS_LANTERN) {
1324 check_unpaid(obj);
1325 pline("%slamp is now on.", Shk_Your(buf, obj));
1326 } else { /* candle(s) */
1327 pline("%s flame%s %s%s", s_suffix(Yname2(obj)), plur(obj->quan),
1328 otense(obj, "burn"), Blind ? "." : " brightly!");
1329 if (obj->unpaid && costly_spot(u.ux, u.uy)
1330 && obj->age == 20L * (long) objects[obj->otyp].oc_cost) {
1331 const char *ithem = (obj->quan > 1L) ? "them" : "it";
1333 verbalize("You burn %s, you bought %s!", ithem, ithem);
1334 bill_dummy_object(obj);
1337 begin_burn(obj, FALSE);
1341 STATIC_OVL void
1342 light_cocktail(optr)
1343 struct obj **optr;
1345 struct obj *obj = *optr; /* obj is a potion of oil */
1346 char buf[BUFSZ];
1347 boolean split1off;
1349 if (u.uswallow) {
1350 You(no_elbow_room);
1351 return;
1354 if (obj->lamplit) {
1355 You("snuff the lit potion.");
1356 end_burn(obj, TRUE);
1358 * Free & add to re-merge potion. This will average the
1359 * age of the potions. Not exactly the best solution,
1360 * but its easy.
1362 freeinv(obj);
1363 *optr = addinv(obj);
1364 return;
1365 } else if (Underwater) {
1366 There("is not enough oxygen to sustain a fire.");
1367 return;
1370 split1off = (obj->quan > 1L);
1371 if (split1off)
1372 obj = splitobj(obj, 1L);
1374 You("light %spotion.%s", shk_your(buf, obj),
1375 Blind ? "" : " It gives off a dim light.");
1377 if (obj->unpaid && costly_spot(u.ux, u.uy)) {
1378 /* Normally, we shouldn't both partially and fully charge
1379 * for an item, but (Yendorian Fuel) Taxes are inevitable...
1381 check_unpaid(obj);
1382 verbalize("That's in addition to the cost of the potion, of course.");
1383 bill_dummy_object(obj);
1385 makeknown(obj->otyp);
1387 begin_burn(obj, FALSE); /* after shop billing */
1388 if (split1off) {
1389 obj_extract_self(obj); /* free from inv */
1390 obj->nomerge = 1;
1391 obj = hold_another_object(obj, "You drop %s!", doname(obj),
1392 (const char *) 0);
1393 if (obj)
1394 obj->nomerge = 0;
1396 *optr = obj;
1399 static NEARDATA const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 };
1402 dorub()
1404 struct obj *obj = getobj(cuddly, "rub");
1406 if (obj && obj->oclass == GEM_CLASS) {
1407 if (is_graystone(obj)) {
1408 use_stone(obj);
1409 return 1;
1410 } else {
1411 pline("Sorry, I don't know how to use that.");
1412 return 0;
1416 if (!obj || !wield_tool(obj, "rub"))
1417 return 0;
1419 /* now uwep is obj */
1420 if (uwep->otyp == MAGIC_LAMP) {
1421 if (uwep->spe > 0 && !rn2(3)) {
1422 check_unpaid_usage(uwep, TRUE); /* unusual item use */
1423 /* bones preparation: perform the lamp transformation
1424 before releasing the djinni in case the latter turns out
1425 to be fatal (a hostile djinni has no chance to attack yet,
1426 but an indebted one who grants a wish might bestow an
1427 artifact which blasts the hero with lethal results) */
1428 uwep->otyp = OIL_LAMP;
1429 uwep->spe = 0; /* for safety */
1430 uwep->age = rn1(500, 1000);
1431 if (uwep->lamplit)
1432 begin_burn(uwep, TRUE);
1433 djinni_from_bottle(uwep);
1434 makeknown(MAGIC_LAMP);
1435 update_inventory();
1436 } else if (rn2(2)) {
1437 You("%s smoke.", !Blind ? "see a puff of" : "smell");
1438 } else
1439 pline1(nothing_happens);
1440 } else if (obj->otyp == BRASS_LANTERN) {
1441 /* message from Adventure */
1442 pline("Rubbing the electric lamp is not particularly rewarding.");
1443 pline("Anyway, nothing exciting happens.");
1444 } else
1445 pline1(nothing_happens);
1446 return 1;
1450 dojump()
1452 /* Physical jump */
1453 return jump(0);
1456 enum jump_trajectory {
1457 jAny = 0, /* any direction => magical jump */
1458 jHorz = 1,
1459 jVert = 2,
1460 jDiag = 3 /* jHorz|jVert */
1463 /* callback routine for walk_path() */
1464 STATIC_PTR boolean
1465 check_jump(arg, x, y)
1466 genericptr arg;
1467 int x, y;
1469 int traj = *(int *) arg;
1470 struct rm *lev = &levl[x][y];
1472 if (Passes_walls)
1473 return TRUE;
1474 if (IS_STWALL(lev->typ))
1475 return FALSE;
1476 if (IS_DOOR(lev->typ)) {
1477 if (closed_door(x, y))
1478 return FALSE;
1479 if ((lev->doormask & D_ISOPEN) != 0 && traj != jAny
1480 /* reject diagonal jump into or out-of or through open door */
1481 && (traj == jDiag
1482 /* reject horizontal jump through horizontal open door
1483 and non-horizontal (ie, vertical) jump through
1484 non-horizontal (vertical) open door */
1485 || ((traj & jHorz) != 0) == (lev->horizontal != 0)))
1486 return FALSE;
1487 /* empty doorways aren't restricted */
1489 /* let giants jump over boulders (what about Flying?
1490 and is there really enough head room for giants to jump
1491 at all, let alone over something tall?) */
1492 if (sobj_at(BOULDER, x, y) && !throws_rocks(youmonst.data))
1493 return FALSE;
1494 return TRUE;
1497 STATIC_OVL boolean
1498 is_valid_jump_pos(x, y, magic, showmsg)
1499 int x, y, magic;
1500 boolean showmsg;
1502 if (!magic && !(HJumping & ~INTRINSIC) && !EJumping && distu(x, y) != 5) {
1503 /* The Knight jumping restriction still applies when riding a
1504 * horse. After all, what shape is the knight piece in chess?
1506 if (showmsg)
1507 pline("Illegal move!");
1508 return FALSE;
1509 } else if (distu(x, y) > (magic ? 6 + magic * 3 : 9)) {
1510 if (showmsg)
1511 pline("Too far!");
1512 return FALSE;
1513 } else if (!isok(x, y)) {
1514 if (showmsg)
1515 You("cannot jump there!");
1516 return FALSE;
1517 } else if (!cansee(x, y)) {
1518 if (showmsg)
1519 You("cannot see where to land!");
1520 return FALSE;
1521 } else {
1522 coord uc, tc;
1523 struct rm *lev = &levl[u.ux][u.uy];
1524 /* we want to categorize trajectory for use in determining
1525 passage through doorways: horizonal, vertical, or diagonal;
1526 since knight's jump and other irregular directions are
1527 possible, we flatten those out to simplify door checks */
1528 int diag, traj,
1529 dx = x - u.ux, dy = y - u.uy,
1530 ax = abs(dx), ay = abs(dy);
1532 /* diag: any non-orthogonal destination classifed as diagonal */
1533 diag = (magic || Passes_walls || (!dx && !dy)) ? jAny
1534 : !dy ? jHorz : !dx ? jVert : jDiag;
1535 /* traj: flatten out the trajectory => some diagonals re-classified */
1536 if (ax >= 2 * ay)
1537 ay = 0;
1538 else if (ay >= 2 * ax)
1539 ax = 0;
1540 traj = (magic || Passes_walls || (!ax && !ay)) ? jAny
1541 : !ay ? jHorz : !ax ? jVert : jDiag;
1542 /* walk_path doesn't process the starting spot;
1543 this is iffy: if you're starting on a closed door spot,
1544 you _can_ jump diagonally from doorway (without needing
1545 Passes_walls); that's intentional but is it correct? */
1546 if (diag == jDiag && IS_DOOR(lev->typ)
1547 && (lev->doormask & D_ISOPEN) != 0
1548 && (traj == jDiag
1549 || ((traj & jHorz) != 0) == (lev->horizontal != 0))) {
1550 if (showmsg)
1551 You_cant("jump diagonally out of a doorway.");
1552 return FALSE;
1554 uc.x = u.ux, uc.y = u.uy;
1555 tc.x = x, tc.y = y; /* target */
1556 if (!walk_path(&uc, &tc, check_jump, (genericptr_t) &traj)) {
1557 if (showmsg)
1558 There("is an obstacle preventing that jump.");
1559 return FALSE;
1562 return TRUE;
1565 static int jumping_is_magic;
1567 void
1568 display_jump_positions(state)
1569 int state;
1571 if (state == 0) {
1572 tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
1573 } else if (state == 1) {
1574 int x, y, dx, dy;
1576 for (dx = -4; dx <= 4; dx++)
1577 for (dy = -4; dy <= 4; dy++) {
1578 x = dx + (int) u.ux;
1579 y = dy + (int) u.uy;
1580 if (isok(x, y)
1581 && (ACCESSIBLE(levl[x][y].typ) || Passes_walls)
1582 && is_valid_jump_pos(x, y, jumping_is_magic, FALSE))
1583 tmp_at(x, y);
1585 } else {
1586 tmp_at(DISP_END, 0);
1591 jump(magic)
1592 int magic; /* 0=Physical, otherwise skill level */
1594 coord cc;
1596 /* attempt "jumping" spell if hero has no innate jumping ability */
1597 if (!magic && !Jumping) {
1598 int sp_no;
1600 for (sp_no = 0; sp_no < MAXSPELL; ++sp_no)
1601 if (spl_book[sp_no].sp_id == NO_SPELL)
1602 break;
1603 else if (spl_book[sp_no].sp_id == SPE_JUMPING)
1604 return spelleffects(sp_no, FALSE);
1607 if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) {
1608 /* normally (nolimbs || slithy) implies !Jumping,
1609 but that isn't necessarily the case for knights */
1610 You_cant("jump; you have no legs!");
1611 return 0;
1612 } else if (!magic && !Jumping) {
1613 You_cant("jump very far.");
1614 return 0;
1615 /* if steed is immobile, can't do physical jump but can do spell one */
1616 } else if (!magic && u.usteed && stucksteed(FALSE)) {
1617 /* stucksteed gave "<steed> won't move" message */
1618 return 0;
1619 } else if (u.uswallow) {
1620 if (magic) {
1621 You("bounce around a little.");
1622 return 1;
1624 pline("You've got to be kidding!");
1625 return 0;
1626 } else if (u.uinwater) {
1627 if (magic) {
1628 You("swish around a little.");
1629 return 1;
1631 pline("This calls for swimming, not jumping!");
1632 return 0;
1633 } else if (u.ustuck) {
1634 if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) {
1635 You("pull free from %s.", mon_nam(u.ustuck));
1636 u.ustuck = 0;
1637 return 1;
1639 if (magic) {
1640 You("writhe a little in the grasp of %s!", mon_nam(u.ustuck));
1641 return 1;
1643 You("cannot escape from %s!", mon_nam(u.ustuck));
1644 return 0;
1645 } else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
1646 if (magic) {
1647 You("flail around a little.");
1648 return 1;
1650 You("don't have enough traction to jump.");
1651 return 0;
1652 } else if (!magic && near_capacity() > UNENCUMBERED) {
1653 You("are carrying too much to jump!");
1654 return 0;
1655 } else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) {
1656 You("lack the strength to jump!");
1657 return 0;
1658 } else if (!magic && Wounded_legs) {
1659 long wl = (Wounded_legs & BOTH_SIDES);
1660 const char *bp = body_part(LEG);
1662 if (wl == BOTH_SIDES)
1663 bp = makeplural(bp);
1664 if (u.usteed)
1665 pline("%s is in no shape for jumping.", Monnam(u.usteed));
1666 else
1667 Your("%s%s %s in no shape for jumping.",
1668 (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right "
1669 : "",
1670 bp, (wl == BOTH_SIDES) ? "are" : "is");
1671 return 0;
1672 } else if (u.usteed && u.utrap) {
1673 pline("%s is stuck in a trap.", Monnam(u.usteed));
1674 return 0;
1677 pline("Where do you want to jump?");
1678 cc.x = u.ux;
1679 cc.y = u.uy;
1680 jumping_is_magic = magic;
1681 getpos_sethilite(display_jump_positions);
1682 if (getpos(&cc, TRUE, "the desired position") < 0)
1683 return 0; /* user pressed ESC */
1684 if (!is_valid_jump_pos(cc.x, cc.y, magic, TRUE)) {
1685 return 0;
1686 } else {
1687 coord uc;
1688 int range, temp;
1690 if (u.utrap)
1691 switch (u.utraptype) {
1692 case TT_BEARTRAP: {
1693 long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
1695 You("rip yourself free of the bear trap! Ouch!");
1696 losehp(Maybe_Half_Phys(rnd(10)), "jumping out of a bear trap",
1697 KILLED_BY);
1698 set_wounded_legs(side, rn1(1000, 500));
1699 break;
1701 case TT_PIT:
1702 You("leap from the pit!");
1703 break;
1704 case TT_WEB:
1705 You("tear the web apart as you pull yourself free!");
1706 deltrap(t_at(u.ux, u.uy));
1707 break;
1708 case TT_LAVA:
1709 You("pull yourself above the %s!", hliquid("lava"));
1710 u.utrap = 0;
1711 return 1;
1712 case TT_BURIEDBALL:
1713 case TT_INFLOOR:
1714 You("strain your %s, but you're still %s.",
1715 makeplural(body_part(LEG)),
1716 (u.utraptype == TT_INFLOOR)
1717 ? "stuck in the floor"
1718 : "attached to the buried ball");
1719 set_wounded_legs(LEFT_SIDE, rn1(10, 11));
1720 set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
1721 return 1;
1725 * Check the path from uc to cc, calling hurtle_step at each
1726 * location. The final position actually reached will be
1727 * in cc.
1729 uc.x = u.ux;
1730 uc.y = u.uy;
1731 /* calculate max(abs(dx), abs(dy)) as the range */
1732 range = cc.x - uc.x;
1733 if (range < 0)
1734 range = -range;
1735 temp = cc.y - uc.y;
1736 if (temp < 0)
1737 temp = -temp;
1738 if (range < temp)
1739 range = temp;
1740 (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range);
1741 /* hurtle_step results in (u.ux, u.uy) == (cc.x, cc.y) and usually
1742 * moves the ball if punished, but does not handle all the effects
1743 * of landing on the final position.
1745 teleds(cc.x, cc.y, FALSE);
1746 sokoban_guilt();
1747 nomul(-1);
1748 multi_reason = "jumping around";
1749 nomovemsg = "";
1750 morehungry(rnd(25));
1751 return 1;
1755 boolean
1756 tinnable(corpse)
1757 struct obj *corpse;
1759 if (corpse->oeaten)
1760 return 0;
1761 if (!mons[corpse->corpsenm].cnutrit)
1762 return 0;
1763 return 1;
1766 STATIC_OVL void
1767 use_tinning_kit(obj)
1768 struct obj *obj;
1770 struct obj *corpse, *can;
1772 /* This takes only 1 move. If this is to be changed to take many
1773 * moves, we've got to deal with decaying corpses...
1775 if (obj->spe <= 0) {
1776 You("seem to be out of tins.");
1777 return;
1779 if (!(corpse = floorfood("tin", 2)))
1780 return;
1781 if (corpse->oeaten) {
1782 You("cannot tin %s which is partly eaten.", something);
1783 return;
1785 if (touch_petrifies(&mons[corpse->corpsenm]) && !Stone_resistance
1786 && !uarmg) {
1787 char kbuf[BUFSZ];
1789 if (poly_when_stoned(youmonst.data))
1790 You("tin %s without wearing gloves.",
1791 an(mons[corpse->corpsenm].mname));
1792 else {
1793 pline("Tinning %s without wearing gloves is a fatal mistake...",
1794 an(mons[corpse->corpsenm].mname));
1795 Sprintf(kbuf, "trying to tin %s without gloves",
1796 an(mons[corpse->corpsenm].mname));
1798 instapetrify(kbuf);
1800 if (is_rider(&mons[corpse->corpsenm])) {
1801 if (revive_corpse(corpse))
1802 verbalize("Yes... But War does not preserve its enemies...");
1803 else
1804 pline_The("corpse evades your grasp.");
1805 return;
1807 if (mons[corpse->corpsenm].cnutrit == 0) {
1808 pline("That's too insubstantial to tin.");
1809 return;
1811 consume_obj_charge(obj, TRUE);
1813 if ((can = mksobj(TIN, FALSE, FALSE)) != 0) {
1814 static const char you_buy_it[] = "You tin it, you bought it!";
1816 can->corpsenm = corpse->corpsenm;
1817 can->cursed = obj->cursed;
1818 can->blessed = obj->blessed;
1819 can->owt = weight(can);
1820 can->known = 1;
1821 /* Mark tinned tins. No spinach allowed... */
1822 set_tin_variety(can, HOMEMADE_TIN);
1823 if (carried(corpse)) {
1824 if (corpse->unpaid)
1825 verbalize(you_buy_it);
1826 useup(corpse);
1827 } else {
1828 if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
1829 verbalize(you_buy_it);
1830 useupf(corpse, 1L);
1832 can = hold_another_object(can, "You make, but cannot pick up, %s.",
1833 doname(can), (const char *) 0);
1834 } else
1835 impossible("Tinning failed.");
1838 void
1839 use_unicorn_horn(obj)
1840 struct obj *obj;
1842 #define PROP_COUNT 7 /* number of properties we're dealing with */
1843 #define ATTR_COUNT (A_MAX * 3) /* number of attribute points we might fix */
1844 int idx, val, val_limit, trouble_count, unfixable_trbl, did_prop,
1845 did_attr;
1846 int trouble_list[PROP_COUNT + ATTR_COUNT];
1848 if (obj && obj->cursed) {
1849 long lcount = (long) rn1(90, 10);
1851 switch (rn2(13) / 2) { /* case 6 is half as likely as the others */
1852 case 0:
1853 make_sick((Sick & TIMEOUT) ? (Sick & TIMEOUT) / 3L + 1L
1854 : (long) rn1(ACURR(A_CON), 20),
1855 xname(obj), TRUE, SICK_NONVOMITABLE);
1856 break;
1857 case 1:
1858 make_blinded((Blinded & TIMEOUT) + lcount, TRUE);
1859 break;
1860 case 2:
1861 if (!Confusion)
1862 You("suddenly feel %s.",
1863 Hallucination ? "trippy" : "confused");
1864 make_confused((HConfusion & TIMEOUT) + lcount, TRUE);
1865 break;
1866 case 3:
1867 make_stunned((HStun & TIMEOUT) + lcount, TRUE);
1868 break;
1869 case 4:
1870 (void) adjattrib(rn2(A_MAX), -1, FALSE);
1871 break;
1872 case 5:
1873 (void) make_hallucinated((HHallucination & TIMEOUT) + lcount,
1874 TRUE, 0L);
1875 break;
1876 case 6:
1877 if (Deaf) /* make_deaf() won't give feedback when already deaf */
1878 pline("Nothing seems to happen.");
1879 make_deaf((HDeaf & TIMEOUT) + lcount, TRUE);
1880 context.botl = TRUE;
1881 break;
1883 return;
1887 * Entries in the trouble list use a very simple encoding scheme.
1889 #define prop2trbl(X) ((X) + A_MAX)
1890 #define attr2trbl(Y) (Y)
1891 #define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X)
1892 #define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y)
1893 #define TimedTrouble(P) (((P) && !((P) & ~TIMEOUT)) ? ((P) & TIMEOUT) : 0L)
1895 trouble_count = unfixable_trbl = did_prop = did_attr = 0;
1897 /* collect property troubles */
1898 if (TimedTrouble(Sick))
1899 prop_trouble(SICK);
1900 if (TimedTrouble(Blinded) > (long) u.ucreamed
1901 && !(u.uswallow
1902 && attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND)))
1903 prop_trouble(BLINDED);
1904 if (TimedTrouble(HHallucination))
1905 prop_trouble(HALLUC);
1906 if (TimedTrouble(Vomiting))
1907 prop_trouble(VOMITING);
1908 if (TimedTrouble(HConfusion))
1909 prop_trouble(CONFUSION);
1910 if (TimedTrouble(HStun))
1911 prop_trouble(STUNNED);
1912 if (TimedTrouble(HDeaf))
1913 prop_trouble(DEAF);
1915 unfixable_trbl = unfixable_trouble_count(TRUE);
1917 /* collect attribute troubles */
1918 for (idx = 0; idx < A_MAX; idx++) {
1919 if (ABASE(idx) >= AMAX(idx))
1920 continue;
1921 val_limit = AMAX(idx);
1922 /* don't recover strength lost from hunger */
1923 if (idx == A_STR && u.uhs >= WEAK)
1924 val_limit--;
1925 if (Fixed_abil) {
1926 /* potion/spell of restore ability override sustain ability
1927 intrinsic but unicorn horn usage doesn't */
1928 unfixable_trbl += val_limit - ABASE(idx);
1929 continue;
1931 /* don't recover more than 3 points worth of any attribute */
1932 if (val_limit > ABASE(idx) + 3)
1933 val_limit = ABASE(idx) + 3;
1935 for (val = ABASE(idx); val < val_limit; val++)
1936 attr_trouble(idx);
1937 /* keep track of unfixed trouble, for message adjustment below */
1938 unfixable_trbl += (AMAX(idx) - val_limit);
1941 if (trouble_count == 0) {
1942 pline1(nothing_happens);
1943 return;
1944 } else if (trouble_count > 1) { /* shuffle */
1945 int i, j, k;
1947 for (i = trouble_count - 1; i > 0; i--)
1948 if ((j = rn2(i + 1)) != i) {
1949 k = trouble_list[j];
1950 trouble_list[j] = trouble_list[i];
1951 trouble_list[i] = k;
1956 * Chances for number of troubles to be fixed
1957 * 0 1 2 3 4 5 6 7
1958 * blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8%
1959 * uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0
1961 val_limit = rn2(d(2, (obj && obj->blessed) ? 4 : 2));
1962 if (val_limit > trouble_count)
1963 val_limit = trouble_count;
1965 /* fix [some of] the troubles */
1966 for (val = 0; val < val_limit; val++) {
1967 idx = trouble_list[val];
1969 switch (idx) {
1970 case prop2trbl(SICK):
1971 make_sick(0L, (char *) 0, TRUE, SICK_ALL);
1972 did_prop++;
1973 break;
1974 case prop2trbl(BLINDED):
1975 make_blinded((long) u.ucreamed, TRUE);
1976 did_prop++;
1977 break;
1978 case prop2trbl(HALLUC):
1979 (void) make_hallucinated(0L, TRUE, 0L);
1980 did_prop++;
1981 break;
1982 case prop2trbl(VOMITING):
1983 make_vomiting(0L, TRUE);
1984 did_prop++;
1985 break;
1986 case prop2trbl(CONFUSION):
1987 make_confused(0L, TRUE);
1988 did_prop++;
1989 break;
1990 case prop2trbl(STUNNED):
1991 make_stunned(0L, TRUE);
1992 did_prop++;
1993 break;
1994 case prop2trbl(DEAF):
1995 make_deaf(0L, TRUE);
1996 did_prop++;
1997 break;
1998 default:
1999 if (idx >= 0 && idx < A_MAX) {
2000 ABASE(idx) += 1;
2001 did_attr++;
2002 } else
2003 panic("use_unicorn_horn: bad trouble? (%d)", idx);
2004 break;
2008 if (did_attr)
2009 pline("This makes you feel %s!",
2010 (did_prop + did_attr) == (trouble_count + unfixable_trbl)
2011 ? "great"
2012 : "better");
2013 else if (!did_prop)
2014 pline("Nothing seems to happen.");
2016 context.botl = (did_attr || did_prop);
2017 #undef PROP_COUNT
2018 #undef ATTR_COUNT
2019 #undef prop2trbl
2020 #undef attr2trbl
2021 #undef prop_trouble
2022 #undef attr_trouble
2023 #undef TimedTrouble
2027 * Timer callback routine: turn figurine into monster
2029 void
2030 fig_transform(arg, timeout)
2031 anything *arg;
2032 long timeout;
2034 struct obj *figurine = arg->a_obj;
2035 struct monst *mtmp;
2036 coord cc;
2037 boolean cansee_spot, silent, okay_spot;
2038 boolean redraw = FALSE;
2039 boolean suppress_see = FALSE;
2040 char monnambuf[BUFSZ], carriedby[BUFSZ];
2042 if (!figurine) {
2043 debugpline0("null figurine in fig_transform()");
2044 return;
2046 silent = (timeout != monstermoves); /* happened while away */
2047 okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0);
2048 if (figurine->where == OBJ_INVENT || figurine->where == OBJ_MINVENT)
2049 okay_spot = enexto(&cc, cc.x, cc.y, &mons[figurine->corpsenm]);
2050 if (!okay_spot || !figurine_location_checks(figurine, &cc, TRUE)) {
2051 /* reset the timer to try again later */
2052 (void) start_timer((long) rnd(5000), TIMER_OBJECT, FIG_TRANSFORM,
2053 obj_to_any(figurine));
2054 return;
2057 cansee_spot = cansee(cc.x, cc.y);
2058 mtmp = make_familiar(figurine, cc.x, cc.y, TRUE);
2059 if (mtmp) {
2060 char and_vanish[BUFSZ];
2061 struct obj *mshelter = level.objects[mtmp->mx][mtmp->my];
2063 Sprintf(monnambuf, "%s", an(m_monnam(mtmp)));
2064 and_vanish[0] = '\0';
2065 if ((mtmp->minvis && !See_invisible)
2066 || (mtmp->data->mlet == S_MIMIC
2067 && mtmp->m_ap_type != M_AP_NOTHING))
2068 suppress_see = TRUE;
2070 if (mtmp->mundetected) {
2071 if (hides_under(mtmp->data) && mshelter) {
2072 Sprintf(and_vanish, " and %s under %s",
2073 locomotion(mtmp->data, "crawl"), doname(mshelter));
2074 } else if (mtmp->data->mlet == S_MIMIC
2075 || mtmp->data->mlet == S_EEL) {
2076 suppress_see = TRUE;
2077 } else
2078 Strcpy(and_vanish, " and vanish");
2081 switch (figurine->where) {
2082 case OBJ_INVENT:
2083 if (Blind || suppress_see)
2084 You_feel("%s %s from your pack!", something,
2085 locomotion(mtmp->data, "drop"));
2086 else
2087 You_see("%s %s out of your pack%s!", monnambuf,
2088 locomotion(mtmp->data, "drop"), and_vanish);
2089 break;
2091 case OBJ_FLOOR:
2092 if (cansee_spot && !silent) {
2093 if (suppress_see)
2094 pline("%s suddenly vanishes!", an(xname(figurine)));
2095 else
2096 You_see("a figurine transform into %s%s!", monnambuf,
2097 and_vanish);
2098 redraw = TRUE; /* update figurine's map location */
2100 break;
2102 case OBJ_MINVENT:
2103 if (cansee_spot && !silent && !suppress_see) {
2104 struct monst *mon;
2106 mon = figurine->ocarry;
2107 /* figurine carrying monster might be invisible */
2108 if (canseemon(figurine->ocarry)
2109 && (!mon->wormno || cansee(mon->mx, mon->my)))
2110 Sprintf(carriedby, "%s pack", s_suffix(a_monnam(mon)));
2111 else if (is_pool(mon->mx, mon->my))
2112 Strcpy(carriedby, "empty water");
2113 else
2114 Strcpy(carriedby, "thin air");
2115 You_see("%s %s out of %s%s!", monnambuf,
2116 locomotion(mtmp->data, "drop"), carriedby,
2117 and_vanish);
2119 break;
2120 #if 0
2121 case OBJ_MIGRATING:
2122 break;
2123 #endif
2125 default:
2126 impossible("figurine came to life where? (%d)",
2127 (int) figurine->where);
2128 break;
2131 /* free figurine now */
2132 if (carried(figurine)) {
2133 useup(figurine);
2134 } else {
2135 obj_extract_self(figurine);
2136 obfree(figurine, (struct obj *) 0);
2138 if (redraw)
2139 newsym(cc.x, cc.y);
2142 STATIC_OVL boolean
2143 figurine_location_checks(obj, cc, quietly)
2144 struct obj *obj;
2145 coord *cc;
2146 boolean quietly;
2148 xchar x, y;
2150 if (carried(obj) && u.uswallow) {
2151 if (!quietly)
2152 You("don't have enough room in here.");
2153 return FALSE;
2155 x = cc ? cc->x : u.ux;
2156 y = cc ? cc->y : u.uy;
2157 if (!isok(x, y)) {
2158 if (!quietly)
2159 You("cannot put the figurine there.");
2160 return FALSE;
2162 if (IS_ROCK(levl[x][y].typ)
2163 && !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x, y))) {
2164 if (!quietly)
2165 You("cannot place a figurine in %s!",
2166 IS_TREE(levl[x][y].typ) ? "a tree" : "solid rock");
2167 return FALSE;
2169 if (sobj_at(BOULDER, x, y) && !passes_walls(&mons[obj->corpsenm])
2170 && !throws_rocks(&mons[obj->corpsenm])) {
2171 if (!quietly)
2172 You("cannot fit the figurine on the boulder.");
2173 return FALSE;
2175 return TRUE;
2178 STATIC_OVL void
2179 use_figurine(optr)
2180 struct obj **optr;
2182 register struct obj *obj = *optr;
2183 xchar x, y;
2184 coord cc;
2186 if (u.uswallow) {
2187 /* can't activate a figurine while swallowed */
2188 if (!figurine_location_checks(obj, (coord *) 0, FALSE))
2189 return;
2191 if (!getdir((char *) 0)) {
2192 context.move = multi = 0;
2193 return;
2195 x = u.ux + u.dx;
2196 y = u.uy + u.dy;
2197 cc.x = x;
2198 cc.y = y;
2199 /* Passing FALSE arg here will result in messages displayed */
2200 if (!figurine_location_checks(obj, &cc, FALSE))
2201 return;
2202 You("%s and it transforms.",
2203 (u.dx || u.dy) ? "set the figurine beside you"
2204 : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
2205 || is_pool(cc.x, cc.y))
2206 ? "release the figurine"
2207 : (u.dz < 0 ? "toss the figurine into the air"
2208 : "set the figurine on the ground"));
2209 (void) make_familiar(obj, cc.x, cc.y, FALSE);
2210 (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
2211 useup(obj);
2212 *optr = 0;
2215 static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 };
2217 STATIC_OVL void
2218 use_grease(obj)
2219 struct obj *obj;
2221 struct obj *otmp;
2223 if (Glib) {
2224 pline("%s from your %s.", Tobjnam(obj, "slip"),
2225 makeplural(body_part(FINGER)));
2226 dropx(obj);
2227 return;
2230 if (obj->spe > 0) {
2231 if ((obj->cursed || Fumbling) && !rn2(2)) {
2232 consume_obj_charge(obj, TRUE);
2234 pline("%s from your %s.", Tobjnam(obj, "slip"),
2235 makeplural(body_part(FINGER)));
2236 dropx(obj);
2237 return;
2239 otmp = getobj(lubricables, "grease");
2240 if (!otmp)
2241 return;
2242 if (inaccessible_equipment(otmp, "grease", FALSE))
2243 return;
2244 consume_obj_charge(obj, TRUE);
2246 if (otmp != &zeroobj) {
2247 You("cover %s with a thick layer of grease.", yname(otmp));
2248 otmp->greased = 1;
2249 if (obj->cursed && !nohands(youmonst.data)) {
2250 incr_itimeout(&Glib, rnd(15));
2251 pline("Some of the grease gets all over your %s.",
2252 makeplural(body_part(HAND)));
2254 } else {
2255 incr_itimeout(&Glib, rnd(15));
2256 You("coat your %s with grease.", makeplural(body_part(FINGER)));
2258 } else {
2259 if (obj->known)
2260 pline("%s empty.", Tobjnam(obj, "are"));
2261 else
2262 pline("%s to be empty.", Tobjnam(obj, "seem"));
2264 update_inventory();
2267 /* touchstones - by Ken Arnold */
2268 STATIC_OVL void
2269 use_stone(tstone)
2270 struct obj *tstone;
2272 struct obj *obj;
2273 boolean do_scratch;
2274 const char *streak_color, *choices;
2275 char stonebuf[QBUFSZ];
2276 static const char scritch[] = "\"scritch, scritch\"";
2277 static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 };
2278 static const char coins_gems[3] = { COIN_CLASS, GEM_CLASS, 0 };
2280 /* in case it was acquired while blinded */
2281 if (!Blind)
2282 tstone->dknown = 1;
2283 /* when the touchstone is fully known, don't bother listing extra
2284 junk as likely candidates for rubbing */
2285 choices = (tstone->otyp == TOUCHSTONE && tstone->dknown
2286 && objects[TOUCHSTONE].oc_name_known)
2287 ? coins_gems
2288 : allowall;
2289 Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan));
2290 if ((obj = getobj(choices, stonebuf)) == 0)
2291 return;
2293 if (obj == tstone && obj->quan == 1L) {
2294 You_cant("rub %s on itself.", the(xname(obj)));
2295 return;
2298 if (tstone->otyp == TOUCHSTONE && tstone->cursed
2299 && obj->oclass == GEM_CLASS && !is_graystone(obj)
2300 && !obj_resists(obj, 80, 100)) {
2301 if (Blind)
2302 pline("You feel something shatter.");
2303 else if (Hallucination)
2304 pline("Oh, wow, look at the pretty shards.");
2305 else
2306 pline("A sharp crack shatters %s%s.",
2307 (obj->quan > 1L) ? "one of " : "", the(xname(obj)));
2308 useup(obj);
2309 return;
2312 if (Blind) {
2313 pline(scritch);
2314 return;
2315 } else if (Hallucination) {
2316 pline("Oh wow, man: Fractals!");
2317 return;
2320 do_scratch = FALSE;
2321 streak_color = 0;
2323 switch (obj->oclass) {
2324 case GEM_CLASS: /* these have class-specific handling below */
2325 case RING_CLASS:
2326 if (tstone->otyp != TOUCHSTONE) {
2327 do_scratch = TRUE;
2328 } else if (obj->oclass == GEM_CLASS
2329 && (tstone->blessed
2330 || (!tstone->cursed && (Role_if(PM_ARCHEOLOGIST)
2331 || Race_if(PM_GNOME))))) {
2332 makeknown(TOUCHSTONE);
2333 makeknown(obj->otyp);
2334 prinv((char *) 0, obj, 0L);
2335 return;
2336 } else {
2337 /* either a ring or the touchstone was not effective */
2338 if (objects[obj->otyp].oc_material == GLASS) {
2339 do_scratch = TRUE;
2340 break;
2343 streak_color = c_obj_colors[objects[obj->otyp].oc_color];
2344 break; /* gem or ring */
2346 default:
2347 switch (objects[obj->otyp].oc_material) {
2348 case CLOTH:
2349 pline("%s a little more polished now.", Tobjnam(tstone, "look"));
2350 return;
2351 case LIQUID:
2352 if (!obj->known) /* note: not "whetstone" */
2353 You("must think this is a wetstone, do you?");
2354 else
2355 pline("%s a little wetter now.", Tobjnam(tstone, "are"));
2356 return;
2357 case WAX:
2358 streak_color = "waxy";
2359 break; /* okay even if not touchstone */
2360 case WOOD:
2361 streak_color = "wooden";
2362 break; /* okay even if not touchstone */
2363 case GOLD:
2364 do_scratch = TRUE; /* scratching and streaks */
2365 streak_color = "golden";
2366 break;
2367 case SILVER:
2368 do_scratch = TRUE; /* scratching and streaks */
2369 streak_color = "silvery";
2370 break;
2371 default:
2372 /* Objects passing the is_flimsy() test will not
2373 scratch a stone. They will leave streaks on
2374 non-touchstones and touchstones alike. */
2375 if (is_flimsy(obj))
2376 streak_color = c_obj_colors[objects[obj->otyp].oc_color];
2377 else
2378 do_scratch = (tstone->otyp != TOUCHSTONE);
2379 break;
2381 break; /* default oclass */
2384 Sprintf(stonebuf, "stone%s", plur(tstone->quan));
2385 if (do_scratch)
2386 You("make %s%sscratch marks on the %s.",
2387 streak_color ? streak_color : (const char *) "",
2388 streak_color ? " " : "", stonebuf);
2389 else if (streak_color)
2390 You_see("%s streaks on the %s.", streak_color, stonebuf);
2391 else
2392 pline(scritch);
2393 return;
2396 static struct trapinfo {
2397 struct obj *tobj;
2398 xchar tx, ty;
2399 int time_needed;
2400 boolean force_bungle;
2401 } trapinfo;
2403 void
2404 reset_trapset()
2406 trapinfo.tobj = 0;
2407 trapinfo.force_bungle = 0;
2410 /* Place a landmine/bear trap. Helge Hafting */
2411 STATIC_OVL void
2412 use_trap(otmp)
2413 struct obj *otmp;
2415 int ttyp, tmp;
2416 const char *what = (char *) 0;
2417 char buf[BUFSZ];
2418 int levtyp = levl[u.ux][u.uy].typ;
2419 const char *occutext = "setting the trap";
2421 if (nohands(youmonst.data))
2422 what = "without hands";
2423 else if (Stunned)
2424 what = "while stunned";
2425 else if (u.uswallow)
2426 what =
2427 is_animal(u.ustuck->data) ? "while swallowed" : "while engulfed";
2428 else if (Underwater)
2429 what = "underwater";
2430 else if (Levitation)
2431 what = "while levitating";
2432 else if (is_pool(u.ux, u.uy))
2433 what = "in water";
2434 else if (is_lava(u.ux, u.uy))
2435 what = "in lava";
2436 else if (On_stairs(u.ux, u.uy))
2437 what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder"
2438 : "on the stairs";
2439 else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp)
2440 || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
2441 what = "here";
2442 else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
2443 what = (levtyp == AIR)
2444 ? "in midair"
2445 : (levtyp == CLOUD)
2446 ? "in a cloud"
2447 : "in this place"; /* Air/Water Plane catch-all */
2448 if (what) {
2449 You_cant("set a trap %s!", what);
2450 reset_trapset();
2451 return;
2453 ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
2454 if (otmp == trapinfo.tobj && u.ux == trapinfo.tx && u.uy == trapinfo.ty) {
2455 You("resume setting %s%s.", shk_your(buf, otmp),
2456 defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
2457 set_occupation(set_trap, occutext, 0);
2458 return;
2460 trapinfo.tobj = otmp;
2461 trapinfo.tx = u.ux, trapinfo.ty = u.uy;
2462 tmp = ACURR(A_DEX);
2463 trapinfo.time_needed =
2464 (tmp > 17) ? 2 : (tmp > 12) ? 3 : (tmp > 7) ? 4 : 5;
2465 if (Blind)
2466 trapinfo.time_needed *= 2;
2467 tmp = ACURR(A_STR);
2468 if (ttyp == BEAR_TRAP && tmp < 18)
2469 trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4;
2470 /*[fumbling and/or confusion and/or cursed object check(s)
2471 should be incorporated here instead of in set_trap]*/
2472 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
2473 boolean chance;
2475 if (Fumbling || otmp->cursed)
2476 chance = (rnl(10) > 3);
2477 else
2478 chance = (rnl(10) > 5);
2479 You("aren't very skilled at reaching from %s.", mon_nam(u.usteed));
2480 Sprintf(buf, "Continue your attempt to set %s?",
2481 the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
2482 if (yn(buf) == 'y') {
2483 if (chance) {
2484 switch (ttyp) {
2485 case LANDMINE: /* set it off */
2486 trapinfo.time_needed = 0;
2487 trapinfo.force_bungle = TRUE;
2488 break;
2489 case BEAR_TRAP: /* drop it without arming it */
2490 reset_trapset();
2491 You("drop %s!",
2492 the(defsyms[trap_to_defsym(what_trap(ttyp))]
2493 .explanation));
2494 dropx(otmp);
2495 return;
2498 } else {
2499 reset_trapset();
2500 return;
2503 You("begin setting %s%s.", shk_your(buf, otmp),
2504 defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
2505 set_occupation(set_trap, occutext, 0);
2506 return;
2509 STATIC_PTR
2511 set_trap()
2513 struct obj *otmp = trapinfo.tobj;
2514 struct trap *ttmp;
2515 int ttyp;
2517 if (!otmp || !carried(otmp) || u.ux != trapinfo.tx
2518 || u.uy != trapinfo.ty) {
2519 /* ?? */
2520 reset_trapset();
2521 return 0;
2524 if (--trapinfo.time_needed > 0)
2525 return 1; /* still busy */
2527 ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
2528 ttmp = maketrap(u.ux, u.uy, ttyp);
2529 if (ttmp) {
2530 ttmp->madeby_u = 1;
2531 feeltrap(ttmp);
2532 if (*in_rooms(u.ux, u.uy, SHOPBASE)) {
2533 add_damage(u.ux, u.uy, 0L); /* schedule removal */
2535 if (!trapinfo.force_bungle)
2536 You("finish arming %s.",
2537 the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
2538 if (((otmp->cursed || Fumbling) && (rnl(10) > 5))
2539 || trapinfo.force_bungle)
2540 dotrap(ttmp,
2541 (unsigned) (trapinfo.force_bungle ? FORCEBUNGLE : 0));
2542 } else {
2543 /* this shouldn't happen */
2544 Your("trap setting attempt fails.");
2546 useup(otmp);
2547 reset_trapset();
2548 return 0;
2551 STATIC_OVL int
2552 use_whip(obj)
2553 struct obj *obj;
2555 char buf[BUFSZ];
2556 struct monst *mtmp;
2557 struct obj *otmp;
2558 int rx, ry, proficient, res = 0;
2559 const char *msg_slipsfree = "The bullwhip slips free.";
2560 const char *msg_snap = "Snap!";
2562 if (obj != uwep) {
2563 if (!wield_tool(obj, "lash"))
2564 return 0;
2565 else
2566 res = 1;
2568 if (!getdir((char *) 0))
2569 return res;
2571 if (u.uswallow) {
2572 mtmp = u.ustuck;
2573 rx = mtmp->mx;
2574 ry = mtmp->my;
2575 } else {
2576 if (Stunned || (Confusion && !rn2(5)))
2577 confdir();
2578 rx = u.ux + u.dx;
2579 ry = u.uy + u.dy;
2580 if (!isok(rx, ry)) {
2581 You("miss.");
2582 return res;
2584 mtmp = m_at(rx, ry);
2587 /* fake some proficiency checks */
2588 proficient = 0;
2589 if (Role_if(PM_ARCHEOLOGIST))
2590 ++proficient;
2591 if (ACURR(A_DEX) < 6)
2592 proficient--;
2593 else if (ACURR(A_DEX) >= 14)
2594 proficient += (ACURR(A_DEX) - 14);
2595 if (Fumbling)
2596 --proficient;
2597 if (proficient > 3)
2598 proficient = 3;
2599 if (proficient < 0)
2600 proficient = 0;
2602 if (u.uswallow && attack(u.ustuck)) {
2603 There("is not enough room to flick your bullwhip.");
2605 } else if (Underwater) {
2606 There("is too much resistance to flick your bullwhip.");
2608 } else if (u.dz < 0) {
2609 You("flick a bug off of the %s.", ceiling(u.ux, u.uy));
2611 } else if ((!u.dx && !u.dy) || (u.dz > 0)) {
2612 int dam;
2614 /* Sometimes you hit your steed by mistake */
2615 if (u.usteed && !rn2(proficient + 2)) {
2616 You("whip %s!", mon_nam(u.usteed));
2617 kick_steed();
2618 return 1;
2620 if (Levitation || u.usteed) {
2621 /* Have a shot at snaring something on the floor */
2622 otmp = level.objects[u.ux][u.uy];
2623 if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) {
2624 pline("Why beat a dead horse?");
2625 return 1;
2627 if (otmp && proficient) {
2628 You("wrap your bullwhip around %s on the %s.",
2629 an(singular(otmp, xname)), surface(u.ux, u.uy));
2630 if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1)
2631 pline1(msg_slipsfree);
2632 return 1;
2635 dam = rnd(2) + dbon() + obj->spe;
2636 if (dam <= 0)
2637 dam = 1;
2638 You("hit your %s with your bullwhip.", body_part(FOOT));
2639 Sprintf(buf, "killed %sself with %s bullwhip", uhim(), uhis());
2640 losehp(Maybe_Half_Phys(dam), buf, NO_KILLER_PREFIX);
2641 context.botl = 1;
2642 return 1;
2644 } else if ((Fumbling || Glib) && !rn2(5)) {
2645 pline_The("bullwhip slips out of your %s.", body_part(HAND));
2646 dropx(obj);
2648 } else if (u.utrap && u.utraptype == TT_PIT) {
2650 * Assumptions:
2652 * if you're in a pit
2653 * - you are attempting to get out of the pit
2654 * or, if you are applying it towards a small monster
2655 * - then it is assumed that you are trying to hit it
2656 * else if the monster is wielding a weapon
2657 * - you are attempting to disarm a monster
2658 * else
2659 * - you are attempting to hit the monster.
2661 * if you're confused (and thus off the mark)
2662 * - you only end up hitting.
2665 const char *wrapped_what = (char *) 0;
2667 if (mtmp) {
2668 if (bigmonst(mtmp->data)) {
2669 wrapped_what = strcpy(buf, mon_nam(mtmp));
2670 } else if (proficient) {
2671 if (attack(mtmp))
2672 return 1;
2673 else
2674 pline1(msg_snap);
2677 if (!wrapped_what) {
2678 if (IS_FURNITURE(levl[rx][ry].typ))
2679 wrapped_what = something;
2680 else if (sobj_at(BOULDER, rx, ry))
2681 wrapped_what = "a boulder";
2683 if (wrapped_what) {
2684 coord cc;
2686 cc.x = rx;
2687 cc.y = ry;
2688 You("wrap your bullwhip around %s.", wrapped_what);
2689 if (proficient && rn2(proficient + 2)) {
2690 if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
2691 You("yank yourself out of the pit!");
2692 teleds(cc.x, cc.y, TRUE);
2693 u.utrap = 0;
2694 vision_full_recalc = 1;
2696 } else {
2697 pline1(msg_slipsfree);
2699 if (mtmp)
2700 wakeup(mtmp, TRUE);
2701 } else
2702 pline1(msg_snap);
2704 } else if (mtmp) {
2705 if (!canspotmon(mtmp) && !glyph_is_invisible(levl[rx][ry].glyph)) {
2706 pline("A monster is there that you couldn't see.");
2707 map_invisible(rx, ry);
2709 otmp = MON_WEP(mtmp); /* can be null */
2710 if (otmp) {
2711 char onambuf[BUFSZ];
2712 const char *mon_hand;
2713 boolean gotit = proficient && (!Fumbling || !rn2(10));
2715 Strcpy(onambuf, cxname(otmp));
2716 if (gotit) {
2717 mon_hand = mbodypart(mtmp, HAND);
2718 if (bimanual(otmp))
2719 mon_hand = makeplural(mon_hand);
2720 } else
2721 mon_hand = 0; /* lint suppression */
2723 You("wrap your bullwhip around %s.", yname(otmp));
2724 if (gotit && mwelded(otmp)) {
2725 pline("%s welded to %s %s%c",
2726 (otmp->quan == 1L) ? "It is" : "They are", mhis(mtmp),
2727 mon_hand, !otmp->bknown ? '!' : '.');
2728 otmp->bknown = 1;
2729 gotit = FALSE; /* can't pull it free */
2731 if (gotit) {
2732 obj_extract_self(otmp);
2733 possibly_unwield(mtmp, FALSE);
2734 setmnotwielded(mtmp, otmp);
2736 switch (rn2(proficient + 1)) {
2737 case 2:
2738 /* to floor near you */
2739 You("yank %s to the %s!", yname(otmp),
2740 surface(u.ux, u.uy));
2741 place_object(otmp, u.ux, u.uy);
2742 stackobj(otmp);
2743 break;
2744 case 3:
2745 #if 0
2746 /* right to you */
2747 if (!rn2(25)) {
2748 /* proficient with whip, but maybe not
2749 so proficient at catching weapons */
2750 int hitu, hitvalu;
2752 hitvalu = 8 + otmp->spe;
2753 hitu = thitu(hitvalu,
2754 dmgval(otmp, &youmonst),
2755 otmp, (char *)0);
2756 if (hitu) {
2757 pline_The("%s hits you as you try to snatch it!",
2758 the(onambuf));
2760 place_object(otmp, u.ux, u.uy);
2761 stackobj(otmp);
2762 break;
2764 #endif /* 0 */
2765 /* right into your inventory */
2766 You("snatch %s!", yname(otmp));
2767 if (otmp->otyp == CORPSE
2768 && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg
2769 && !Stone_resistance
2770 && !(poly_when_stoned(youmonst.data)
2771 && polymon(PM_STONE_GOLEM))) {
2772 char kbuf[BUFSZ];
2774 Sprintf(kbuf, "%s corpse",
2775 an(mons[otmp->corpsenm].mname));
2776 pline("Snatching %s is a fatal mistake.", kbuf);
2777 instapetrify(kbuf);
2779 otmp = hold_another_object(
2780 otmp, "You drop %s!", doname(otmp), (const char *) 0);
2781 break;
2782 default:
2783 /* to floor beneath mon */
2784 You("yank %s from %s %s!", the(onambuf),
2785 s_suffix(mon_nam(mtmp)), mon_hand);
2786 obj_no_longer_held(otmp);
2787 place_object(otmp, mtmp->mx, mtmp->my);
2788 stackobj(otmp);
2789 break;
2791 } else {
2792 pline1(msg_slipsfree);
2794 wakeup(mtmp, TRUE);
2795 } else {
2796 if (mtmp->m_ap_type && !Protection_from_shape_changers
2797 && !sensemon(mtmp))
2798 stumble_onto_mimic(mtmp);
2799 else
2800 You("flick your bullwhip towards %s.", mon_nam(mtmp));
2801 if (proficient) {
2802 if (attack(mtmp))
2803 return 1;
2804 else
2805 pline1(msg_snap);
2809 } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
2810 /* it must be air -- water checked above */
2811 You("snap your whip through thin air.");
2813 } else {
2814 pline1(msg_snap);
2816 return 1;
2819 static const char
2820 not_enough_room[] = "There's not enough room here to use that.",
2821 where_to_hit[] = "Where do you want to hit?",
2822 cant_see_spot[] = "won't hit anything if you can't see that spot.",
2823 cant_reach[] = "can't reach that spot from here.";
2825 /* find pos of monster in range, if only one monster */
2826 boolean
2827 find_poleable_mon(pos, min_range, max_range)
2828 coord *pos;
2829 int min_range, max_range;
2831 struct monst *mtmp;
2832 struct monst *selmon = (struct monst *) 0;
2834 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
2835 if (mtmp && !DEADMONSTER(mtmp) && !mtmp->mtame
2836 && cansee(mtmp->mx, mtmp->my)
2837 && distu(mtmp->mx, mtmp->my) <= max_range
2838 && distu(mtmp->mx, mtmp->my) >= min_range) {
2839 if (selmon)
2840 return FALSE;
2841 selmon = mtmp;
2843 if (!selmon)
2844 return FALSE;
2845 pos->x = selmon->mx;
2846 pos->y = selmon->my;
2847 return TRUE;
2850 static int polearm_range_min = -1;
2851 static int polearm_range_max = -1;
2853 void
2854 display_polearm_positions(state)
2855 int state;
2857 if (state == 0) {
2858 tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos));
2859 } else if (state == 1) {
2860 int x, y, dx, dy;
2862 for (dx = -4; dx <= 4; dx++)
2863 for (dy = -4; dy <= 4; dy++) {
2864 x = dx + (int) u.ux;
2865 y = dy + (int) u.uy;
2866 if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
2867 && distu(x, y) >= polearm_range_min
2868 && distu(x, y) <= polearm_range_max) {
2869 tmp_at(x, y);
2872 } else {
2873 tmp_at(DISP_END, 0);
2877 /* Distance attacks by pole-weapons */
2878 STATIC_OVL int
2879 use_pole(obj)
2880 struct obj *obj;
2882 int res = 0, typ, max_range, min_range, glyph;
2883 coord cc;
2884 struct monst *mtmp;
2885 struct monst *hitm = context.polearm.hitmon;
2887 /* Are you allowed to use the pole? */
2888 if (u.uswallow) {
2889 pline(not_enough_room);
2890 return 0;
2892 if (obj != uwep) {
2893 if (!wield_tool(obj, "swing"))
2894 return 0;
2895 else
2896 res = 1;
2898 /* assert(obj == uwep); */
2901 * Calculate allowable range (pole's reach is always 2 steps):
2902 * unskilled and basic: orthogonal direction, 4..4;
2903 * skilled: as basic, plus knight's jump position, 4..5;
2904 * expert: as skilled, plus diagonal, 4..8.
2905 * ...9...
2906 * .85458.
2907 * .52125.
2908 * 9410149
2909 * .52125.
2910 * .85458.
2911 * ...9...
2912 * (Note: no roles in nethack can become expert or better
2913 * for polearm skill; Yeoman in slash'em can become expert.)
2915 min_range = 4;
2916 typ = uwep_skill_type();
2917 if (typ == P_NONE || P_SKILL(typ) <= P_BASIC)
2918 max_range = 4;
2919 else if (P_SKILL(typ) == P_SKILLED)
2920 max_range = 5;
2921 else
2922 max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */
2924 polearm_range_min = min_range;
2925 polearm_range_max = max_range;
2927 /* Prompt for a location */
2928 pline(where_to_hit);
2929 cc.x = u.ux;
2930 cc.y = u.uy;
2931 if (!find_poleable_mon(&cc, min_range, max_range) && hitm
2932 && !DEADMONSTER(hitm) && cansee(hitm->mx, hitm->my)
2933 && distu(hitm->mx, hitm->my) <= max_range
2934 && distu(hitm->mx, hitm->my) >= min_range) {
2935 cc.x = hitm->mx;
2936 cc.y = hitm->my;
2938 getpos_sethilite(display_polearm_positions);
2939 if (getpos(&cc, TRUE, "the spot to hit") < 0)
2940 return res; /* ESC; uses turn iff polearm became wielded */
2942 glyph = glyph_at(cc.x, cc.y);
2943 if (distu(cc.x, cc.y) > max_range) {
2944 pline("Too far!");
2945 return res;
2946 } else if (distu(cc.x, cc.y) < min_range) {
2947 pline("Too close!");
2948 return res;
2949 } else if (!cansee(cc.x, cc.y) && !glyph_is_monster(glyph)
2950 && !glyph_is_invisible(glyph) && !glyph_is_statue(glyph)) {
2951 You(cant_see_spot);
2952 return res;
2953 } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
2954 You(cant_reach);
2955 return res;
2958 context.polearm.hitmon = NULL;
2959 /* Attack the monster there */
2960 bhitpos = cc;
2961 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *) 0) {
2962 if (attack_checks(mtmp, uwep))
2963 return res;
2964 if (overexertion())
2965 return 1; /* burn nutrition; maybe pass out */
2966 context.polearm.hitmon = mtmp;
2967 check_caitiff(mtmp);
2968 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
2969 (void) thitmonst(mtmp, uwep);
2970 } else if (glyph_is_statue(glyph) /* might be hallucinatory */
2971 && sobj_at(STATUE, bhitpos.x, bhitpos.y)) {
2972 struct trap *t = t_at(bhitpos.x, bhitpos.y);
2974 if (t && t->ttyp == STATUE_TRAP
2975 && activate_statue_trap(t, t->tx, t->ty, FALSE)) {
2976 ; /* feedback has been give by animate_statue() */
2977 } else {
2978 /* Since statues look like monsters now, we say something
2979 different from "you miss" or "there's nobody there".
2980 Note: we only do this when a statue is displayed here,
2981 because the player is probably attempting to attack it;
2982 other statues obscured by anything are just ignored. */
2983 pline("Thump! Your blow bounces harmlessly off the statue.");
2984 wake_nearto(bhitpos.x, bhitpos.y, 25);
2986 } else {
2987 /* no monster here and no statue seen or remembered here */
2988 if (glyph_is_invisible(glyph)) {
2989 /* now you know that nothing is there... */
2990 unmap_object(bhitpos.x, bhitpos.y);
2991 newsym(bhitpos.x, bhitpos.y);
2993 You("miss; there is no one there to hit.");
2995 u_wipe_engr(2); /* same as for melee or throwing */
2996 return 1;
2999 STATIC_OVL int
3000 use_cream_pie(obj)
3001 struct obj *obj;
3003 boolean wasblind = Blind;
3004 boolean wascreamed = u.ucreamed;
3005 boolean several = FALSE;
3007 if (obj->quan > 1L) {
3008 several = TRUE;
3009 obj = splitobj(obj, 1L);
3011 if (Hallucination)
3012 You("give yourself a facial.");
3013 else
3014 pline("You immerse your %s in %s%s.", body_part(FACE),
3015 several ? "one of " : "",
3016 several ? makeplural(the(xname(obj))) : the(xname(obj)));
3017 if (can_blnd((struct monst *) 0, &youmonst, AT_WEAP, obj)) {
3018 int blindinc = rnd(25);
3019 u.ucreamed += blindinc;
3020 make_blinded(Blinded + (long) blindinc, FALSE);
3021 if (!Blind || (Blind && wasblind))
3022 pline("There's %ssticky goop all over your %s.",
3023 wascreamed ? "more " : "", body_part(FACE));
3024 else /* Blind && !wasblind */
3025 You_cant("see through all the sticky goop on your %s.",
3026 body_part(FACE));
3029 setnotworn(obj);
3030 /* useup() is appropriate, but we want costly_alteration()'s message */
3031 costly_alteration(obj, COST_SPLAT);
3032 obj_extract_self(obj);
3033 delobj(obj);
3034 return 0;
3037 STATIC_OVL int
3038 use_grapple(obj)
3039 struct obj *obj;
3041 int res = 0, typ, max_range = 4, tohit;
3042 boolean save_confirm;
3043 coord cc;
3044 struct monst *mtmp;
3045 struct obj *otmp;
3047 /* Are you allowed to use the hook? */
3048 if (u.uswallow) {
3049 pline(not_enough_room);
3050 return 0;
3052 if (obj != uwep) {
3053 if (!wield_tool(obj, "cast"))
3054 return 0;
3055 else
3056 res = 1;
3058 /* assert(obj == uwep); */
3060 /* Prompt for a location */
3061 pline(where_to_hit);
3062 cc.x = u.ux;
3063 cc.y = u.uy;
3064 if (getpos(&cc, TRUE, "the spot to hit") < 0)
3065 return res; /* ESC; uses turn iff grapnel became wielded */
3067 /* Calculate range; unlike use_pole(), there's no minimum for range */
3068 typ = uwep_skill_type();
3069 if (typ == P_NONE || P_SKILL(typ) <= P_BASIC)
3070 max_range = 4;
3071 else if (P_SKILL(typ) == P_SKILLED)
3072 max_range = 5;
3073 else
3074 max_range = 8;
3075 if (distu(cc.x, cc.y) > max_range) {
3076 pline("Too far!");
3077 return res;
3078 } else if (!cansee(cc.x, cc.y)) {
3079 You(cant_see_spot);
3080 return res;
3081 } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
3082 You(cant_reach);
3083 return res;
3086 /* What do you want to hit? */
3087 tohit = rn2(5);
3088 if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) {
3089 winid tmpwin = create_nhwindow(NHW_MENU);
3090 anything any;
3091 char buf[BUFSZ];
3092 menu_item *selected;
3094 any = zeroany; /* set all bits to zero */
3095 any.a_int = 1; /* use index+1 (cant use 0) as identifier */
3096 start_menu(tmpwin);
3097 any.a_int++;
3098 Sprintf(buf, "an object on the %s", surface(cc.x, cc.y));
3099 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3100 MENU_UNSELECTED);
3101 any.a_int++;
3102 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "a monster",
3103 MENU_UNSELECTED);
3104 any.a_int++;
3105 Sprintf(buf, "the %s", surface(cc.x, cc.y));
3106 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
3107 MENU_UNSELECTED);
3108 end_menu(tmpwin, "Aim for what?");
3109 tohit = rn2(4);
3110 if (select_menu(tmpwin, PICK_ONE, &selected) > 0
3111 && rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2))
3112 tohit = selected[0].item.a_int - 1;
3113 free((genericptr_t) selected);
3114 destroy_nhwindow(tmpwin);
3117 /* possibly scuff engraving at your feet;
3118 any engraving at the target location is unaffected */
3119 if (tohit == 2 || !rn2(2))
3120 u_wipe_engr(rnd(2));
3122 /* What did you hit? */
3123 switch (tohit) {
3124 case 0: /* Trap */
3125 /* FIXME -- untrap needs to deal with non-adjacent traps */
3126 break;
3127 case 1: /* Object */
3128 if ((otmp = level.objects[cc.x][cc.y]) != 0) {
3129 You("snag an object from the %s!", surface(cc.x, cc.y));
3130 (void) pickup_object(otmp, 1L, FALSE);
3131 /* If pickup fails, leave it alone */
3132 newsym(cc.x, cc.y);
3133 return 1;
3135 break;
3136 case 2: /* Monster */
3137 bhitpos = cc;
3138 if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *) 0)
3139 break;
3140 notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
3141 save_confirm = flags.confirm;
3142 if (verysmall(mtmp->data) && !rn2(4)
3143 && enexto(&cc, u.ux, u.uy, (struct permonst *) 0)) {
3144 flags.confirm = FALSE;
3145 (void) attack_checks(mtmp, uwep);
3146 flags.confirm = save_confirm;
3147 check_caitiff(mtmp); /* despite fact there's no damage */
3148 You("pull in %s!", mon_nam(mtmp));
3149 mtmp->mundetected = 0;
3150 rloc_to(mtmp, cc.x, cc.y);
3151 return 1;
3152 } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data))
3153 || rn2(4)) {
3154 flags.confirm = FALSE;
3155 (void) attack_checks(mtmp, uwep);
3156 flags.confirm = save_confirm;
3157 check_caitiff(mtmp);
3158 (void) thitmonst(mtmp, uwep);
3159 return 1;
3161 /* FALL THROUGH */
3162 case 3: /* Surface */
3163 if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y))
3164 pline_The("hook slices through the %s.", surface(cc.x, cc.y));
3165 else {
3166 You("are yanked toward the %s!", surface(cc.x, cc.y));
3167 hurtle(sgn(cc.x - u.ux), sgn(cc.y - u.uy), 1, FALSE);
3168 spoteffects(TRUE);
3170 return 1;
3171 default: /* Yourself (oops!) */
3172 if (P_SKILL(typ) <= P_BASIC) {
3173 You("hook yourself!");
3174 losehp(Maybe_Half_Phys(rn1(10, 10)), "a grappling hook",
3175 KILLED_BY);
3176 return 1;
3178 break;
3180 pline1(nothing_happens);
3181 return 1;
3184 #define BY_OBJECT ((struct monst *) 0)
3186 /* return 1 if the wand is broken, hence some time elapsed */
3187 STATIC_OVL int
3188 do_break_wand(obj)
3189 struct obj *obj;
3191 static const char nothing_else_happens[] = "But nothing else happens...";
3192 register int i, x, y;
3193 register struct monst *mon;
3194 int dmg, damage;
3195 boolean affects_objects;
3196 boolean shop_damage = FALSE;
3197 boolean fillmsg = FALSE;
3198 int expltype = EXPL_MAGICAL;
3199 char confirm[QBUFSZ], buf[BUFSZ];
3200 boolean is_fragile = (!strcmp(OBJ_DESCR(objects[obj->otyp]), "balsa"));
3202 if (!paranoid_query(ParanoidBreakwand,
3203 safe_qbuf(confirm,
3204 "Are you really sure you want to break ",
3205 "?", obj, yname, ysimple_name, "the wand")))
3206 return 0;
3208 if (nohands(youmonst.data)) {
3209 You_cant("break %s without hands!", yname(obj));
3210 return 0;
3211 } else if (ACURR(A_STR) < (is_fragile ? 5 : 10)) {
3212 You("don't have the strength to break %s!", yname(obj));
3213 return 0;
3215 pline("Raising %s high above your %s, you %s it in two!", yname(obj),
3216 body_part(HEAD), is_fragile ? "snap" : "break");
3218 /* [ALI] Do this first so that wand is removed from bill. Otherwise,
3219 * the freeinv() below also hides it from setpaid() which causes problems.
3221 if (obj->unpaid) {
3222 check_unpaid(obj); /* Extra charge for use */
3223 costly_alteration(obj, COST_DSTROY);
3226 current_wand = obj; /* destroy_item might reset this */
3227 freeinv(obj); /* hide it from destroy_item instead... */
3228 setnotworn(obj); /* so we need to do this ourselves */
3230 if (!zappable(obj)) {
3231 pline(nothing_else_happens);
3232 goto discard_broken_wand;
3234 /* successful call to zappable() consumes a charge; put it back */
3235 obj->spe++;
3236 /* might have "wrested" a final charge, taking it from 0 to -1;
3237 if so, we just brought it back up to 0, which wouldn't do much
3238 below so give it 1..3 charges now, usually making it stronger
3239 than an ordinary last charge (the wand is already gone from
3240 inventory, so perm_invent can't accidentally reveal this) */
3241 if (!obj->spe)
3242 obj->spe = rnd(3);
3244 obj->ox = u.ux;
3245 obj->oy = u.uy;
3246 dmg = obj->spe * 4;
3247 affects_objects = FALSE;
3249 switch (obj->otyp) {
3250 case WAN_WISHING:
3251 case WAN_NOTHING:
3252 case WAN_LOCKING:
3253 case WAN_PROBING:
3254 case WAN_ENLIGHTENMENT:
3255 case WAN_OPENING:
3256 case WAN_SECRET_DOOR_DETECTION:
3257 pline(nothing_else_happens);
3258 goto discard_broken_wand;
3259 case WAN_DEATH:
3260 case WAN_LIGHTNING:
3261 dmg *= 4;
3262 goto wanexpl;
3263 case WAN_FIRE:
3264 expltype = EXPL_FIERY;
3265 case WAN_COLD:
3266 if (expltype == EXPL_MAGICAL)
3267 expltype = EXPL_FROSTY;
3268 dmg *= 2;
3269 case WAN_MAGIC_MISSILE:
3270 wanexpl:
3271 explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype);
3272 makeknown(obj->otyp); /* explode describes the effect */
3273 goto discard_broken_wand;
3274 case WAN_STRIKING:
3275 /* we want this before the explosion instead of at the very end */
3276 pline("A wall of force smashes down around you!");
3277 dmg = d(1 + obj->spe, 6); /* normally 2d12 */
3278 /*FALLTHRU*/
3279 case WAN_CANCELLATION:
3280 case WAN_POLYMORPH:
3281 case WAN_TELEPORTATION:
3282 case WAN_UNDEAD_TURNING:
3283 affects_objects = TRUE;
3284 break;
3285 default:
3286 break;
3289 /* magical explosion and its visual effect occur before specific effects
3291 /* [TODO? This really ought to prevent the explosion from being
3292 fatal so that we never leave a bones file where none of the
3293 surrounding targets (or underlying objects) got affected yet.] */
3294 explode(obj->ox, obj->oy, -(obj->otyp), rnd(dmg), WAND_CLASS,
3295 EXPL_MAGICAL);
3297 /* prepare for potential feedback from polymorph... */
3298 zapsetup();
3300 /* this makes it hit us last, so that we can see the action first */
3301 for (i = 0; i <= 8; i++) {
3302 bhitpos.x = x = obj->ox + xdir[i];
3303 bhitpos.y = y = obj->oy + ydir[i];
3304 if (!isok(x, y))
3305 continue;
3307 if (obj->otyp == WAN_DIGGING) {
3308 schar typ;
3310 if (dig_check(BY_OBJECT, FALSE, x, y)) {
3311 if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) {
3312 /* normally, pits and holes don't anger guards, but they
3313 * do if it's a wall or door that's being dug */
3314 watch_dig((struct monst *) 0, x, y, TRUE);
3315 if (*in_rooms(x, y, SHOPBASE))
3316 shop_damage = TRUE;
3319 * Let liquid flow into the newly created pits.
3320 * Adjust corresponding code in music.c for
3321 * drum of earthquake if you alter this sequence.
3323 typ = fillholetyp(x, y, FALSE);
3324 if (typ != ROOM) {
3325 levl[x][y].typ = typ;
3326 liquid_flow(x, y, typ, t_at(x, y),
3327 fillmsg
3328 ? (char *) 0
3329 : "Some holes are quickly filled with %s!");
3330 fillmsg = TRUE;
3331 } else
3332 digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3
3333 || (!Can_dig_down(&u.uz)
3334 && !levl[x][y].candig))
3335 ? PIT
3336 : HOLE);
3338 continue;
3339 } else if (obj->otyp == WAN_CREATE_MONSTER) {
3340 /* u.ux,u.uy creates it near you--x,y might create it in rock */
3341 (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS);
3342 continue;
3343 } else if (x != u.ux || y != u.uy) {
3345 * Wand breakage is targetting a square adjacent to the hero,
3346 * which might contain a monster or a pile of objects or both.
3347 * Handle objects last; avoids having undead turning raise an
3348 * undead's corpse and then attack resulting undead monster.
3349 * obj->bypass in bhitm() prevents the polymorphing of items
3350 * dropped due to monster's polymorph and prevents undead
3351 * turning that kills an undead from raising resulting corpse.
3353 if ((mon = m_at(x, y)) != 0) {
3354 (void) bhitm(mon, obj);
3355 /* if (context.botl) bot(); */
3357 if (affects_objects && level.objects[x][y]) {
3358 (void) bhitpile(obj, bhito, x, y, 0);
3359 if (context.botl)
3360 bot(); /* potion effects */
3362 } else {
3364 * Wand breakage is targetting the hero. Using xdir[]+ydir[]
3365 * deltas for location selection causes this case to happen
3366 * after all the surrounding squares have been handled.
3367 * Process objects first, in case damage is fatal and leaves
3368 * bones, or teleportation sends one or more of the objects to
3369 * same destination as hero (lookhere/autopickup); also avoids
3370 * the polymorphing of gear dropped due to hero's transformation.
3371 * (Unlike with monsters being hit by zaps, we can't rely on use
3372 * of obj->bypass in the zap code to accomplish that last case
3373 * since it's also used by retouch_equipment() for polyself.)
3375 if (affects_objects && level.objects[x][y]) {
3376 (void) bhitpile(obj, bhito, x, y, 0);
3377 if (context.botl)
3378 bot(); /* potion effects */
3380 damage = zapyourself(obj, FALSE);
3381 if (damage) {
3382 Sprintf(buf, "killed %sself by breaking a wand", uhim());
3383 losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX);
3385 if (context.botl)
3386 bot(); /* blindness */
3390 /* potentially give post zap/break feedback */
3391 zapwrapup();
3393 /* Note: if player fell thru, this call is a no-op.
3394 Damage is handled in digactualhole in that case */
3395 if (shop_damage)
3396 pay_for_damage("dig into", FALSE);
3398 if (obj->otyp == WAN_LIGHT)
3399 litroom(TRUE, obj); /* only needs to be done once */
3401 discard_broken_wand:
3402 obj = current_wand; /* [see dozap() and destroy_item()] */
3403 current_wand = 0;
3404 if (obj)
3405 delobj(obj);
3406 nomul(0);
3407 return 1;
3410 STATIC_OVL void
3411 add_class(cl, class)
3412 char *cl;
3413 char class;
3415 char tmp[2];
3417 tmp[0] = class;
3418 tmp[1] = '\0';
3419 Strcat(cl, tmp);
3422 static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
3424 /* augment tools[] if various items are carried */
3425 STATIC_OVL void
3426 setapplyclasses(class_list)
3427 char class_list[];
3429 register struct obj *otmp;
3430 int otyp;
3431 boolean knowoil, knowtouchstone, addpotions, addstones, addfood;
3433 knowoil = objects[POT_OIL].oc_name_known;
3434 knowtouchstone = objects[TOUCHSTONE].oc_name_known;
3435 addpotions = addstones = addfood = FALSE;
3436 for (otmp = invent; otmp; otmp = otmp->nobj) {
3437 otyp = otmp->otyp;
3438 if (otyp == POT_OIL
3439 || (otmp->oclass == POTION_CLASS
3440 && (!otmp->dknown
3441 || (!knowoil && !objects[otyp].oc_name_known))))
3442 addpotions = TRUE;
3443 if (otyp == TOUCHSTONE
3444 || (is_graystone(otmp)
3445 && (!otmp->dknown
3446 || (!knowtouchstone && !objects[otyp].oc_name_known))))
3447 addstones = TRUE;
3448 if (otyp == CREAM_PIE || otyp == EUCALYPTUS_LEAF)
3449 addfood = TRUE;
3452 class_list[0] = '\0';
3453 if (addpotions || addstones)
3454 add_class(class_list, ALL_CLASSES);
3455 Strcat(class_list, tools);
3456 if (addpotions)
3457 add_class(class_list, POTION_CLASS);
3458 if (addstones)
3459 add_class(class_list, GEM_CLASS);
3460 if (addfood)
3461 add_class(class_list, FOOD_CLASS);
3464 /* the 'a' command */
3466 doapply()
3468 struct obj *obj;
3469 register int res = 1;
3470 char class_list[MAXOCLASSES + 2];
3472 if (check_capacity((char *) 0))
3473 return 0;
3475 setapplyclasses(class_list); /* tools[] */
3476 obj = getobj(class_list, "use or apply");
3477 if (!obj)
3478 return 0;
3480 if (!retouch_object(&obj, FALSE))
3481 return 1; /* evading your grasp costs a turn; just be
3482 grateful that you don't drop it as well */
3484 if (obj->oclass == WAND_CLASS)
3485 return do_break_wand(obj);
3487 switch (obj->otyp) {
3488 case BLINDFOLD:
3489 case LENSES:
3490 if (obj == ublindf) {
3491 if (!cursed(obj))
3492 Blindf_off(obj);
3493 } else if (!ublindf) {
3494 Blindf_on(obj);
3495 } else {
3496 You("are already %s.", ublindf->otyp == TOWEL
3497 ? "covered by a towel"
3498 : ublindf->otyp == BLINDFOLD
3499 ? "wearing a blindfold"
3500 : "wearing lenses");
3502 break;
3503 case CREAM_PIE:
3504 res = use_cream_pie(obj);
3505 break;
3506 case BULLWHIP:
3507 res = use_whip(obj);
3508 break;
3509 case GRAPPLING_HOOK:
3510 res = use_grapple(obj);
3511 break;
3512 case LARGE_BOX:
3513 case CHEST:
3514 case ICE_BOX:
3515 case SACK:
3516 case BAG_OF_HOLDING:
3517 case OILSKIN_SACK:
3518 res = use_container(&obj, 1, FALSE);
3519 break;
3520 case BAG_OF_TRICKS:
3521 (void) bagotricks(obj, FALSE, (int *) 0);
3522 break;
3523 case CAN_OF_GREASE:
3524 use_grease(obj);
3525 break;
3526 case LOCK_PICK:
3527 case CREDIT_CARD:
3528 case SKELETON_KEY:
3529 res = (pick_lock(obj) != 0);
3530 break;
3531 case PICK_AXE:
3532 case DWARVISH_MATTOCK:
3533 res = use_pick_axe(obj);
3534 break;
3535 case TINNING_KIT:
3536 use_tinning_kit(obj);
3537 break;
3538 case LEASH:
3539 use_leash(obj);
3540 break;
3541 case SADDLE:
3542 res = use_saddle(obj);
3543 break;
3544 case MAGIC_WHISTLE:
3545 use_magic_whistle(obj);
3546 break;
3547 case TIN_WHISTLE:
3548 use_whistle(obj);
3549 break;
3550 case EUCALYPTUS_LEAF:
3551 /* MRKR: Every Australian knows that a gum leaf makes an excellent
3552 * whistle, especially if your pet is a tame kangaroo named Skippy.
3554 if (obj->blessed) {
3555 use_magic_whistle(obj);
3556 /* sometimes the blessing will be worn off */
3557 if (!rn2(49)) {
3558 if (!Blind) {
3559 pline("%s %s.", Yobjnam2(obj, "glow"), hcolor("brown"));
3560 obj->bknown = 1;
3562 unbless(obj);
3564 } else {
3565 use_whistle(obj);
3567 break;
3568 case STETHOSCOPE:
3569 res = use_stethoscope(obj);
3570 break;
3571 case MIRROR:
3572 res = use_mirror(obj);
3573 break;
3574 case BELL:
3575 case BELL_OF_OPENING:
3576 use_bell(&obj);
3577 break;
3578 case CANDELABRUM_OF_INVOCATION:
3579 use_candelabrum(obj);
3580 break;
3581 case WAX_CANDLE:
3582 case TALLOW_CANDLE:
3583 use_candle(&obj);
3584 break;
3585 case OIL_LAMP:
3586 case MAGIC_LAMP:
3587 case BRASS_LANTERN:
3588 use_lamp(obj);
3589 break;
3590 case POT_OIL:
3591 light_cocktail(&obj);
3592 break;
3593 case EXPENSIVE_CAMERA:
3594 res = use_camera(obj);
3595 break;
3596 case TOWEL:
3597 res = use_towel(obj);
3598 break;
3599 case CRYSTAL_BALL:
3600 use_crystal_ball(&obj);
3601 break;
3602 case MAGIC_MARKER:
3603 res = dowrite(obj);
3604 break;
3605 case TIN_OPENER:
3606 res = use_tin_opener(obj);
3607 break;
3608 case FIGURINE:
3609 use_figurine(&obj);
3610 break;
3611 case UNICORN_HORN:
3612 use_unicorn_horn(obj);
3613 break;
3614 case WOODEN_FLUTE:
3615 case MAGIC_FLUTE:
3616 case TOOLED_HORN:
3617 case FROST_HORN:
3618 case FIRE_HORN:
3619 case WOODEN_HARP:
3620 case MAGIC_HARP:
3621 case BUGLE:
3622 case LEATHER_DRUM:
3623 case DRUM_OF_EARTHQUAKE:
3624 res = do_play_instrument(obj);
3625 break;
3626 case HORN_OF_PLENTY: /* not a musical instrument */
3627 (void) hornoplenty(obj, FALSE);
3628 break;
3629 case LAND_MINE:
3630 case BEARTRAP:
3631 use_trap(obj);
3632 break;
3633 case FLINT:
3634 case LUCKSTONE:
3635 case LOADSTONE:
3636 case TOUCHSTONE:
3637 use_stone(obj);
3638 break;
3639 default:
3640 /* Pole-weapons can strike at a distance */
3641 if (is_pole(obj)) {
3642 res = use_pole(obj);
3643 break;
3644 } else if (is_pick(obj) || is_axe(obj)) {
3645 res = use_pick_axe(obj);
3646 break;
3648 pline("Sorry, I don't know how to use that.");
3649 nomul(0);
3650 return 0;
3652 if (res && obj && obj->oartifact)
3653 arti_speak(obj);
3654 nomul(0);
3655 return res;
3658 /* Keep track of unfixable troubles for purposes of messages saying you feel
3659 * great.
3662 unfixable_trouble_count(is_horn)
3663 boolean is_horn;
3665 int unfixable_trbl = 0;
3667 if (Stoned)
3668 unfixable_trbl++;
3669 if (Strangled)
3670 unfixable_trbl++;
3671 if (Wounded_legs && !u.usteed)
3672 unfixable_trbl++;
3673 if (Slimed)
3674 unfixable_trbl++;
3675 /* lycanthropy is undesirable, but it doesn't actually make you feel bad */
3677 if (!is_horn || (Confusion & ~TIMEOUT))
3678 unfixable_trbl++;
3679 if (!is_horn || (Sick & ~TIMEOUT))
3680 unfixable_trbl++;
3681 if (!is_horn || (HHallucination & ~TIMEOUT))
3682 unfixable_trbl++;
3683 if (!is_horn || (Vomiting & ~TIMEOUT))
3684 unfixable_trbl++;
3685 if (!is_horn || (HStun & ~TIMEOUT))
3686 unfixable_trbl++;
3687 if (!is_horn || (HDeaf & ~TIMEOUT))
3688 unfixable_trbl++;
3690 return unfixable_trbl;
3693 /*apply.c*/