1    | /*	SCCS Id: @(#)apply.c	3.3	2000/07/23	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | #include "edog.h"
7    | 
8    | #ifdef OVLB
9    | 
10   | static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
11   | static const char tools_too[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS,
12   | 					  WEAPON_CLASS, WAND_CLASS, 0 };
13   | 
14   | #ifdef TOURIST
15   | STATIC_DCL int FDECL(use_camera, (struct obj *));
16   | #endif
17   | STATIC_DCL int FDECL(use_towel, (struct obj *));
18   | STATIC_DCL boolean FDECL(its_dead, (int,int,int *));
19   | STATIC_DCL int FDECL(use_stethoscope, (struct obj *));
20   | STATIC_DCL void FDECL(use_whistle, (struct obj *));
21   | STATIC_DCL void FDECL(use_magic_whistle, (struct obj *));
22   | STATIC_DCL void FDECL(use_leash, (struct obj *));
23   | STATIC_DCL int FDECL(use_mirror, (struct obj *));
24   | STATIC_DCL void FDECL(use_bell, (struct obj *));
25   | STATIC_DCL void FDECL(use_candelabrum, (struct obj *));
26   | STATIC_DCL void FDECL(use_candle, (struct obj *));
27   | STATIC_DCL void FDECL(use_lamp, (struct obj *));
28   | STATIC_DCL void FDECL(light_cocktail, (struct obj *));
29   | STATIC_DCL void FDECL(use_tinning_kit, (struct obj *));
30   | STATIC_DCL void FDECL(use_figurine, (struct obj *));
31   | STATIC_DCL void FDECL(use_grease, (struct obj *));
32   | STATIC_DCL void FDECL(use_trap, (struct obj *));
33   | STATIC_PTR int NDECL(set_trap);		/* occupation callback */
34   | STATIC_DCL int FDECL(use_whip, (struct obj *));
35   | STATIC_DCL int FDECL(use_pole, (struct obj *));
36   | STATIC_DCL int FDECL(use_grapple, (struct obj *));
37   | STATIC_DCL int FDECL(do_break_wand, (struct obj *));
38   | STATIC_DCL boolean FDECL(figurine_location_checks,
39   | 				(struct obj *, coord *, BOOLEAN_P));
40   | 
41   | #ifdef	AMIGA
42   | void FDECL( amii_speaker, ( struct obj *, char *, int ) );
43   | #endif
44   | 
45   | static char no_elbow_room[] = "don't have enough elbow-room to maneuver.";
46   | 
47   | #ifdef TOURIST
48   | STATIC_OVL int
49   | use_camera(obj)
50   | 	struct obj *obj;
51   | {
52   | 	register struct monst *mtmp;
53   | 
54   | 	if(Underwater) {
55   | 		pline("Using your camera underwater would void the warranty.");
56   | 		return(0);
57   | 	}
58   | 	if(!getdir((char *)0)) return(0);
59   | 
60   | 	if (obj->spe <= 0) {
61   | 		pline(nothing_happens);
62   | 		return (1);
63   | 	}
64   | 	obj->spe--;
65   | 	if (obj->cursed && !rn2(2)) {
66   | 		(void) zapyourself(obj, TRUE);
67   | 	} else if (u.uswallow) {
68   | 		You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)),
69   | 		    is_animal(u.ustuck->data) ? "stomach" : "interior");
70   | 	} else if (u.dz) {
71   | 		You("take a picture of the %s.",
72   | 			(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
73   | 	} else if (!u.dx && !u.dy) {
74   | 		(void) zapyourself(obj, TRUE);
75   | 	} else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
76   | 				(int FDECL((*),(MONST_P,OBJ_P)))0,
77   | 				(int FDECL((*),(OBJ_P,OBJ_P)))0,
78   | 				obj)) != 0) {
79   | 		obj->ox = u.ux,  obj->oy = u.uy;
80   | 		(void) flash_hits_mon(mtmp, obj);
81   | 	}
82   | 	return 1;
83   | }
84   | #endif
85   | 
86   | STATIC_OVL int
87   | use_towel(obj)
88   | 	struct obj *obj;
89   | {
90   | 	if(!freehand()) {
91   | 		You("have no free %s!", body_part(HAND));
92   | 		return 0;
93   | 	} else if (obj->owornmask) {
94   | 		You("cannot use it while you're wearing it!");
95   | 		return 0;
96   | 	} else if (obj->cursed) {
97   | 		long old;
98   | 		switch (rn2(3)) {
99   | 		case 2:
100  | 		    old = Glib;
101  | 		    Glib += rn1(10, 3);
102  | 		    Your("%s %s!", makeplural(body_part(HAND)),
103  | 			(old ? "are filthier than ever" : "get slimy"));
104  | 		    return 1;
105  | 		case 1:
106  | 		    if (!ublindf) {
107  | 			old = u.ucreamed;
108  | 			u.ucreamed += rn1(10, 3);
109  | 			pline("Yecch! Your %s %s gunk on it!", body_part(FACE),
110  | 			      (old ? "has more" : "now has"));
111  | 			make_blinded(Blinded + (long)u.ucreamed - old, TRUE);
112  | 		    } else {
113  | 			const char *what = (ublindf->otyp == LENSES) ?
114  | 					    "lenses" : "blindfold";
115  | 			if (ublindf->cursed) {
116  | 			    You("push your %s %s.", what,
117  | 				rn2(2) ? "cock-eyed" : "crooked");
118  | 			} else {
119  | 			    struct obj *saved_ublindf = ublindf;
120  | 			    You("push your %s off.", what);
121  | 			    Blindf_off(ublindf);
122  | 			    dropx(saved_ublindf);
123  | 			}
124  | 		    }
125  | 		    return 1;
126  | 		case 0:
127  | 		    break;
128  | 		}
129  | 	}
130  | 
131  | 	if (Glib) {
132  | 		Glib = 0;
133  | 		You("wipe off your %s.", makeplural(body_part(HAND)));
134  | 		return 1;
135  | 	} else if(u.ucreamed) {
136  | 		Blinded -= u.ucreamed;
137  | 		u.ucreamed = 0;
138  | 
139  | 		if (!Blinded) {
140  | 			pline("You've got the glop off.");
141  | 			Blinded = 1;
142  | 			make_blinded(0L,TRUE);
143  | 		} else {
144  | 			Your("%s feels clean now.", body_part(FACE));
145  | 		}
146  | 		return 1;
147  | 	}
148  | 
149  | 	Your("%s and %s are already clean.",
150  | 		body_part(FACE), makeplural(body_part(HAND)));
151  | 
152  | 	return 0;
153  | }
154  | 
155  | /* maybe give a stethoscope message based on floor objects */
156  | STATIC_OVL boolean
157  | its_dead(rx, ry, resp)
158  | int rx, ry, *resp;
159  | {
160  | 	struct obj *otmp;
161  | 	struct trap *ttmp;
162  | 
163  | 	/* additional stethoscope messages from jyoung@apanix.apana.org.au */
164  | 	if (Hallucination && sobj_at(CORPSE, rx, ry)) {
165  | 	    /* (a corpse doesn't retain the monster's sex,
166  | 	       so we're forced to use generic pronoun here) */
167  | 	    You_hear("a voice say, \"It's dead, Jim.\"");
168  | 	    *resp = 1;
169  | 	    return TRUE;
170  | 	} else if (Role_if(PM_HEALER) && ((otmp = sobj_at(CORPSE, rx, ry)) != 0 ||
171  | 				    (otmp = sobj_at(STATUE, rx, ry)) != 0)) {
172  | 	    /* possibly should check uppermost {corpse,statue} in the pile
173  | 	       if both types are present, but it's not worth the effort */
174  | 	    if (vobj_at(rx, ry)->otyp == STATUE) otmp = vobj_at(rx, ry);
175  | 	    if (otmp->otyp == CORPSE) {
176  | 		You("determine that %s unfortunate being is dead.",
177  | 		    (rx == u.ux && ry == u.uy) ? "this" : "that");
178  | 	    } else {
179  | 		ttmp = t_at(rx, ry);
180  | 		pline("%s appears to be in %s health for a statue.",
181  | 		      The(mons[otmp->corpsenm].mname),
182  | 		      (ttmp && ttmp->ttyp == STATUE_TRAP) ?
183  | 			"extraordinary" : "excellent");
184  | 	    }
185  | 	    return TRUE;
186  | 	}
187  | 	return FALSE;
188  | }
189  | 
190  | static char hollow_str[] = "a hollow sound.  This must be a secret %s!";
191  | 
192  | /* Strictly speaking it makes no sense for usage of a stethoscope to
193  |    not take any time; however, unless it did, the stethoscope would be
194  |    almost useless.  As a compromise, one use per turn is free, another
195  |    uses up the turn; this makes curse status have a tangible effect. */
196  | STATIC_OVL int
197  | use_stethoscope(obj)
198  | 	register struct obj *obj;
199  | {
200  | 	static long last_used = 0;
201  | 	struct monst *mtmp;
202  | 	struct rm *lev;
203  | 	int rx, ry, res;
204  | 
205  | 	if (nohands(youmonst.data)) {	/* should also check for no ears and/or deaf */
206  | 		You("have no hands!");	/* not `body_part(HAND)' */
207  | 		return 0;
208  | 	} else if (!freehand()) {
209  | 		You("have no free %s.", body_part(HAND));
210  | 		return 0;
211  | 	}
212  | 	if (!getdir((char *)0)) return 0;
213  | 
214  | 	res = (moves + monstermoves == last_used);
215  | 	last_used = moves + monstermoves;
216  | 
217  | 	if (u.uswallow && (u.dx || u.dy || u.dz)) {
218  | 		mstatusline(u.ustuck);
219  | 		return res;
220  | #ifdef STEED
221  | 	} else if (u.usteed && u.dz > 0) {
222  | 		mstatusline(u.usteed);
223  | 		return res;
224  | #endif
225  | 	} else if (u.dz) {
226  | 		if (Underwater)
227  | 		    You_hear("faint splashing.");
228  | 		else if (u.dz < 0 || !can_reach_floor())
229  | 		    You_cant("reach the %s.",
230  | 			(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
231  | 		else if (its_dead(u.ux, u.uy, &res))
232  | 		    ;	/* message already given */
233  | 		else if (Is_stronghold(&u.uz))
234  | 		    You_hear("the crackling of hellfire.");
235  | 		else
236  | 		    pline_The("%s seems healthy enough.", surface(u.ux,u.uy));
237  | 		return res;
238  | 	} else if (obj->cursed && !rn2(2)) {
239  | 		You_hear("your heart beat.");
240  | 		return res;
241  | 	}
242  | 	if (Stunned || (Confusion && !rn2(5))) confdir();
243  | 	if (!u.dx && !u.dy) {
244  | 		ustatusline();
245  | 		return res;
246  | 	}
247  | 	rx = u.ux + u.dx; ry = u.uy + u.dy;
248  | 	if (!isok(rx,ry)) {
249  | 		You_hear("a faint typing noise.");
250  | 		return 0;
251  | 	}
252  | 	if ((mtmp = m_at(rx,ry)) != 0) {
253  | 		mstatusline(mtmp);
254  | 		if (mtmp->mundetected) {
255  | 			mtmp->mundetected = 0;
256  | 			if (cansee(rx,ry)) newsym(mtmp->my,mtmp->my);
257  | 		}
258  | 		if (!canspotmon(mtmp))
259  | 			map_invisible(rx,ry);
260  | 		return res;
261  | 	}
262  | 	if (glyph_is_invisible(levl[rx][ry].glyph)) {
263  | 		unmap_object(rx, ry);
264  | 		newsym(rx, ry);
265  | 		pline_The("invisible monster must have moved.");
266  | 	}
267  | 	lev = &levl[rx][ry];
268  | 	switch(lev->typ) {
269  | 	case SDOOR:
270  | 		You_hear(hollow_str, "door");
271  | 		cvt_sdoor_to_door(lev);		/* ->typ = DOOR */
272  | 		if (Blind) feel_location(rx,ry);
273  | 		else newsym(rx,ry);
274  | 		return res;
275  | 	case SCORR:
276  | 		You_hear(hollow_str, "passage");
277  | 		lev->typ = CORR;
278  | 		if (Blind) feel_location(rx,ry);
279  | 		else newsym(rx,ry);
280  | 		return res;
281  | 	}
282  | 
283  | 	if (!its_dead(rx, ry, &res))
284  | 	    You("hear nothing special.");	/* not You_hear()  */
285  | 	return res;
286  | }
287  | 
288  | static char whistle_str[] = "produce a %s whistling sound.";
289  | 
290  | STATIC_OVL void
291  | use_whistle(obj)
292  | struct obj *obj;
293  | {
294  | 	You(whistle_str, obj->cursed ? "shrill" : "high");
295  | 	wake_nearby();
296  | }
297  | 
298  | STATIC_OVL void
299  | use_magic_whistle(obj)
300  | struct obj *obj;
301  | {
302  | 	register struct monst *mtmp, *nextmon;
303  | 
304  | 	if(obj->cursed && !rn2(2)) {
305  | 		You("produce a high-pitched humming noise.");
306  | 		wake_nearby();
307  | 	} else {
308  | 		int pet_cnt = 0;
309  | 		You(whistle_str, Hallucination ? "normal" : "strange");
310  | 		for(mtmp = fmon; mtmp; mtmp = nextmon) {
311  | 		    nextmon = mtmp->nmon; /* trap might kill mon */
312  | 		    if (DEADMONSTER(mtmp)) continue;
313  | 		    if (mtmp->mtame) {
314  | 			if (mtmp->mtrapped) {
315  | 			    /* no longer in previous trap (affects mintrap) */
316  | 			    mtmp->mtrapped = 0;
317  | 			    fill_pit(mtmp->mx, mtmp->my);
318  | 			}
319  | 			mnexto(mtmp);
320  | 			if (canspotmon(mtmp)) ++pet_cnt;
321  | 			if (mintrap(mtmp) == 2) change_luck(-1);
322  | 		    }
323  | 		}
324  | 		if (pet_cnt > 0) makeknown(MAGIC_WHISTLE);
325  | 	}
326  | }
327  | 
328  | boolean
329  | um_dist(x,y,n)
330  | register xchar x, y, n;
331  | {
332  | 	return((boolean)(abs(u.ux - x) > n  || abs(u.uy - y) > n));
333  | }
334  | 
335  | int
336  | number_leashed()
337  | {
338  | 	register int i = 0;
339  | 	register struct obj *obj;
340  | 
341  | 	for(obj = invent; obj; obj = obj->nobj)
342  | 		if(obj->otyp == LEASH && obj->leashmon != 0) i++;
343  | 	return(i);
344  | }
345  | 
346  | void
347  | o_unleash(otmp)		/* otmp is about to be destroyed or stolen */
348  | register struct obj *otmp;
349  | {
350  | 	register struct monst *mtmp;
351  | 
352  | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
353  | 		if(mtmp->m_id == (unsigned)otmp->leashmon)
354  | 			mtmp->mleashed = 0;
355  | 	otmp->leashmon = 0;
356  | }
357  | 
358  | void
359  | m_unleash(mtmp)		/* mtmp is about to die, or become untame */
360  | register struct monst *mtmp;
361  | {
362  | 	register struct obj *otmp;
363  | 
364  | 	for(otmp = invent; otmp; otmp = otmp->nobj)
365  | 		if(otmp->otyp == LEASH &&
366  | 				otmp->leashmon == (int)mtmp->m_id)
367  | 			otmp->leashmon = 0;
368  | 	mtmp->mleashed = 0;
369  | }
370  | 
371  | void
372  | unleash_all()		/* player is about to die (for bones) */
373  | {
374  | 	register struct obj *otmp;
375  | 	register struct monst *mtmp;
376  | 
377  | 	for(otmp = invent; otmp; otmp = otmp->nobj)
378  | 		if(otmp->otyp == LEASH) otmp->leashmon = 0;
379  | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
380  | 		if(mtmp->mtame) mtmp->mleashed = 0;
381  | }
382  | 
383  | #define MAXLEASHED	2
384  | 
385  | /* ARGSUSED */
386  | STATIC_OVL void
387  | use_leash(obj)
388  | struct obj *obj;
389  | {
390  | 	register int x, y;
391  | 	register struct monst *mtmp;
392  | 	int spotmon;
393  | 
394  | 	if(!obj->leashmon && number_leashed() >= MAXLEASHED) {
395  | 		You("cannot leash any more pets.");
396  | 		return;
397  | 	}
398  | 
399  | 	if(!getdir((char *)0)) return;
400  | 
401  | 	x = u.ux + u.dx;
402  | 	y = u.uy + u.dy;
403  | 
404  | 	if((x == u.ux) && (y == u.uy)) {
405  | 		pline("Leash yourself?  Very funny...");
406  | 		return;
407  | 	}
408  | 
409  | 	if(!(mtmp = m_at(x, y))) {
410  | 		There("is no creature there.");
411  | 		return;
412  | 	}
413  | 
414  | 	spotmon = canspotmon(mtmp);
415  | 
416  | 	if(!mtmp->mtame) {
417  | 	    if(!spotmon)
418  | 		There("is no creature there.");
419  | 	    else
420  | 		pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ?
421  | 				"cannot be" : "is not");
422  | 	    return;
423  | 	}
424  | 	if(!obj->leashmon) {
425  | 		if(mtmp->mleashed) {
426  | 			pline("This %s is already leashed.",
427  | 			      spotmon ? l_monnam(mtmp) : "monster");
428  | 			return;
429  | 		}
430  | 		You("slip the leash around %s%s.",
431  | 		    spotmon ? "your " : "", l_monnam(mtmp));
432  | 		mtmp->mleashed = 1;
433  | 		obj->leashmon = (int)mtmp->m_id;
434  | 		mtmp->msleeping = 0;
435  | 		return;
436  | 	}
437  | 	if(obj->leashmon != (int)mtmp->m_id) {
438  | 		pline("This leash is not attached to that creature.");
439  | 		return;
440  | 	} else {
441  | 		if(obj->cursed) {
442  | 			pline_The("leash would not come off!");
443  | 			obj->bknown = TRUE;
444  | 			return;
445  | 		}
446  | 		mtmp->mleashed = 0;
447  | 		obj->leashmon = 0;
448  | 		You("remove the leash from %s%s.",
449  | 		    spotmon ? "your " : "", l_monnam(mtmp));
450  | 	}
451  | 	return;
452  | }
453  | 
454  | struct obj *
455  | get_mleash(mtmp)	/* assuming mtmp->mleashed has been checked */
456  | register struct monst *mtmp;
457  | {
458  | 	register struct obj *otmp;
459  | 
460  | 	otmp = invent;
461  | 	while(otmp) {
462  | 		if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id)
463  | 			return(otmp);
464  | 		otmp = otmp->nobj;
465  | 	}
466  | 	return((struct obj *)0);
467  | }
468  | 
469  | #endif /* OVLB */
470  | #ifdef OVL1
471  | 
472  | boolean
473  | next_to_u()
474  | {
475  | 	register struct monst *mtmp;
476  | 	register struct obj *otmp;
477  | 
478  | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
479  | 		if (DEADMONSTER(mtmp)) continue;
480  | 		if(mtmp->mleashed) {
481  | 			if (distu(mtmp->mx,mtmp->my) > 2) mnexto(mtmp);
482  | 			if (distu(mtmp->mx,mtmp->my) > 2) {
483  | 			    for(otmp = invent; otmp; otmp = otmp->nobj)
484  | 				if(otmp->otyp == LEASH &&
485  | 					otmp->leashmon == (int)mtmp->m_id) {
486  | 				    if(otmp->cursed) return(FALSE);
487  | 				    You_feel("%s leash go slack.",
488  | 					(number_leashed() > 1) ? "a" : "the");
489  | 				    mtmp->mleashed = 0;
490  | 				    otmp->leashmon = 0;
491  | 				}
492  | 			}
493  | 		}
494  | 	}
495  | 	return(TRUE);
496  | }
497  | 
498  | #endif /* OVL1 */
499  | #ifdef OVL0
500  | 
501  | void
502  | check_leash(x, y)
503  | register xchar x, y;
504  | {
505  | 	register struct obj *otmp;
506  | 	register struct monst *mtmp = fmon;
507  | 
508  | 	for(otmp = invent; otmp; otmp = otmp->nobj)
509  | 	    if(otmp->otyp == LEASH && otmp->leashmon != 0) {
510  | 		while(mtmp) {
511  | 		    if(!DEADMONSTER(mtmp) && ((int)mtmp->m_id == otmp->leashmon &&
512  | 			    (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) >
513  | 				dist2(x,y,mtmp->mx,mtmp->my)))
514  | 			) {
515  | 			if(otmp->cursed && !breathless(mtmp->data)) {
516  | 			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
517  | 				pline("%s chokes to death!",Monnam(mtmp));
518  | 				mondied(mtmp);
519  | 			    } else
520  | 				if(um_dist(mtmp->mx, mtmp->my, 3))
521  | 					pline("%s chokes on the leash!",
522  | 						Monnam(mtmp));
523  | 			} else {
524  | 			    if(um_dist(mtmp->mx, mtmp->my, 5)) {
525  | 				pline("%s leash snaps loose!",
526  | 					s_suffix(Monnam(mtmp)));
527  | 				m_unleash(mtmp);
528  | 			    } else {
529  | 				if(um_dist(mtmp->mx, mtmp->my, 3)) {
530  | 				    You("pull on the leash.");
531  | 				    if (mtmp->data->msound != MS_SILENT)
532  | 					switch(rn2(3)) {
533  | 					    case 0:  growl(mtmp);	break;
534  | 					    case 1:  yelp(mtmp);	break;
535  | 					    default: whimper(mtmp); break;
536  | 					}
537  | 				}
538  | 			    }
539  | 			}
540  | 		    }
541  | 		    mtmp = mtmp->nmon;
542  | 		}
543  | 	    }
544  | }
545  | 
546  | #endif /* OVL0 */
547  | #ifdef OVLB
548  | 
549  | boolean
550  | wield_tool(obj)
551  | struct obj *obj;
552  | {
553  | 	if(welded(uwep)) {
554  | 		/* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */
555  | 		if(flags.verbose) {
556  | 			pline("Since your weapon is welded to your %s,",
557  | 				bimanual(uwep) ?
558  | 				(const char *)makeplural(body_part(HAND))
559  | 				: body_part(HAND));
560  | 			pline("you cannot wield that %s.", xname(obj));
561  | 		}
562  | 		return(FALSE);
563  | 	}
564  | 	if (cantwield(youmonst.data)) {
565  | 		You_cant("hold it strongly enough.");
566  | 		return(FALSE);
567  | 	}
568  | 	/* Check shield */
569  | 	if (uarms && bimanual(obj)) {
570  | 		You("cannot wield a two-handed tool while wearing a shield.");
571  | 		return(FALSE);
572  | 	}
573  | 	if(uquiver == obj) setuqwep((struct obj *)0);
574  | 	if(uswapwep == obj) {
575  | 	    (void) doswapweapon();
576  | 	    /* If doswapweapon failed... */
577  | 	    if(uswapwep == obj) return (FALSE);
578  | 	} else {
579  | 	    You("now wield %s.", doname(obj));
580  | 	    setuwep(obj);
581  | 	}
582  | 	if (uwep != obj) return(FALSE); /* rewielded old object after dying */
583  | 	/* applying weapon or tool that gets wielded ends two-weapon combat */
584  | 	if (u.twoweap)
585  | 		untwoweapon();
586  | 	if (obj->oclass != WEAPON_CLASS)
587  | 		unweapon = TRUE;
588  | 	return(TRUE);
589  | }
590  | 
591  | #define WEAK	3	/* from eat.c */
592  | 
593  | static char look_str[] = "look %s.";
594  | 
595  | STATIC_OVL int
596  | use_mirror(obj)
597  | struct obj *obj;
598  | {
599  | 	register struct monst *mtmp;
600  | 	register char mlet;
601  | 	boolean vis;
602  | 
603  | 	if(!getdir((char *)0)) return 0;
604  | 	if(obj->cursed && !rn2(2)) {
605  | 		if (!Blind)
606  | 			pline_The("mirror fogs up and doesn't reflect!");
607  | 		return 1;
608  | 	}
609  | 	if(!u.dx && !u.dy && !u.dz) {
610  | 		if(!Blind && !Invisible) {
611  | 		    if (u.umonnum == PM_FLOATING_EYE) {
612  | 			if (!Free_action) {
613  | 			pline(Hallucination ?
614  | 			      "Yow!  The mirror stares back!" :
615  | 			      "Yikes!  You've frozen yourself!");
616  | 			nomul(-rnd((MAXULEV+6) - u.ulevel));
617  | 			} else You("stiffen momentarily under your gaze.");
618  | 		    } else if (youmonst.data->mlet == S_VAMPIRE)
619  | 			You("don't have a reflection.");
620  | 		    else if (u.umonnum == PM_UMBER_HULK) {
621  | 			pline("Huh?  That doesn't look like you!");
622  | 			make_confused(HConfusion + d(3,4),FALSE);
623  | 		    } else if (Hallucination)
624  | 			You(look_str, hcolor((char *)0));
625  | 		    else if (Sick)
626  | 			You(look_str, "peaked");
627  | 		    else if (u.uhs >= WEAK)
628  | 			You(look_str, "undernourished");
629  | 		    else You("look as %s as ever.",
630  | 				ACURR(A_CHA) > 14 ?
631  | 				(poly_gender()==1 ? "beautiful" : "handsome") :
632  | 				"ugly");
633  | 		} else {
634  | 			You_cant("see your %s %s.",
635  | 				ACURR(A_CHA) > 14 ?
636  | 				(poly_gender()==1 ? "beautiful" : "handsome") :
637  | 				"ugly",
638  | 				body_part(FACE));
639  | 		}
640  | 		return 1;
641  | 	}
642  | 	if(u.uswallow) {
643  | 		if (!Blind) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
644  | 		    is_animal(u.ustuck->data)? "stomach" : "interior");
645  | 		return 1;
646  | 	}
647  | 	if(Underwater) {
648  | 		You(Hallucination ?
649  | 		    "give the fish a chance to fix their makeup." :
650  | 		    "reflect the murky water.");
651  | 		return 1;
652  | 	}
653  | 	if(u.dz) {
654  | 		if (!Blind)
655  | 		    You("reflect the %s.",
656  | 			(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
657  | 		return 1;
658  | 	}
659  | 	mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM,
660  | 		    (int FDECL((*),(MONST_P,OBJ_P)))0,
661  | 		    (int FDECL((*),(OBJ_P,OBJ_P)))0,
662  | 		    obj);
663  | 	if (!mtmp || !haseyes(mtmp->data))
664  | 		return 1;
665  | 
666  | 	vis = canseemon(mtmp);
667  | 	mlet = mtmp->data->mlet;
668  | 	if (mtmp->msleeping) {
669  | 		if (vis)
670  | 		    pline ("%s is too tired to look at your mirror.",
671  | 			    Monnam(mtmp));
672  | 	} else if (!mtmp->mcansee) {
673  | 	    if (vis)
674  | 		pline("%s can't see anything right now.", Monnam(mtmp));
675  | 	/* some monsters do special things */
676  | 	} else if (mlet == S_VAMPIRE || mlet == S_GHOST) {
677  | 	    if (vis)
678  | 		pline ("%s doesn't have a reflection.", Monnam(mtmp));
679  | 	} else if(!mtmp->mcan && mtmp->data == &mons[PM_MEDUSA]) {
680  | 		if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
681  | 			return 1;
682  | 		if (vis)
683  | 			pline("%s is turned to stone!", Monnam(mtmp));
684  | 		stoned = TRUE;
685  | 		killed(mtmp);
686  | 	} else if(!mtmp->mcan && !mtmp->minvis &&
687  | 					mtmp->data == &mons[PM_FLOATING_EYE]) {
688  | 		int tmp = d((int)mtmp->m_lev, (int)mtmp->data->mattk[0].damd);
689  | 		if (!rn2(4)) tmp = 120;
690  | 	/* Note: floating eyes cannot use their abilities while invisible,
691  | 	 * but Medusa and umber hulks can.
692  | 	 */
693  | 		if (vis)
694  | 			pline("%s is frozen by its reflection.", Monnam(mtmp));
695  | 		else You_hear("%s stop moving.",something);
696  | 		mtmp->mcanmove = 0;
697  | 		if ( (int) mtmp->mfrozen + tmp > 127)
698  | 			mtmp->mfrozen = 127;
699  | 		else mtmp->mfrozen += tmp;
700  | 	} else if(!mtmp->mcan && mtmp->data == &mons[PM_UMBER_HULK]) {
701  | 		if (vis)
702  | 			pline ("%s confuses itself!", Monnam(mtmp));
703  | 		mtmp->mconf = 1;
704  | 	} else if(!mtmp->mcan && !mtmp->minvis && (mlet == S_NYMPH
705  | 				     || mtmp->data==&mons[PM_SUCCUBUS])) {
706  | 		if (vis) {
707  | 		    pline ("%s admires herself in your mirror.", Monnam(mtmp));
708  | 		    pline ("She takes it!");
709  | 		} else pline ("It steals your mirror!");
710  | 		setnotworn(obj); /* in case mirror was wielded */
711  | 		freeinv(obj);
712  | 		(void) mpickobj(mtmp,obj);
713  | 		if (!tele_restrict(mtmp)) rloc(mtmp);
714  | 	} else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) &&
715  | 			(!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
716  | 		if (vis)
717  | 			pline ("%s is frightened by its reflection.",
718  | 				Monnam(mtmp));
719  | 		mtmp->mflee = 1;
720  | 		mtmp->mfleetim += d(2,4);
721  | 	} else if (!Blind) {
722  | 		if (mtmp->minvis && !See_invisible)
723  | 		    ;
724  | 		else if ((mtmp->minvis && !perceives(mtmp->data))
725  | 			 || !haseyes(mtmp->data))
726  | 		    pline("%s doesn't seem to notice its reflection.",
727  | 			Monnam(mtmp));
728  | 		else
729  | 		    pline("%s ignores %s reflection.",
730  | 			  Monnam(mtmp), his[pronoun_gender(mtmp)]);
731  | 	}
732  | 	return 1;
733  | }
734  | 
735  | STATIC_OVL void
736  | use_bell(obj)
737  | register struct obj *obj;
738  | {
739  | 	struct monst *mtmp;
740  | 	boolean wakem = FALSE, learno = FALSE,
741  | 		ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe),
742  | 		invoking = (obj->otyp == BELL_OF_OPENING &&
743  | 			 invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy));
744  | 
745  | 	You("ring %s.", the(xname(obj)));
746  | 
747  | 	if (Underwater || (u.uswallow && ordinary)) {
748  | #ifdef	AMIGA
749  | 	    amii_speaker( obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME );
750  | #endif
751  | 	    pline("But the sound is muffled.");
752  | 
753  | 	} else if (invoking && ordinary) {
754  | 	    /* needs to be recharged... */
755  | 	    pline("But it makes no sound.");
756  | 	    learno = TRUE;	/* help player figure out why */
757  | 
758  | 	} else if (ordinary) {
759  | #ifdef	AMIGA
760  | 	    amii_speaker( obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME );
761  | #endif
762  | 	    if (obj->cursed && !rn2(4) &&
763  | 		    /* note: once any of them are gone, we stop all of them */
764  | 		    !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) &&
765  | 		    !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) &&
766  | 		    !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) &&
767  | 		    (mtmp = makemon(mkclass(S_NYMPH, 0),
768  | 					u.ux, u.uy, NO_MINVENT)) != 0) {
769  | 		You("summon %s!", a_monnam(mtmp));
770  | 		if (!obj_resists(obj, 93, 100)) {
771  | 		    pline("%s has shattered!", The(xname(obj)));
772  | 		    useup(obj);
773  | 		} else switch (rn2(3)) {
774  | 			default:
775  | 				break;
776  | 			case 1: mon_adjust_speed(mtmp, 2);
777  | 				break;
778  | 			case 2: /* no explanation; it just happens... */
779  | 				nomovemsg = "";
780  | 				nomul(-rnd(2));
781  | 				break;
782  | 		}
783  | 	    }
784  | 	    wakem = TRUE;
785  | 
786  | 	} else {
787  | 	    /* charged Bell of Opening */
788  | 	    check_unpaid(obj);
789  | 	    obj->spe--;
790  | 
791  | 	    if (u.uswallow) {
792  | 		if (!obj->cursed)
793  | 		    (void) openit();
794  | 		else
795  | 		    pline(nothing_happens);
796  | 
797  | 	    } else if (obj->cursed) {
798  | 		coord mm;
799  | 
800  | 		mm.x = u.ux;
801  | 		mm.y = u.uy;
802  | 		mkundead(&mm, FALSE, NO_MINVENT);
803  | 		wakem = TRUE;
804  | 
805  | 	    } else  if (invoking) {
806  | 		pline("%s issues an unsettling shrill sound...",
807  | 		      The(xname(obj)));
808  | #ifdef	AMIGA
809  | 		amii_speaker( obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME );
810  | #endif
811  | 		obj->age = moves;
812  | 		learno = TRUE;
813  | 		wakem = TRUE;
814  | 
815  | 	    } else if (obj->blessed) {
816  | 		int res = 0;
817  | 
818  | #ifdef	AMIGA
819  | 		amii_speaker( obj, "ahahahDhEhCw", AMII_SOFT_VOLUME );
820  | #endif
821  | 		if (uchain) {
822  | 		    unpunish();
823  | 		    res = 1;
824  | 		}
825  | 		res += openit();
826  | 		switch (res) {
827  | 		  case 0:  pline(nothing_happens); break;
828  | 		  case 1:  pline("%s opens...", Something);
829  | 			   learno = TRUE; break;
830  | 		  default: pline("Things open around you...");
831  | 			   learno = TRUE; break;
832  | 		}
833  | 
834  | 	    } else {  /* uncursed */
835  | #ifdef	AMIGA
836  | 		amii_speaker( obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME );
837  | #endif
838  | 		if (findit() != 0) learno = TRUE;
839  | 		else pline(nothing_happens);
840  | 	    }
841  | 
842  | 	}	/* charged BofO */
843  | 
844  | 	if (learno) {
845  | 	    makeknown(BELL_OF_OPENING);
846  | 	    obj->known = 1;
847  | 	}
848  | 	if (wakem) wake_nearby();
849  | }
850  | 
851  | STATIC_OVL void
852  | use_candelabrum(obj)
853  | register struct obj *obj;
854  | {
855  | 	if(Underwater) {
856  | 		You("cannot make fire under water.");
857  | 		return;
858  | 	}
859  | 	if(obj->lamplit) {
860  | 		You("snuff the candle%s.", obj->spe > 1 ? "s" : "");
861  | 		end_burn(obj, TRUE);
862  | 		return;
863  | 	}
864  | 	if(obj->spe <= 0) {
865  | 		pline("This %s has no candles.", xname(obj));
866  | 		return;
867  | 	}
868  | 	if(u.uswallow || obj->cursed) {
869  | 		if (!Blind)
870  | 		    pline_The("candle%s flicker%s for a moment, then die%s.",
871  | 		    	obj->spe > 1 ? "s" : "",
872  | 		    	obj->spe > 1 ? "" : "s",
873  | 		    	obj->spe > 1 ? "" : "s");
874  | 		return;
875  | 	}
876  | 	if(obj->spe < 7) {
877  | 		There("%s only %d candle%s in %s.",
878  | 		       obj->spe == 1 ? "is" : "are",
879  | 		       obj->spe,
880  | 		       obj->spe > 1 ? "s" : "",
881  | 		       the(xname(obj)));
882  | 		if (!Blind)
883  | 		    pline("%s lit.  %s shines dimly.",
884  | 		       obj->spe == 1 ? "It is" : "They are", The(xname(obj)));
885  | 	} else {
886  | 		pline("%s's candles burn%s", The(xname(obj)),
887  | 			(Blind ? "." : " brightly!"));
888  | 	}
889  | 	if (!invocation_pos(u.ux, u.uy)) {
890  | 		pline_The("candle%s being rapidly consumed!",
891  | 			(obj->spe > 1 ? "s are" : " is"));
892  | 		obj->age /= 2;
893  | 	} else {
894  | 		if(obj->spe == 7) {
895  | 		    if (Blind)
896  | 		      pline("%s radiates a strange warmth!", The(xname(obj)));
897  | 		    else
898  | 		      pline("%s glows with a strange light!", The(xname(obj)));
899  | 		}
900  | 		obj->known = 1;
901  | 	}
902  | 	begin_burn(obj, FALSE);
903  | }
904  | 
905  | STATIC_OVL void
906  | use_candle(obj)
907  | register struct obj *obj;
908  | {
909  | 	register struct obj *otmp;
910  | 	char qbuf[QBUFSZ];
911  | 
912  | 	if(u.uswallow) {
913  | 		You(no_elbow_room);
914  | 		return;
915  | 	}
916  | 	if(Underwater) {
917  | 		pline("Sorry, fire and water don't mix.");
918  | 		return;
919  | 	}
920  | 
921  | 	otmp = carrying(CANDELABRUM_OF_INVOCATION);
922  | 	if(!otmp || otmp->spe == 7) {
923  | 		use_lamp(obj);
924  | 		return;
925  | 	}
926  | 
927  | 	Sprintf(qbuf, "Attach %s", the(xname(obj)));
928  | 	Sprintf(eos(qbuf), " to %s?", the(xname(otmp)));
929  | 	if(yn(qbuf) == 'n') {
930  | 		if (!obj->lamplit)
931  | 		    You("try to light %s...", the(xname(obj)));
932  | 		use_lamp(obj);
933  | 		return;
934  | 	} else {
935  | 		if ((long)otmp->spe + obj->quan > 7L)
936  | 		    (void)splitobj(obj, 7L - (long)otmp->spe);
937  | 		You("attach %ld%s candle%s to %s.",
938  | 		    obj->quan, !otmp->spe ? "" : " more",
939  | 		    plur(obj->quan), the(xname(otmp)));
940  | 		if (!otmp->spe || otmp->age > obj->age)
941  | 		    otmp->age = obj->age;
942  | 		otmp->spe += (int)obj->quan;
943  | 		if (otmp->lamplit && !obj->lamplit)
944  | 		    pline_The("new candle%s magically ignite%s!",
945  | 			      plur(obj->quan),
946  | 			      (obj->quan > 1L) ? "" : "s");
947  | 		else if (!otmp->lamplit && obj->lamplit)
948  | 		    pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
949  | 		if (obj->unpaid)
950  | 		    verbalize("You %s %s, you bought %s!",
951  | 			      otmp->lamplit ? "burn" : "use",
952  | 			      (obj->quan > 1L) ? "them" : "it",
953  | 			      (obj->quan > 1L) ? "them" : "it");
954  | 		if (obj->quan < 7L && otmp->spe == 7)
955  | 		    pline("%s now has seven%s candles attached.",
956  | 			  The(xname(otmp)), otmp->lamplit ? " lit" : "");
957  | 		/* candelabrum's light range might increase */
958  | 		if (otmp->lamplit) obj_merge_light_sources(otmp, otmp);
959  | 		/* candles are no longer a separate light source */
960  | 		if (obj->lamplit) end_burn(obj, TRUE);
961  | 		/* candles are now gone */
962  | 		useupall(obj);
963  | 	}
964  | }
965  | 
966  | boolean
967  | snuff_candle(otmp)  /* call in drop, throw, and put in box, etc. */
968  | register struct obj *otmp;
969  | {
970  | 	register boolean candle = Is_candle(otmp);
971  | 
972  | 	if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) &&
973  | 		otmp->lamplit) {
974  | 	    char buf[BUFSZ];
975  | 	    xchar x, y;
976  | 	    register boolean many = candle ? otmp->quan > 1L : otmp->spe > 1;
977  | 
978  | 	    (void) get_obj_location(otmp, &x, &y, 0);
979  | 	    if (otmp->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
980  | 		pline("%s %scandle%s flame%s extinguished.",
981  | 		      Shk_Your(buf, otmp),
982  | 		      (candle ? "" : "candelabrum's "),
983  | 		      (many ? "s'" : "'s"), (many ? "s are" : " is"));
984  | 	   end_burn(otmp, TRUE);
985  | 	   return(TRUE);
986  | 	}
987  | 	return(FALSE);
988  | }
989  | 
990  | /* called when lit lamp is hit by water or put into a container or
991  |    you've been swallowed by a monster; obj might be in transit while
992  |    being thrown or dropped so don't assume that its location is valid */
993  | boolean
994  | snuff_lit(obj)
995  | struct obj *obj;
996  | {
997  | 	xchar x, y;
998  | 
999  | 	if (obj->lamplit) {
1000 | 	    if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
1001 | 		    obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) {
1002 | 		(void) get_obj_location(obj, &x, &y, 0);
1003 | 		if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind)
1004 | 		    pline("%s goes out!", Yname2(obj));
1005 | 		end_burn(obj, TRUE);
1006 | 		return TRUE;
1007 | 	    }
1008 | 	    if (snuff_candle(obj)) return TRUE;
1009 | 	}
1010 | 	return FALSE;
1011 | }
1012 | 
1013 | STATIC_OVL void
1014 | use_lamp(obj)
1015 | struct obj *obj;
1016 | {
1017 | 	char buf[BUFSZ];
1018 | 
1019 | 	if(Underwater) {
1020 | 		pline("This is not a diving lamp.");
1021 | 		return;
1022 | 	}
1023 | 	if(obj->lamplit) {
1024 | 		if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
1025 | 				obj->otyp == BRASS_LANTERN)
1026 | 		    pline("%s lamp is now off.", Shk_Your(buf, obj));
1027 | 		else
1028 | 		    You("snuff out %s.", yname(obj));
1029 | 		end_burn(obj, TRUE);
1030 | 		return;
1031 | 	}
1032 | 	/* magic lamps with an spe == 0 (wished for) cannot be lit */
1033 | 	if ((!Is_candle(obj) && obj->age == 0)
1034 | 			|| (obj->otyp == MAGIC_LAMP && obj->spe == 0)) {
1035 | 		if (obj->otyp == BRASS_LANTERN)
1036 | 			Your("lamp has run out of power.");
1037 | 		else pline("This %s has no oil.", xname(obj));
1038 | 		return;
1039 | 	}
1040 | 	if (obj->cursed && !rn2(2)) {
1041 | 		pline("%s flicker%s for a moment, then die%s.",
1042 | 		       The(xname(obj)),
1043 | 		       obj->quan > 1L ? "" : "s",
1044 | 		       obj->quan > 1L ? "" : "s");
1045 | 	} else {
1046 | 		if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
1047 | 				obj->otyp == BRASS_LANTERN) {
1048 | 		    check_unpaid(obj);
1049 | 		    pline("%s lamp is now on.", Shk_Your(buf, obj));
1050 | 		} else {	/* candle(s) */
1051 | 		    pline("%s flame%s burn%s%s",
1052 | 			s_suffix(Yname2(obj)),
1053 | 			plur(obj->quan),
1054 | 			obj->quan > 1L ? "" : "s",
1055 | 			Blind ? "." : " brightly!");
1056 | 		    if (obj->unpaid && costly_spot(u.ux, u.uy) &&
1057 | 			  obj->age == 20L * (long)objects[obj->otyp].oc_cost) {
1058 | 			const char *ithem = obj->quan > 1L ? "them" : "it";
1059 | 			verbalize("You burn %s, you bought %s!", ithem, ithem);
1060 | 			bill_dummy_object(obj);
1061 | 		    }
1062 | 		}
1063 | 		begin_burn(obj, FALSE);
1064 | 	}
1065 | }
1066 | 
1067 | STATIC_OVL void
1068 | light_cocktail(obj)
1069 | 	struct obj *obj;	/* obj is a potion of oil */
1070 | {
1071 | 	char buf[BUFSZ];
1072 | 
1073 | 	if (u.uswallow) {
1074 | 	    You(no_elbow_room);
1075 | 	    return;
1076 | 	}
1077 | 
1078 | 	if (obj->lamplit) {
1079 | 	    You("snuff the lit potion.");
1080 | 	    end_burn(obj, TRUE);
1081 | 	    /*
1082 | 	     * Free & add to re-merge potion.  This will average the
1083 | 	     * age of the potions.  Not exactly the best solution,
1084 | 	     * but its easy.
1085 | 	     */
1086 | 	    freeinv(obj);
1087 | 	    (void) addinv(obj);
1088 | 	    return;
1089 | 	} else if (Underwater) {
1090 | 	    There("is not enough oxygen to sustain a fire.");
1091 | 	    return;
1092 | 	}
1093 | 
1094 | 	You("light %s potion.%s", shk_your(buf, obj),
1095 | 	    Blind ? "" : "  It gives off a dim light.");
1096 | 	if (obj->unpaid && costly_spot(u.ux, u.uy)) {
1097 | 	    /* Normally, we shouldn't both partially and fully charge
1098 | 	     * for an item, but (Yendorian Fuel) Taxes are inevitable...
1099 | 	     */
1100 | 	    check_unpaid(obj);
1101 | 	    bill_dummy_object(obj);
1102 | 	}
1103 | 	makeknown(obj->otyp);
1104 | 
1105 | 	if (obj->quan > 1L) {
1106 | 	    (void) splitobj(obj, 1L);
1107 | 	    begin_burn(obj, FALSE);	/* burn before free to get position */
1108 | 	    obj_extract_self(obj);	/* free from inv */
1109 | 
1110 | 	    /* shouldn't merge */
1111 | 	    obj = hold_another_object(obj, "You drop %s!",
1112 | 				      doname(obj), (const char *)0);
1113 | 	} else
1114 | 	    begin_burn(obj, FALSE);
1115 | }
1116 | 
1117 | static NEARDATA const char cuddly[] = { TOOL_CLASS, 0 };
1118 | 
1119 | int
1120 | dorub()
1121 | {
1122 | 	struct obj *obj = getobj(cuddly, "rub");
1123 | 
1124 | 	if(!obj || (obj != uwep && !wield_tool(obj))) return 0;
1125 | 
1126 | 	/* now uwep is obj */
1127 | 	if (uwep->otyp == MAGIC_LAMP) {
1128 | 	    if (uwep->spe > 0 && !rn2(3)) {
1129 | 		check_unpaid_usage(uwep, TRUE);		/* unusual item use */
1130 | 		djinni_from_bottle(uwep);
1131 | 		makeknown(MAGIC_LAMP);
1132 | 		uwep->otyp = OIL_LAMP;
1133 | 		uwep->spe = 0; /* for safety */
1134 | 		uwep->age = rn1(500,1000);
1135 | 		if (uwep->lamplit) begin_burn(uwep, TRUE);
1136 | 	    } else if (rn2(2) && !Blind)
1137 | 		You("see a puff of smoke.");
1138 | 	    else pline(nothing_happens);
1139 | 	} else if (obj->otyp == BRASS_LANTERN) {
1140 | 	    /* message from Adventure */
1141 | 	    pline("Rubbing the electric lamp is not particularly rewarding.");
1142 | 	    pline("Anyway, nothing exciting happens.");
1143 | 	} else pline(nothing_happens);
1144 | 	return 1;
1145 | }
1146 | 
1147 | int
1148 | dojump()
1149 | {
1150 | 	/* Physical jump */
1151 | 	return jump(0);
1152 | }
1153 | 
1154 | int
1155 | jump(magic)
1156 | int magic; /* 0=Physical, otherwise skill level */
1157 | {
1158 | 	coord cc;
1159 | 
1160 | 	if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) {
1161 | 		/* normally (nolimbs || slithy) implies !Jumping,
1162 | 		   but that isn't necessarily the case for knights */
1163 | 		You_cant("jump; you have no legs!");
1164 | 		return 0;
1165 | 	} else if (!magic && !Jumping) {
1166 | 		You_cant("jump very far.");
1167 | 		return 0;
1168 | 	} else if (u.uswallow) {
1169 | 		if (magic) {
1170 | 			You("bounce around a little.");
1171 | 			return 1;
1172 | 		}
1173 | 		pline("You've got to be kidding!");
1174 | 		return 0;
1175 | 	} else if (u.uinwater) {
1176 | 		if (magic) {
1177 | 			You("swish around a little.");
1178 | 			return 1;
1179 | 		}
1180 | 		pline("This calls for swimming, not jumping!");
1181 | 		return 0;
1182 | 	} else if (u.ustuck) {
1183 | 		if (magic) {
1184 | 			You("writhe a little in the grasp of %s!", mon_nam(u.ustuck));
1185 | 			return 1;
1186 | 		}
1187 | 		You("cannot escape from %s!", mon_nam(u.ustuck));
1188 | 		return 0;
1189 | 	} else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
1190 | 		if (magic) {
1191 | 			You("flail around a little.");
1192 | 			return 1;
1193 | 		}
1194 | 		You("don't have enough traction to jump.");
1195 | 		return 0;
1196 | 	} else if (!magic && near_capacity() > UNENCUMBERED) {
1197 | 		You("are carrying too much to jump!");
1198 | 		return 0;
1199 | 	} else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) {
1200 | 		You("lack the strength to jump!");
1201 | 		return 0;
1202 | 	} else if (Wounded_legs) {
1203 | 		long wl = (Wounded_legs & BOTH_SIDES);
1204 | 		const char *bp = body_part(LEG);
1205 | 
1206 | 		if (wl == BOTH_SIDES) bp = makeplural(bp);
1207 | #ifdef STEED
1208 | 		if (u.usteed)
1209 | 	 	    pline("%s is in no shape for jumping.", Monnam(u.usteed));
1210 | 		else
1211 | #endif
1212 | 		Your("%s%s %s in no shape for jumping.",
1213 | 		     (wl == LEFT_SIDE) ? "left " :
1214 | 			(wl == RIGHT_SIDE) ? "right " : "",
1215 | 		     bp, (wl == BOTH_SIDES) ? "are" : "is");
1216 | 		return 0;
1217 | 	}
1218 | #ifdef STEED
1219 | 	else if (u.usteed && u.utrap) {
1220 | 		pline("%s is stuck in a trap.", Monnam(u.usteed));
1221 | 		return (0);
1222 | 	}
1223 | #endif
1224 | 
1225 | 	pline("Where do you want to jump?");
1226 | 	cc.x = u.ux;
1227 | 	cc.y = u.uy;
1228 | 	if (getpos(&cc, TRUE, "the desired position") < 0)
1229 | 		return 0;	/* user pressed ESC */
1230 | 	if (!magic && !(HJumping & ~INTRINSIC) && !EJumping &&
1231 | 			distu(cc.x, cc.y) != 5) {
1232 | 		/* The Knight jumping restriction still applies when riding a
1233 | 		 * horse.  After all, what shape is the knight piece in chess?
1234 | 		 */
1235 | 		pline("Illegal move!");
1236 | 		return 0;
1237 | 	} else if (distu(cc.x, cc.y) > (magic ? 6+magic*3 : 9)) {
1238 | 		pline("Too far!");
1239 | 		return 0;
1240 | 	} else if (!cansee(cc.x, cc.y)) {
1241 | 		You("cannot see where to land!");
1242 | 		return 0;
1243 | 	} else if (!isok(cc.x, cc.y)) {
1244 | 		You("cannot jump there!");
1245 | 		return 0;
1246 | 	} else {
1247 | 	    coord uc;
1248 | 	    int range, temp;
1249 | 
1250 | 	    if(u.utrap)
1251 | 		switch(u.utraptype) {
1252 | 		case TT_BEARTRAP: {
1253 | 		    register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
1254 | 		    You("rip yourself free of the bear trap!  Ouch!");
1255 | 		    losehp(rnd(10), "jumping out of a bear trap", KILLED_BY);
1256 | 		    set_wounded_legs(side, rn1(1000,500));
1257 | 		    break;
1258 | 		  }
1259 | 		case TT_PIT:
1260 | 		    You("leap from the pit!");
1261 | 		    break;
1262 | 		case TT_WEB:
1263 | 		    You("tear the web apart as you pull yourself free!");
1264 | 		    deltrap(t_at(u.ux,u.uy));
1265 | 		    break;
1266 | 		case TT_LAVA:
1267 | 		    You("pull yourself above the lava!");
1268 | 		    u.utrap = 0;
1269 | 		    return 1;
1270 | 		case TT_INFLOOR:
1271 | 		    You("strain your %s, but you're still stuck in the floor.",
1272 | 			makeplural(body_part(LEG)));
1273 | 		    set_wounded_legs(LEFT_SIDE, rn1(10, 11));
1274 | 		    set_wounded_legs(RIGHT_SIDE, rn1(10, 11));
1275 | 		    return 1;
1276 | 		}
1277 | 
1278 | 	    /*
1279 | 	     * Check the path from uc to cc, calling hurtle_step at each
1280 | 	     * location.  The final position actually reached will be
1281 | 	     * in cc.
1282 | 	     */
1283 | 	    uc.x = u.ux;
1284 | 	    uc.y = u.uy;
1285 | 	    /* calculate max(abs(dx), abs(dy)) as the range */
1286 | 	    range = cc.x - uc.x;
1287 | 	    if (range < 0) range = -range;
1288 | 	    temp = cc.y - uc.y;
1289 | 	    if (temp < 0) temp = -temp;
1290 | 	    if (range < temp)
1291 | 		range = temp;
1292 | 	    (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range);
1293 | 
1294 | 	    /* A little Sokoban guilt... */
1295 | 	    if (In_sokoban(&u.uz))
1296 | 		change_luck(-1);
1297 | 
1298 | 	    teleds(cc.x, cc.y);
1299 | 	    nomul(-1);
1300 | 	    nomovemsg = "";
1301 | 	    morehungry(rnd(25));
1302 | 	    return 1;
1303 | 	}
1304 | }
1305 | 
1306 | boolean
1307 | tinnable(corpse)
1308 | struct obj *corpse;
1309 | {
1310 | 	if (corpse->oeaten) return 0;
1311 | 	if (!mons[corpse->corpsenm].cnutrit) return 0;
1312 | 	return 1;
1313 | }
1314 | 
1315 | STATIC_OVL void
1316 | use_tinning_kit(obj)
1317 | register struct obj *obj;
1318 | {
1319 | 	register struct obj *corpse, *can;
1320 | 
1321 | 	/* This takes only 1 move.  If this is to be changed to take many
1322 | 	 * moves, we've got to deal with decaying corpses...
1323 | 	 */
1324 | 	if (obj->spe <= 0) {
1325 | 		You("seem to be out of tins.");
1326 | 		return;
1327 | 	}
1328 | 	if (!(corpse = floorfood("tin", 2))) return;
1329 | 	if (corpse->oeaten) {
1330 | 		You("cannot tin %s which is partly eaten.",something);
1331 | 		return;
1332 | 	}
1333 | 	if (touch_petrifies(&mons[corpse->corpsenm])
1334 | 		&& !Stone_resistance && !uarmg) {
1335 | 	    char kbuf[BUFSZ];
1336 | 
1337 | 	    if (poly_when_stoned(youmonst.data))
1338 | 		You("tin %s without wearing gloves.",
1339 | 			an(mons[corpse->corpsenm].mname));
1340 | 	    else {
1341 | 		pline("Tinning %s without wearing gloves is a fatal mistake...",
1342 | 			an(mons[corpse->corpsenm].mname));
1343 | 		Sprintf(kbuf, "trying to tin %s without gloves",
1344 | 			an(mons[corpse->corpsenm].mname));
1345 | 	    }
1346 | 	    instapetrify(kbuf);
1347 | 	}
1348 | 	if (is_rider(&mons[corpse->corpsenm])) {
1349 | 		(void) revive_corpse(corpse);
1350 | 		verbalize("Yes...  But War does not preserve its enemies...");
1351 | 		return;
1352 | 	}
1353 | 	if (mons[corpse->corpsenm].cnutrit == 0) {
1354 | 		pline("That's too insubstantial to tin.");
1355 | 		return;
1356 | 	}
1357 | 	obj->spe--;
1358 | 	if ((can = mksobj(TIN, FALSE, FALSE)) != 0) {
1359 | 	    static const char you_buy_it[] = "You tin it, you bought it!";
1360 | 
1361 | 	    can->corpsenm = corpse->corpsenm;
1362 | 	    can->cursed = obj->cursed;
1363 | 	    can->blessed = obj->blessed;
1364 | 	    can->owt = weight(can);
1365 | 	    can->known = 1;
1366 | 	    can->spe = -1;  /* Mark tinned tins. No spinach allowed... */
1367 | 	    if (carried(corpse)) {
1368 | 		if (corpse->unpaid)
1369 | 		    verbalize(you_buy_it);
1370 | 		useup(corpse);
1371 | 	    } else {
1372 | 		if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
1373 | 		    verbalize(you_buy_it);
1374 | 		useupf(corpse, 1L);
1375 | 	    }
1376 | 	    can = hold_another_object(can, "You make, but cannot pick up, %s.",
1377 | 				      doname(can), (const char *)0);
1378 | 	} else impossible("Tinning failed.");
1379 | }
1380 | 
1381 | void
1382 | use_unicorn_horn(obj)
1383 | struct obj *obj;
1384 | {
1385 | #define PROP_COUNT 6		/* number of properties we're dealing with */
1386 | #define ATTR_COUNT (A_MAX*3)	/* number of attribute points we might fix */
1387 | 	int idx, val, val_limit,
1388 | 	    trouble_count, unfixable_trbl, did_prop, did_attr;
1389 | 	int trouble_list[PROP_COUNT + ATTR_COUNT];
1390 | 
1391 | 	if (obj && obj->cursed) {
1392 | 	    long lcount = (long) rnd(100);
1393 | 
1394 | 	    switch (rn2(6)) {
1395 | 	    case 0: make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON),20),
1396 | 			xname(obj), TRUE, SICK_NONVOMITABLE);
1397 | 		    break;
1398 | 	    case 1: make_blinded(Blinded + lcount, TRUE);
1399 | 		    break;
1400 | 	    case 2: if (!Confusion)
1401 | 			You("suddenly feel %s.",
1402 | 			    Hallucination ? "trippy" : "confused");
1403 | 		    make_confused(HConfusion + lcount, TRUE);
1404 | 		    break;
1405 | 	    case 3: make_stunned(HStun + lcount, TRUE);
1406 | 		    break;
1407 | 	    case 4: (void) adjattrib(rn2(A_MAX), -1, FALSE);
1408 | 		    break;
1409 | 	    case 5: make_hallucinated(HHallucination + lcount, TRUE, 0L);
1410 | 		    break;
1411 | 	    }
1412 | 	    return;
1413 | 	}
1414 | 
1415 | /*
1416 |  * Entries in the trouble list use a very simple encoding scheme.
1417 |  */
1418 | #define prop2trbl(X)	((X) + A_MAX)
1419 | #define attr2trbl(Y)	(Y)
1420 | #define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X)
1421 | #define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y)
1422 | 
1423 | 	trouble_count = unfixable_trbl = did_prop = did_attr = 0;
1424 | 
1425 | 	/* collect property troubles */
1426 | 	if (Sick) prop_trouble(SICK);
1427 | 	if (Blinded > (long)(u.ucreamed + 1)) prop_trouble(BLINDED);
1428 | 	if (HHallucination) prop_trouble(HALLUC);
1429 | 	if (Vomiting) prop_trouble(VOMITING);
1430 | 	if (HConfusion) prop_trouble(CONFUSION);
1431 | 	if (HStun) prop_trouble(STUNNED);
1432 | 	/* keep track of unfixed trouble, for message adjustment below
1433 | 	   (can't "feel great" with these problems present) */
1434 | 	if (Stoned) unfixable_trbl++;
1435 | 	if (Strangled) unfixable_trbl++;
1436 | 	if (Wounded_legs) unfixable_trbl++;
1437 | 
1438 | 	/* collect attribute troubles */
1439 | 	for (idx = 0; idx < A_MAX; idx++) {
1440 | 	    val_limit = AMAX(idx);
1441 | 	    /* don't recover strength lost from hunger */
1442 | 	    if (idx == A_STR && u.uhs >= WEAK) val_limit--;
1443 | 	    /* don't recover more than 3 points worth of any attribute */
1444 | 	    if (val_limit > ABASE(idx) + 3) val_limit = ABASE(idx) + 3;
1445 | 
1446 | 	    for (val = ABASE(idx); val < val_limit; val++)
1447 | 		attr_trouble(idx);
1448 | 	    /* keep track of unfixed trouble, for message adjustment below */
1449 | 	    unfixable_trbl += (AMAX(idx) - val_limit);
1450 | 	}
1451 | 
1452 | 	if (trouble_count == 0) {
1453 | 	    pline(nothing_happens);
1454 | 	    return;
1455 | 	} else if (trouble_count > 1) {		/* shuffle */
1456 | 	    int i, j, k;
1457 | 
1458 | 	    for (i = trouble_count - 1; i > 0; i--)
1459 | 		if ((j = rn2(i + 1)) != i) {
1460 | 		    k = trouble_list[j];
1461 | 		    trouble_list[j] = trouble_list[i];
1462 | 		    trouble_list[i] = k;
1463 | 		}
1464 | 	}
1465 | 
1466 | 	/*
1467 | 	 *		Chances for number of troubles to be fixed
1468 | 	 *		 0	1      2      3      4	    5	   6	  7
1469 | 	 *   blessed:  22.7%  22.7%  19.5%  15.4%  10.7%   5.7%   2.6%	 0.8%
1470 | 	 *  uncursed:  35.4%  35.4%  22.9%   6.3%    0	    0	   0	  0
1471 | 	 */
1472 | 	val_limit = rn2( d(2, (obj && obj->blessed) ? 4 : 2) );
1473 | 	if (val_limit > trouble_count) val_limit = trouble_count;
1474 | 
1475 | 	/* fix [some of] the troubles */
1476 | 	for (val = 0; val < val_limit; val++) {
1477 | 	    idx = trouble_list[val];
1478 | 
1479 | 	    switch (idx) {
1480 | 	    case prop2trbl(SICK):
1481 | 		make_sick(0L, (char *) 0, TRUE, SICK_ALL);
1482 | 		did_prop++;
1483 | 		break;
1484 | 	    case prop2trbl(BLINDED):
1485 | 		make_blinded(u.ucreamed ? (long)(u.ucreamed+1) : 0L, TRUE);
1486 | 		did_prop++;
1487 | 		break;
1488 | 	    case prop2trbl(HALLUC):
1489 | 		make_hallucinated(0L, TRUE, 0L);
1490 | 		did_prop++;
1491 | 		break;
1492 | 	    case prop2trbl(VOMITING):
1493 | 		make_vomiting(0L, TRUE);
1494 | 		did_prop++;
1495 | 		break;
1496 | 	    case prop2trbl(CONFUSION):
1497 | 		make_confused(0L, TRUE);
1498 | 		did_prop++;
1499 | 		break;
1500 | 	    case prop2trbl(STUNNED):
1501 | 		make_stunned(0L, TRUE);
1502 | 		did_prop++;
1503 | 		break;
1504 | 	    default:
1505 | 		if (idx >= 0 && idx < A_MAX) {
1506 | 		    ABASE(idx) += 1;
1507 | 		    did_attr++;
1508 | 		} else
1509 | 		    panic("use_unicorn_horn: bad trouble? (%d)", idx);
1510 | 		break;
1511 | 	    }
1512 | 	}
1513 | 
1514 | 	if (did_attr)
1515 | 	    pline("This makes you feel %s!",
1516 | 		  (did_prop + did_attr) == (trouble_count + unfixable_trbl) ?
1517 | 		  "great" : "better");
1518 | 	else if (!did_prop)
1519 | 	    pline("Nothing seems to happen.");
1520 | 
1521 | 	flags.botl = (did_attr || did_prop);
1522 | #undef PROP_COUNT
1523 | #undef ATTR_COUNT
1524 | #undef prop2trbl
1525 | #undef attr2trbl
1526 | #undef prop_trouble
1527 | #undef attr_trouble
1528 | }
1529 | 
1530 | /*
1531 |  * Timer callback routine: turn figurine into monster
1532 |  */
1533 | void
1534 | fig_transform(arg, timeout)
1535 | genericptr_t arg;
1536 | long timeout;
1537 | {
1538 | 	struct obj *figurine = (struct obj *)arg;
1539 | 	struct monst *mtmp;
1540 | 	coord cc;
1541 | 	boolean cansee_spot, silent, okay_spot;
1542 | 	boolean redraw = FALSE;
1543 | 	char monnambuf[BUFSZ], carriedby[BUFSZ];
1544 | 
1545 | 	if (!figurine) {
1546 | #ifdef DEBUG
1547 | 	    pline("null figurine in fig_transform()");
1548 | #endif
1549 | 	    return;
1550 | 	}
1551 | 	silent = (timeout != monstermoves); /* happened while away */
1552 | 	okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0);
1553 | 	if (figurine->where == OBJ_INVENT ||
1554 | 	    figurine->where == OBJ_MINVENT) 
1555 | 	        okay_spot = enexto(&cc, cc.x, cc.y,
1556 | 				   &mons[figurine->corpsenm]);
1557 | 	if (!okay_spot ||
1558 | 	    !figurine_location_checks(figurine,&cc, TRUE)) {
1559 | 	    	/* reset the timer to try again later */
1560 | 		(void) start_timer((long)rnd(5000), TIMER_OBJECT,
1561 | 				FIG_TRANSFORM, (genericptr_t)figurine);
1562 | 		return;
1563 | 	}
1564 | 	
1565 | 	cansee_spot = cansee(cc.x, cc.y);
1566 | 	mtmp = make_familiar(figurine, cc.x, cc.y, TRUE);
1567 | 	if (mtmp) {
1568 | 	    Sprintf(monnambuf, "%s",a_monnam(mtmp));
1569 | 	    switch (figurine->where) {
1570 | 		case OBJ_INVENT:
1571 | 		    if (Blind)
1572 | 			You_feel("%s %s from your pack!", something,
1573 | 			    locomotion(mtmp->data,"drop"));
1574 | 		    else
1575 | 			You("see %s %s out of your pack!",
1576 | 			    monnambuf,
1577 | 			    locomotion(mtmp->data,"drop"));
1578 | 		    break;
1579 | 
1580 | 		case OBJ_FLOOR:
1581 | 		    if (cansee_spot && !silent) {
1582 | 			You("suddenly see a figurine transform into %s!",
1583 | 				monnambuf);
1584 | 			redraw = TRUE;	/* update figurine's map location */
1585 | 		    }
1586 | 		    break;
1587 | 
1588 | 		case OBJ_MINVENT:
1589 | 		    if (cansee_spot && !silent) {
1590 | 		    	struct monst *mon;
1591 | 		    	mon = figurine->ocarry;
1592 | 			/* figurine carring monster might be invisible */
1593 | 			if (canseemon(figurine->ocarry)) {
1594 | 			    Sprintf(carriedby, "%s pack",
1595 | 				     s_suffix(a_monnam(mon)));
1596 | 			}
1597 | 			else if (is_pool(mon->mx, mon->my))
1598 | 			    Strcpy(carriedby, "empty water");
1599 | 			else
1600 | 			    Strcpy(carriedby, "thin air");
1601 | 			You("see %s %s out of %s!", monnambuf,
1602 | 			    locomotion(mtmp->data, "drop"), carriedby);
1603 | 		    }
1604 | 		    break;
1605 | #if 0
1606 | 		case OBJ_MIGRATING:
1607 | 		    break;
1608 | #endif
1609 | 
1610 | 		default:
1611 | 		    impossible("figurine came to life where? (%d)",
1612 | 				(int)figurine->where);
1613 | 		break;
1614 | 	    }
1615 | 	}
1616 | 	/* free figurine now */
1617 | 	obj_extract_self(figurine);
1618 | 	obfree(figurine, (struct obj *)0);
1619 | 	if (redraw) newsym(cc.x, cc.y);
1620 | }
1621 | 
1622 | STATIC_OVL boolean
1623 | figurine_location_checks(obj, cc, quietly)
1624 | struct obj *obj;
1625 | coord *cc;
1626 | boolean quietly;
1627 | {
1628 | 	xchar x,y;
1629 | 	
1630 | 	x = cc->x; y = cc->y;
1631 | 	if (!isok(x,y)) {
1632 | 		if (!quietly)
1633 | 			You("cannot put the figurine there.");
1634 | 		return FALSE;
1635 | 	}
1636 | 	if (IS_ROCK(levl[x][y].typ) &&
1637 | 	    !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x,y))) {
1638 | 		if (!quietly)
1639 | 			You("cannot place a figurine in solid rock!");
1640 | 		return FALSE;
1641 | 	}
1642 | 	if (sobj_at(BOULDER,x,y) && !passes_walls(&mons[obj->corpsenm])
1643 | 			&& !throws_rocks(&mons[obj->corpsenm])) {
1644 | 		if (!quietly)
1645 | 			You("cannot fit the figurine on the boulder.");
1646 | 		return FALSE;
1647 | 	}
1648 | 	return TRUE;
1649 | }
1650 | 
1651 | STATIC_OVL void
1652 | use_figurine(obj)
1653 | register struct obj *obj;
1654 | {
1655 | 	xchar x, y;
1656 | 	coord cc;
1657 | 	
1658 | 	if(!getdir((char *)0)) {
1659 | 		flags.move = multi = 0;
1660 | 		return;
1661 | 	}
1662 | 	x = u.ux + u.dx; y = u.uy + u.dy;
1663 | 	cc.x = x; cc.y = y;
1664 | 	/* Passing FALSE arg here will result in messages displayed */
1665 | 	if (!figurine_location_checks(obj, &cc, FALSE)) return;
1666 | 	You("%s and it transforms.",
1667 | 	    (u.dx||u.dy) ? "set the figurine beside you" :
1668 | 	    (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) ?
1669 | 		"release the figurine" :
1670 | 	    (u.dz < 0 ?
1671 | 		"toss the figurine into the air" :
1672 | 		"set the figurine on the ground"));
1673 | 	(void) make_familiar(obj, u.ux+u.dx, u.uy+u.dy, FALSE);
1674 | 	(void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj);
1675 | 	useup(obj);
1676 | }
1677 | 
1678 | static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 };
1679 | static NEARDATA const char need_to_remove_outer_armor[] =
1680 | 			"need to remove your %s to grease your %s.";
1681 | 
1682 | STATIC_OVL void
1683 | use_grease(obj)
1684 | struct obj *obj;
1685 | {
1686 | 	struct obj *otmp;
1687 | 	char buf[BUFSZ];
1688 | 
1689 | 	if (Glib) {
1690 | 	    dropx(obj);
1691 | 	    pline("%s slips from your %s.", The(xname(obj)),
1692 | 		  makeplural(body_part(FINGER)));
1693 | 	    return;
1694 | 	}
1695 | 
1696 | 	if (obj->spe > 0) {
1697 | 		if ((obj->cursed || Fumbling) && !rn2(2)) {
1698 | 			check_unpaid(obj);
1699 | 			obj->spe--;
1700 | 			dropx(obj);
1701 | 			pline("%s slips from your %s.", The(xname(obj)),
1702 | 			      makeplural(body_part(FINGER)));
1703 | 			return;
1704 | 		}
1705 | 		otmp = getobj(lubricables, "grease");
1706 | 		if (!otmp) return;
1707 | 		if ((otmp->owornmask & WORN_ARMOR) && uarmc) {
1708 | 			Strcpy(buf, xname(uarmc));
1709 | 			You(need_to_remove_outer_armor, buf, xname(otmp));
1710 | 			return;
1711 | 		}
1712 | #ifdef TOURIST
1713 | 		if ((otmp->owornmask & WORN_SHIRT) && (uarmc || uarm)) {
1714 | 			Strcpy(buf, uarmc ? xname(uarmc) : "");
1715 | 			if (uarmc && uarm) Strcat(buf, " and ");
1716 | 			Strcat(buf, uarm ? xname(uarm) : "");
1717 | 			You(need_to_remove_outer_armor, buf, xname(otmp));
1718 | 			return;
1719 | 		}
1720 | #endif
1721 | 		check_unpaid(obj);
1722 | 		obj->spe--;
1723 | 		if (otmp != &zeroobj) {
1724 | 			You("cover %s with a thick layer of grease.",
1725 | 			    yname(otmp));
1726 | 			otmp->greased = 1;
1727 | 			if (obj->cursed && !nohands(youmonst.data)) {
1728 | 			    incr_itimeout(&Glib, rnd(15));
1729 | 			    pline("Some of the grease gets all over your %s.",
1730 | 				makeplural(body_part(HAND)));
1731 | 			}
1732 | 		} else {
1733 | 			Glib += rnd(15);
1734 | 			You("coat your %s with grease.",
1735 | 			    makeplural(body_part(FINGER)));
1736 | 		}
1737 | 	} else {
1738 | 		pline("%s %s empty.", The(xname(obj)),
1739 | 			obj->known ? "is" : "seems to be");
1740 | 	}
1741 | }
1742 | 
1743 | static struct trapinfo {
1744 | 	struct obj *tobj;
1745 | 	xchar tx, ty;
1746 | 	int time_needed;
1747 | } trapinfo;
1748 | 
1749 | void
1750 | reset_trapset()
1751 | {
1752 | 	trapinfo.tobj = 0;
1753 | }
1754 | 
1755 | /* Place a landmine/bear trap.  Helge Hafting */
1756 | STATIC_OVL void
1757 | use_trap(otmp)
1758 | struct obj *otmp;
1759 | {
1760 | 	int ttyp, tmp;
1761 | 	const char *what = (char *)0;
1762 | 	char buf[BUFSZ];
1763 | 	const char *occutext = "setting the trap";
1764 | 
1765 | 	if (nohands(youmonst.data))
1766 | 	    what = "without hands";
1767 | 	else if (Stunned)
1768 | 	    what = "while stunned";
1769 | 	else if (u.uswallow)
1770 | 	    what = is_animal(u.ustuck->data) ? "while swallowed" :
1771 | 			"while engulfed";
1772 | 	else if (Underwater)
1773 | 	    what = "underwater";
1774 | 	else if (Levitation)
1775 | 	    what = "while levitating";
1776 | 	else if (is_pool(u.ux, u.uy))
1777 | 	    what = "in water";
1778 | 	else if (is_lava(u.ux, u.uy))
1779 | 	    what = "in lava";
1780 | 	else if (On_stairs(u.ux, u.uy))
1781 | 	    what = (u.ux == xdnladder || u.ux == xupladder) ?
1782 | 			"on the ladder" : "on the stairs";
1783 | 	else if (IS_FURNITURE(levl[u.ux][u.uy].typ) ||
1784 | 		IS_ROCK(levl[u.ux][u.uy].typ) ||
1785 | 		closed_door(u.ux, u.uy) || t_at(u.ux, u.uy))
1786 | 	    what = "here";
1787 | 	if (what) {
1788 | 	    You_cant("set a trap %s!",what);
1789 | 	    reset_trapset();
1790 | 	    return;
1791 | 	}
1792 | 	ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
1793 | 	if (otmp == trapinfo.tobj &&
1794 | 		u.ux == trapinfo.tx && u.uy == trapinfo.ty) {
1795 | 	    You("resume setting %s %s.",
1796 | 		shk_your(buf, otmp),
1797 | 		defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
1798 | 	    set_occupation(set_trap, occutext, 0);
1799 | 	    return;
1800 | 	}
1801 | 	trapinfo.tobj = otmp;
1802 | 	trapinfo.tx = u.ux,  trapinfo.ty = u.uy;
1803 | 	tmp = ACURR(A_DEX);
1804 | 	trapinfo.time_needed = (tmp > 17) ? 2 : (tmp > 12) ? 3 :
1805 | 				(tmp > 7) ? 4 : 5;
1806 | 	if (Blind) trapinfo.time_needed *= 2;
1807 | 	tmp = ACURR(A_STR);
1808 | 	if (ttyp == BEAR_TRAP && tmp < 18)
1809 | 	    trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4;
1810 | 	/*[fumbling and/or confusion and/or cursed object check(s)
1811 | 	   should be incorporated here instead of in set_trap]*/
1812 | 
1813 | 	You("begin setting %s %s.",
1814 | 	    shk_your(buf, otmp),
1815 | 	    defsyms[trap_to_defsym(what_trap(ttyp))].explanation);
1816 | 	set_occupation(set_trap, occutext, 0);
1817 | 	return;
1818 | }
1819 | 
1820 | STATIC_PTR
1821 | int
1822 | set_trap()
1823 | {
1824 | 	struct obj *otmp = trapinfo.tobj;
1825 | 	struct trap *ttmp;
1826 | 	int ttyp;
1827 | 
1828 | 	if (!otmp || !carried(otmp) ||
1829 | 		u.ux != trapinfo.tx || u.uy != trapinfo.ty) {
1830 | 	    /* ?? */
1831 | 	    reset_trapset();
1832 | 	    return 0;
1833 | 	}
1834 | 
1835 | 	if (--trapinfo.time_needed > 0) return 1;	/* still busy */
1836 | 
1837 | 	ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP;
1838 | 	ttmp = maketrap(u.ux, u.uy, ttyp);
1839 | 	if (ttmp) {
1840 | 	    ttmp->tseen = 1;
1841 | 	    ttmp->madeby_u = 1;
1842 | 	    newsym(u.ux, u.uy); /* if our hero happens to be invisible */
1843 | 	    if (*in_rooms(u.ux,u.uy,SHOPBASE)) {
1844 | 		add_damage(u.ux, u.uy, 0L);		/* schedule removal */
1845 | 	    }
1846 | 	    You("finish arming %s.",
1847 | 		the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation));
1848 | 	    if ((otmp->cursed || Fumbling) && (rnl(10) > 5)) dotrap(ttmp);
1849 | 	} else {
1850 | 	    /* this shouldn't happen */
1851 | 	    Your("trap setting attempt fails.");
1852 | 	}
1853 | 	useup(otmp);
1854 | 	reset_trapset();
1855 | 	return 0;
1856 | }
1857 | 
1858 | STATIC_OVL int
1859 | use_whip(obj)
1860 | struct obj *obj;
1861 | {
1862 |     char buf[BUFSZ];
1863 |     struct monst *mtmp;
1864 |     struct obj *otmp;
1865 |     int rx, ry, proficient, res = 0;
1866 |     const char *msg_slipsfree = "The bullwhip slips free.";
1867 |     const char *msg_snap = "Snap!";
1868 | 
1869 |     if (obj != uwep) {
1870 | 	if (!wield_tool(obj)) return 0;
1871 | 	else res = 1;
1872 | 	/* prevent bashing msg */
1873 | 	unweapon = FALSE;
1874 |     }
1875 |     if (!getdir((char *)0)) return res;
1876 | 
1877 |     if (Stunned || (Confusion && !rn2(5))) confdir();
1878 |     rx = u.ux + u.dx;
1879 |     ry = u.uy + u.dy;
1880 |     mtmp = m_at(rx, ry);
1881 | 
1882 |     /* fake some proficiency checks */
1883 |     proficient = 0;
1884 |     if (Role_if(PM_ARCHEOLOGIST)) ++proficient;
1885 |     if (ACURR(A_DEX) < 6) proficient--;
1886 |     else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 14);
1887 |     if (Fumbling) --proficient;
1888 |     if (proficient > 3) proficient = 3;
1889 |     if (proficient < 0) proficient = 0;
1890 | 
1891 |     if (u.uswallow && attack(u.ustuck)) {
1892 | 	There("is not enough room to flick your bullwhip.");
1893 | 
1894 |     } else if (Underwater) {
1895 | 	There("is too much resistance to flick your bullwhip.");
1896 | 
1897 |     } else if (u.dz < 0) {
1898 | 	You("flick a bug off of the %s.",ceiling(u.ux,u.uy));
1899 | 
1900 |     } else if ((!u.dx && !u.dy) || (u.dz > 0)) {
1901 | 	int dam;
1902 | 
1903 | #ifdef STEED
1904 | 	/* Sometimes you hit your steed by mistake */
1905 | 	if (u.usteed && !rn2(proficient + 2)) {
1906 | 	    You("whip %s!", mon_nam(u.usteed));
1907 | 	    kick_steed();
1908 | 	    return 1;
1909 | 	}
1910 | #endif
1911 | 	if (Levitation
1912 | #ifdef STEED
1913 | 			|| u.usteed
1914 | #endif
1915 | 		) {
1916 | 	    /* Have a shot at snaring something on the floor */
1917 | 	    otmp = level.objects[u.ux][u.uy];
1918 | 	    if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) {
1919 | 		pline("Why beat a dead horse?");
1920 | 		return 1;
1921 | 	    }
1922 | 	    if (otmp && proficient) {
1923 | 		You("wrap your bullwhip around %s on the %s.",
1924 | 		    an(singular(otmp, xname)), surface(u.ux, u.uy));
1925 | 		if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1)
1926 | 		    pline(msg_slipsfree);
1927 | 		return 1;
1928 | 	    }
1929 | 	}
1930 | 	dam = rnd(2) + dbon() + obj->spe;
1931 | 	if (dam <= 0) dam = 1;
1932 | 	You("hit your %s with your bullwhip.", body_part(FOOT));
1933 | 	/* self_pronoun() won't work twice in a sentence */
1934 | 	Strcpy(buf, self_pronoun("killed %sself with %%s bullwhip", "him"));
1935 | 	losehp(dam, self_pronoun(buf, "his"), NO_KILLER_PREFIX);
1936 | 	flags.botl = 1;
1937 | 	return 1;
1938 | 
1939 |     } else if ((Fumbling || Glib) && !rn2(5)) {
1940 | 	pline_The("bullwhip slips out of your %s.", body_part(HAND));
1941 | 	dropx(obj);
1942 | 	setuwep((struct obj *)0);
1943 | 
1944 |     } else if (u.utrap && u.utraptype == TT_PIT) {
1945 | 	/*
1946 | 	 *     Assumptions:
1947 | 	 *
1948 | 	 *	if you're in a pit
1949 | 	 *		- you are attempting to get out of the pit
1950 | 	 *		- or, if you are applying it towards a small
1951 | 	 *		  monster then it is assumed that you are
1952 | 	 *		  trying to hit it.
1953 | 	 *	else if the monster is wielding a weapon
1954 | 	 *		- you are attempting to disarm a monster
1955 | 	 *	else
1956 | 	 *		- you are attempting to hit the monster
1957 | 	 *
1958 | 	 *	if you're confused (and thus off the mark)
1959 | 	 *		- you only end up hitting.
1960 | 	 *
1961 | 	 */
1962 | 	const char *wrapped_what = (char *)0;
1963 | 
1964 | 	if (mtmp) {
1965 | 	    if (bigmonst(mtmp->data)) {
1966 | 		wrapped_what = strcpy(buf, mon_nam(mtmp));
1967 | 	    } else if (proficient) {
1968 | 		if (attack(mtmp)) return 1;
1969 | 		else pline(msg_snap);
1970 | 	    }
1971 | 	}
1972 | 	if (!wrapped_what) {
1973 | 	    if (IS_FURNITURE(levl[rx][ry].typ))
1974 | 		wrapped_what = something;
1975 | 	    else if (sobj_at(BOULDER, rx, ry))
1976 | 		wrapped_what = "a boulder";
1977 | 	}
1978 | 	if (wrapped_what) {
1979 | 	    coord cc;
1980 | 
1981 | 	    cc.x = rx; cc.y = ry;
1982 | 	    You("wrap your bullwhip around %s.", wrapped_what);
1983 | 	    if (proficient && rn2(proficient + 2)) {
1984 | 		if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
1985 | 		    You("yank yourself out of the pit!");
1986 | 		    teleds(cc.x, cc.y);
1987 | 		    u.utrap = 0;
1988 | 		    vision_full_recalc = 1;
1989 | 		}
1990 | 	    } else {
1991 | 		pline(msg_slipsfree);
1992 | 	    }
1993 | 	    if (mtmp) wakeup(mtmp);
1994 | 	} else pline(msg_snap);
1995 | 
1996 |     } else if (mtmp) {
1997 | 	if (!canspotmon(mtmp) &&
1998 | 		!glyph_is_invisible(levl[rx][ry].glyph)) {
1999 | 	   pline("A monster is there that you couldn't see.");
2000 | 	   map_invisible(rx, ry);
2001 | 	}
2002 | 	otmp = MON_WEP(mtmp);	/* can be null */
2003 | 	if (otmp) {
2004 | 	    char onambuf[BUFSZ];
2005 | 	    const char *mon_hand;
2006 | 	    boolean gotit = proficient && (!Fumbling || !rn2(10));
2007 | 
2008 | 	    Strcpy(onambuf, xname(otmp));
2009 | 	    if (gotit) {
2010 | 		mon_hand = mbodypart(mtmp, HAND);
2011 | 		if (bimanual(otmp)) mon_hand = makeplural(mon_hand);
2012 | 	    } else
2013 | 		mon_hand = 0;	/* lint suppression */
2014 | 
2015 | 	    You("wrap your bullwhip around %s %s.",
2016 | 		s_suffix(mon_nam(mtmp)), onambuf);
2017 | 	    if (gotit && otmp->cursed) {
2018 | 		pline("%s welded to %s %s%c",
2019 | 		      (otmp->quan == 1L) ? "It is" : "They are",
2020 | 		      his[pronoun_gender(mtmp)], mon_hand,
2021 | 		      !otmp->bknown ? '!' : '.');
2022 | 		otmp->bknown = 1;
2023 | 		gotit = FALSE;	/* can't pull it free */
2024 | 	    }
2025 | 	    if (gotit) {
2026 | 		obj_extract_self(otmp);
2027 | 		possibly_unwield(mtmp);
2028 | 		otmp->owornmask &= ~W_WEP;
2029 | 
2030 | 		switch (rn2(proficient + 1)) {
2031 | 		case 2:
2032 | 		    /* to floor near you */
2033 | 		    You("yank %s %s to the %s!", s_suffix(mon_nam(mtmp)),
2034 | 			onambuf, surface(u.ux, u.uy));
2035 | 		    if (otmp->otyp == CRYSKNIFE &&
2036 | 			    (!otmp->oerodeproof || !rn2(10))) {
2037 | 			otmp->otyp = WORM_TOOTH;
2038 | 			otmp->oerodeproof = 0;
2039 | 		    }
2040 | 		    place_object(otmp, u.ux, u.uy);
2041 | 		    stackobj(otmp);
2042 | 		    break;
2043 | 		case 3:
2044 | 		    /* right to you */
2045 | #if 0
2046 | 		    if (!rn2(25)) {
2047 | 			/* proficient with whip, but maybe not
2048 | 			   so proficient at catching weapons */
2049 | 			int hitu, hitvalu;
2050 | 
2051 | 			hitvalu = 8 + otmp->spe;
2052 | 			hitu = thitu(hitvalu,
2053 | 				     dmgval(otmp, &youmonst),
2054 | 				     otmp, (char *)0);
2055 | 			if (hitu) {
2056 | 			    You("The %s hits you as you try to snatch it!",
2057 | 				the(onambuf));
2058 | 			}
2059 | 			place_object(otmp, u.ux, u.uy);
2060 | 			stackobj(otmp);
2061 | 			break;
2062 | 		    }
2063 | #endif /* 0 */
2064 | 		    /* right into your inventory */
2065 | 		    You("snatch %s %s!", s_suffix(mon_nam(mtmp)), onambuf);
2066 | 		    if (otmp->otyp == CORPSE &&
2067 | 			    touch_petrifies(&mons[otmp->corpsenm]) &&
2068 | 			    !uarmg && !Stone_resistance &&
2069 | 			    !(poly_when_stoned(youmonst.data) &&
2070 | 				polymon(PM_STONE_GOLEM))) {
2071 | 			char kbuf[BUFSZ];
2072 | 
2073 | 			Sprintf(kbuf, "%s corpse",
2074 | 			        an(mons[otmp->corpsenm].mname));
2075 | 			pline("Snatching %s is a fatal mistake.", kbuf);
2076 | 			instapetrify(kbuf);
2077 | 		    }
2078 | 		    otmp = hold_another_object(otmp, "You drop %s!",
2079 | 					       doname(otmp), (const char *)0);
2080 | 		    break;
2081 | 		default:
2082 | 		    /* to floor beneath mon */
2083 | 		    You("yank %s from %s %s!", the(onambuf),
2084 | 			s_suffix(mon_nam(mtmp)), mon_hand);
2085 | 		    if (otmp->otyp == CRYSKNIFE &&
2086 | 			    (!otmp->oerodeproof || !rn2(10))) {
2087 | 			otmp->otyp = WORM_TOOTH;
2088 | 			otmp->oerodeproof = 0;
2089 | 		    }
2090 | 		    place_object(otmp, mtmp->mx, mtmp->my);
2091 | 		    stackobj(otmp);
2092 | 		    break;
2093 | 		}
2094 | 	    } else {
2095 | 		pline(msg_slipsfree);
2096 | 	    }
2097 | 	    wakeup(mtmp);
2098 | 	} else {
2099 | 	    You("flick your bullwhip towards %s.", mon_nam(mtmp));
2100 | 	    if (proficient) {
2101 | 		if (attack(mtmp)) return 1;
2102 | 		else pline(msg_snap);
2103 | 	    }
2104 | 	}
2105 | 
2106 |     } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
2107 | 	    /* it must be air -- water checked above */
2108 | 	    You("snap your whip through thin air.");
2109 | 
2110 |     } else {
2111 | 	pline(msg_snap);
2112 | 
2113 |     }
2114 |     return 1;
2115 | }
2116 | 
2117 | 
2118 | static const char
2119 | 	*not_enough_room = "There's not enough room here to use that.",
2120 | 	*where_to_hit = "Where do you want to hit?",
2121 | 	*cant_see_spot = "won't hit anything if you can't see that spot.";
2122 | 
2123 | /* Distance attacks by pole-weapons */
2124 | STATIC_OVL int
2125 | use_pole (obj)
2126 | 	struct obj *obj;
2127 | {
2128 | 	int res = 0, typ, max_range = 4, min_range = 4;
2129 | 	coord cc;
2130 | 	struct monst *mtmp;
2131 | 
2132 | 
2133 | 	/* Are you allowed to use the pole? */
2134 | 	if (u.uswallow) {
2135 | 	    pline(not_enough_room);
2136 | 	    return (0);
2137 | 	}
2138 | 	if (obj != uwep) {
2139 | 	    if (!wield_tool(obj)) return(0);
2140 | 	    else res = 1;
2141 | 	}
2142 |      /* assert(obj == uwep); */
2143 | 
2144 | 	/* Prompt for a location */
2145 | 	pline(where_to_hit);
2146 | 	cc.x = u.ux;
2147 | 	cc.y = u.uy;
2148 | 	if (getpos(&cc, TRUE, "the spot to hit") < 0)
2149 | 	    return 0;	/* user pressed ESC */
2150 | 
2151 | 	/* Calculate range */
2152 | 	typ = uwep_skill_type();
2153 | 	if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
2154 | 	else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
2155 | 	else max_range = 8;
2156 | 	if (distu(cc.x, cc.y) > max_range) {
2157 | 	    pline("Too far!");
2158 | 	    return (res);
2159 | 	} else if (distu(cc.x, cc.y) < min_range) {
2160 | 	    pline("Too close!");
2161 | 	    return (res);
2162 | 	} else if (!cansee(cc.x, cc.y)) {
2163 | 	    You(cant_see_spot);
2164 | 	    return (res);
2165 | 	}
2166 | 
2167 | 	/* Attack the monster there */
2168 | 	if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0)
2169 | 	    (void) thitmonst(mtmp, uwep);
2170 | 	else
2171 | 	    /* Now you know that nothing is there... */
2172 | 	    pline(nothing_happens);
2173 | 	return (1);
2174 | }
2175 | 
2176 | 
2177 | STATIC_OVL int
2178 | use_grapple (obj)
2179 | 	struct obj *obj;
2180 | {
2181 | 	int res = 0, typ, max_range = 4;
2182 | 	coord cc;
2183 | 	struct monst *mtmp;
2184 | 	struct obj *otmp;
2185 | 
2186 | 	/* Are you allowed to use the hook? */
2187 | 	if (u.uswallow) {
2188 | 	    pline(not_enough_room);
2189 | 	    return (0);
2190 | 	}
2191 | 	if (obj != uwep) {
2192 | 	    if (!wield_tool(obj)) return(0);
2193 | 	    else res = 1;
2194 | 	}
2195 |      /* assert(obj == uwep); */
2196 | 
2197 | 	/* Prompt for a location */
2198 | 	pline(where_to_hit);
2199 | 	cc.x = u.ux;
2200 | 	cc.y = u.uy;
2201 | 	if (getpos(&cc, TRUE, "the spot to hit") < 0)
2202 | 	    return 0;	/* user pressed ESC */
2203 | 
2204 | 	/* Calculate range */
2205 | 	typ = uwep_skill_type();
2206 | 	if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
2207 | 	else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
2208 | 	else max_range = 8;
2209 | 	if (distu(cc.x, cc.y) > max_range) {
2210 | 		pline("Too far!");
2211 | 		return (res);
2212 | 	} else if (!cansee(cc.x, cc.y)) {
2213 | 		You(cant_see_spot);
2214 | 		return (res);
2215 | 	}
2216 | 
2217 | 	/* What did you hit? */
2218 | 	switch (rn2(5))
2219 | 	{
2220 | 	case 0:	/* Trap */
2221 | 	    /* FIXME -- untrap needs to deal with non-adjacent traps */
2222 | 	    break;
2223 | 	case 1:	/* Object */
2224 | 	    if ((otmp = level.objects[cc.x][cc.y]) != 0) {
2225 | 		You("snag an object from the %s!", surface(cc.x, cc.y));
2226 | 		(void) pickup_object(otmp, 1L, FALSE);
2227 | 		/* If pickup fails, leave it alone */
2228 | 		newsym(cc.x, cc.y);
2229 | 		return (1);
2230 | 	    }
2231 | 	    break;
2232 | 	case 2:	/* Monster */
2233 | 	    if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break;
2234 | 	    if (verysmall(mtmp->data) && !rn2(4) &&
2235 | 			enexto(&cc, u.ux, u.uy, (struct permonst *)0)) {
2236 | 		You("pull in %s!", mon_nam(mtmp));
2237 | 		mtmp->mundetected = 0;
2238 | 		rloc_to(mtmp, cc.x, cc.y);
2239 | 		return (1);
2240 | 	    } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) ||
2241 | 		       rn2(4)) {
2242 | 		(void) thitmonst(mtmp, uwep);
2243 | 		return (1);
2244 | 	    }
2245 | 	    /* FALL THROUGH */
2246 | 	case 3:	/* Surface */
2247 | 	    You("are yanked toward the %s!",
2248 | 			surface(cc.x, cc.y));
2249 | 	    hurtle(sgn(cc.x-u.ux), sgn(cc.y-u.uy), 1, FALSE);
2250 | 	    return (1);
2251 | 	default:	/* Yourself (oops!) */
2252 | 	    if (P_SKILL(typ) <= P_BASIC) {
2253 | 		You("hook yourself!");
2254 | 		losehp(rn1(10,10), "a grappling hook", KILLED_BY);
2255 | 		return (1);
2256 | 	    }
2257 | 	    break;
2258 | 	}
2259 | 	pline(nothing_happens);
2260 | 	return (1);
2261 | }
2262 | 
2263 | 
2264 | #define BY_OBJECT	((struct monst *)0)
2265 | 
2266 | /* return 1 if the wand is broken, hence some time elapsed */
2267 | STATIC_OVL int
2268 | do_break_wand(obj)
2269 |     struct obj *obj;
2270 | {
2271 |     static const char nothing_else_happens[] = "But nothing else happens...";
2272 |     register int i, x, y;
2273 |     register struct monst *mon;
2274 |     int dmg, damage;
2275 |     boolean affects_objects;
2276 |     char confirm[QBUFSZ], the_wand[BUFSZ];
2277 | 
2278 |     Strcpy(the_wand, yname(obj));
2279 |     Sprintf(confirm, "Are you really sure you want to break %s?", the_wand);
2280 |     if (yn(confirm) == 'n' ) return 0;
2281 | 
2282 |     if (nohands(youmonst.data)) {
2283 | 	You_cant("break %s without hands!", the_wand);
2284 | 	return 0;
2285 |     } else if (ACURR(A_STR) < 10) {
2286 | 	You("don't have the strength to break %s!", the_wand);
2287 | 	return 0;
2288 |     }
2289 |     pline("Raising %s high above your %s, you break it in two!",
2290 | 	  the_wand, body_part(HEAD));
2291 | 
2292 |     current_wand = obj;		/* destroy_item might reset this */
2293 |     freeinv(obj);		/* hide it from destroy_item instead... */
2294 |     setnotworn(obj);		/* so we need to do this ourselves */
2295 | 
2296 |     if (obj->spe <= 0) {
2297 | 	pline(nothing_else_happens);
2298 | 	goto discard_broken_wand;
2299 |     }
2300 |     obj->ox = u.ux;
2301 |     obj->oy = u.uy;
2302 |     dmg = obj->spe * 4;
2303 |     affects_objects = FALSE;
2304 | 
2305 |     switch (obj->otyp) {
2306 |     case WAN_WISHING:
2307 |     case WAN_NOTHING:
2308 |     case WAN_LOCKING:
2309 |     case WAN_PROBING:
2310 |     case WAN_ENLIGHTENMENT:
2311 |     case WAN_OPENING:
2312 |     case WAN_SECRET_DOOR_DETECTION:
2313 | 	pline(nothing_else_happens);
2314 | 	goto discard_broken_wand;
2315 |     case WAN_DEATH:
2316 |     case WAN_LIGHTNING:
2317 | 	dmg *= 2;
2318 |     case WAN_FIRE:
2319 |     case WAN_COLD:
2320 | 	dmg *= 2;
2321 |     case WAN_MAGIC_MISSILE:
2322 | 	explode(u.ux, u.uy, (obj->otyp - WAN_MAGIC_MISSILE), dmg, WAND_CLASS);
2323 | 	makeknown(obj->otyp);	/* explode described the effect */
2324 | 	goto discard_broken_wand;
2325 |     case WAN_STRIKING:
2326 | 	/* we want this before the explosion instead of at the very end */
2327 | 	pline("A wall of force smashes down around you!");
2328 | 	dmg = d(1 + obj->spe,6);	/* normally 2d12 */
2329 |     case WAN_CANCELLATION:
2330 |     case WAN_POLYMORPH:
2331 |     case WAN_TELEPORTATION:
2332 |     case WAN_UNDEAD_TURNING:
2333 | 	affects_objects = TRUE;
2334 | 	break;
2335 |     default:
2336 | 	break;
2337 |     }
2338 | 
2339 |     /* magical explosion and its visual effect occur before specific effects */
2340 |     explode(obj->ox, obj->oy, 0, rnd(dmg), WAND_CLASS);
2341 | 
2342 |     /* this makes it hit us last, so that we can see the action first */
2343 |     for (i = 0; i <= 8; i++) {
2344 | 	bhitpos.x = x = obj->ox + xdir[i];
2345 | 	bhitpos.y = y = obj->oy + ydir[i];
2346 | 	if (!isok(x,y)) continue;
2347 | 
2348 | 	if (obj->otyp == WAN_DIGGING) {
2349 | 	    if(dig_check(BY_OBJECT, FALSE, x, y))
2350 | 		digactualhole(x, y, BY_OBJECT,
2351 | 			      (rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ?
2352 | 			       PIT : HOLE);
2353 | 	    continue;
2354 | 	} else if(obj->otyp == WAN_CREATE_MONSTER) {
2355 | 	    /* u.ux,u.uy creates it near you--x,y might create it in rock */
2356 | 	    (void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS);
2357 | 	    continue;
2358 | 	} else {
2359 | 	    if (x == u.ux && y == u.uy) {
2360 | 		/* teleport objects first to avoid race with tele control and
2361 | 		   autopickup.  Other wand/object effects handled after
2362 | 		   possible wand damage is assessed */
2363 | 		if (obj->otyp == WAN_TELEPORTATION &&
2364 | 		    affects_objects && level.objects[x][y]) {
2365 | 		    (void) bhitpile(obj, bhito, x, y);
2366 | 		    if (flags.botl) bot();		/* potion effects */
2367 | 		}
2368 | 		damage = zapyourself(obj, FALSE);
2369 | 		if (damage)
2370 | 		    losehp(damage,
2371 | 			   self_pronoun("killed %sself by breaking a wand",
2372 | 					"him"),
2373 | 			   NO_KILLER_PREFIX);
2374 | 		if (flags.botl) bot();		/* blindness */
2375 | 	    } else if ((mon = m_at(x, y)) != 0) {
2376 | 		(void) bhitm(mon, obj);
2377 | 	     /* if (flags.botl) bot(); */
2378 | 	    }
2379 | 	    if (affects_objects && level.objects[x][y]) {
2380 | 		(void) bhitpile(obj, bhito, x, y);
2381 | 		if (flags.botl) bot();		/* potion effects */
2382 | 	    }
2383 | 	}
2384 |     }
2385 | 
2386 |     if (obj->otyp == WAN_LIGHT)
2387 | 	litroom(TRUE, obj);	/* only needs to be done once */
2388 | 
2389 |  discard_broken_wand:
2390 |     obj = current_wand;		/* [see dozap() and destroy_item()] */
2391 |     current_wand = 0;
2392 |     if (obj) {
2393 | 	/* extra charge for _use_ prior to destruction */
2394 | 	check_unpaid(obj);
2395 | 	delobj(obj);
2396 |     }
2397 |     nomul(0);
2398 |     return 1;
2399 | }
2400 | 
2401 | int
2402 | doapply()
2403 | {
2404 | 	register struct obj *obj;
2405 | 	register int res = 1;
2406 | 
2407 | 	if(check_capacity((char *)0)) return (0);
2408 | 	obj = getobj(carrying(POT_OIL) ? tools_too : tools, "use or apply");
2409 | 	if(!obj) return 0;
2410 | 
2411 | 	if (obj->oclass == WAND_CLASS)
2412 | 	    return do_break_wand(obj);
2413 | 
2414 | 	switch(obj->otyp){
2415 | 	case BLINDFOLD:
2416 | 	case LENSES:
2417 | 		if (obj == ublindf) {
2418 | 		    if (!cursed(obj)) Blindf_off(obj);
2419 | 		} else if (!ublindf)
2420 | 		    Blindf_on(obj);
2421 | 		else You("are already %s.",
2422 | 			ublindf->otyp == TOWEL ?     "covered by a towel" : 
2423 | 			ublindf->otyp == BLINDFOLD ? "wearing a blindfold" :
2424 | 						     "wearing lenses");
2425 | 		break;
2426 | 	case BULLWHIP:
2427 | 		res = use_whip(obj);
2428 | 		break;
2429 | 	case GRAPPLING_HOOK:
2430 | 		res = use_grapple(obj);
2431 | 		break;
2432 | 	case LARGE_BOX:
2433 | 	case CHEST:
2434 | 	case ICE_BOX:
2435 | 	case SACK:
2436 | 	case BAG_OF_HOLDING:
2437 | 	case OILSKIN_SACK:
2438 | 		res = use_container(obj, 1);
2439 | 		break;
2440 | 	case BAG_OF_TRICKS:
2441 | 		if(obj->spe > 0) {
2442 | 			register int cnt = 1;
2443 | 
2444 | 			check_unpaid(obj);
2445 | 			obj->spe--;
2446 | 			if(!rn2(23)) cnt += rn2(7) + 1;
2447 | 			while(cnt--)
2448 | 			   (void) makemon((struct permonst *) 0,
2449 | 						u.ux, u.uy, NO_MM_FLAGS);
2450 | 			makeknown(BAG_OF_TRICKS);
2451 | 		} else
2452 | 			pline(nothing_happens);
2453 | 		break;
2454 | 	case CAN_OF_GREASE:
2455 | 		use_grease(obj);
2456 | 		break;
2457 | 	case LOCK_PICK:
2458 | #ifdef TOURIST
2459 | 	case CREDIT_CARD:
2460 | #endif
2461 | 	case SKELETON_KEY:
2462 | 		(void) pick_lock(obj);
2463 | 		break;
2464 | 	case PICK_AXE:
2465 | 	case DWARVISH_MATTOCK:
2466 | 		res = use_pick_axe(obj);
2467 | 		break;
2468 | 	case TINNING_KIT:
2469 | 		use_tinning_kit(obj);
2470 | 		break;
2471 | 	case LEASH:
2472 | 		use_leash(obj);
2473 | 		break;
2474 | #ifdef STEED
2475 | 	case SADDLE:
2476 | 		res = use_saddle(obj);
2477 | 		break;
2478 | #endif
2479 | 	case MAGIC_WHISTLE:
2480 | 		use_magic_whistle(obj);
2481 | 		break;
2482 | 	case TIN_WHISTLE:
2483 | 		use_whistle(obj);
2484 | 		break;
2485 | 	case STETHOSCOPE:
2486 | 		res = use_stethoscope(obj);
2487 | 		break;
2488 | 	case MIRROR:
2489 | 		res = use_mirror(obj);
2490 | 		break;
2491 | 	case BELL:
2492 | 	case BELL_OF_OPENING:
2493 | 		use_bell(obj);
2494 | 		break;
2495 | 	case CANDELABRUM_OF_INVOCATION:
2496 | 		use_candelabrum(obj);
2497 | 		break;
2498 | 	case WAX_CANDLE:
2499 | 	case TALLOW_CANDLE:
2500 | 		use_candle(obj);
2501 | 		break;
2502 | 	case OIL_LAMP:
2503 | 	case MAGIC_LAMP:
2504 | 	case BRASS_LANTERN:
2505 | 		use_lamp(obj);
2506 | 		break;
2507 | 	case POT_OIL:
2508 | 		light_cocktail(obj);
2509 | 		break;
2510 | #ifdef TOURIST
2511 | 	case EXPENSIVE_CAMERA:
2512 | 		res = use_camera(obj);
2513 | 		break;
2514 | #endif
2515 | 	case TOWEL:
2516 | 		res = use_towel(obj);
2517 | 		break;
2518 | 	case CRYSTAL_BALL:
2519 | 		use_crystal_ball(obj);
2520 | 		break;
2521 | 	case MAGIC_MARKER:
2522 | 		res = dowrite(obj);
2523 | 		break;
2524 | 	case TIN_OPENER:
2525 | 		if(!carrying(TIN)) {
2526 | 			You("have no tin to open.");
2527 | 			goto xit;
2528 | 		}
2529 | 		You("cannot open a tin without eating or discarding its contents.");
2530 | 		if(flags.verbose)
2531 | 			pline("In order to eat, use the 'e' command.");
2532 | 		if(obj != uwep)
2533 |     pline("Opening the tin will be much easier if you wield the tin opener.");
2534 | 		goto xit;
2535 | 
2536 | 	case FIGURINE:
2537 | 		use_figurine(obj);
2538 | 		break;
2539 | 	case UNICORN_HORN:
2540 | 		use_unicorn_horn(obj);
2541 | 		break;
2542 | 	case WOODEN_FLUTE:
2543 | 	case MAGIC_FLUTE:
2544 | 	case TOOLED_HORN:
2545 | 	case FROST_HORN:
2546 | 	case FIRE_HORN:
2547 | 	case WOODEN_HARP:
2548 | 	case MAGIC_HARP:
2549 | 	case BUGLE:
2550 | 	case LEATHER_DRUM:
2551 | 	case DRUM_OF_EARTHQUAKE:
2552 | 		res = do_play_instrument(obj);
2553 | 		break;
2554 | 	case HORN_OF_PLENTY:	/* not a musical instrument */
2555 | 		if (obj->spe > 0) {
2556 | 		    struct obj *otmp;
2557 | 		    const char *what;
2558 | 
2559 | 		    check_unpaid(obj);
2560 | 		    obj->spe--;
2561 | 		    if (!rn2(13)) {
2562 | 			otmp = mkobj(POTION_CLASS, FALSE);
2563 | 			if (objects[otmp->otyp].oc_magic) do {
2564 | 			    otmp->otyp = rnd_class(POT_BOOZE, POT_WATER);
2565 | 			} while (otmp->otyp == POT_SICKNESS);
2566 | 			what = "A potion";
2567 | 		    } else {
2568 | 			otmp = mkobj(FOOD_CLASS, FALSE);
2569 | 			if (otmp->otyp == FOOD_RATION && !rn2(7))
2570 | 			    otmp->otyp = LUMP_OF_ROYAL_JELLY;
2571 | 			what = "Some food";
2572 | 		    }
2573 | 		    pline("%s spills out.", what);
2574 | 		    otmp->blessed = obj->blessed;
2575 | 		    otmp->cursed = obj->cursed;
2576 | 		    otmp->owt = weight(otmp);
2577 | 		    otmp = hold_another_object(otmp,
2578 | 					(u.uswallow || Is_airlevel(&u.uz) ||
2579 | 					 u.uinwater || Is_waterlevel(&u.uz)) ?
2580 | 					       "Oops!  %s away from you!" :
2581 | 					       "Oops!  %s to the floor!",
2582 | 					       The(aobjnam(otmp, "slip")),
2583 | 					       (const char *)0);
2584 | 		    makeknown(HORN_OF_PLENTY);
2585 | 		} else
2586 | 		    pline(nothing_happens);
2587 | 		break;
2588 | 	case LAND_MINE:
2589 | 	case BEARTRAP:
2590 | 		use_trap(obj);
2591 | 		break;
2592 | 	default:
2593 | 		/* Pole-weapons can strike at a distance */
2594 | 		if (is_pole(obj)) {
2595 | 			res = use_pole(obj);
2596 | 			break;
2597 | 		} else if (is_pick(obj) /* || is_axe(obj) */) {
2598 | 			res = use_pick_axe(obj);
2599 | 			break;
2600 | 		}
2601 | 		pline("Sorry, I don't know how to use that.");
2602 | 	xit:
2603 | 		nomul(0);
2604 | 		return 0;
2605 | 	}
2606 | 	if (res && obj->oartifact) arti_speak(obj);
2607 | 	nomul(0);
2608 | 	return res;
2609 | }
2610 | 
2611 | #endif /* OVLB */
2612 | 
2613 | /*apply.c*/