1    | /*	SCCS Id: @(#)zap.c	3.3	2000/08/01	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | /* Disintegration rays have special treatment; corpses are never left.
8    |  * But the routine which calculates the damage is separate from the routine
9    |  * which kills the monster.  The damage routine returns this cookie to
10   |  * indicate that the monster should be disintegrated.
11   |  */
12   | #define MAGIC_COOKIE 1000
13   | 
14   | #ifdef OVLB
15   | static NEARDATA boolean obj_zapped;
16   | static NEARDATA int poly_zapped;
17   | #endif
18   | 
19   | extern boolean notonhead;	/* for long worms */
20   | 
21   | /* kludge to use mondied instead of killed */
22   | extern boolean m_using;
23   | 
24   | STATIC_DCL void FDECL(costly_cancel, (struct obj *));
25   | STATIC_DCL void FDECL(polyuse, (struct obj*, int, int));
26   | STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
27   | STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
28   | STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **));
29   | STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P));
30   | STATIC_DCL void FDECL(revive_egg, (struct obj *));
31   | STATIC_DCL boolean FDECL(hits_bars, (int));
32   | #ifdef STEED
33   | STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
34   | #endif
35   | 
36   | #ifdef OVLB
37   | STATIC_DCL int FDECL(zap_hit, (int,int));
38   | #endif
39   | #ifdef OVL0
40   | STATIC_DCL void FDECL(backfire, (struct obj *));
41   | STATIC_DCL int FDECL(spell_hit_bonus, (int));
42   | #endif
43   | 
44   | #define ZT_MAGIC_MISSILE	(AD_MAGM-1)
45   | #define ZT_FIRE			(AD_FIRE-1)
46   | #define ZT_COLD			(AD_COLD-1)
47   | #define ZT_SLEEP		(AD_SLEE-1)
48   | #define ZT_DEATH		(AD_DISN-1)	/* or disintegration */
49   | #define ZT_LIGHTNING		(AD_ELEC-1)
50   | #define ZT_POISON_GAS		(AD_DRST-1)
51   | #define ZT_ACID			(AD_ACID-1)
52   | /* 8 and 9 are currently unassigned */
53   | 
54   | #define ZT_WAND(x)		(x)
55   | #define ZT_SPELL(x)		(10+(x))
56   | #define ZT_BREATH(x)		(20+(x))
57   | 
58   | #define is_hero_spell(type)	((type) >= 10 && (type) < 20)
59   | 
60   | #ifndef OVLB
61   | STATIC_VAR const char are_blinded_by_the_flash[];
62   | extern const char *flash_types[];
63   | #else
64   | STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
65   | 
66   | const char *flash_types[] = {		/* also used in buzzmu(mcastu.c) */
67   | 	"magic missile",	/* Wands must be 0-9 */
68   | 	"bolt of fire",
69   | 	"bolt of cold",
70   | 	"sleep ray",
71   | 	"death ray",
72   | 	"bolt of lightning",
73   | 	"",
74   | 	"",
75   | 	"",
76   | 	"",
77   | 
78   | 	"magic missile",	/* Spell equivalents must be 10-19 */
79   | 	"fireball",
80   | 	"cone of cold",
81   | 	"sleep ray",
82   | 	"finger of death",
83   | 	"bolt of lightning",	/* There is no spell, used for retribution */
84   | 	"",
85   | 	"",
86   | 	"",
87   | 	"",
88   | 
89   | 	"blast of missiles",	/* Dragon breath equivalents 20-29*/
90   | 	"blast of fire",
91   | 	"blast of frost",
92   | 	"blast of sleep gas",
93   | 	"blast of disintegration",
94   | 	"blast of lightning",
95   | 	"blast of poison gas",
96   | 	"blast of acid",
97   | 	"",
98   | 	""
99   | };
100  | 
101  | /* Routines for IMMEDIATE wands and spells. */
102  | /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
103  | int
104  | bhitm(mtmp, otmp)
105  | struct monst *mtmp;
106  | struct obj *otmp;
107  | {
108  | 	boolean wake = TRUE;	/* Most 'zaps' should wake monster */
109  | 	boolean reveal_invis = FALSE;
110  | 	boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
111  | 	int dmg, otyp = otmp->otyp;
112  | 	const char *zap_type_text = "spell";
113  | #ifdef STEED
114  | 	struct obj *obj;
115  | #endif
116  | 
117  | 	if (u.uswallow && mtmp == u.ustuck)
118  | 	    reveal_invis = FALSE;
119  | 
120  | 	switch(otyp) {
121  | 	case WAN_STRIKING:
122  | 		zap_type_text = "wand";
123  | 		/* fall through */
124  | 	case SPE_FORCE_BOLT:
125  | 		reveal_invis = TRUE;
126  | 		if (resists_magm(mtmp)) {	/* match effect on player */
127  | 			shieldeff(mtmp->mx, mtmp->my);
128  | 			break;	/* skip makeknown */
129  | 		} else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
130  | 			dmg = d(2,12);
131  | 			if(dbldam) dmg *= 2;
132  | 			if (otyp == SPE_FORCE_BOLT)
133  | 			    dmg += spell_damage_bonus();
134  | 			hit(zap_type_text, mtmp, exclam(dmg));
135  | 			(void) resist(mtmp, otmp->oclass, dmg, TELL);
136  | 		} else miss(zap_type_text, mtmp);
137  | 		makeknown(otyp);
138  | 		break;
139  | 	case WAN_SLOW_MONSTER:
140  | 	case SPE_SLOW_MONSTER:
141  | 		if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
142  | 			mon_adjust_speed(mtmp, -1);
143  | 			if (u.uswallow && (mtmp == u.ustuck) &&
144  | 			    is_whirly(mtmp->data)) {
145  | 				You("disrupt %s!", mon_nam(mtmp));
146  | 				pline("A huge hole opens up...");
147  | 				expels(mtmp, mtmp->data, TRUE);
148  | 			}
149  | 		}
150  | 		break;
151  | 	case WAN_SPEED_MONSTER:
152  | 		if (!resist(mtmp, otmp->oclass, 0, NOTELL))
153  | 			mon_adjust_speed(mtmp, 1);
154  | 		break;
155  | 	case WAN_UNDEAD_TURNING:
156  | 	case SPE_TURN_UNDEAD:
157  | 		wake = FALSE;
158  | 		if (unturn_dead(mtmp)) wake = TRUE;
159  | 		if (is_undead(mtmp->data)) {
160  | 			reveal_invis = TRUE;
161  | 			wake = TRUE;
162  | 			dmg = rnd(8);
163  | 			if(dbldam) dmg *= 2;
164  | 			if (otyp == SPE_TURN_UNDEAD)
165  | 				dmg += spell_damage_bonus();
166  | 			if(!resist(mtmp, otmp->oclass, dmg, NOTELL))
167  | 				mtmp->mflee = TRUE;
168  | 		}
169  | 		break;
170  | 	case WAN_POLYMORPH:
171  | 	case SPE_POLYMORPH:
172  | 	case POT_POLYMORPH:
173  | 		if (resists_magm(mtmp)) {
174  | 		    /* magic resistance protects from polymorph traps, so make
175  | 		       it guard against involuntary polymorph attacks too... */
176  | 		    shieldeff(mtmp->mx, mtmp->my);
177  | 		} else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
178  | 		    if (!rn2(25)) {
179  | 			if (canseemon(mtmp)) {
180  | 			    pline("%s shudders!", Monnam(mtmp));
181  | 			    makeknown(otyp);
182  | 			}
183  | 			/* no corpse after system shock */
184  | 			xkilled(mtmp, 3);
185  | 		    }
186  | 		    else if (newcham(mtmp, (struct permonst *)0) )
187  | 			if (!Hallucination && canspotmon(mtmp))
188  | 			    makeknown(otyp);
189  | 		}
190  | 		break;
191  | 	case WAN_CANCELLATION:
192  | 	case SPE_CANCELLATION:
193  | 		cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
194  | 		break;
195  | 	case WAN_TELEPORTATION:
196  | 	case SPE_TELEPORT_AWAY:
197  | 		reveal_invis = !u_teleport_mon(mtmp, TRUE);
198  | 		break;
199  | 	case WAN_MAKE_INVISIBLE:
200  | 	    {
201  | 		int oldinvis = mtmp->minvis;
202  | 		char nambuf[BUFSZ];
203  | 
204  | 		/* format monster's name before altering its visibility */
205  | 		Strcpy(nambuf, Monnam(mtmp));
206  | 		mon_set_minvis(mtmp);
207  | 		if (!oldinvis && knowninvisible(mtmp)) {
208  | 		    pline("%s turns transparent!", nambuf);
209  | 		    makeknown(otyp);
210  | 		}
211  | 		break;
212  | 	    }
213  | 	case WAN_NOTHING:
214  | 	case WAN_LOCKING:
215  | 	case SPE_WIZARD_LOCK:
216  | 		wake = FALSE;
217  | 		break;
218  | 	case WAN_PROBING:
219  | 		wake = FALSE;
220  | 		reveal_invis = TRUE;
221  | 		probe_monster(mtmp);
222  | 		makeknown(otyp);
223  | 		break;
224  | 	case WAN_OPENING:
225  | 	case SPE_KNOCK:
226  | 		wake = FALSE;	/* don't want immediate counterattack */
227  | 		if (u.uswallow && mtmp == u.ustuck) {
228  | 			if (is_animal(mtmp->data)) {
229  | 				if (Blind) You_feel("a sudden rush of air!");
230  | 				else pline("%s opens its mouth!", Monnam(mtmp));
231  | 			}
232  | 			expels(mtmp, mtmp->data, TRUE);
233  | #ifdef STEED
234  | 		} else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
235  | 			mtmp->misc_worn_check &= ~obj->owornmask;
236  | 			obj->owornmask = 0L;
237  | 			update_mon_intrinsics(mtmp, obj, FALSE);
238  | 			obj_extract_self(obj);
239  | 			place_object(obj, mtmp->mx, mtmp->my);
240  | 			/* call stackobj() if we ever drop anything that can merge */
241  | 			newsym(mtmp->mx, mtmp->my);
242  | #endif
243  | 		}
244  | 		break;
245  | 	case SPE_HEALING:
246  | 	case SPE_EXTRA_HEALING:
247  | 		reveal_invis = TRUE;
248  | 	    if (mtmp->data != &mons[PM_PESTILENCE]) {
249  | 		wake = FALSE;		/* wakeup() makes the target angry */
250  | 		mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
251  | 		if (mtmp->mhp > mtmp->mhpmax)
252  | 		    mtmp->mhp = mtmp->mhpmax;
253  | 		if (canseemon(mtmp))
254  | 		    pline("%s looks%s better.", Monnam(mtmp),
255  | 			  otyp == SPE_EXTRA_HEALING ? " much" : "" );
256  | 		if (mtmp->mtame || mtmp->mpeaceful) {
257  | 		    adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
258  | 		}
259  | 	    } else {	/* Pestilence */
260  | 		/* Pestilence will always resist; damage is half of 3d{4,8} */
261  | 		(void) resist(mtmp, otmp->oclass,
262  | 			      d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
263  | 	    }
264  | 		break;
265  | 	case WAN_LIGHT:	/* (broken wand) */
266  | 		if (flash_hits_mon(mtmp, otmp)) {
267  | 		    makeknown(WAN_LIGHT);
268  | 		    reveal_invis = TRUE;
269  | 		}
270  | 		break;
271  | 	case WAN_SLEEP:	/* (broken wand) */
272  | 		/* [wakeup() doesn't rouse victims of temporary sleep,
273  | 		    so it's okay to leave `wake' set to TRUE here] */
274  | 		reveal_invis = TRUE;
275  | 		if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
276  | 		    slept_monst(mtmp);
277  | 		if (!Blind) makeknown(WAN_SLEEP);
278  | 		break;
279  | 	case SPE_STONE_TO_FLESH:
280  | 		if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
281  | 		    char *name = Monnam(mtmp);
282  | 		    /* turn into flesh golem */
283  | 		    if (newcham(mtmp, &mons[PM_FLESH_GOLEM])) {
284  | 			if (canseemon(mtmp))
285  | 			    pline("%s turns to flesh!", name);
286  | 		    } else {
287  | 			if (canseemon(mtmp))
288  | 			    pline("%s looks rather fleshy for a moment.",
289  | 				  name);
290  | 		    }
291  | 		} else
292  | 		    wake = FALSE;
293  | 		break;
294  | 	case SPE_DRAIN_LIFE:
295  | 		dmg = rnd(8);
296  | 		if(dbldam) dmg *= 2;
297  | 		if (otyp == SPE_DRAIN_LIFE)
298  | 			dmg += spell_damage_bonus();
299  | 		if (resists_drli(mtmp))
300  | 		    shieldeff(mtmp->mx, mtmp->my);
301  | 		else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) &&
302  | 				mtmp->mhp > 0) {
303  | 		    mtmp->mhp -= dmg;
304  | 		    mtmp->mhpmax -= dmg;
305  | 		    if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev <= 0)
306  | 		    	xkilled(mtmp, 1);
307  | 		    else {
308  | 		    	mtmp->m_lev--;
309  | 		    	if (canseemon(mtmp))
310  | 		    	    pline("%s suddenly seems weaker!", Monnam(mtmp));
311  | 		    }
312  | 		}
313  | 		break;
314  | 	default:
315  | 		impossible("What an interesting effect (%d)", otyp);
316  | 		break;
317  | 	}
318  | 	if(wake) {
319  | 	    if(mtmp->mhp > 0) {
320  | 		wakeup(mtmp);
321  | 		m_respond(mtmp);
322  | 		if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp);
323  | 	    } else if(mtmp->m_ap_type)
324  | 		seemimic(mtmp); /* might unblock if mimicing a boulder/door */
325  | 	}
326  | 	/* note: bhitpos won't be set if swallowed, but that's okay since
327  | 	 * reveal_invis will be false.  We can't use mtmp->mx, my since it
328  | 	 * might be an invisible worm hit on the tail.
329  | 	 */
330  | 	if (reveal_invis) {
331  | 	    if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
332  | 							!canspotmon(mtmp))
333  | 		map_invisible(bhitpos.x, bhitpos.y);
334  | 	}
335  | 	return 0;
336  | }
337  | 
338  | void
339  | probe_monster(mtmp)
340  | struct monst *mtmp;
341  | {
342  | 	struct obj *otmp;
343  | 
344  | 	mstatusline(mtmp);
345  | 	if (notonhead) return;	/* don't show minvent for long worm tail */
346  | 
347  | 	if (mtmp->minvent || mtmp->mgold) {
348  | 	    for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
349  | 		otmp->dknown = 1;	/* treat as "seen" */
350  | 	    (void) display_minventory(mtmp, MINV_ALL);
351  | 	} else {
352  | 	    pline("%s is not carrying anything.", noit_Monnam(mtmp));
353  | 	}
354  | }
355  | 
356  | #endif /*OVLB*/
357  | #ifdef OVL1
358  | 
359  | /*
360  |  * Return the object's physical location.  This only makes sense for
361  |  * objects that are currently on the level (i.e. migrating objects
362  |  * are nowhere).  By default, only things that can be seen (in hero's
363  |  * inventory, monster's inventory, or on the ground) are reported.
364  |  * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
365  |  * the location of buried and contained objects.  Note that if an
366  |  * object is carried by a monster, its reported position may change
367  |  * from turn to turn.  This function returns FALSE if the position
368  |  * is not available or subject to the constraints above.
369  |  */
370  | boolean
371  | get_obj_location(obj, xp, yp, locflags)
372  | struct obj *obj;
373  | xchar *xp, *yp;
374  | int locflags;
375  | {
376  | 	switch (obj->where) {
377  | 	    case OBJ_INVENT:
378  | 		*xp = u.ux;
379  | 		*yp = u.uy;
380  | 		return TRUE;
381  | 	    case OBJ_FLOOR:
382  | 		*xp = obj->ox;
383  | 		*yp = obj->oy;
384  | 		return TRUE;
385  | 	    case OBJ_MINVENT:
386  | 		if (obj->ocarry->mx) {
387  | 		    *xp = obj->ocarry->mx;
388  | 		    *yp = obj->ocarry->my;
389  | 		    return TRUE;
390  | 		}
391  | 		break;	/* !mx => migrating monster */
392  | 	    case OBJ_BURIED:
393  | 		if (locflags & BURIED_TOO) {
394  | 		    *xp = obj->ox;
395  | 		    *yp = obj->oy;
396  | 		    return TRUE;
397  | 		}
398  | 		break;
399  | 	    case OBJ_CONTAINED:
400  | 		if (locflags & CONTAINED_TOO)
401  | 		    return get_obj_location(obj->ocontainer, xp, yp, locflags);
402  | 		break;
403  | 	}
404  | 	*xp = *yp = 0;
405  | 	return FALSE;
406  | }
407  | 
408  | boolean
409  | get_mon_location(mon, xp, yp, locflags)
410  | struct monst *mon;
411  | xchar *xp, *yp;
412  | int locflags;	/* non-zero means get location even if monster is buried */
413  | {
414  | 	if (mon == &youmonst) {
415  | 	    *xp = u.ux;
416  | 	    *yp = u.uy;
417  | 	    return TRUE;
418  | 	} else if (mon->mx > 0 && (!mon->mburied || locflags)) {
419  | 	    *xp = mon->mx;
420  | 	    *yp = mon->my;
421  | 	    return TRUE;
422  | 	} else {	/* migrating or buried */
423  | 	    *xp = *yp = 0;
424  | 	    return FALSE;
425  | 	}
426  | }
427  | 
428  | /* used by revive() and animate_statue() */
429  | struct monst *
430  | montraits(obj,cc)
431  | struct obj *obj;
432  | coord *cc;
433  | {
434  | 	struct monst *mtmp = (struct monst *)0;
435  | 	struct monst *mtmp2 = (struct monst *)0;
436  | 
437  | 	if (obj->oxlth && (obj->oattached == OATTACHED_MONST))
438  | 		mtmp2 = get_mtraits(obj, TRUE);
439  | 	if (mtmp2) {
440  | 		/* save_mtraits() validated mtmp2->mnum */
441  | 		mtmp2->data = &mons[mtmp2->mnum];
442  | 		if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
443  | 			return (struct monst *)0;
444  | 		mtmp = makemon(mtmp2->data,
445  | 				cc->x, cc->y, NO_MINVENT|MM_NOWAIT);
446  | 		if (!mtmp) return mtmp;
447  | 
448  | 		/* heal the monster */
449  | 		if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
450  | 			mtmp2->mhpmax = mtmp->mhpmax;
451  | 		mtmp2->mhp = mtmp2->mhpmax;
452  | 		/* Get these ones from mtmp */
453  | 		mtmp2->minvent = mtmp->minvent; /*redundant*/
454  | 		mtmp2->m_id = mtmp->m_id;
455  | 		mtmp2->mx   = mtmp->mx;
456  | 		mtmp2->my   = mtmp->my;
457  | 		mtmp2->mux  = mtmp->mux;
458  | 		mtmp2->muy  = mtmp->muy;
459  | 		mtmp2->mw   = mtmp->mw;
460  | 		mtmp2->wormno = mtmp->wormno;
461  | 		mtmp2->misc_worn_check = mtmp->misc_worn_check;
462  | 		mtmp2->weapon_check = mtmp->weapon_check;
463  | 		mtmp2->mtrapseen = mtmp->mtrapseen;
464  | 		mtmp2->mflee = mtmp->mflee;
465  | 		mtmp2->mburied = mtmp->mburied;
466  | 		mtmp2->mundetected = mtmp->mundetected;
467  | 		mtmp2->mfleetim = mtmp->mfleetim;
468  | 		mtmp2->mlstmv = mtmp->mlstmv;
469  | 		mtmp2->m_ap_type = mtmp->m_ap_type;
470  | 		/* set these ones explicitly */
471  | 		mtmp2->meating = 0;
472  | 		mtmp2->mleashed = 0;
473  | 		mtmp2->mtrapped = 0;
474  | 		mtmp2->msleeping = 0;
475  | 		mtmp2->mfrozen = 0;
476  | 		mtmp2->mcan = 0;
477  | 		mtmp2->mcansee = 1;	/* set like in makemon */
478  | 		mtmp2->mblinded = 0;
479  | 		mtmp2->mcanmove = 1;	/* set like in makemon */
480  | 		mtmp2->mstun = 0;
481  | 		mtmp2->mconf = 0;
482  | 		replmon(mtmp,mtmp2);
483  | 	}
484  | 	return mtmp2;
485  | }
486  | 
487  | /*
488  |  * Attempt to revive the given corpse, return the revived monster if
489  |  * successful.  Note: this does NOT use up the corpse if it fails.
490  |  */
491  | struct monst *
492  | revive(obj)
493  | register struct obj *obj;
494  | {
495  | 	register struct monst *mtmp = (struct monst *)0;
496  | 	schar savetame = 0;
497  | 	boolean recorporealization = FALSE;
498  | 
499  | 	if(obj->otyp == CORPSE) {
500  | 		int montype = obj->corpsenm;
501  | 		xchar x, y;
502  | 
503  | 		/* only for invent, minvent, or floor */
504  | 		if (!get_obj_location(obj, &x, &y, 0))
505  | 		    return (struct monst *) 0;
506  | 
507  | 		if (MON_AT(x,y)) {
508  | 		    coord new_xy;
509  | 
510  | 		    if (enexto(&new_xy, x, y, &mons[montype]))
511  | 			x = new_xy.x,  y = new_xy.y;
512  | 		}
513  | 
514  | 		if(cant_create(&montype, TRUE)) {
515  | 			/* make a zombie or worm instead */
516  | 			mtmp = makemon(&mons[montype], x, y,
517  | 				       NO_MINVENT|MM_NOWAIT);
518  | 			if (mtmp) {
519  | 				mtmp->mhp = mtmp->mhpmax = 100;
520  | 				mon_adjust_speed(mtmp, 2);	/* MFAST */
521  | 			}
522  | 		} else {
523  | 		    if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
524  | 			    coord xy;
525  | 			    xy.x = x; xy.y = y;
526  | 		    	    mtmp = montraits(obj, &xy);
527  | 		    	    if (mtmp && mtmp->mtame && !mtmp->isminion)
528  | 				wary_dog(mtmp, TRUE);
529  | 		    } else
530  |  		            mtmp = makemon(&mons[montype], x, y,
531  | 				       NO_MINVENT|MM_NOWAIT);
532  | 		    if (mtmp) {
533  | 			if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
534  | 			    unsigned m_id;
535  | 			    struct monst *ghost;
536  | 			    (void) memcpy((genericptr_t)&m_id,
537  | 				    (genericptr_t)obj->oextra, sizeof(m_id));
538  | 			    ghost = find_mid(m_id, FM_FMON);
539  | 		    	    if (ghost && ghost->data == &mons[PM_GHOST]) {
540  | 		    		    int x2, y2;
541  | 		    		    x2 = ghost->mx; y2 = ghost->my;
542  | 		    		    if (ghost->mtame)
543  | 		    		    	savetame = ghost->mtame;
544  | 		    		    if (canseemon(ghost))
545  | 		    		  	pline("%s is suddenly drawn into its former body!",
546  | 						Monnam(ghost));
547  | 				    mongone(ghost);
548  | 				    recorporealization = TRUE;
549  | 				    newsym(x2, y2);
550  | 			    }
551  | 			    /* don't mess with obj->oxlth here */
552  | 			    obj->oattached = OATTACHED_NOTHING;
553  | 			}
554  | 			/* Monster retains its name */
555  | 			if (obj->onamelth)
556  | 			    mtmp = christen_monst(mtmp, ONAME(obj));
557  | 		    }
558  | 		}
559  | 		if (mtmp) {
560  | 			if (obj->oeaten)
561  | 				mtmp->mhp = eaten_stat(mtmp->mhp, obj);
562  | 			/* track that this monster was revived at least once */
563  | 			mtmp->mrevived = 1;
564  | 
565  | 			if (recorporealization) {
566  | 				/* If mtmp is revivification of former tame ghost*/
567  | 				if (savetame) {
568  | 				    struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
569  | 				    if (mtmp2) {
570  | 					mtmp2->mtame = savetame;
571  | 					mtmp = mtmp2;
572  | 				    }
573  | 				}
574  | 				/* was ghost, now alive, it's all very confusing */
575  | 				mtmp->mconf = 1;
576  | 			}
577  | 
578  | 			switch (obj->where) {
579  | 			    case OBJ_INVENT:
580  | 				useup(obj);
581  | 				break;
582  | 			    case OBJ_FLOOR:
583  | 				/* in case MON_AT+enexto for invisible mon */
584  | 				x = obj->ox,  y = obj->oy;
585  | 				/* not useupf(), which charges */
586  | 				if (obj->quan > 1L)
587  | 				    (void) splitobj(obj, 1L);
588  | 				delobj(obj);
589  | 				newsym(x, y);
590  | 				break;
591  | 			    case OBJ_MINVENT:
592  | 				m_useup(obj->ocarry, obj);
593  | 				break;
594  | 			    default:
595  | 				panic("revive");
596  | 			}
597  | 		}
598  | 	}
599  | 	return mtmp;
600  | }
601  | 
602  | STATIC_OVL void
603  | revive_egg(obj)
604  | struct obj *obj;
605  | {
606  | 	/*
607  | 	 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
608  | 	 */
609  | 	if (obj->otyp != EGG) return;
610  | 	if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
611  | 	    attach_egg_hatch_timeout(obj);
612  | }
613  | 
614  | /* try to revive all corpses and eggs carried by `mon' */
615  | int
616  | unturn_dead(mon)
617  | struct monst *mon;
618  | {
619  | 	struct obj *otmp, *otmp2;
620  | 	struct monst *mtmp2;
621  | 	char owner[BUFSZ], corpse[BUFSZ];
622  | 	boolean youseeit;
623  | 	int once = 0, res = 0;
624  | 
625  | 	youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
626  | 	otmp2 = (mon == &youmonst) ? invent : mon->minvent;
627  | 
628  | 	while ((otmp = otmp2) != 0) {
629  | 	    otmp2 = otmp->nobj;
630  | 	    if (otmp->otyp == EGG)
631  | 		revive_egg(otmp);
632  | 	    if (otmp->otyp != CORPSE) continue;
633  | 	    /* save the name; the object is liable to go away */
634  | 	    if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE));
635  | 
636  | 	    /* for a merged group, only one is revived; should this be fixed? */
637  | 	    if ((mtmp2 = revive(otmp)) != 0) {
638  | 		++res;
639  | 		if (youseeit) {
640  | 		    if (!once++) Strcpy(owner,
641  | 					(mon == &youmonst) ? "Your" :
642  | 					s_suffix(Monnam(mon)));
643  | 		    pline("%s %s suddenly comes alive!", owner, corpse);
644  | 		} else if (canseemon(mtmp2))
645  | 		    pline("%s suddenly appears!", Amonnam(mtmp2));
646  | 	    }
647  | 	}
648  | 	return res;
649  | }
650  | #endif /*OVL1*/
651  | 
652  | #ifdef OVLB
653  | static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
654  | 
655  | STATIC_OVL void
656  | costly_cancel(obj)
657  | register struct obj *obj;
658  | {
659  | 	char objroom;
660  | 	struct monst *shkp = (struct monst *)0;
661  | 
662  | 	if (obj->no_charge) return;
663  | 
664  | 	switch (obj->where) {
665  | 	case OBJ_INVENT:
666  | 		if (obj->unpaid) {
667  | 		    shkp = shop_keeper(*u.ushops);
668  | 		    if (!shkp) return;
669  | 		    Norep("You cancel an unpaid object, you pay for it!");
670  | 		    bill_dummy_object(obj);
671  | 		}
672  | 		break;
673  | 	case OBJ_FLOOR:
674  | 		objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE);
675  | 		shkp = shop_keeper(objroom);
676  | 		if (!shkp || !inhishop(shkp)) return;
677  | 		if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
678  | 		    Norep("You cancel it, you pay for it!");
679  | 		    bill_dummy_object(obj);
680  | 		} else
681  | 		    (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
682  | 		break;
683  | 	}
684  | }
685  | 
686  | /* cancel obj, possibly carried by you or a monster */
687  | void
688  | cancel_item(obj)
689  | register struct obj *obj;
690  | {
691  | 	boolean	u_ring = (obj == uleft) || (obj == uright);
692  | 	register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
693  | 
694  | 	switch(obj->otyp) {
695  | 		case RIN_GAIN_STRENGTH:
696  | 			if ((obj->owornmask & W_RING) && u_ring) {
697  | 				ABON(A_STR) -= obj->spe;
698  | 				flags.botl = 1;
699  | 			}
700  | 			break;
701  | 		case RIN_GAIN_CONSTITUTION:
702  | 			if ((obj->owornmask & W_RING) && u_ring) {
703  | 				ABON(A_CON) -= obj->spe;
704  | 				flags.botl = 1;
705  | 			}
706  | 			break;
707  | 		case RIN_ADORNMENT:
708  | 			if ((obj->owornmask & W_RING) && u_ring) {
709  | 				ABON(A_CHA) -= obj->spe;
710  | 				flags.botl = 1;
711  | 			}
712  | 			break;
713  | 		case RIN_INCREASE_ACCURACY:
714  | 			if ((obj->owornmask & W_RING) && u_ring)
715  | 				u.uhitinc -= obj->spe;
716  | 			break;
717  | 		case RIN_INCREASE_DAMAGE:
718  | 			if ((obj->owornmask & W_RING) && u_ring)
719  | 				u.udaminc -= obj->spe;
720  | 			break;
721  | 		case GAUNTLETS_OF_DEXTERITY:
722  | 			if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
723  | 				ABON(A_DEX) -= obj->spe;
724  | 				flags.botl = 1;
725  | 			}
726  | 			break;
727  | 		case HELM_OF_BRILLIANCE:
728  | 			if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
729  | 				ABON(A_INT) -= obj->spe;
730  | 				ABON(A_WIS) -= obj->spe;
731  | 				flags.botl = 1;
732  | 			}
733  | 			break;
734  | 		/* case RIN_PROTECTION:  not needed */
735  | 	}
736  | 	if (objects[obj->otyp].oc_magic
737  | 	    || (obj->spe && (obj->oclass == ARMOR_CLASS ||
738  | 			     obj->oclass == WEAPON_CLASS || is_weptool(obj)))
739  | 	    || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) {
740  | 	    if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) &&
741  | 	       obj->otyp != WAN_CANCELLATION &&
742  | 		 /* can't cancel cancellation */
743  | 		 obj->otyp != MAGIC_LAMP &&
744  | 		 obj->otyp != CANDELABRUM_OF_INVOCATION) {
745  | 		costly_cancel(obj);
746  | 		obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
747  | 	    }
748  | 	    switch (obj->oclass) {
749  | 	      case SCROLL_CLASS:
750  | 		costly_cancel(obj);
751  | 		obj->otyp = SCR_BLANK_PAPER;
752  | 		obj->spe = 0;
753  | 		break;
754  | 	      case SPBOOK_CLASS:
755  | 		if (obj->otyp != SPE_CANCELLATION &&
756  | 			obj->otyp != SPE_BOOK_OF_THE_DEAD) {
757  | 		    costly_cancel(obj);
758  | 		    obj->otyp = SPE_BLANK_PAPER;
759  | 		}
760  | 		break;
761  | 	      case POTION_CLASS:
762  | 		costly_cancel(obj);
763  | 		if (obj->otyp == POT_SICKNESS ||
764  | 		    obj->otyp == POT_SEE_INVISIBLE) {
765  | 	    /* sickness is "biologically contaminated" fruit juice; cancel it
766  | 	     * and it just becomes fruit juice... whereas see invisible
767  | 	     * tastes like "enchanted" fruit juice, it similarly cancels.
768  | 	     */
769  | 		    obj->otyp = POT_FRUIT_JUICE;
770  | 		} else {
771  | 	            obj->otyp = POT_WATER;
772  | 		    obj->odiluted = 0; /* same as any other water */
773  | 		}
774  | 		break;
775  | 	    }
776  | 	}
777  | 	if (holy) costly_cancel(obj);
778  | 	unbless(obj);
779  | 	uncurse(obj);
780  | #ifdef INVISIBLE_OBJECTS
781  | 	if (obj->oinvis) obj->oinvis = 0;
782  | #endif
783  | 	return;
784  | }
785  | 
786  | /* Remove a positive enchantment or charge from obj,
787  |  * possibly carried by you or a monster
788  |  */
789  | boolean
790  | drain_item(obj)
791  | register struct obj *obj;
792  | {
793  | 	boolean u_ring;
794  | 
795  | 
796  | 	/* Is this a charged/enchanted object? */
797  | 	if (!obj || (!objects[obj->otyp].oc_charged &&
798  | 			obj->oclass != WEAPON_CLASS &&
799  | 			obj->oclass != ARMOR_CLASS && !is_weptool(obj)) ||
800  | 			obj->spe <= 0)
801  | 	    return (FALSE);
802  | 	if (obj_resists(obj, 10, 90))
803  | 	    return (FALSE);
804  | 
805  | 	/* Charge for the cost of the object */
806  | 	costly_cancel(obj);	/* The term "cancel" is okay for now */
807  | 
808  | 	/* Drain the object and any implied effects */
809  | 	obj->spe--;
810  | 	u_ring = (obj == uleft) || (obj == uright);
811  | 	switch(obj->otyp) {
812  | 	case RIN_GAIN_STRENGTH:
813  | 	    if ((obj->owornmask & W_RING) && u_ring) {
814  | 	    	ABON(A_STR)--;
815  | 	    	flags.botl = 1;
816  | 	    }
817  | 	    break;
818  | 	case RIN_GAIN_CONSTITUTION:
819  | 	    if ((obj->owornmask & W_RING) && u_ring) {
820  | 	    	ABON(A_CON)--;
821  | 	    	flags.botl = 1;
822  | 	    }
823  | 	    break;
824  | 	case RIN_ADORNMENT:
825  | 	    if ((obj->owornmask & W_RING) && u_ring) {
826  | 	    	ABON(A_CHA)--;
827  | 	    	flags.botl = 1;
828  | 	    }
829  | 	    break;
830  | 	case RIN_INCREASE_ACCURACY:
831  | 	    if ((obj->owornmask & W_RING) && u_ring)
832  | 	    	u.uhitinc--;
833  | 	    break;
834  | 	case RIN_INCREASE_DAMAGE:
835  | 	    if ((obj->owornmask & W_RING) && u_ring)
836  | 	    	u.udaminc--;
837  | 	    break;
838  | 	case HELM_OF_BRILLIANCE:
839  | 	    if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
840  | 	    	ABON(A_INT)--;
841  | 	    	ABON(A_WIS)--;
842  | 	    	flags.botl = 1;
843  | 	    }
844  | 	    break;
845  | 	case GAUNTLETS_OF_DEXTERITY:
846  | 	    if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
847  | 	    	ABON(A_DEX)--;
848  | 	    	flags.botl = 1;
849  | 	    }
850  | 	    break;
851  | 	case RIN_PROTECTION:
852  | 	    flags.botl = 1;
853  | 	    break;
854  | 	}
855  | 	return (TRUE);
856  | }
857  | 
858  | #endif /*OVLB*/
859  | #ifdef OVL0
860  | 
861  | boolean
862  | obj_resists(obj, ochance, achance)
863  | struct obj *obj;
864  | int ochance, achance;	/* percent chance for ordinary objects, artifacts */
865  | {
866  | 	if (obj->otyp == AMULET_OF_YENDOR ||
867  | 	    obj->otyp == SPE_BOOK_OF_THE_DEAD ||
868  | 	    obj->otyp == CANDELABRUM_OF_INVOCATION ||
869  | 	    obj->otyp == BELL_OF_OPENING ||
870  | 	    (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
871  | 		return TRUE;
872  | 	} else {
873  | 		int chance = rn2(100);
874  | 
875  | 		return((boolean)(chance < (obj->oartifact ? achance : ochance)));
876  | 	}
877  | }
878  | 
879  | boolean
880  | obj_shudders(obj)
881  | struct obj *obj;
882  | {
883  | 	int	zap_odds;
884  | 
885  | 	if (obj->oclass == WAND_CLASS)
886  | 		zap_odds = 3;	/* half-life = 2 zaps */
887  | 	else if (obj->cursed)
888  | 		zap_odds = 3;	/* half-life = 2 zaps */
889  | 	else if (obj->blessed)
890  | 		zap_odds = 12;	/* half-life = 8 zaps */
891  | 	else
892  | 		zap_odds = 8;	/* half-life = 6 zaps */
893  | 
894  | 	/* adjust for "large" quantities of identical things */
895  | 	if(obj->quan > 4L) zap_odds /= 2;
896  | 
897  | 	return((boolean)(! rn2(zap_odds)));
898  | }
899  | #endif /*OVL0*/
900  | #ifdef OVLB
901  | 
902  | /* Use up at least minwt number of things made of material mat.
903  |  * There's also a chance that other stuff will be used up.  Finally,
904  |  * there's a random factor here to keep from always using the stuff
905  |  * at the top of the pile.
906  |  */
907  | STATIC_OVL void
908  | polyuse(objhdr, mat, minwt)
909  |     struct obj *objhdr;
910  |     int mat, minwt;
911  | {
912  |     register struct obj *otmp, *otmp2;
913  | 
914  |     for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
915  | 	otmp2 = otmp->nexthere;
916  | 	if (otmp == uball || otmp == uchain) continue;
917  | 	if (obj_resists(otmp, 0, 0)) continue;	/* preserve unique objects */
918  | #ifdef MAIL
919  | 	if (otmp->otyp == SCR_MAIL) continue;
920  | #endif
921  | 
922  | 	if (((int) objects[otmp->otyp].oc_material == mat) ==
923  | 		(rn2(minwt + 1) != 0)) {
924  | 	    /* appropriately add damage to bill */
925  | 	    if (costly_spot(otmp->ox, otmp->oy)) {
926  | 		if (*u.ushops)
927  | 			addtobill(otmp, FALSE, FALSE, FALSE);
928  | 		else
929  | 			(void)stolen_value(otmp,
930  | 					   otmp->ox, otmp->oy, FALSE, FALSE);
931  | 	    }
932  | 	    if (otmp->quan < LARGEST_INT)
933  | 		minwt -= (int)otmp->quan;
934  | 	    else
935  | 		minwt = 0;
936  | 	    delobj(otmp);
937  | 	}
938  |     }
939  | }
940  | 
941  | /*
942  |  * Polymorph some of the stuff in this pile into a monster, preferably
943  |  * a golem of the kind okind.
944  |  */
945  | STATIC_OVL void
946  | create_polymon(obj, okind)
947  |     struct obj *obj;
948  |     int okind;
949  | {
950  | 	struct permonst *mdat = (struct permonst *)0;
951  | 	struct monst *mtmp;
952  | 	const char *material;
953  | 	int pm_index;
954  | 
955  | 	/* no golems if you zap only one object -- not enough stuff */
956  | 	if(!obj || (!obj->nexthere && obj->quan == 1L)) return;
957  | 
958  | 	/* some of these choices are arbitrary */
959  | 	switch(okind) {
960  | 	case IRON:
961  | 	case METAL:
962  | 	case MITHRIL:
963  | 	    pm_index = PM_IRON_GOLEM;
964  | 	    material = "metal ";
965  | 	    break;
966  | 	case COPPER:
967  | 	case SILVER:
968  | 	case PLATINUM:
969  | 	case GEMSTONE:
970  | 	case MINERAL:
971  | 	    pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
972  | 	    material = "lithic ";
973  | 	    break;
974  | 	case 0:
975  | 	case FLESH:
976  | 	    /* there is no flesh type, but all food is type 0, so we use it */
977  | 	    pm_index = PM_FLESH_GOLEM;
978  | 	    material = "organic ";
979  | 	    break;
980  | 	case WOOD:
981  | 	    pm_index = PM_WOOD_GOLEM;
982  | 	    material = "wood ";
983  | 	    break;
984  | 	case LEATHER:
985  | 	    pm_index = PM_LEATHER_GOLEM;
986  | 	    material = "leather ";
987  | 	    break;
988  | 	case CLOTH:
989  | 	    pm_index = PM_ROPE_GOLEM;
990  | 	    material = "cloth ";
991  | 	    break;
992  | 	case BONE:
993  | 	    pm_index = PM_SKELETON;     /* nearest thing to "bone golem" */
994  | 	    material = "bony ";
995  | 	    break;
996  | 	case GOLD:
997  | 	    pm_index = PM_GOLD_GOLEM;
998  | 	    material = "gold ";
999  | 	    break;
1000 | 	case GLASS:
1001 | 	    pm_index = PM_GLASS_GOLEM;
1002 | 	    material = "glassy ";
1003 | 	    break;
1004 | 	case PAPER:
1005 | 	    pm_index = PM_PAPER_GOLEM;
1006 | 	    material = "paper ";
1007 | 	    break;
1008 | 	default:
1009 | 	    /* if all else fails... */
1010 | 	    pm_index = PM_STRAW_GOLEM;
1011 | 	    material = "";
1012 | 	    break;
1013 | 	}
1014 | 
1015 | 	if (!(mvitals[pm_index].mvflags & G_GENOD))
1016 | 		mdat = &mons[pm_index];
1017 | 
1018 | 	mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1019 | 	polyuse(obj, okind, (int)mons[pm_index].cwt);
1020 | 
1021 | 	if(!Blind && mtmp) {
1022 | 	    pline("Some %sobjects meld, and %s arises from the pile!",
1023 | 		  material, a_monnam(mtmp));
1024 | 	}
1025 | }
1026 | 
1027 | /* Assumes obj is on the floor. */
1028 | void
1029 | do_osshock(obj)
1030 | struct obj *obj;
1031 | {
1032 | 	long i;
1033 | 
1034 | #ifdef MAIL
1035 | 	if (obj->otyp == SCR_MAIL) return;
1036 | #endif
1037 | 	obj_zapped = TRUE;
1038 | 
1039 | 	if(poly_zapped < 0) {
1040 | 	    /* some may metamorphosize */
1041 | 	    for (i = obj->quan; i; i--)
1042 | 		if (! rn2(Luck + 45)) {
1043 | 		    poly_zapped = objects[obj->otyp].oc_material;
1044 | 		    break;
1045 | 		}
1046 | 	}
1047 | 
1048 | 	/* if quan > 1 then some will survive intact */
1049 | 	if (obj->quan > 1L) {
1050 | 	    if (obj->quan > LARGEST_INT)
1051 | 		(void) splitobj(obj, (long)rnd(30000));
1052 | 	    else
1053 | 		(void) splitobj(obj, (long)rnd((int)obj->quan - 1));
1054 | 	}
1055 | 
1056 | 	/* appropriately add damage to bill */
1057 | 	if (costly_spot(obj->ox, obj->oy)) {
1058 | 		if (*u.ushops)
1059 | 			addtobill(obj, FALSE, FALSE, FALSE);
1060 | 		else
1061 | 			(void)stolen_value(obj,
1062 | 					   obj->ox, obj->oy, FALSE, FALSE);
1063 | 	}
1064 | 
1065 | 	/* zap the object */
1066 | 	delobj(obj);
1067 | }
1068 | 
1069 | /*
1070 |  * Polymorph the object to the given object ID.  If the ID is STRANGE_OBJECT
1071 |  * then pick random object from the source's class (this is the standard
1072 |  * "polymorph" case).  If ID is set to a specific object, inhibit fusing
1073 |  * n objects into 1.  This could have been added as a flag, but currently
1074 |  * it is tied to not being the standard polymorph case. The new polymorphed
1075 |  * object replaces obj in its link chains.
1076 |  *
1077 |  * This should be safe to call for an object anywhere.
1078 |  */
1079 | void
1080 | poly_obj(obj, id)
1081 | 	struct obj *obj;
1082 | 	int id;
1083 | {
1084 | 	struct obj *otmp;
1085 | 	xchar ox, oy;
1086 | 	boolean can_merge = (id == STRANGE_OBJECT);
1087 | 	int obj_location = obj->where;
1088 | 
1089 | 	if (id == STRANGE_OBJECT) { /* preserve symbol */
1090 | 	    int try_limit = 3;
1091 | 	    /* Try up to 3 times to make the magic-or-not status of
1092 | 	       the new item be the same as it was for the old one. */
1093 | 	    otmp = (struct obj *)0;
1094 | 	    do {
1095 | 		if (otmp) delobj(otmp);
1096 | 		otmp = mkobj(obj->oclass, FALSE);
1097 | 	    } while (--try_limit > 0 &&
1098 | 		  objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic);
1099 | 	} else {
1100 | 	    /* literally replace obj with this new thing */
1101 | 	    otmp = mksobj(id, FALSE, FALSE);
1102 | 	/* Actually more things use corpsenm but they polymorph differently */
1103 | #define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE)
1104 | 	    if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
1105 | 		otmp->corpsenm = obj->corpsenm;
1106 | #undef USES_CORPSENM
1107 | 	}
1108 | 
1109 | 	/* preserve quantity */
1110 | 	otmp->quan = obj->quan;
1111 | 	/* preserve the shopkeepers (lack of) interest */
1112 | 	otmp->no_charge = obj->no_charge;
1113 | 	/* preserve inventory letter if in inventory */
1114 | 	if (obj_location == OBJ_INVENT)
1115 | 	    otmp->invlet = obj->invlet;
1116 | #ifdef MAIL
1117 | 	/* You can't send yourself 100 mail messages and then
1118 | 	 * polymorph them into useful scrolls
1119 | 	 */
1120 | 	if (obj->otyp == SCR_MAIL) {
1121 | 		otmp->otyp = SCR_MAIL;
1122 | 		otmp->spe = 1;
1123 | 	}
1124 | #endif
1125 | 
1126 | 	/* avoid abusing eggs laid by you */
1127 | 	if (obj->otyp == EGG && obj->spe) {
1128 | 		int mnum, tryct = 100;
1129 | 
1130 | 		/* first, turn into a generic egg */
1131 | 		if (otmp->otyp == EGG)
1132 | 		    kill_egg(otmp);
1133 | 		else {
1134 | 		    otmp->otyp = EGG;
1135 | 		    otmp->owt = weight(otmp);
1136 | 		}
1137 | 		otmp->corpsenm = NON_PM;
1138 | 		otmp->spe = 0;
1139 | 
1140 | 		/* now change it into something layed by the hero */
1141 | 		while (tryct--) {
1142 | 		    mnum = can_be_hatched(random_monster());
1143 | 		    if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
1144 | 			otmp->spe = 1;	/* layed by hero */
1145 | 			otmp->corpsenm = mnum;
1146 | 			attach_egg_hatch_timeout(otmp);
1147 | 			break;
1148 | 		    }
1149 | 		}
1150 | 	}
1151 | 
1152 | 	/* keep special fields (including charges on wands) */
1153 | 	if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe;
1154 | 	otmp->recharged = obj->recharged;
1155 | 
1156 | 	otmp->cursed = obj->cursed;
1157 | 	otmp->blessed = obj->blessed;
1158 | 	otmp->oeroded = obj->oeroded;
1159 | 	otmp->oeroded2 = obj->oeroded2;
1160 | 	if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0;
1161 | 	if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0;
1162 | 	if (is_damageable(otmp))
1163 | 	    otmp->oerodeproof = obj->oerodeproof;
1164 | 
1165 | 	/* Keep chest/box traps and poisoned ammo if we may */
1166 | 	if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE;
1167 | 
1168 | 	if (obj->opoisoned && is_poisonable(otmp))
1169 | 		otmp->opoisoned = TRUE;
1170 | 
1171 | 	if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
1172 | 	/* turn crocodile corpses into shoes */
1173 | 	    if (obj->corpsenm == PM_CROCODILE) {
1174 | 		otmp->otyp = LOW_BOOTS;
1175 | 		otmp->oclass = ARMOR_CLASS;
1176 | 		otmp->spe = 0;
1177 | 		otmp->oeroded = 0;
1178 | 		otmp->oerodeproof = TRUE;
1179 | 		otmp->quan = 1L;
1180 | 		otmp->cursed = FALSE;
1181 | 	    }
1182 | 	}
1183 | 
1184 | 	/* no box contents --KAA */
1185 | 	if (Has_contents(otmp)) delete_contents(otmp);
1186 | 
1187 | 	/* 'n' merged objects may be fused into 1 object */
1188 | 	if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge ||
1189 | 				(can_merge && otmp->quan > (long)rn2(1000))))
1190 | 	    otmp->quan = 1L;
1191 | 
1192 | 	switch (otmp->oclass) {
1193 | 
1194 | 	case TOOL_CLASS:
1195 | 	    if (otmp->otyp == MAGIC_LAMP) {
1196 | 		otmp->otyp = OIL_LAMP;
1197 | 		otmp->age = 1500L;	/* "best" oil lamp possible */
1198 | 	    } else if (otmp->otyp == MAGIC_MARKER) {
1199 | 		otmp->recharged = 1;	/* degraded quality */
1200 | 	    }
1201 | 	    /* don't care about the recharge count of other tools */
1202 | 	    break;
1203 | 
1204 | 	case WAND_CLASS:
1205 | 	    while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
1206 | 		otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
1207 | 	    /* altering the object tends to degrade its quality
1208 | 	       (analogous to spellbook `read count' handling) */
1209 | 	    if ((int)otmp->recharged < rn2(7))	/* recharge_limit */
1210 | 		otmp->recharged++;
1211 | 	    break;
1212 | 
1213 | 	case POTION_CLASS:
1214 | 	    while (otmp->otyp == POT_POLYMORPH)
1215 | 		otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1216 | 	    break;
1217 | 
1218 | 	case SPBOOK_CLASS:
1219 | 	    while (otmp->otyp == SPE_POLYMORPH)
1220 | 		otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
1221 | 	    /* reduce spellbook abuse */
1222 | 	    otmp->spestudied += 1;
1223 | 	    break;
1224 | 
1225 | 	case GEM_CLASS:
1226 | 	    if (otmp->quan > (long) rnd(4) &&
1227 | 		    objects[obj->otyp].oc_material == MINERAL &&
1228 | 		    objects[otmp->otyp].oc_material != MINERAL) {
1229 | 		otmp->otyp = ROCK;	/* transmutation backfired */
1230 | 		otmp->quan /= 2L;	/* some material has been lost */
1231 | 	    }
1232 | 	    break;
1233 | 	}
1234 | 
1235 | 	/* update the weight */
1236 | 	otmp->owt = weight(otmp);
1237 | 
1238 | 	/* for now, take off worn items being polymorphed */
1239 | 	if (obj_location == OBJ_INVENT) {
1240 | 	    if (id == STRANGE_OBJECT)
1241 | 		remove_worn_item(obj);
1242 | 	    else {
1243 | 		/* This is called only for stone to flesh.  It's a lot simpler
1244 | 		 * than it otherwise might be.  We don't need to check for
1245 | 		 * special effects when putting them on (no meat objects have
1246 | 		 * any) and only three worn masks are possible.
1247 | 		 */
1248 | 		otmp->owornmask = obj->owornmask;
1249 | 		remove_worn_item(obj);
1250 | 		setworn(otmp, otmp->owornmask);
1251 | 		if (otmp->owornmask & LEFT_RING)
1252 | 		    uleft = otmp;
1253 | 		if (otmp->owornmask & RIGHT_RING)
1254 | 		    uright = otmp;
1255 | 		if (otmp->owornmask & W_WEP)
1256 | 		    uwep = otmp;
1257 | 		if (otmp->owornmask & W_SWAPWEP)
1258 | 		    uswapwep = otmp;
1259 | 		if (otmp->owornmask & W_QUIVER)
1260 | 		    uquiver = otmp;
1261 | 		goto no_unwear;
1262 | 	    }
1263 | 	}
1264 | 
1265 | 	/* preserve the mask in case being used by something else */
1266 | 	otmp->owornmask = obj->owornmask;
1267 | no_unwear:
1268 | 
1269 | 	if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER &&
1270 | 		otmp->otyp != BOULDER)
1271 | 	    unblock_point(obj->ox, obj->oy);
1272 | 
1273 | 	/* ** we are now done adjusting the object ** */
1274 | 
1275 | 
1276 | 	/* swap otmp for obj */
1277 | 	replace_object(obj, otmp);
1278 | 	if (obj_location == OBJ_INVENT) {
1279 | 	    /*
1280 | 	     * We may need to do extra adjustments for the hero if we're
1281 | 	     * messing with the hero's inventory.  The following calls are
1282 | 	     * equivalent to calling freeinv on obj and addinv on otmp,
1283 | 	     * while doing an in-place swap of the actual objects.
1284 | 	     */
1285 | 	    freeinv_core(obj);
1286 | 	    addinv_core1(otmp);
1287 | 	    addinv_core2(otmp);
1288 | 	}
1289 | 
1290 | 	if ((!carried(otmp) || obj->unpaid) &&
1291 | 		get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
1292 | 		costly_spot(ox, oy)) {
1293 | 	    register struct monst *shkp =
1294 | 		shop_keeper(*in_rooms(ox, oy, SHOPBASE));
1295 | 
1296 | 	    if ((!obj->no_charge ||
1297 | 		 (Has_contents(obj) &&
1298 | 		    (contained_cost(obj, shkp, 0L, FALSE) != 0L)))
1299 | 	       && inhishop(shkp)) {
1300 | 		if(shkp->mpeaceful) {
1301 | 		    if(*u.ushops && *in_rooms(u.ux, u.uy, 0) ==
1302 | 			    *in_rooms(shkp->mx, shkp->my, 0) &&
1303 | 			    !costly_spot(u.ux, u.uy))
1304 | 			make_angry_shk(shkp, ox, oy);
1305 | 		    else {
1306 | 			pline("%s gets angry!", Monnam(shkp));
1307 | 			hot_pursuit(shkp);
1308 | 		    }
1309 | 		} else Norep("%s is furious!", Monnam(shkp));
1310 | 	    }
1311 | 	}
1312 | 	delobj(obj);
1313 | 	return;
1314 | }
1315 | 
1316 | /*
1317 |  * Object obj was hit by the effect of the wand/spell otmp.  Return
1318 |  * non-zero if the wand/spell had any effect.
1319 |  */
1320 | int
1321 | bhito(obj, otmp)
1322 | struct obj *obj, *otmp;
1323 | {
1324 | 	int res = 1;	/* affected object by default */
1325 | 
1326 | 	/*
1327 | 	 * Some parts of this function expect the object to on the floor
1328 | 	 * obj->{ox,oy} to be valid.  The exception to this (so far) is
1329 | 	 * for the STONE_TO_FLESH spell.
1330 | 	 */
1331 | 	if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
1332 | 	    impossible("bhito: obj is not floor or Stone To Flesh spell");
1333 | 
1334 | 	if (obj == uball) {
1335 | 		res = 0;
1336 | 	} else if (obj == uchain) {
1337 | 		if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
1338 | 		    unpunish();
1339 | 		    makeknown(otmp->otyp);
1340 | 		} else
1341 | 		    res = 0;
1342 | 	} else
1343 | 	switch(otmp->otyp) {
1344 | 	case WAN_POLYMORPH:
1345 | 	case SPE_POLYMORPH:
1346 | 		if (obj->otyp == WAN_POLYMORPH ||
1347 | 			obj->otyp == SPE_POLYMORPH ||
1348 | 			obj->otyp == POT_POLYMORPH ||
1349 | 			obj_resists(obj, 5, 95)) {
1350 | 		    res = 0;
1351 | 		    break;
1352 | 		}
1353 | 		/* KMH, conduct */
1354 | 		u.uconduct.polypiles++;
1355 | 		/* any saved lock context will be dangerously obsolete */
1356 | 		if (Is_box(obj)) (void) boxlock(obj, otmp);
1357 | 
1358 | 		if (obj_shudders(obj)) {
1359 | 		    if (cansee(obj->ox, obj->oy))
1360 | 			makeknown(otmp->otyp);
1361 | 		    do_osshock(obj);
1362 | 		    break;
1363 | 		}
1364 | 		poly_obj(obj, STRANGE_OBJECT);
1365 | 		newsym(obj->ox,obj->oy);
1366 | 		break;
1367 | 	case WAN_PROBING:
1368 | 		res = !obj->dknown;
1369 | 		/* target object has now been "seen (up close)" */
1370 | 		obj->dknown = 1;
1371 | 		if (Has_contents(obj)) {
1372 | 		    if (!obj->cobj)
1373 | 			pline("%s is empty.", The(xname(obj)));
1374 | 		    else {
1375 | 			struct obj *o;
1376 | 			/* view contents (not recursively) */
1377 | 			for (o = obj->cobj; o; o = o->nobj)
1378 | 			    o->dknown = 1;	/* "seen", even if blind */
1379 | 			(void) display_cinventory(obj);
1380 | 		    }
1381 | 		    res = 1;
1382 | 		}
1383 | 		if (res) makeknown(WAN_PROBING);
1384 | 		break;
1385 | 	case WAN_STRIKING:
1386 | 	case SPE_FORCE_BOLT:
1387 | 		if (obj->otyp == BOULDER)
1388 | 			fracture_rock(obj);
1389 | 		else if (obj->otyp == STATUE)
1390 | 			(void) break_statue(obj);
1391 | 		else {
1392 | 			if (!flags.mon_moving)
1393 | 			    (void)hero_breaks(obj, obj->ox, obj->oy, FALSE);
1394 | 			else
1395 | 			    (void)breaks(obj, obj->ox, obj->oy);
1396 | 			res = 0;
1397 | 		}
1398 | 		/* BUG[?]: shouldn't this depend upon you seeing it happen? */
1399 | 		makeknown(otmp->otyp);
1400 | 		break;
1401 | 	case WAN_CANCELLATION:
1402 | 	case SPE_CANCELLATION:
1403 | 		cancel_item(obj);
1404 | #ifdef TEXTCOLOR
1405 | 		newsym(obj->ox,obj->oy);	/* might change color */
1406 | #endif
1407 | 		break;
1408 | 	case SPE_DRAIN_LIFE:
1409 | 		(void) drain_item(obj);
1410 | 		break;
1411 | 	case WAN_TELEPORTATION:
1412 | 	case SPE_TELEPORT_AWAY:
1413 | 		rloco(obj);
1414 | 		break;
1415 | 	case WAN_MAKE_INVISIBLE:
1416 | #ifdef INVISIBLE_OBJECTS
1417 | 		obj->oinvis = TRUE;
1418 | 		newsym(obj->ox,obj->oy);	/* make object disappear */
1419 | #endif
1420 | 		break;
1421 | 	case WAN_UNDEAD_TURNING:
1422 | 	case SPE_TURN_UNDEAD:
1423 | 		if (obj->otyp == EGG)
1424 | 			revive_egg(obj);
1425 | 		else
1426 | 			res = !!revive(obj);
1427 | 		break;
1428 | 	case WAN_OPENING:
1429 | 	case SPE_KNOCK:
1430 | 	case WAN_LOCKING:
1431 | 	case SPE_WIZARD_LOCK:
1432 | 		if(Is_box(obj))
1433 | 			res = boxlock(obj, otmp);
1434 | 		else
1435 | 			res = 0;
1436 | 		if (res /* && otmp->oclass == WAND_CLASS */)
1437 | 			makeknown(otmp->otyp);
1438 | 		break;
1439 | 	case WAN_SLOW_MONSTER:		/* no effect on objects */
1440 | 	case SPE_SLOW_MONSTER:
1441 | 	case WAN_SPEED_MONSTER:
1442 | 	case WAN_NOTHING:
1443 | 	case SPE_HEALING:
1444 | 	case SPE_EXTRA_HEALING:
1445 | 		res = 0;
1446 | 		break;
1447 | 	case SPE_STONE_TO_FLESH:
1448 | 		if (objects[obj->otyp].oc_material != MINERAL &&
1449 | 			objects[obj->otyp].oc_material != GEMSTONE) {
1450 | 		    res = 0;
1451 | 		    break;
1452 | 		}
1453 | 		/* add more if stone objects are added.. */
1454 | 		switch (objects[obj->otyp].oc_class) {
1455 | 		    case ROCK_CLASS:	/* boulders and statues */
1456 | 			if (obj->otyp == BOULDER) {
1457 | 			    poly_obj(obj, HUGE_CHUNK_OF_MEAT);
1458 | 			    if (In_sokoban(&u.uz))
1459 | 				change_luck(-1);	/* Sokoban guilt */
1460 | 			    goto smell;
1461 | 			} else if (obj->otyp == STATUE) {
1462 | 			    xchar oox, ooy;
1463 | 
1464 | 			    (void) get_obj_location(obj, &oox, &ooy, 0);
1465 | 			    if (!animate_statue(obj, oox, ooy,
1466 | 						ANIMATE_SPELL, (int *)0)) {
1467 | makecorpse:			if (mons[obj->corpsenm].geno &
1468 | 							(G_NOCORPSE|G_UNIQ)) {
1469 | 				    res = 0;
1470 | 				    break;
1471 | 				}
1472 | 				/* Unlikely to get here since genociding
1473 | 				 * monsters also sets the G_NOCORPSE flag.
1474 | 				 */
1475 | 				poly_obj(obj, CORPSE);
1476 | 				break;
1477 | 			    }
1478 | 			} else { /* new rock class object... */
1479 | 			    /* impossible? */
1480 | 			    res = 0;
1481 | 			}
1482 | 			break;
1483 | 		    case TOOL_CLASS:	/* figurine */
1484 | 		    {
1485 | 			struct monst *mon;
1486 | 			xchar oox, ooy;
1487 | 
1488 | 			if (obj->otyp != FIGURINE) {
1489 | 			    res = 0;
1490 | 			    break;
1491 | 			}
1492 | 			(void) get_obj_location(obj, &oox, &ooy, 0);
1493 | 			mon = makemon(&mons[obj->corpsenm],
1494 | 				      oox, ooy, NO_MM_FLAGS);
1495 | 			if (mon) {
1496 | 			    delobj(obj);
1497 | 			    if (cansee(mon->mx, mon->my))
1498 | 				pline_The("figurine animates!");
1499 | 			    break;
1500 | 			}
1501 | 			goto makecorpse;
1502 | 		    }
1503 | 		    /* maybe add weird things to become? */
1504 | 		    case RING_CLASS:	/* some of the rings are stone */
1505 | 			poly_obj(obj, MEAT_RING);
1506 | 			goto smell;
1507 | 		    case WAND_CLASS:	/* marble wand */
1508 | 			poly_obj(obj, MEAT_STICK);
1509 | 			goto smell;
1510 | 		    case GEM_CLASS:	/* rocks & gems */
1511 | 			poly_obj(obj, MEATBALL);
1512 | smell:
1513 | 			if (herbivorous(youmonst.data) &&
1514 | 				!carnivorous(youmonst.data))
1515 | 			    Norep("You smell the odor of meat.");
1516 | 			else
1517 | 			    Norep("You smell a delicious smell.");
1518 | 			break;
1519 | 		    default:
1520 | 			res = 0;
1521 | 			break;
1522 | 		}
1523 | 		newsym(obj->ox,obj->oy);
1524 | 		break;
1525 | 	default:
1526 | 		impossible("What an interesting effect (%d)", otmp->otyp);
1527 | 		break;
1528 | 	}
1529 | 	return res;
1530 | }
1531 | 
1532 | /* returns nonzero if something was hit */
1533 | int
1534 | bhitpile(obj,fhito,tx,ty)
1535 |     struct obj *obj;
1536 |     int FDECL((*fhito), (OBJ_P,OBJ_P));
1537 |     int tx, ty;
1538 | {
1539 |     int hitanything = 0;
1540 |     register struct obj *otmp, *next_obj;
1541 | 
1542 |     if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
1543 | 	struct trap *t = t_at(tx, ty);
1544 | 
1545 | 	/* We can't settle for the default calling sequence of
1546 | 	   bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1547 | 	   because that last call might end up operating on our `next_obj'
1548 | 	   (below), rather than on the current object, if it happens to
1549 | 	   encounter a statue which mustn't become animated. */
1550 | 	if (t && t->ttyp == STATUE_TRAP)
1551 | 	    (void) activate_statue_trap(t, tx, ty, TRUE);
1552 |     }
1553 | 
1554 |     poly_zapped = -1;
1555 |     for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
1556 | 	/* Fix for polymorph bug, Tim Wright */
1557 | 	next_obj = otmp->nexthere;
1558 | 	hitanything += (*fhito)(otmp, obj);
1559 |     }
1560 |     if(poly_zapped >= 0)
1561 | 	create_polymon(level.objects[tx][ty], poly_zapped);
1562 | 
1563 |     return hitanything;
1564 | }
1565 | #endif /*OVLB*/
1566 | #ifdef OVL1
1567 | 
1568 | /*
1569 |  * zappable - returns 1 if zap is available, 0 otherwise.
1570 |  *	      it removes a charge from the wand if zappable.
1571 |  * added by GAN 11/03/86
1572 |  */
1573 | int
1574 | zappable(wand)
1575 | register struct obj *wand;
1576 | {
1577 | 	if(wand->spe < 0 || (wand->spe == 0 && rn2(121)))
1578 | 		return 0;
1579 | 	if(wand->spe == 0)
1580 | 		You("wrest one last charge from the worn-out wand.");
1581 | 	wand->spe--;
1582 | 	return 1;
1583 | }
1584 | 
1585 | /*
1586 |  * zapnodir - zaps a NODIR wand/spell.
1587 |  * added by GAN 11/03/86
1588 |  */
1589 | void
1590 | zapnodir(obj)
1591 | register struct obj *obj;
1592 | {
1593 | 	boolean known = FALSE;
1594 | 
1595 | 	switch(obj->otyp) {
1596 | 		case WAN_LIGHT:
1597 | 		case SPE_LIGHT:
1598 | 			litroom(TRUE,obj);
1599 | 			if (!Blind) known = TRUE;
1600 | 			break;
1601 | 		case WAN_SECRET_DOOR_DETECTION:
1602 | 		case SPE_DETECT_UNSEEN:
1603 | 			if(!findit()) return;
1604 | 			if (!Blind) known = TRUE;
1605 | 			break;
1606 | 		case WAN_CREATE_MONSTER:
1607 | 			known = create_critters(rn2(23) ? 1 : rn1(7,2),
1608 | 					(struct permonst *)0);
1609 | 			break;
1610 | 		case WAN_WISHING:
1611 | 			known = TRUE;
1612 | 			if(Luck + rn2(5) < 0) {
1613 | 				pline("Unfortunately, nothing happens.");
1614 | 				break;
1615 | 			}
1616 | 			makewish();
1617 | 			break;
1618 | 		case WAN_ENLIGHTENMENT:
1619 | 			known = TRUE;
1620 | 			You_feel("self-knowledgeable...");
1621 | 			display_nhwindow(WIN_MESSAGE, FALSE);
1622 | 			enlightenment(FALSE);
1623 | 			pline_The("feeling subsides.");
1624 | 			exercise(A_WIS, TRUE);
1625 | 			break;
1626 | 	}
1627 | 	if (known && !objects[obj->otyp].oc_name_known) {
1628 | 		makeknown(obj->otyp);
1629 | 		more_experienced(0,10);
1630 | 	}
1631 | }
1632 | #endif /*OVL1*/
1633 | #ifdef OVL0
1634 | 
1635 | STATIC_OVL void
1636 | backfire(otmp)
1637 | struct obj *otmp;
1638 | {
1639 | 	otmp->in_use = TRUE;	/* in case losehp() is fatal */
1640 | 	pline("%s suddenly explodes!", The(xname(otmp)));
1641 | 	losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN);
1642 | 	useup(otmp);
1643 | }
1644 | 
1645 | static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
1646 | 
1647 | int
1648 | dozap()
1649 | {
1650 | 	register struct obj *obj;
1651 | 	int	damage;
1652 | 
1653 | 	if(check_capacity((char *)0)) return(0);
1654 | 	obj = getobj(zap_syms, "zap");
1655 | 	if(!obj) return(0);
1656 | 
1657 | 	check_unpaid(obj);
1658 | 
1659 | 	/* zappable addition done by GAN 11/03/86 */
1660 | 	if(!zappable(obj)) pline(nothing_happens);
1661 | 	else if(obj->cursed && !rn2(100)) {
1662 | 		backfire(obj);	/* the wand blows up in your face! */
1663 | 		exercise(A_STR, FALSE);
1664 | 		return(1);
1665 | 	} else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) {
1666 | 		if (!Blind)
1667 | 		    pline("%s glows and fades.", The(xname(obj)));
1668 | 		/* make him pay for knowing !NODIR */
1669 | 	} else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) {
1670 | 	    if ((damage = zapyourself(obj, TRUE)) != 0)
1671 | 		losehp(damage, self_pronoun("zapped %sself with a wand", "him"),
1672 | 			NO_KILLER_PREFIX);
1673 | 	} else {
1674 | 
1675 | 		/*	Are we having fun yet?
1676 | 		 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
1677 | 		 * attack -> hitum -> known_hitum -> ghod_hitsu ->
1678 | 		 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
1679 | 		 * useup -> obfree -> dealloc_obj -> free(obj)
1680 | 		 */
1681 | 		current_wand = obj;
1682 | 		weffects(obj);
1683 | 		obj = current_wand;
1684 | 		current_wand = 0;
1685 | 	}
1686 | 	if (obj && obj->spe < 0) {
1687 | 	    pline("%s turns to dust.", The(xname(obj)));
1688 | 	    useup(obj);
1689 | 	}
1690 | 	update_inventory();	/* maybe used a charge */
1691 | 	return(1);
1692 | }
1693 | 
1694 | int
1695 | zapyourself(obj, ordinary)
1696 | struct obj *obj;
1697 | boolean ordinary;
1698 | {
1699 | 	int	damage = 0;
1700 | 
1701 | 	switch(obj->otyp) {
1702 | 		case WAN_STRIKING:
1703 | 		    makeknown(WAN_STRIKING);
1704 | 		case SPE_FORCE_BOLT:
1705 | 		    if(Antimagic) {
1706 | 			shieldeff(u.ux, u.uy);
1707 | 			pline("Boing!");
1708 | 		    } else {
1709 | 			if (ordinary) {
1710 | 			    You("bash yourself!");
1711 | 			    damage = d(2,12);
1712 | 			} else
1713 | 			    damage = d(1 + obj->spe,6);
1714 | 			exercise(A_STR, FALSE);
1715 | 		    }
1716 | 		    break;
1717 | 
1718 | 		case WAN_LIGHTNING:
1719 | 		    makeknown(WAN_LIGHTNING);
1720 | 		    if (!Shock_resistance) {
1721 | 			You("shock yourself!");
1722 | 			damage = d(12,6);
1723 | 			exercise(A_CON, FALSE);
1724 | 		    } else {
1725 | 			shieldeff(u.ux, u.uy);
1726 | 			You("zap yourself, but seem unharmed.");
1727 | 			ugolemeffects(AD_ELEC, d(12,6));
1728 | 		    }
1729 | 		    destroy_item(WAND_CLASS, AD_ELEC);
1730 | 		    destroy_item(RING_CLASS, AD_ELEC);
1731 | 		    if (!resists_blnd(&youmonst)) {
1732 | 			    You(are_blinded_by_the_flash);
1733 | 			    make_blinded((long)rnd(100),FALSE);
1734 | 		    }
1735 | 		    break;
1736 | 
1737 | 		case SPE_FIREBALL:
1738 | 		    You("explode a fireball on top of yourself!");
1739 | 		    explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS);
1740 | 		    break;
1741 | 		case WAN_FIRE:
1742 | 		    makeknown(WAN_FIRE);
1743 | 		case FIRE_HORN:
1744 | 		    if (Fire_resistance) {
1745 | 			shieldeff(u.ux, u.uy);
1746 | 			You_feel("rather warm.");
1747 | 			ugolemeffects(AD_FIRE, d(12,6));
1748 | 		    } else {
1749 | 			pline("You've set yourself afire!");
1750 | 			damage = d(12,6);
1751 | 		    }
1752 | 		    burn_away_slime();
1753 | 		    (void) burnarmor(&youmonst);
1754 | 		    destroy_item(SCROLL_CLASS, AD_FIRE);
1755 | 		    destroy_item(POTION_CLASS, AD_FIRE);
1756 | 		    destroy_item(SPBOOK_CLASS, AD_FIRE);
1757 | 		    break;
1758 | 
1759 | 		case WAN_COLD:
1760 | 		    makeknown(WAN_COLD);
1761 | 		case SPE_CONE_OF_COLD:
1762 | 		case FROST_HORN:
1763 | 		    if (Cold_resistance) {
1764 | 			shieldeff(u.ux, u.uy);
1765 | 			You_feel("a little chill.");
1766 | 			ugolemeffects(AD_COLD, d(12,6));
1767 | 		    } else {
1768 | 			You("imitate a popsicle!");
1769 | 			damage = d(12,6);
1770 | 		    }
1771 | 		    destroy_item(POTION_CLASS, AD_COLD);
1772 | 		    break;
1773 | 
1774 | 		case WAN_MAGIC_MISSILE:
1775 | 		    makeknown(WAN_MAGIC_MISSILE);
1776 | 		case SPE_MAGIC_MISSILE:
1777 | 		    if(Antimagic) {
1778 | 			shieldeff(u.ux, u.uy);
1779 | 			pline_The("missiles bounce!");
1780 | 		    } else {
1781 | 			damage = d(4,6);
1782 | 			pline("Idiot!  You've shot yourself!");
1783 | 		    }
1784 | 		    break;
1785 | 
1786 | 		case WAN_POLYMORPH:
1787 | 		    if (!Unchanging)
1788 | 		    	makeknown(WAN_POLYMORPH);
1789 | 		case SPE_POLYMORPH:
1790 | 		    if (!Unchanging)
1791 | 		    	polyself();
1792 | 		    break;
1793 | 
1794 | 		case WAN_CANCELLATION:
1795 | 		case SPE_CANCELLATION:
1796 | 		    cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
1797 | 		    break;
1798 | 
1799 | 		case SPE_DRAIN_LIFE:
1800 | 			if (!Drain_resistance) {
1801 | 				losexp("life drainage");
1802 | 				makeknown(obj->otyp);
1803 | 			}
1804 | 			damage = 0;	/* No additional damage */
1805 | 			break;
1806 | 
1807 | 		case WAN_MAKE_INVISIBLE: {
1808 | 		    /* have to test before changing HInvis but must change
1809 | 		     * HInvis before doing newsym().
1810 | 		     */
1811 | 		    int msg = !Invis && !Blind && !BInvis;
1812 | 
1813 | 		    if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
1814 | 			/* A mummy wrapping absorbs it and protects you */
1815 | 		        You_feel("rather itchy under your %s.", xname(uarmc));
1816 | 		        break;
1817 | 		    }
1818 | 		    if (ordinary || !rn2(10)) {	/* permanent */
1819 | 			HInvis |= FROMOUTSIDE;
1820 | 		    } else {			/* temporary */
1821 | 		    	incr_itimeout(&HInvis, d(obj->spe, 250));
1822 | 		    }
1823 | 		    if (msg) {
1824 | 			makeknown(WAN_MAKE_INVISIBLE);
1825 | 			newsym(u.ux, u.uy);
1826 | 			self_invis_message();
1827 | 		    }
1828 | 		    break;
1829 | 		}
1830 | 
1831 | 		case WAN_SPEED_MONSTER:
1832 | 		    if (!(HFast & INTRINSIC)) {
1833 | 			if (!Fast)
1834 | 			    You("speed up.");
1835 | 			else
1836 | 			    Your("quickness feels more natural.");
1837 | 			makeknown(WAN_SPEED_MONSTER);
1838 | 			exercise(A_DEX, TRUE);
1839 | 		    }
1840 | 		    HFast |= FROMOUTSIDE;
1841 | 		    break;
1842 | 
1843 | 		case WAN_SLEEP:
1844 | 		    makeknown(WAN_SLEEP);
1845 | 		case SPE_SLEEP:
1846 | 		    if(Sleep_resistance) {
1847 | 			shieldeff(u.ux, u.uy);
1848 | 			You("don't feel sleepy!");
1849 | 		    } else {
1850 | 			pline_The("sleep ray hits you!");
1851 | 			fall_asleep(-rnd(50), TRUE);
1852 | 		    }
1853 | 		    break;
1854 | 
1855 | 		case WAN_SLOW_MONSTER:
1856 | 		case SPE_SLOW_MONSTER:
1857 | 		    if(HFast & (TIMEOUT | INTRINSIC)) {
1858 | 			u_slow_down();
1859 | 			makeknown(obj->otyp);
1860 | 		    }
1861 | 		    break;
1862 | 
1863 | 		case WAN_TELEPORTATION:
1864 | 		case SPE_TELEPORT_AWAY:
1865 | 		    tele();
1866 | 		    break;
1867 | 
1868 | 		case WAN_DEATH:
1869 | 		case SPE_FINGER_OF_DEATH:
1870 | 		    if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
1871 | 			pline((obj->otyp == WAN_DEATH) ?
1872 | 			  "The wand shoots an apparently harmless beam at you."
1873 | 			  : "You seem no deader than before.");
1874 | 			break;
1875 | 		    }
1876 | 		    killer_format = NO_KILLER_PREFIX;
1877 | 		    killer = self_pronoun("shot %sself with a death ray","him");
1878 | 		    You("irradiate yourself with pure energy!");
1879 | 		    You("die.");
1880 | 		    makeknown(obj->otyp);
1881 | 			/* They might survive with an amulet of life saving */
1882 | 		    done(DIED);
1883 | 		    break;
1884 | 		case WAN_UNDEAD_TURNING:
1885 | 		    makeknown(WAN_UNDEAD_TURNING);
1886 | 		case SPE_TURN_UNDEAD:
1887 | 		    (void) unturn_dead(&youmonst);
1888 | 		    if (is_undead(youmonst.data)) {
1889 | 			You_feel("frightened and %sstunned.",
1890 | 			     Stunned ? "even more " : "");
1891 | 			make_stunned(HStun + rnd(30), FALSE);
1892 | 		    } else
1893 | 			You("shudder in dread.");
1894 | 		    break;
1895 | 		case SPE_HEALING:
1896 | 		case SPE_EXTRA_HEALING:
1897 | 		    healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4),
1898 | 			   0, FALSE, (obj->otyp == SPE_EXTRA_HEALING));
1899 | 		    You_feel("%sbetter.",
1900 | 			obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
1901 | 		    break;
1902 | 		case WAN_LIGHT:	/* (broken wand) */
1903 | 		 /* assert( !ordinary ); */
1904 | 		    damage = d(obj->spe, 25);
1905 | #ifdef TOURIST
1906 | 		case EXPENSIVE_CAMERA:
1907 | #endif
1908 | 		    damage += rnd(25);
1909 | 		    if (!resists_blnd(&youmonst)) {
1910 | 			You(are_blinded_by_the_flash);
1911 | 			make_blinded((long)damage, FALSE);
1912 | 			makeknown(obj->otyp);
1913 | 		    }
1914 | 		    damage = 0;	/* reset */
1915 | 		    break;
1916 | 		case WAN_OPENING:
1917 | 		    if (Punished) makeknown(WAN_OPENING);
1918 | 		case SPE_KNOCK:
1919 | 		    if (Punished) Your("chain quivers for a moment.");
1920 | 		    break;
1921 | 		case WAN_DIGGING:
1922 | 		case SPE_DIG:
1923 | 		case SPE_DETECT_UNSEEN:
1924 | 		case WAN_NOTHING:
1925 | 		case WAN_LOCKING:
1926 | 		case SPE_WIZARD_LOCK:
1927 | 		    break;
1928 | 		case WAN_PROBING:
1929 | 		    for (obj = invent; obj; obj = obj->nobj)
1930 | 			obj->dknown = 1;
1931 | 		    /* note: `obj' reused; doesn't point at wand anymore */
1932 | 		    makeknown(WAN_PROBING);
1933 | 		    ustatusline();
1934 | 		    break;
1935 | 		case SPE_STONE_TO_FLESH:
1936 | 		    {
1937 | 		    struct obj *otemp, *onext;
1938 | 		    boolean didmerge;
1939 | 
1940 | 		    if (u.umonnum == PM_STONE_GOLEM)
1941 | 			(void) polymon(PM_FLESH_GOLEM);
1942 | 		    if (Stoned) fix_petrification();	/* saved! */
1943 | 		    /* but at a cost.. */
1944 | 		    for (otemp = invent; otemp; otemp = onext) {
1945 | 			onext = otemp->nobj;
1946 | 			(void) bhito(otemp, obj);
1947 | 			}
1948 | 		    /*
1949 | 		     * It is possible that we can now merge some inventory.
1950 | 		     * Do a higly paranoid merge.  Restart from the beginning
1951 | 		     * until no merges.
1952 | 		     */
1953 | 		    do {
1954 | 			didmerge = FALSE;
1955 | 			for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj)
1956 | 			    for (onext = otemp->nobj; onext; onext = onext->nobj)
1957 | 			    	if (merged(&otemp, &onext)) {
1958 | 			    		didmerge = TRUE;
1959 | 			    		break;
1960 | 			    		}
1961 | 		    } while (didmerge);
1962 | 		    }
1963 | 		    break;
1964 | 		default: impossible("object %d used?",obj->otyp);
1965 | 		    break;
1966 | 	}
1967 | 	return(damage);
1968 | }
1969 | 
1970 | #ifdef STEED
1971 | /* you've zapped a wand downwards while riding
1972 |  * Return TRUE if the steed was hit by the wand.
1973 |  * Return FALSE if the steed was not hit by the wand.
1974 |  */
1975 | STATIC_OVL boolean
1976 | zap_steed(obj)
1977 | struct obj *obj;	/* wand or spell */
1978 | {
1979 | 	int steedhit = FALSE;
1980 | 	
1981 | 	switch (obj->otyp) {
1982 | 
1983 | 	   /*
1984 | 	    * Wands that are allowed to hit the steed
1985 | 	    * Carefully test the results of any that are
1986 | 	    * moved here from the bottom section.
1987 | 	    */
1988 | 		case WAN_PROBING:
1989 | 		    probe_monster(u.usteed);
1990 | 		    makeknown(WAN_PROBING);
1991 | 		    steedhit = TRUE;
1992 | 		    break;
1993 | 		case WAN_TELEPORTATION:
1994 | 		case SPE_TELEPORT_AWAY:
1995 | 		    /* you go together */
1996 | 		    tele();
1997 | 		    if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
1998 | 			(distu(u.ux0, u.uy0) >= 16))
1999 | 				makeknown(obj->otyp);
2000 | 		    steedhit = TRUE;
2001 | 		    break;
2002 | 
2003 | 		/* Default processing via bhitm() for these */
2004 | 		case SPE_CURE_SICKNESS:
2005 | 		case WAN_MAKE_INVISIBLE:
2006 | 		case WAN_CANCELLATION:
2007 | 		case SPE_CANCELLATION:
2008 | 		case WAN_POLYMORPH:
2009 | 		case SPE_POLYMORPH:
2010 | 		case WAN_STRIKING:
2011 | 		case SPE_FORCE_BOLT:
2012 | 		case WAN_SLOW_MONSTER:
2013 | 		case SPE_SLOW_MONSTER:
2014 | 		case WAN_SPEED_MONSTER:
2015 | 		case SPE_HEALING:
2016 | 		case SPE_EXTRA_HEALING:
2017 | 		case SPE_DRAIN_LIFE:
2018 | 		case WAN_OPENING:
2019 | 		case SPE_KNOCK:
2020 | 		    (void) bhitm(u.usteed, obj);
2021 | 		    steedhit = TRUE;
2022 | 		    break;
2023 | 
2024 | 		default:
2025 | 		    steedhit = FALSE;
2026 | 		    break;
2027 | 	}
2028 | 	return steedhit;
2029 | }
2030 | #endif
2031 | 
2032 | #endif /*OVL0*/
2033 | #ifdef OVL3
2034 | 
2035 | /*
2036 |  * cancel a monster (possibly the hero).  inventory is cancelled only
2037 |  * if the monster is zapping itself directly, since otherwise the
2038 |  * effect is too strong.  currently non-hero monsters do not zap
2039 |  * themselves with cancellation.
2040 |  */
2041 | void
2042 | cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
2043 | register struct monst	*mdef;
2044 | register struct obj	*obj;
2045 | boolean			youattack, allow_cancel_kill, self_cancel;
2046 | {
2047 | 	boolean	youdefend = (mdef == &youmonst);
2048 | 	static const char writing_vanishes[] =
2049 | 				"Some writing vanishes from %s head!";
2050 | 	static const char your[] = "your";	/* should be extern */
2051 | 
2052 | 	if (youdefend ? (!youattack && Antimagic)
2053 | 		      : resist(mdef, obj->oclass, 0, NOTELL))
2054 | 		return;		/* resisted cancellation */
2055 | 
2056 | 	if (self_cancel) {	/* 1st cancel inventory */
2057 | 	    struct obj *otmp;
2058 | 
2059 | 	    for (otmp = (youdefend ? invent : mdef->minvent);
2060 | 			    otmp; otmp = otmp->nobj)
2061 | 		cancel_item(otmp);
2062 | 	    if (youdefend) {
2063 | 		flags.botl = 1;	/* potential AC change */
2064 | 		find_ac();
2065 | 	    }
2066 | 	}
2067 | 
2068 | 	/* now handle special cases */
2069 | 	if (youdefend) {
2070 | 	    if (Upolyd) {
2071 | 		if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
2072 | 		    pline(writing_vanishes, your);
2073 | 		rehumanize();
2074 | 	    }
2075 | 	} else {
2076 | 	    mdef->mcan = TRUE;
2077 | 
2078 | 	    if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
2079 | 		were_change(mdef);
2080 | 
2081 | 	    if (mdef->data == &mons[PM_CLAY_GOLEM]) {
2082 | 		if (canseemon(mdef))
2083 | 		    pline(writing_vanishes, s_suffix(mon_nam(mdef)));
2084 | 
2085 | 		if (allow_cancel_kill) {
2086 | 		    if (youattack)
2087 | 			killed(mdef);
2088 | 		    else
2089 | 			monkilled(mdef, "", AD_SPEL);
2090 | 		}
2091 | 	    }
2092 | 	}
2093 | }
2094 | 
2095 | /* you've zapped an immediate type wand up or down */
2096 | STATIC_OVL boolean
2097 | zap_updown(obj)
2098 | struct obj *obj;	/* wand or spell */
2099 | {
2100 | 	boolean striking = FALSE, disclose = FALSE;
2101 | 	int x, y, xx, yy, ptmp;
2102 | 	struct obj *otmp;
2103 | 	struct engr *e;
2104 | 	char buf[BUFSZ];
2105 | 
2106 | 	/* some wands have special effects other than normal bhitpile */
2107 | 	/* drawbridge might change <u.ux,u.uy> */
2108 | 	x = xx = u.ux;	/* <x,y> is zap location */
2109 | 	y = yy = u.uy;	/* <xx,yy> is drawbridge (portcullis) position */
2110 | 	switch (obj->otyp) {
2111 | 	case WAN_PROBING:
2112 | 	    ptmp = 0;
2113 | 	    if (u.dz < 0) {
2114 | 		You("probe towards the %s.", ceiling(x,y));
2115 | 	    } else {
2116 | 		ptmp += bhitpile(obj, bhito, x, y);
2117 | 		You("probe beneath the %s.", surface(x,y));
2118 | 		ptmp += display_binventory(x, y, TRUE);
2119 | 	    }
2120 | 	    if (!ptmp) Your("probe reveals nothing.");
2121 | 	    return TRUE;	/* we've done our own bhitpile */
2122 | 	case WAN_OPENING:
2123 | 	case SPE_KNOCK:
2124 | 	    /* up or down, but at closed portcullis only */
2125 | 	    if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) {
2126 | 		open_drawbridge(xx, yy);
2127 | 		disclose = TRUE;
2128 | 	    } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) &&
2129 | 			/* can't use the stairs down to quest level 2 until
2130 | 			   leader "unlocks" them; give feedback if you try */
2131 | 			on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
2132 | 		pline_The("stairs seem to ripple momentarily.");
2133 | 		disclose = TRUE;
2134 | 	    }
2135 | 	    break;
2136 | 	case WAN_STRIKING:
2137 | 	case SPE_FORCE_BOLT:
2138 | 	    striking = TRUE;
2139 | 	    /*FALLTHRU*/
2140 | 	case WAN_LOCKING:
2141 | 	case SPE_WIZARD_LOCK:
2142 | 	    /* down at open bridge or up or down at open portcullis */
2143 | 	    if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
2144 | 			(is_drawbridge_wall(x,y) && !is_db_wall(x,y)) &&
2145 | 		    find_drawbridge(&xx, &yy)) {
2146 | 		if (!striking)
2147 | 		    close_drawbridge(xx, yy);
2148 | 		else
2149 | 		    destroy_drawbridge(xx, yy);
2150 | 		disclose = TRUE;
2151 | 	    } else if (striking && u.dz < 0 && rn2(3) &&
2152 | 			!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) &&
2153 | 			!Underwater && !Is_qstart(&u.uz)) {
2154 | 		/* similar to zap_dig() */
2155 | 		pline("A rock is dislodged from the %s and falls on your %s.",
2156 | 		      ceiling(x, y), body_part(HEAD));
2157 | 		losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
2158 | 		       "falling rock", KILLED_BY_AN);
2159 | 		if ((otmp = mksobj_at(ROCK, x, y, FALSE)) != 0) {
2160 | 		    (void)xname(otmp);	/* set dknown, maybe bknown */
2161 | 		    stackobj(otmp);
2162 | 		}
2163 | 		newsym(x, y);
2164 | 	    }
2165 | 	    break;
2166 | 	case SPE_STONE_TO_FLESH:
2167 | 	    if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
2168 | 		     Underwater || (Is_qstart(&u.uz) && u.dz < 0)) {
2169 | 		pline(nothing_happens);
2170 | 	    } else if (u.dz < 0) {	/* we should do more... */
2171 | 		pline("Blood drips on your %s.", body_part(FACE));
2172 | 	    } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
2173 | 		/*
2174 | 		Print this message only if there wasn't an engraving
2175 | 		affected here.
2176 | 		*/
2177 | 		e = engr_at(u.ux, u.uy);
2178 | 		if (!(e && e->engr_type == ENGRAVE))
2179 | 		    pline("Blood pools at your %s.",
2180 | 			  makeplural(body_part(FOOT)));
2181 | 		}
2182 | 	    break;
2183 | 	default:
2184 | 	    break;
2185 | 	}
2186 | 
2187 | 	if (u.dz > 0) {
2188 | 	    /* zapping downward */
2189 | 	    (void) bhitpile(obj, bhito, x, y);
2190 | 
2191 | 	    /* subset of engraving effects; none sets `disclose' */
2192 | 	    if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
2193 | 		switch (obj->otyp) {
2194 | 		case WAN_POLYMORPH:
2195 | 		case SPE_POLYMORPH:
2196 | 		    del_engr(e);
2197 | 		    make_engr_at(x, y, random_engraving(buf), moves, (xchar)0);
2198 | 		    break;
2199 | 		case WAN_CANCELLATION:
2200 | 		case SPE_CANCELLATION:
2201 | 		case WAN_MAKE_INVISIBLE:
2202 | 		    del_engr(e);
2203 | 		    break;
2204 | 		case WAN_TELEPORTATION:
2205 | 		case SPE_TELEPORT_AWAY:
2206 | 		    rloc_engr(e);
2207 | 		    break;
2208 | 		case SPE_STONE_TO_FLESH:
2209 | 		    if (e->engr_type == ENGRAVE) {
2210 | 			/* only affects things in stone */
2211 | 			pline_The(Hallucination ?
2212 | 			    "floor runs like butter!" :
2213 | 			    "edges on the floor get smoother.");
2214 | 			wipe_engr_at(x, y, d(2,4));
2215 | 			}
2216 | 		    break;
2217 | 		case WAN_STRIKING:
2218 | 		case SPE_FORCE_BOLT:
2219 | 		    wipe_engr_at(x, y, d(2,4));
2220 | 		    break;
2221 | 		case SPE_DRAIN_LIFE:
2222 | 		    u_wipe_engr(3);
2223 | 		    break;
2224 | 		default:
2225 | 		    break;
2226 | 		}
2227 | 	    }
2228 | 	}
2229 | 
2230 | 	return disclose;
2231 | }
2232 | 
2233 | #endif /*OVL3*/
2234 | #ifdef OVLB
2235 | 
2236 | /* called for various wand and spell effects - M. Stephenson */
2237 | void
2238 | weffects(obj)
2239 | register struct	obj	*obj;
2240 | {
2241 | 	int otyp = obj->otyp;
2242 | 	boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
2243 | 
2244 | 	exercise(A_WIS, TRUE);
2245 | #ifdef STEED
2246 | 	if (u.usteed && (objects[otyp].oc_dir != NODIR) &&
2247 | 	    !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) {
2248 | 		disclose = TRUE;
2249 | 	} else
2250 | #endif
2251 | 	if (objects[otyp].oc_dir == IMMEDIATE) {
2252 | 	    obj_zapped = FALSE;
2253 | 
2254 | 	    if (u.uswallow) {
2255 | 		(void) bhitm(u.ustuck, obj);
2256 | 		/* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2257 | 	    } else if (u.dz) {
2258 | 		disclose = zap_updown(obj);
2259 | 	    } else {
2260 | 		(void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj);
2261 | 	    }
2262 | 	    /* give a clue if obj_zapped */
2263 | 	    if (obj_zapped)
2264 | 		You_feel("shuddering vibrations.");
2265 | 
2266 | 	} else if (objects[otyp].oc_dir == NODIR) {
2267 | 	    zapnodir(obj);
2268 | 
2269 | 	} else {
2270 | 	    /* neither immediate nor directionless */
2271 | 
2272 | 	    if (otyp == WAN_DIGGING || otyp == SPE_DIG)
2273 | 		zap_dig();
2274 | 	    else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
2275 | 		buzz(otyp - SPE_MAGIC_MISSILE + 10,
2276 | 		     u.ulevel / 2 + 1,
2277 | 		     u.ux, u.uy, u.dx, u.dy);
2278 | 	    else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
2279 | 		buzz(otyp - WAN_MAGIC_MISSILE,
2280 | 		     (otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
2281 | 		     u.ux, u.uy, u.dx, u.dy);
2282 | 	    else
2283 | 		impossible("weffects: unexpected spell or wand");
2284 | 	    disclose = TRUE;
2285 | 	}
2286 | 	if (disclose && was_unkn) {
2287 | 	    makeknown(otyp);
2288 | 	    more_experienced(0,10);
2289 | 	}
2290 | 	return;
2291 | }
2292 | #endif /*OVLB*/
2293 | #ifdef OVL0
2294 | 
2295 | /*
2296 |  * Generate the to damage bonus for a spell. Based on the hero's intelligence
2297 |  */
2298 | int
2299 | spell_damage_bonus()
2300 | {
2301 |     int tmp, intell = ACURR(A_INT);
2302 | 
2303 |     /* Punish low intellegence before low level else low intellegence
2304 |        gets punished only when high level */
2305 |     if (intell < 10)
2306 | 	tmp = -3;
2307 |     else if (u.ulevel < 5)
2308 | 	tmp = 0;
2309 |     else if (intell < 14)
2310 | 	tmp = 0;
2311 |     else if (intell <= 18)
2312 | 	tmp = 1;
2313 |     else		/* helm of brilliance */
2314 | 	tmp = 2;
2315 | 
2316 |     return tmp;
2317 | }
2318 | 
2319 | /*
2320 |  * Generate the to hit bonus for a spell.  Based on the hero's skill in
2321 |  * spell class and dexterity.
2322 |  */
2323 | STATIC_OVL int
2324 | spell_hit_bonus(skill)
2325 | int skill;
2326 | {
2327 |     int hit_bon = 0;
2328 |     int dex = ACURR(A_DEX);
2329 | 
2330 |     switch (P_SKILL(spell_skilltype(skill))) {
2331 | 	case P_ISRESTRICTED:
2332 | 	case P_UNSKILLED:   hit_bon = -4; break;
2333 | 	case P_BASIC:       hit_bon =  0; break;
2334 | 	case P_SKILLED:     hit_bon =  2; break;
2335 | 	case P_EXPERT:      hit_bon =  3; break;
2336 |     }
2337 | 
2338 |     if (dex < 4)
2339 | 	hit_bon -= 3;
2340 |     else if (dex < 6)
2341 | 	hit_bon -= 2;
2342 |     else if (dex < 8)
2343 | 	hit_bon -= 1;
2344 |     else if (dex < 14)
2345 | 	hit_bon -= 0;		/* Will change when print stuff below removed */
2346 |     else
2347 | 	hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */
2348 | 
2349 |     return hit_bon;
2350 | }
2351 | 
2352 | const char *
2353 | exclam(force)
2354 | register int force;
2355 | {
2356 | 	/* force == 0 occurs e.g. with sleep ray */
2357 | 	/* note that large force is usual with wands so that !! would
2358 | 		require information about hand/weapon/wand */
2359 | 	return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!");
2360 | }
2361 | 
2362 | void
2363 | hit(str,mtmp,force)
2364 | register const char *str;
2365 | register struct monst *mtmp;
2366 | register const char *force;		/* usually either "." or "!" */
2367 | {
2368 | 	if(!cansee(bhitpos.x,bhitpos.y) || !flags.verbose)
2369 | 	    pline("%s hits it.", The(str));
2370 | 	else pline("%s hits %s%s", The(str), mon_nam(mtmp), force);
2371 | }
2372 | 
2373 | void
2374 | miss(str,mtmp)
2375 | register const char *str;
2376 | register struct monst *mtmp;
2377 | {
2378 | 	pline("%s misses %s.", The(str),
2379 | 	      (cansee(bhitpos.x,bhitpos.y) && flags.verbose) ?
2380 | 	      mon_nam(mtmp) : "it");
2381 | }
2382 | #endif /*OVL0*/
2383 | #ifdef OVL1
2384 | 
2385 | /* return TRUE if obj_type can't pass through iron bars */
2386 | static boolean
2387 | hits_bars(obj_type)
2388 | int obj_type;
2389 | {
2390 |     /*
2391 |     There should be a _lot_ of things here..., but lets start
2392 |     with what started this change...
2393 |     */
2394 |     if (obj_type == HEAVY_IRON_BALL)
2395 | 	return TRUE;
2396 |     return FALSE;
2397 | }
2398 | 
2399 | /*
2400 |  *  Called for the following distance effects:
2401 |  *	when a weapon is thrown (weapon == THROWN_WEAPON)
2402 |  *	when an object is kicked (KICKED_WEAPON)
2403 |  *	when an IMMEDIATE wand is zapped (ZAPPED_WAND)
2404 |  *	when a light beam is flashed (FLASHED_LIGHT)
2405 |  *	when a mirror is applied (INVIS_BEAM)
2406 |  *  A thrown/kicked object falls down at the end of its range or when a monster
2407 |  *  is hit.  The variable 'bhitpos' is set to the final position of the weapon
2408 |  *  thrown/zapped.  The ray of a wand may affect (by calling a provided
2409 |  *  function) several objects and monsters on its path.  The return value
2410 |  *  is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
2411 |  *
2412 |  *  Check !u.uswallow before calling bhit().
2413 |  *  This function reveals the absence of a remembered invisible monster in
2414 |  *  necessary cases (throwing or kicking weapons).  The presence of a real
2415 |  *  one is revealed for a weapon, but if not a weapon is left up to fhitm().
2416 |  */
2417 | struct monst *
2418 | bhit(ddx,ddy,range,weapon,fhitm,fhito,obj)
2419 | register int ddx,ddy,range;		/* direction and range */
2420 | int weapon;				/* see values in hack.h */
2421 | int FDECL((*fhitm), (MONST_P, OBJ_P)),	/* fns called when mon/obj hit */
2422 |     FDECL((*fhito), (OBJ_P, OBJ_P));
2423 | struct obj *obj;			/* object tossed/used */
2424 | {
2425 | 	register struct monst *mtmp;
2426 | 	register uchar typ;
2427 | 	register boolean shopdoor = FALSE;
2428 | 
2429 | 	if (weapon == KICKED_WEAPON) {
2430 | 	    /* object starts one square in front of player */
2431 | 	    bhitpos.x = u.ux + ddx;
2432 | 	    bhitpos.y = u.uy + ddy;
2433 | 	    range--;
2434 | 	} else {
2435 | 	    bhitpos.x = u.ux;
2436 | 	    bhitpos.y = u.uy;
2437 | 	}
2438 | 
2439 | 	if (weapon == FLASHED_LIGHT) {
2440 | 	    tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
2441 | 	} else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
2442 | 	    tmp_at(DISP_FLASH, obj_to_glyph(obj));
2443 | 
2444 | 	while(range-- > 0) {
2445 | 	    int x,y;
2446 | 
2447 | 	    bhitpos.x += ddx;
2448 | 	    bhitpos.y += ddy;
2449 | 	    x = bhitpos.x; y = bhitpos.y;
2450 | 
2451 | 	    if(!isok(x, y)) {
2452 | 		bhitpos.x -= ddx;
2453 | 		bhitpos.y -= ddy;
2454 | 		break;
2455 | 	    }
2456 | 
2457 | 	    if(is_pick(obj) && inside_shop(x, y) &&
2458 | 					   shkcatch(obj, x, y)) {
2459 | 		tmp_at(DISP_END, 0);
2460 | 		return(m_at(x, y));
2461 | 	    }
2462 | 
2463 | 	    typ = levl[bhitpos.x][bhitpos.y].typ;
2464 | 
2465 | 	    /* iron bars will block anything big enough */
2466 | 	    if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
2467 | 	    		 && typ == IRONBARS && hits_bars(obj->otyp)) {
2468 | 		bhitpos.x -= ddx;
2469 | 		bhitpos.y -= ddy;
2470 | 		break;
2471 | 	    }
2472 | 
2473 | 	    if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
2474 | 		switch (obj->otyp) {
2475 | 		    case WAN_OPENING:
2476 | 		    case SPE_KNOCK:
2477 | 			if (is_db_wall(bhitpos.x, bhitpos.y)) {
2478 | 			    if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y))
2479 | 				makeknown(obj->otyp);
2480 | 			    open_drawbridge(x,y);
2481 | 			}
2482 | 			break;
2483 | 		    case WAN_LOCKING:
2484 | 		    case SPE_WIZARD_LOCK:
2485 | 			if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y))
2486 | 			    && levl[x][y].typ == DRAWBRIDGE_DOWN)
2487 | 			    makeknown(obj->otyp);
2488 | 			close_drawbridge(x,y);
2489 | 			break;
2490 | 		    case WAN_STRIKING:
2491 | 		    case SPE_FORCE_BOLT:
2492 | 			if (typ != DRAWBRIDGE_UP)
2493 | 			    destroy_drawbridge(x,y);
2494 | 			makeknown(obj->otyp);
2495 | 			break;
2496 | 		}
2497 | 
2498 | 	    if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
2499 | 		notonhead = (bhitpos.x != mtmp->mx ||
2500 | 			     bhitpos.y != mtmp->my);
2501 | 		    /* TODO: FLASHED_LIGHT hitting invisible monster
2502 | 		       should pass through instead of stop... */
2503 | 		if(weapon != ZAPPED_WAND) {
2504 | 		    if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2505 | 		    if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
2506 | 			if (weapon != INVIS_BEAM) {
2507 | 			    map_invisible(bhitpos.x, bhitpos.y);
2508 | 			    return(mtmp);
2509 | 			}
2510 | 		    } else
2511 | 			return(mtmp);
2512 | 		}
2513 | 		if (weapon != INVIS_BEAM) {
2514 | 		    (*fhitm)(mtmp, obj);
2515 | 		    range -= 3;
2516 | 		}
2517 | 	    } else {
2518 | 		if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
2519 | 		   glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
2520 | 		    unmap_object(bhitpos.x, bhitpos.y);
2521 | 		    newsym(x, y);
2522 | 		}
2523 | 	    }
2524 | 	    if(fhito) {
2525 | 		if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
2526 | 		    range--;
2527 | 	    } else {
2528 | boolean costly = shop_keeper(*in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) &&
2529 | 				costly_spot(bhitpos.x, bhitpos.y);
2530 | 
2531 | 		if(weapon == KICKED_WEAPON &&
2532 | 		      ((obj->oclass == GOLD_CLASS &&
2533 | 			 OBJ_AT(bhitpos.x, bhitpos.y)) ||
2534 | 		    ship_object(obj, bhitpos.x, bhitpos.y, costly))) {
2535 | 			tmp_at(DISP_END, 0);
2536 | 			return (struct monst *)0;
2537 | 		}
2538 | 	    }
2539 | 	    if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
2540 | 		switch (obj->otyp) {
2541 | 		case WAN_OPENING:
2542 | 		case WAN_LOCKING:
2543 | 		case WAN_STRIKING:
2544 | 		case SPE_KNOCK:
2545 | 		case SPE_WIZARD_LOCK:
2546 | 		case SPE_FORCE_BOLT:
2547 | 		    if (doorlock(obj, bhitpos.x, bhitpos.y)) {
2548 | 			if (cansee(bhitpos.x, bhitpos.y) ||
2549 | 			    (obj->otyp == WAN_STRIKING))
2550 | 			    makeknown(obj->otyp);
2551 | 			if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
2552 | 			    && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
2553 | 			    shopdoor = TRUE;
2554 | 			    add_damage(bhitpos.x, bhitpos.y, 400L);
2555 | 			}
2556 | 		    }
2557 | 		    break;
2558 | 		}
2559 | 	    }
2560 | 	    if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
2561 | 		bhitpos.x -= ddx;
2562 | 		bhitpos.y -= ddy;
2563 | 		break;
2564 | 	    }
2565 | 	    if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
2566 | 		/* 'I' present but no monster: erase */
2567 | 		/* do this before the tmp_at() */
2568 | 		if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
2569 | 			&& cansee(x, y)) {
2570 | 		    unmap_object(bhitpos.x, bhitpos.y);
2571 | 		    newsym(x, y);
2572 | 		}
2573 | 		tmp_at(bhitpos.x, bhitpos.y);
2574 | 		delay_output();
2575 | 		/* kicked objects fall in pools */
2576 | 		if((weapon == KICKED_WEAPON) &&
2577 | 		   is_pool(bhitpos.x, bhitpos.y))
2578 | 		    break;
2579 | #ifdef SINKS
2580 | 		if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
2581 | 		    break;	/* physical objects fall onto sink */
2582 | #endif
2583 | 	    }
2584 | 	}
2585 | 
2586 | 	if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2587 | 
2588 | 	if(shopdoor)
2589 | 	    pay_for_damage("destroy");
2590 | 
2591 | 	return (struct monst *)0;
2592 | }
2593 | 
2594 | struct monst *
2595 | boomhit(dx, dy)
2596 | int dx, dy;
2597 | {
2598 | 	register int i, ct;
2599 | 	int boom = S_boomleft;	/* showsym[] index  */
2600 | 	struct monst *mtmp;
2601 | 
2602 | 	bhitpos.x = u.ux;
2603 | 	bhitpos.y = u.uy;
2604 | 
2605 | 	for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break;
2606 | 	tmp_at(DISP_FLASH, cmap_to_glyph(boom));
2607 | 	for (ct = 0; ct < 10; ct++) {
2608 | 		if(i == 8) i = 0;
2609 | 		boom = (boom == S_boomleft) ? S_boomright : S_boomleft;
2610 | 		tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */
2611 | 		dx = xdir[i];
2612 | 		dy = ydir[i];
2613 | 		bhitpos.x += dx;
2614 | 		bhitpos.y += dy;
2615 | 		if(MON_AT(bhitpos.x, bhitpos.y)) {
2616 | 			mtmp = m_at(bhitpos.x,bhitpos.y);
2617 | 			m_respond(mtmp);
2618 | 			tmp_at(DISP_END, 0);
2619 | 			return(mtmp);
2620 | 		}
2621 | 		if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) ||
2622 | 		   closed_door(bhitpos.x, bhitpos.y)) {
2623 | 			bhitpos.x -= dx;
2624 | 			bhitpos.y -= dy;
2625 | 			break;
2626 | 		}
2627 | 		if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
2628 | 			if(Fumbling || rn2(20) >= ACURR(A_DEX)) {
2629 | 				/* we hit ourselves */
2630 | 				(void) thitu(10, rnd(10), (struct obj *)0,
2631 | 					"boomerang");
2632 | 				break;
2633 | 			} else {	/* we catch it */
2634 | 				tmp_at(DISP_END, 0);
2635 | 				You("skillfully catch the boomerang.");
2636 | 				return(&youmonst);
2637 | 			}
2638 | 		}
2639 | 		tmp_at(bhitpos.x, bhitpos.y);
2640 | 		delay_output();
2641 | 		if(ct % 5 != 0) i++;
2642 | #ifdef SINKS
2643 | 		if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ))
2644 | 			break;	/* boomerang falls on sink */
2645 | #endif
2646 | 	}
2647 | 	tmp_at(DISP_END, 0);	/* do not leave last symbol */
2648 | 	return (struct monst *)0;
2649 | }
2650 | 
2651 | STATIC_OVL int
2652 | zhitm(mon, type, nd, ootmp)			/* returns damage to mon */
2653 | register struct monst *mon;
2654 | register int type, nd;
2655 | struct obj **ootmp;	/* to return worn armor for caller to disintegrate */
2656 | {
2657 | 	register int tmp = 0;
2658 | 	register int abstype = abs(type) % 10;
2659 | 	boolean sho_shieldeff = FALSE;
2660 | 	boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
2661 | 
2662 | 	*ootmp = (struct obj *)0;
2663 | 	switch(abstype) {
2664 | 	case ZT_MAGIC_MISSILE:
2665 | 		if (resists_magm(mon)) {
2666 | 		    sho_shieldeff = TRUE;
2667 | 		    break;
2668 | 		}
2669 | 		tmp = d(nd,6);
2670 | 		if (spellcaster)
2671 | 		    tmp += spell_damage_bonus();
2672 | #ifdef WIZ_PATCH_DEBUG
2673 | 		if (spellcaster)
2674 | 		    pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2675 | 			spell_damage_bonus());
2676 | #endif
2677 | 		break;
2678 | 	case ZT_FIRE:
2679 | 		if (resists_fire(mon)) {
2680 | 		    sho_shieldeff = TRUE;
2681 | 		    break;
2682 | 		}
2683 | 		tmp = d(nd,6);
2684 | 		if (resists_cold(mon)) tmp += 7;
2685 | 		if (spellcaster)
2686 | 		    tmp += spell_damage_bonus();
2687 | #ifdef WIZ_PATCH_DEBUG
2688 | 		if (spellcaster)
2689 | 		    pline("Damage = %d + %d",tmp-spell_damage_bonus(),
2690 | 			spell_damage_bonus());
2691 | #endif
2692 | 		if (burnarmor(mon)) {
2693 | 		    if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE);
2694 | 		    if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
2695 | 		    if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
2696 | 		}
2697 | 		break;
2698 | 	case ZT_COLD:
2699 | 		if (resists_cold(mon)) {
2700 | 		    sho_shieldeff = TRUE;
2701 | 		    break;
2702 | 		}
2703 | 		tmp = d(nd,6);
2704 | 		if (resists_fire(mon)) tmp += d(nd, 3);
2705 | 		if (spellcaster)
2706 | 		    tmp += spell_damage_bonus();
2707 | #ifdef WIZ_PATCH_DEBUG
2708 | 		if (spellcaster)
2709 | 		    pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2710 | 			spell_damage_bonus());
2711 | #endif
2712 | 		if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD);
2713 | 		break;
2714 | 	case ZT_SLEEP:
2715 | 		tmp = 0;
2716 | 		(void)sleep_monst(mon, d(nd, 25),
2717 | 				type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
2718 | 		break;
2719 | 	case ZT_DEATH:		/* death/disintegration */
2720 | 		if(abs(type) != ZT_BREATH(ZT_DEATH)) {	/* death */
2721 | 		    if(mon->data == &mons[PM_DEATH]) {
2722 | 			mon->mhpmax += mon->mhpmax/2;
2723 | 			if (mon->mhpmax >= MAGIC_COOKIE)
2724 | 			    mon->mhpmax = MAGIC_COOKIE - 1;
2725 | 			mon->mhp = mon->mhpmax;
2726 | 			tmp = 0;
2727 | 			break;
2728 | 		    }
2729 | 		    if (nonliving(mon->data) || is_demon(mon->data) ||
2730 | 			    resists_magm(mon)) {	/* similar to player */
2731 | 			sho_shieldeff = TRUE;
2732 | 			break;
2733 | 		    }
2734 | 		    type = -1; /* so they don't get saving throws */
2735 | 		} else {
2736 | 		    struct obj *otmp2;
2737 | 
2738 | 		    if (resists_disint(mon)) {
2739 | 			sho_shieldeff = TRUE;
2740 | 		    } else if (mon->misc_worn_check & W_ARMS) {
2741 | 			/* destroy shield; victim survives */
2742 | 			*ootmp = which_armor(mon, W_ARMS);
2743 | 		    } else if (mon->misc_worn_check & W_ARM) {
2744 | 			/* destroy body armor, also cloak if present */
2745 | 			*ootmp = which_armor(mon, W_ARM);
2746 | 			if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
2747 | 			    m_useup(mon, otmp2);
2748 | 		    } else {
2749 | 			/* no body armor, victim dies; destroy cloak
2750 | 			   and shirt now in case target gets life-saved */
2751 | 			tmp = MAGIC_COOKIE;
2752 | 			if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
2753 | 			    m_useup(mon, otmp2);
2754 | #ifdef TOURIST
2755 | 			if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
2756 | 			    m_useup(mon, otmp2);
2757 | #endif
2758 | 		    }
2759 | 		    type = -1;	/* no saving throw wanted */
2760 | 		    break;	/* not ordinary damage */
2761 | 		}
2762 | 		tmp = mon->mhp+1;
2763 | 		break;
2764 | 	case ZT_LIGHTNING:
2765 | 		if (resists_elec(mon)) {
2766 | 		    sho_shieldeff = TRUE;
2767 | 		    tmp = 0;
2768 | 		    /* can still blind the monster */
2769 | 		} else
2770 | 		    tmp = d(nd,6);
2771 | 		if (spellcaster)
2772 | 		    tmp += spell_damage_bonus();
2773 | #ifdef WIZ_PATCH_DEBUG
2774 | 		if (spellcaster)
2775 | 		    pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2776 | 			spell_damage_bonus());
2777 | #endif
2778 | 		if (!resists_blnd(mon) &&
2779 | 				!(type > 0 && u.uswallow && mon == u.ustuck)) {
2780 | 			register unsigned rnd_tmp = rnd(50);
2781 | 			mon->mcansee = 0;
2782 | 			if((mon->mblinded + rnd_tmp) > 127)
2783 | 				mon->mblinded = 127;
2784 | 			else mon->mblinded += rnd_tmp;
2785 | 		}
2786 | 		if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC);
2787 | 		/* not actually possible yet */
2788 | 		if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC);
2789 | 		break;
2790 | 	case ZT_POISON_GAS:
2791 | 		if (resists_poison(mon)) {
2792 | 		    sho_shieldeff = TRUE;
2793 | 		    break;
2794 | 		}
2795 | 		tmp = d(nd,6);
2796 | 		break;
2797 | 	case ZT_ACID:
2798 | 		if (resists_acid(mon)) {
2799 | 		    sho_shieldeff = TRUE;
2800 | 		    break;
2801 | 		}
2802 | 		tmp = d(nd,6);
2803 | 		if (!rn2(6)) erode_weapon(MON_WEP(mon), TRUE);
2804 | 		if (!rn2(6)) erode_armor(mon, TRUE);
2805 | 		break;
2806 | 	}
2807 | 	if (sho_shieldeff) shieldeff(mon->mx, mon->my);
2808 | 	if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
2809 | 	    tmp *= 2;
2810 | 	if (tmp > 0 && type >= 0 &&
2811 | 		resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
2812 | 	    tmp /= 2;
2813 | #ifdef WIZ_PATCH_DEBUG
2814 | 	pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp);
2815 | #endif
2816 | 	mon->mhp -= tmp;
2817 | 	return(tmp);
2818 | }
2819 | 
2820 | STATIC_OVL void
2821 | zhitu(type, nd, fltxt, sx, sy)
2822 | int type, nd;
2823 | const char *fltxt;
2824 | xchar sx, sy;
2825 | {
2826 | 	int dam = 0;
2827 | 
2828 | 	switch (abs(type) % 10) {
2829 | 	case ZT_MAGIC_MISSILE:
2830 | 	    if (Antimagic) {
2831 | 		shieldeff(sx, sy);
2832 | 		pline_The("missiles bounce off!");
2833 | 	    } else {
2834 | 		dam = d(nd,6);
2835 | 		exercise(A_STR, FALSE);
2836 | 	    }
2837 | 	    break;
2838 | 	case ZT_FIRE:
2839 | 	    if (Fire_resistance) {
2840 | 		shieldeff(sx, sy);
2841 | 		You("don't feel hot!");
2842 | 		ugolemeffects(AD_FIRE, d(nd, 6));
2843 | 	    } else {
2844 | 		dam = d(nd, 6);
2845 | 	    }
2846 | 	    burn_away_slime();
2847 | 	    if (burnarmor(&youmonst)) {	/* "body hit" */
2848 | 		if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE);
2849 | 		if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE);
2850 | 		if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE);
2851 | 	    }
2852 | 	    break;
2853 | 	case ZT_COLD:
2854 | 	    if (Cold_resistance) {
2855 | 		shieldeff(sx, sy);
2856 | 		You("don't feel cold.");
2857 | 		ugolemeffects(AD_COLD, d(nd, 6));
2858 | 	    } else {
2859 | 		dam = d(nd, 6);
2860 | 	    }
2861 | 	    if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
2862 | 	    break;
2863 | 	case ZT_SLEEP:
2864 | 	    if (Sleep_resistance) {
2865 | 		shieldeff(u.ux, u.uy);
2866 | 		You("don't feel sleepy.");
2867 | 	    } else {
2868 | 		fall_asleep(-d(nd,25), TRUE); /* sleep ray */
2869 | 	    }
2870 | 	    break;
2871 | 	case ZT_DEATH:
2872 | 	    if (abs(type) == ZT_BREATH(ZT_DEATH)) {
2873 | 		if (Disint_resistance) {
2874 | 		    You("are not disintegrated.");
2875 | 		    break;
2876 | 		} else if (uarms) {
2877 | 		    /* destroy shield; other possessions are safe */
2878 | 		    (void) destroy_arm(uarms);
2879 | 		    break;
2880 | 		} else if (uarm) {
2881 | 		    /* destroy suit; if present, cloak goes too */
2882 | 		    if (uarmc) (void) destroy_arm(uarmc);
2883 | 		    (void) destroy_arm(uarm);
2884 | 		    break;
2885 | 		}
2886 | 		/* no shield or suit, you're dead; wipe out cloak
2887 | 		   and/or shirt in case of life-saving or bones */
2888 | 		if (uarmc) (void) destroy_arm(uarmc);
2889 | #ifdef TOURIST
2890 | 		if (uarmu) (void) destroy_arm(uarmu);
2891 | #endif
2892 | 	    } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
2893 | 		shieldeff(sx, sy);
2894 | 		You("seem unaffected.");
2895 | 		break;
2896 | 	    } else if (Antimagic) {
2897 | 		shieldeff(sx, sy);
2898 | 		You("aren't affected.");
2899 | 		break;
2900 | 	    }
2901 | 	    killer_format = KILLED_BY_AN;
2902 | 	    killer = fltxt;
2903 | 	    /* when killed by disintegration breath, don't leave corpse */
2904 | 	    u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
2905 | 	    done(DIED);
2906 | 	    return; /* lifesaved */
2907 | 	case ZT_LIGHTNING:
2908 | 	    if (Shock_resistance) {
2909 | 		shieldeff(sx, sy);
2910 | 		You("aren't affected.");
2911 | 		ugolemeffects(AD_ELEC, d(nd, 6));
2912 | 	    } else {
2913 | 		dam = d(nd, 6);
2914 | 		exercise(A_CON, FALSE);
2915 | 	    }
2916 | 	    if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
2917 | 	    if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
2918 | 	    break;
2919 | 	case ZT_POISON_GAS:
2920 | 	    poisoned("blast", A_DEX, "poisoned blast", 15);
2921 | 	    break;
2922 | 	case ZT_ACID:
2923 | 	    if (Acid_resistance) {
2924 | 		dam = 0;
2925 | 	    } else {
2926 | 		pline_The("acid burns!");
2927 | 		dam = d(nd,6);
2928 | 		exercise(A_STR, FALSE);
2929 | 	    }
2930 | 	    /* using two weapons at once makes both of them more vulnerable */
2931 | 	    if (!rn2(u.twoweap ? 3 : 6)) erode_weapon(uwep, TRUE);
2932 | 	    if (u.twoweap && !rn2(3)) erode_weapon(uswapwep, TRUE);
2933 | 	    if (!rn2(6)) erode_armor(&youmonst, TRUE);
2934 | 	    break;
2935 | 	}
2936 | 
2937 | 	if (Half_spell_damage && dam &&
2938 | 	   type < 0 && (type > -20 || type < -29)) /* !Breath */
2939 | 	    dam = (dam + 1) / 2;
2940 | 	losehp(dam, fltxt, KILLED_BY_AN);
2941 | 	return;
2942 | }
2943 | 
2944 | #endif /*OVL1*/
2945 | #ifdef OVLB
2946 | 
2947 | /*
2948 |  * burn scrolls and spellbooks on floor at position x,y
2949 |  * return the number of scrolls and spellbooks burned
2950 |  */
2951 | int
2952 | burn_floor_paper(x, y, give_feedback)
2953 | int x, y;
2954 | boolean give_feedback;	/* caller needs to decide about visibility checks */
2955 | {
2956 | 	struct obj *obj, *obj2;
2957 | 	long i, scrquan, delquan;
2958 | 	const char *what;
2959 | 	int cnt = 0;
2960 | 
2961 | 	for (obj = level.objects[x][y]; obj; obj = obj2) {
2962 | 	    obj2 = obj->nexthere;
2963 | 	    if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
2964 | 		if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL ||
2965 | 			obj_resists(obj, 2, 100))
2966 | 		    continue;
2967 | 		scrquan = obj->quan;	/* number present */
2968 | 		delquan = 0;		/* number to destroy */
2969 | 		for (i = scrquan; i > 0; i--)
2970 | 		    if (!rn2(3)) delquan++;
2971 | 		if (delquan) {
2972 | 		    /* save name before potential delobj() */
2973 | 		    what = !give_feedback ? 0 : (x == u.ux && y == u.uy) ?
2974 | 				xname(obj) : distant_name(obj, xname);
2975 | 		    /* not useupf(), which charges */
2976 | 		    if (delquan < scrquan) obj->quan -= delquan;
2977 | 		    else delobj(obj);
2978 | 		    cnt += delquan;
2979 | 		    if (give_feedback) {
2980 | 			if (delquan > 1)
2981 | 			    pline("%ld %s burn.", delquan, what);
2982 | 			else
2983 | 			    pline("%s burns.", An(what));
2984 | 		    }
2985 | 		}
2986 | 	    }
2987 | 	}
2988 | 	return cnt;
2989 | }
2990 | 
2991 | /* will zap/spell/breath attack score a hit against armor class `ac'? */
2992 | STATIC_OVL int
2993 | zap_hit(ac, type)
2994 | int ac;
2995 | int type;	/* either hero cast spell type or 0 */
2996 | {
2997 |     int chance = rn2(20);
2998 |     int spell_bonus = type ? spell_hit_bonus(type) : 0;
2999 | 
3000 |     /* small chance for naked target to avoid being hit */
3001 |     if (!chance) return rnd(10) < ac+spell_bonus;
3002 | 
3003 |     /* very high armor protection does not achieve invulnerability */
3004 |     ac = AC_VALUE(ac);
3005 | 
3006 |     return (3 - chance) < ac+spell_bonus;
3007 | }
3008 | 
3009 | /* type ==   0 to   9 : you shooting a wand */
3010 | /* type ==  10 to  19 : you casting a spell */
3011 | /* type ==  20 to  29 : you breathing as a monster */
3012 | /* type == -10 to -19 : monster casting spell */
3013 | /* type == -20 to -29 : monster breathing at you */
3014 | /* type == -30 to -39 : monster shooting a wand */
3015 | /* called with dx = dy = 0 with vertical bolts */
3016 | void
3017 | buzz(type,nd,sx,sy,dx,dy)
3018 | register int type, nd;
3019 | register xchar sx,sy;
3020 | register int dx,dy;
3021 | {
3022 |     int range, abstype = abs(type) % 10;
3023 |     struct rm *lev;
3024 |     register xchar lsx, lsy;
3025 |     struct monst *mon;
3026 |     coord save_bhitpos;
3027 |     boolean shopdamage = FALSE;
3028 |     register const char *fltxt;
3029 |     struct obj *otmp;
3030 |     int spell_type;
3031 | 
3032 |     /* if its a Hero Spell then get its SPE_TYPE */
3033 |     spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
3034 | 
3035 |     fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
3036 |     if(u.uswallow) {
3037 | 	register int tmp;
3038 | 
3039 | 	if(type < 0) return;
3040 | 	tmp = zhitm(u.ustuck, type, nd, &otmp);
3041 | 	if(!u.ustuck)	u.uswallow = 0;
3042 | 	else	pline("%s rips into %s%s",
3043 | 		      The(fltxt), mon_nam(u.ustuck), exclam(tmp));
3044 | 	/* Using disintegration from the inside only makes a hole... */
3045 | 	if (tmp == MAGIC_COOKIE)
3046 | 	    u.ustuck->mhp = 0;
3047 | 	if (u.ustuck->mhp < 1)
3048 | 	    killed(u.ustuck);
3049 | 	return;
3050 |     }
3051 |     if(type < 0) newsym(u.ux,u.uy);
3052 |     range = rn1(7,7);
3053 |     if(dx == 0 && dy == 0) range = 1;
3054 |     save_bhitpos = bhitpos;
3055 | 
3056 |     tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
3057 |     while(range-- > 0) {
3058 | 	lsx = sx; sx += dx;
3059 | 	lsy = sy; sy += dy;
3060 | 	if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) {
3061 | 	    mon = m_at(sx, sy);
3062 | 	    if(cansee(sx,sy)) {
3063 | 		/* reveal/unreveal invisible monsters before tmp_at() */
3064 | 		if (mon && !canspotmon(mon))
3065 | 		    map_invisible(sx, sy);
3066 | 		else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
3067 | 		    unmap_object(sx, sy);
3068 | 		    newsym(sx, sy);
3069 | 		}
3070 | 		if(ZAP_POS(lev->typ) || cansee(lsx,lsy))
3071 | 		    tmp_at(sx,sy);
3072 | 		delay_output(); /* wait a little */
3073 | 	    }
3074 | 	} else
3075 | 	    goto make_bounce;
3076 | 
3077 | 	/* hit() and miss() need bhitpos to match the target */
3078 | 	bhitpos.x = sx,  bhitpos.y = sy;
3079 | 	/* Fireballs only damage when they explode */
3080 | 	if (type != ZT_SPELL(ZT_FIRE))
3081 | 	    range += zap_over_floor(sx, sy, type, &shopdamage);
3082 | 
3083 | 	if (mon) {
3084 | 	    if (type == ZT_SPELL(ZT_FIRE)) break;
3085 | 	    if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK;
3086 | #ifdef STEED
3087 | 	    buzzmonst:
3088 | #endif
3089 | 	    if (zap_hit(find_mac(mon), spell_type)) {
3090 | 		if (mon_reflects(mon, (char *)0)) {
3091 | 		    if(cansee(mon->mx,mon->my)) {
3092 | 			hit(fltxt, mon, exclam(0));
3093 | 			shieldeff(mon->mx, mon->my);
3094 | 			(void) mon_reflects(mon, "But it reflects from %s %s!");
3095 | 		    }
3096 | 		    dx = -dx;
3097 | 		    dy = -dy;
3098 | 		} else {
3099 | 		    boolean mon_could_move = mon->mcanmove;
3100 | 		    int tmp = zhitm(mon, type, nd, &otmp);
3101 | 
3102 | 		    if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) {
3103 | 			if (canseemon(mon)) {
3104 | 			    hit(fltxt, mon, ".");
3105 | 			    pline("%s disintegrates.", Monnam(mon));
3106 | 			    pline("%s body reintegrates before your %s!",
3107 | 				  s_suffix(Monnam(mon)),
3108 | 				  makeplural(body_part(EYE)));
3109 | 			    pline("%s resurrects!", Monnam(mon));
3110 | 			}
3111 | 			mon->mhp = mon->mhpmax;
3112 | 			break; /* Out of while loop */
3113 | 		    }
3114 | 		    if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
3115 | 			if (canseemon(mon)) {
3116 | 			    hit(fltxt, mon, ".");
3117 | 			    pline("%s absorbs the deadly %s!", Monnam(mon),
3118 | 				  type == ZT_BREATH(ZT_DEATH) ?
3119 | 					"blast" : "ray");
3120 | 			    pline("It seems even stronger than before.");
3121 | 			}
3122 | 			break; /* Out of while loop */
3123 | 		    }
3124 | 
3125 | 		    if (tmp == MAGIC_COOKIE) { /* disintegration */
3126 | 			struct obj *otmp2, *m_amulet = mlifesaver(mon);
3127 | 
3128 | 			if (canseemon(mon)) {
3129 | 			    if (!m_amulet)
3130 | 				pline("%s is disintegrated!", Monnam(mon));
3131 | 			    else
3132 | 				hit(fltxt, mon, "!");
3133 | 			}
3134 | 			mon->mgold = 0L;
3135 | 
3136 | /* note: worn amulet of life saving must be preserved in order to operate */
3137 | #define oresist_disintegration(obj) \
3138 | 		(objects[obj->otyp].oc_oprop == DISINT_RES || \
3139 | 		 obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
3140 | 		 obj == m_amulet)
3141 | 
3142 | 			for (otmp = mon->minvent; otmp; otmp = otmp2) {
3143 | 			    otmp2 = otmp->nobj;
3144 | 			    if (!oresist_disintegration(otmp)) {
3145 | 				obj_extract_self(otmp);
3146 | 				obfree(otmp, (struct obj *)0);
3147 | 			    }
3148 | 			}
3149 | 
3150 | 			if (type < 0)
3151 | 			    monkilled(mon, (char *)0, -AD_RBRE);
3152 | 			else
3153 | 			    xkilled(mon, 2);
3154 | 		    } else if(mon->mhp < 1) {
3155 | 			if(type < 0)
3156 | 			    monkilled(mon, fltxt, AD_RBRE);
3157 | 			else
3158 | 			    killed(mon);
3159 | 		    } else {
3160 | 			if (!otmp) {
3161 | 			    /* normal non-fatal hit */
3162 | 			    hit(fltxt, mon, exclam(tmp));
3163 | 			} else {
3164 | 			    /* some armor was destroyed; no damage done */
3165 | 			    if (canseemon(mon))
3166 | 				pline("%s %s is disintegrated!",
3167 | 				      s_suffix(Monnam(mon)),
3168 | 				      distant_name(otmp, xname));
3169 | 			    m_useup(mon, otmp);
3170 | 			}
3171 | 			if (mon_could_move && !mon->mcanmove)	/* ZT_SLEEP */
3172 | 			    slept_monst(mon);
3173 | 		    }
3174 | 		}
3175 | 		range -= 2;
3176 | 	    } else {
3177 | 		miss(fltxt,mon);
3178 | 	    }
3179 | 	} else if (sx == u.ux && sy == u.uy && range >= 0) {
3180 | 	    nomul(0);
3181 | #ifdef STEED
3182 | 	    if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) {
3183 | 		    mon = u.usteed;
3184 | 		    goto buzzmonst;
3185 | 	    } else
3186 | #endif
3187 | 	    if (zap_hit((int) u.uac, 0)) {
3188 | 		range -= 2;
3189 | 		pline("%s hits you!", The(fltxt));
3190 | 		if (Reflecting) {
3191 | 		    if (!Blind) {
3192 | 		    	(void) ureflects("But %s reflects from your %s!", "it");
3193 | 		    } else
3194 | 			pline("For some reason you are not affected.");
3195 | 		    dx = -dx;
3196 | 		    dy = -dy;
3197 | 		    shieldeff(sx, sy);
3198 | 		} else {
3199 | 		    zhitu(type, nd, fltxt, sx, sy);
3200 | 		}
3201 | 	    } else {
3202 | 		pline("%s whizzes by you!", The(fltxt));
3203 | 	    }
3204 | 	    if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) {
3205 | 		You(are_blinded_by_the_flash);
3206 | 		make_blinded((long)d(nd,50),FALSE);
3207 | 	    }
3208 | 	    stop_occupation();
3209 | 	    nomul(0);
3210 | 	}
3211 | 
3212 | 	if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
3213 | 	    int bounce;
3214 | 	    uchar rmn;
3215 | 
3216 |  make_bounce:
3217 | 	    if (type == ZT_SPELL(ZT_FIRE)) {
3218 | 		sx = lsx;
3219 | 		sy = lsy;
3220 | 		break; /* fireballs explode before the wall */
3221 | 	    }
3222 | 	    bounce = 0;
3223 | 	    range--;
3224 | 	    if(range && isok(lsx, lsy) && cansee(lsx,lsy))
3225 | 		pline("%s bounces!", The(fltxt));
3226 | 	    if(!dx || !dy || !rn2(20)) {
3227 | 		dx = -dx;
3228 | 		dy = -dy;
3229 | 	    } else {
3230 | 		if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) &&
3231 | 		   (IS_ROOM(rmn) || (isok(sx+dx,lsy) &&
3232 | 				     ZAP_POS(levl[sx+dx][lsy].typ))))
3233 | 		    bounce = 1;
3234 | 		if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) &&
3235 | 		   (IS_ROOM(rmn) || (isok(lsx,sy+dy) &&
3236 | 				     ZAP_POS(levl[lsx][sy+dy].typ))))
3237 | 		    if(!bounce || rn2(2))
3238 | 			bounce = 2;
3239 | 
3240 | 		switch(bounce) {
3241 | 		case 0: dx = -dx; /* fall into... */
3242 | 		case 1: dy = -dy; break;
3243 | 		case 2: dx = -dx; break;
3244 | 		}
3245 | 		tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype));
3246 | 	    }
3247 | 	}
3248 |     }
3249 |     tmp_at(DISP_END,0);
3250 |     if (type == ZT_SPELL(ZT_FIRE))
3251 | 	explode(sx, sy, type, d(12,6), 0);
3252 |     if (shopdamage)
3253 | 	pay_for_damage(abstype == ZT_FIRE ?  "burn away" :
3254 | 		       abstype == ZT_COLD ?  "shatter" :
3255 | 		       abstype == ZT_DEATH ? "disintegrate" : "destroy");
3256 |     bhitpos = save_bhitpos;
3257 | }
3258 | #endif /*OVLB*/
3259 | #ifdef OVL0
3260 | 
3261 | void
3262 | melt_ice(x, y)
3263 | xchar x, y;
3264 | {
3265 | 	struct rm *lev = &levl[x][y];
3266 | 	struct obj *otmp;
3267 | 
3268 | 	if (lev->typ == DRAWBRIDGE_UP)
3269 | 	    lev->drawbridgemask &= ~DB_ICE;	/* revert to DB_MOAT */
3270 | 	else {	/* lev->typ == ICE */
3271 | #ifdef STUPID
3272 | 	    if (lev->icedpool == ICED_POOL) lev->typ = POOL;
3273 | 	    else lev->typ = MOAT;
3274 | #else
3275 | 	    lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
3276 | #endif
3277 | 	    lev->icedpool = 0;
3278 | 	}
3279 | 	obj_ice_effects(x, y, FALSE);
3280 | 	unearth_objs(x, y);
3281 | 	if (Underwater) vision_recalc(1);
3282 | 	newsym(x,y);
3283 | 	if (cansee(x,y)) Norep("The ice crackles and melts.");
3284 | 	if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
3285 | 	    if (cansee(x,y)) pline("%s settles...", An(xname(otmp)));
3286 | 	    do {
3287 | 		obj_extract_self(otmp);	/* boulder isn't being pushed */
3288 | 		if (!boulder_hits_pool(otmp, x, y, FALSE))
3289 | 		    impossible("melt_ice: no pool?");
3290 | 		/* try again if there's another boulder and pool didn't fill */
3291 | 	    } while (is_pool(x,y) && (otmp = sobj_at(BOULDER, x, y)) != 0);
3292 | 	    newsym(x,y);
3293 | 	}
3294 | 	if (x == u.ux && y == u.uy)
3295 | 		spoteffects(TRUE);	/* possibly drown, notice objects */
3296 | }
3297 | 
3298 | /* Burn floor scrolls, evaporate pools, etc...  in a single square.  Used
3299 |  * both for normal bolts of fire, cold, etc... and for fireballs.
3300 |  * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
3301 |  * amount by which range is reduced (the latter is just ignored by fireballs)
3302 |  */
3303 | int
3304 | zap_over_floor(x, y, type, shopdamage)
3305 | xchar x, y;
3306 | int type;
3307 | boolean *shopdamage;
3308 | {
3309 | 	struct monst *mon;
3310 | 	int abstype = abs(type) % 10;
3311 | 	struct rm *lev = &levl[x][y];
3312 | 	int rangemod = 0;
3313 | 
3314 | 	if(abstype == ZT_FIRE) {
3315 | 	    if(is_ice(x, y)) {
3316 | 		melt_ice(x, y);
3317 | 	    } else if(is_pool(x,y)) {
3318 | 		const char *msgtxt = "You hear hissing gas.";
3319 | 		if(lev->typ != POOL) {	/* MOAT or DRAWBRIDGE_UP */
3320 | 		    if (cansee(x,y)) msgtxt = "Some water evaporates.";
3321 | 		} else {
3322 | 		    register struct trap *ttmp;
3323 | 
3324 | 		    rangemod -= 3;
3325 | 		    lev->typ = ROOM;
3326 | 		    ttmp = maketrap(x, y, PIT);
3327 | 		    if (ttmp) ttmp->tseen = 1;
3328 | 		    if (cansee(x,y)) msgtxt = "The water evaporates.";
3329 | 		}
3330 | 		Norep(msgtxt);
3331 | 		if (lev->typ == ROOM) newsym(x,y);
3332 | 	    } else if(IS_FOUNTAIN(lev->typ)) {
3333 | 		    if (cansee(x,y))
3334 | 			pline("Steam billows from the fountain.");
3335 | 		    rangemod -= 1;
3336 | 		    dryup(x, y, type > 0);
3337 | 	    }
3338 | 	}
3339 | 	else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y))) {
3340 | 		boolean lava = is_lava(x,y);
3341 | 		boolean moat = (!lava && (lev->typ != POOL) &&
3342 | 				(lev->typ != WATER) &&
3343 | 				!Is_medusa_level(&u.uz) &&
3344 | 				!Is_waterlevel(&u.uz));
3345 | 
3346 | 		if (lev->typ == WATER) {
3347 | 		    /* For now, don't let WATER freeze. */
3348 | 		    if (cansee(x,y))
3349 | 			pline_The("water freezes for a moment.");
3350 | 		    else
3351 | 			You_hear("a soft crackling.");
3352 | 		    rangemod -= 1000;	/* stop */
3353 | 		} else {
3354 | 		    rangemod -= 3;
3355 | 		    if (lev->typ == DRAWBRIDGE_UP) {
3356 | 			lev->drawbridgemask &= ~DB_UNDER;  /* clear lava */
3357 | 			lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
3358 | 		    } else {
3359 | 			if (!lava)
3360 | 			    lev->icedpool =
3361 | 				    (lev->typ == POOL ? ICED_POOL : ICED_MOAT);
3362 | 			lev->typ = (lava ? ROOM : ICE);
3363 | 		    }
3364 | 		    bury_objs(x,y);
3365 | 		    if(cansee(x,y)) {
3366 | 			if(moat)
3367 | 				Norep("The moat is bridged with ice!");
3368 | 			else if(lava)
3369 | 				Norep("The lava cools and solidifies.");
3370 | 			else
3371 | 				Norep("The water freezes.");
3372 | 			newsym(x,y);
3373 | 		    } else if(flags.soundok && !lava)
3374 | 			You_hear("a crackling sound.");
3375 | 
3376 | 		    if (x == u.ux && y == u.uy) {
3377 | 			if (u.uinwater) {   /* not just `if (Underwater)' */
3378 | 			    /* leave the no longer existent water */
3379 | 			    u.uinwater = 0;
3380 | 			    docrt();
3381 | 			    vision_full_recalc = 1;
3382 | 			} else if (u.utrap && u.utraptype == TT_LAVA) {
3383 | 			    if (Passes_walls) {
3384 | 				You("pass through the now-solid rock.");
3385 | 			    } else {
3386 | 				u.utrap = rn1(50,20);
3387 | 				u.utraptype = TT_INFLOOR;
3388 | 				You("are firmly stuck in the cooling rock.");
3389 | 			    }
3390 | 			}
3391 | 		    } else if ((mon = m_at(x,y)) != 0) {
3392 | 			/* probably ought to do some hefty damage to any
3393 | 			   non-ice creature caught in freezing water;
3394 | 			   at a minimum, eels are forced out of hiding */
3395 | 			if (is_swimmer(mon->data) && mon->mundetected) {
3396 | 			    mon->mundetected = 0;
3397 | 			    newsym(x,y);
3398 | 			}
3399 | 		    }
3400 | 		}
3401 | 		obj_ice_effects(x,y,TRUE);
3402 | 	}
3403 | 	if(closed_door(x, y)) {
3404 | 		int new_doormask = -1;
3405 | 		const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
3406 | 		rangemod = -1000;
3407 | 		switch(abstype) {
3408 | 		case ZT_FIRE:
3409 | 		    new_doormask = D_NODOOR;
3410 | 		    see_txt = "The door is consumed in flames!";
3411 | 		    sense_txt = "smell smoke.";
3412 | 		    break;
3413 | 		case ZT_COLD:
3414 | 		    new_doormask = D_NODOOR;
3415 | 		    see_txt = "The door freezes and shatters!";
3416 | 		    sense_txt = "feel cold.";
3417 | 		    break;
3418 | 		case ZT_DEATH:
3419 | 		    /* death spells/wands don't disintegrate */
3420 | 		    if(abs(type) != ZT_BREATH(ZT_DEATH))
3421 | 			goto def_case;
3422 | 		    new_doormask = D_NODOOR;
3423 | 		    see_txt = "The door disintegrates!";
3424 | 		    hear_txt = "crashing wood.";
3425 | 		    break;
3426 | 		case ZT_LIGHTNING:
3427 | 		    new_doormask = D_BROKEN;
3428 | 		    see_txt = "The door splinters!";
3429 | 		    hear_txt = "crackling.";
3430 | 		    break;
3431 | 		default:
3432 | 		def_case:
3433 | 		    if(cansee(x,y)) {
3434 | 			pline_The("door absorbs %s %s!",
3435 | 			      (type < 0) ? "the" : "your",
3436 | 			      abs(type) < ZT_SPELL(0) ? "bolt" :
3437 | 			      abs(type) < ZT_BREATH(0) ? "spell" :
3438 | 			      "blast");
3439 | 		    } else You_feel("vibrations.");
3440 | 		    break;
3441 | 		}
3442 | 		if (new_doormask >= 0) {	/* door gets broken */
3443 | 		    if (*in_rooms(x, y, SHOPBASE)) {
3444 | 			if (type >= 0) {
3445 | 			    add_damage(x, y, 400L);
3446 | 			    *shopdamage = TRUE;
3447 | 			} else	/* caused by monster */
3448 | 			    add_damage(x, y, 0L);
3449 | 		    }
3450 | 		    lev->doormask = new_doormask;
3451 | 		    unblock_point(x, y);	/* vision */
3452 | 		    if (cansee(x, y)) {
3453 | 			pline(see_txt);
3454 | 			newsym(x, y);
3455 | 		    } else if (sense_txt) {
3456 | 			You(sense_txt);
3457 | 		    } else if (hear_txt) {
3458 | 			if (flags.soundok) You_hear(hear_txt);
3459 | 		    }
3460 | 		    if (picking_at(x, y)) {
3461 | 			stop_occupation();
3462 | 			reset_pick();
3463 | 		    }
3464 | 		}
3465 | 	}
3466 | 
3467 | 	if(OBJ_AT(x, y) && abstype == ZT_FIRE)
3468 | 		if (burn_floor_paper(x, y, FALSE) && couldsee(x, y))  {
3469 | 		    newsym(x,y);
3470 | 		    You("%s of smoke.",
3471 | 			!Blind ? "see a puff" : "smell a whiff");
3472 | 		}
3473 | 	if ((mon = m_at(x,y)) != 0) {
3474 | 		/* Cannot use wakeup() which also angers the monster */
3475 | 		mon->msleeping = 0;
3476 | 		if(mon->m_ap_type) seemimic(mon);
3477 | 		if(type >= 0) {
3478 | 		    setmangry(mon);
3479 | 		    if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
3480 | 			ghod_hitsu(mon);
3481 | 		    if(mon->isshk && !*u.ushops)
3482 | 			hot_pursuit(mon);
3483 | 		}
3484 | 	}
3485 | 	return rangemod;
3486 | }
3487 | 
3488 | #endif /*OVL0*/
3489 | #ifdef OVL3
3490 | 
3491 | void
3492 | fracture_rock(obj)	/* fractured by pick-axe or wand of striking */
3493 | register struct obj *obj;		   /* no texts here! */
3494 | {
3495 | 	/* A little Sokoban guilt... */
3496 | 	if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
3497 | 	    change_luck(-1);
3498 | 
3499 | 	obj->otyp = ROCK;
3500 | 	obj->quan = (long) rn1(60, 7);
3501 | 	obj->owt = weight(obj);
3502 | 	obj->oclass = GEM_CLASS;
3503 | 	obj->known = FALSE;
3504 | 	obj->onamelth = 0;		/* no names */
3505 | 	obj->oxlth = 0;			/* no extra data */
3506 | 	obj->oattached = OATTACHED_NOTHING;
3507 | 	if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
3508 | 	    unblock_point(obj->ox,obj->oy);
3509 | 	if(cansee(obj->ox,obj->oy))
3510 | 	    newsym(obj->ox,obj->oy);
3511 | }
3512 | 
3513 | /* handle statue hit by striking/force bolt/pick-axe */
3514 | boolean
3515 | break_statue(obj)
3516 | register struct obj *obj;
3517 | {
3518 | 	/* [obj is assumed to be on floor, so no get_obj_location() needed] */
3519 | 	struct trap *trap = t_at(obj->ox, obj->oy);
3520 | 	struct obj *item;
3521 | 
3522 | 	if (trap && trap->ttyp == STATUE_TRAP &&
3523 | 		activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
3524 | 	    return FALSE;
3525 | 	/* drop any objects contained inside the statue */
3526 | 	while ((item = obj->cobj) != 0) {
3527 | 	    obj_extract_self(item);
3528 | 	    place_object(item, obj->ox, obj->oy);
3529 | 	}
3530 | 	if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && obj->spe) {
3531 | 	    You_feel("guilty about damaging such a historic statue.");
3532 | 	    adjalign(-1);
3533 | 	}
3534 | 	obj->spe = 0;
3535 | 	fracture_rock(obj);
3536 | 	return TRUE;
3537 | }
3538 | 
3539 | const char *destroy_strings[] = {
3540 | 	"freezes and shatters", "freeze and shatter", "shattered potion",
3541 | 	"boils and explodes", "boil and explode", "boiling potion",
3542 | 	"catches fire and burns", "catch fire and burn", "burning scroll",
3543 | 	"catches fire and burns", "catch fire and burn", "burning book",
3544 | 	"turns to dust and vanishes", "turn to dust and vanish", "",
3545 | 	"breaks apart and explodes", "break apart and explode", "exploding wand"
3546 | };
3547 | 
3548 | void
3549 | destroy_item(osym, dmgtyp)
3550 | register int osym, dmgtyp;
3551 | {
3552 | 	register struct obj *obj, *obj2;
3553 | 	register int dmg, xresist, skip;
3554 | 	register long i, cnt, quan;
3555 | 	register int dindx;
3556 | 	const char *mult;
3557 | 
3558 | 	for(obj = invent; obj; obj = obj2) {
3559 | 	    obj2 = obj->nobj;
3560 | 	    if(obj->oclass != osym) continue; /* test only objs of type osym */
3561 | 	    if(obj->oartifact) continue; /* don't destroy artifacts */
3562 | 	    xresist = skip = 0;
3563 | #ifdef GCC_WARN
3564 | 	    dmg = dindx = 0;
3565 | 	    quan = 0L;
3566 | #endif
3567 | 	    switch(dmgtyp) {
3568 | 		case AD_COLD:
3569 | 		    if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3570 | 			quan = obj->quan;
3571 | 			dindx = 0;
3572 | 			dmg = rnd(4);
3573 | 		    } else skip++;
3574 | 		    break;
3575 | 		case AD_FIRE:
3576 | 		    xresist = (Fire_resistance && obj->oclass != POTION_CLASS);
3577 | 
3578 | 		    if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3579 | 			skip++;
3580 | 		    if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3581 | 			skip++;
3582 | 			if (!Blind)
3583 | 			    pline("%s glows a strange %s, but remains intact.",
3584 | 				The(xname(obj)), hcolor("dark red"));
3585 | 		    }
3586 | 		    quan = obj->quan;
3587 | 		    switch(osym) {
3588 | 			case POTION_CLASS:
3589 | 			    dindx = 1;
3590 | 			    dmg = rnd(6);
3591 | 			    break;
3592 | 			case SCROLL_CLASS:
3593 | 			    dindx = 2;
3594 | 			    dmg = 1;
3595 | 			    break;
3596 | 			case SPBOOK_CLASS:
3597 | 			    dindx = 3;
3598 | 			    dmg = 1;
3599 | 			    break;
3600 | 			default:
3601 | 			    skip++;
3602 | 			    break;
3603 | 		    }
3604 | 		    break;
3605 | 		case AD_ELEC:
3606 | 		    xresist = (Shock_resistance && obj->oclass != RING_CLASS);
3607 | 		    quan = obj->quan;
3608 | 		    switch(osym) {
3609 | 			case RING_CLASS:
3610 | 			    if(obj->otyp == RIN_SHOCK_RESISTANCE)
3611 | 				    { skip++; break; }
3612 | 			    dindx = 4;
3613 | 			    dmg = 0;
3614 | 			    break;
3615 | 			case WAND_CLASS:
3616 | 			    if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
3617 | #if 0
3618 | 			    if (obj == current_wand) { skip++; break; }
3619 | #endif
3620 | 			    dindx = 5;
3621 | 			    dmg = rnd(10);
3622 | 			    break;
3623 | 			default:
3624 | 			    skip++;
3625 | 			    break;
3626 | 		    }
3627 | 		    break;
3628 | 		default:
3629 | 		    skip++;
3630 | 		    break;
3631 | 	    }
3632 | 	    if(!skip) {
3633 | 		for(i = cnt = 0L; i < quan; i++)
3634 | 		    if(!rn2(3)) cnt++;
3635 | 
3636 | 		if(!cnt) continue;
3637 | 		if(cnt == quan)	mult = "Your";
3638 | 		else	mult = (cnt == 1L) ? "One of your" : "Some of your";
3639 | 		pline("%s %s %s!", mult, xname(obj),
3640 | 			(cnt > 1L) ? destroy_strings[dindx*3 + 1]
3641 | 				  : destroy_strings[dindx*3]);
3642 | 		if(osym == POTION_CLASS && dmgtyp != AD_COLD)
3643 | 		    potionbreathe(obj);
3644 | 		if (obj->owornmask) {
3645 | 		    if (obj->owornmask & W_RING) /* ring being worn */
3646 | 			Ring_gone(obj);
3647 | 		    else
3648 | 			setnotworn(obj);
3649 | 		}
3650 | 		if (obj == current_wand) current_wand = 0;	/* destroyed */
3651 | 		for (i = 0; i < cnt; i++)
3652 | 		    useup(obj);
3653 | 		if(dmg) {
3654 | 		    if(xresist)	You("aren't hurt!");
3655 | 		    else {
3656 | 			const char *how = destroy_strings[dindx * 3 + 2];
3657 | 			boolean one = (cnt == 1L);
3658 | 
3659 | 			losehp(dmg, one ? how : (const char *)makeplural(how),
3660 | 			       one ? KILLED_BY_AN : KILLED_BY);
3661 | 			exercise(A_STR, FALSE);
3662 | 		    }
3663 | 		}
3664 | 	    }
3665 | 	}
3666 | 	return;
3667 | }
3668 | 
3669 | int
3670 | destroy_mitem(mtmp, osym, dmgtyp)
3671 | struct monst *mtmp;
3672 | int osym, dmgtyp;
3673 | {
3674 | 	struct obj *obj, *obj2;
3675 | 	int skip, tmp = 0;
3676 | 	long i, cnt, quan;
3677 | 	int dindx;
3678 | 	boolean vis;
3679 | 
3680 | 	if (mtmp == &youmonst) {	/* this simplifies artifact_hit() */
3681 | 	    destroy_item(osym, dmgtyp);
3682 | 	    return 0;	/* arbitrary; value doesn't matter to artifact_hit() */
3683 | 	}
3684 | 
3685 | 	vis = canseemon(mtmp);
3686 | 	for(obj = mtmp->minvent; obj; obj = obj2) {
3687 | 	    obj2 = obj->nobj;
3688 | 	    if(obj->oclass != osym) continue; /* test only objs of type osym */
3689 | 	    skip = 0;
3690 | 	    quan = 0L;
3691 | 	    dindx = 0;
3692 | 
3693 | 	    switch(dmgtyp) {
3694 | 		case AD_COLD:
3695 | 		    if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3696 | 			quan = obj->quan;
3697 | 			dindx = 0;
3698 | 			tmp++;
3699 | 		    } else skip++;
3700 | 		    break;
3701 | 		case AD_FIRE:
3702 | 		    if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3703 | 			skip++;
3704 | 		    if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3705 | 			skip++;
3706 | 			if (vis)
3707 | 			    pline("%s glows a strange %s, but remains intact.",
3708 | 				The(distant_name(obj, xname)),
3709 | 				hcolor("dark red"));
3710 | 		    }
3711 | 		    quan = obj->quan;
3712 | 		    switch(osym) {
3713 | 			case POTION_CLASS:
3714 | 			    dindx = 1;
3715 | 			    tmp++;
3716 | 			    break;
3717 | 			case SCROLL_CLASS:
3718 | 			    dindx = 2;
3719 | 			    tmp++;
3720 | 			    break;
3721 | 			case SPBOOK_CLASS:
3722 | 			    dindx = 3;
3723 | 			    tmp++;
3724 | 			    break;
3725 | 			default:
3726 | 			    skip++;
3727 | 			    break;
3728 | 		    }
3729 | 		    break;
3730 | 		case AD_ELEC:
3731 | 		    quan = obj->quan;
3732 | 		    switch(osym) {
3733 | 			case RING_CLASS:
3734 | 			    if(obj->otyp == RIN_SHOCK_RESISTANCE)
3735 | 				    { skip++; break; }
3736 | 			    dindx = 4;
3737 | 			    break;
3738 | 			case WAND_CLASS:
3739 | 			    if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
3740 | 			    dindx = 5;
3741 | 			    tmp++;
3742 | 			    break;
3743 | 			default:
3744 | 			    skip++;
3745 | 			    break;
3746 | 		    }
3747 | 		    break;
3748 | 		default:
3749 | 		    skip++;
3750 | 		    break;
3751 | 	    }
3752 | 	    if(!skip) {
3753 | 		for(i = cnt = 0L; i < quan; i++)
3754 | 		    if(!rn2(3)) cnt++;
3755 | 
3756 | 		if(!cnt) continue;
3757 | 		if (vis) pline("%s %s %s!",
3758 | 			s_suffix(Monnam(mtmp)), xname(obj),
3759 | 			(cnt > 1L) ? destroy_strings[dindx*3 + 1]
3760 | 				  : destroy_strings[dindx*3]);
3761 | 		for(i = 0; i < cnt; i++) m_useup(mtmp, obj);
3762 | 	    }
3763 | 	}
3764 | 	return(tmp);
3765 | }
3766 | 
3767 | #endif /*OVL3*/
3768 | #ifdef OVL2
3769 | 
3770 | int
3771 | resist(mtmp, oclass, damage, tell)
3772 | struct monst *mtmp;
3773 | char oclass;
3774 | int damage, tell;
3775 | {
3776 | 	int resisted;
3777 | 	int alev, dlev;
3778 | 
3779 | 	/* attack level */
3780 | 	switch (oclass) {
3781 | 	    case WAND_CLASS:	alev = 12;	 break;
3782 | 	    case SCROLL_CLASS:	alev =  9;	 break;
3783 | 	    case POTION_CLASS:	alev =  6;	 break;
3784 | 	    default:		alev = u.ulevel; break;		/* spell */
3785 | 	}
3786 | 	/* defense level */
3787 | 	dlev = (int)mtmp->m_lev;
3788 | 	if (dlev > 50) dlev = 50;
3789 | 	else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
3790 | 
3791 | 	resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
3792 | 	if(resisted) {
3793 | 
3794 | 		if(tell) {
3795 | 		    shieldeff(mtmp->mx, mtmp->my);
3796 | 		    pline("%s resists!", Monnam(mtmp));
3797 | 		}
3798 | 		mtmp->mhp -= damage/2;
3799 | 	} else  mtmp->mhp -= damage;
3800 | 
3801 | 	if(mtmp->mhp < 1) {
3802 | 		if(m_using) monkilled(mtmp, "", AD_RBRE);
3803 | 		else killed(mtmp);
3804 | 	}
3805 | 	return(resisted);
3806 | }
3807 | 
3808 | void
3809 | makewish()
3810 | {
3811 | 	char buf[BUFSZ];
3812 | 	register struct obj *otmp;
3813 | 	int tries = 0;
3814 | 
3815 | 	if (flags.verbose) You("may wish for an object.");
3816 | retry:
3817 | 	getlin("For what do you wish?", buf);
3818 | 	if(buf[0] == '\033') buf[0] = 0;
3819 | 	/*
3820 | 	 *  Note: if they wished for and got a non-object successfully,
3821 | 	 *  otmp == &zeroobj
3822 | 	 */
3823 | 	otmp = readobjnam(buf);
3824 | 	if (!otmp) {
3825 | 	    pline("Nothing fitting that description exists in the game.");
3826 | 	    if (++tries < 5) goto retry;
3827 | 	    pline(thats_enough_tries);
3828 | 	    if (!(otmp = readobjnam((char *)0)))
3829 | 		return; /* for safety; should never happen */
3830 | 	}
3831 | 
3832 | 	/* KMH, conduct */
3833 | 	u.uconduct.wishes++;
3834 | 
3835 | 	if (otmp != &zeroobj) {
3836 | 	    if(otmp->oartifact && !touch_artifact(otmp,&youmonst))
3837 | 		dropy(otmp);
3838 | 	    else
3839 | 		/* The(aobjnam()) is safe since otmp is unidentified -dlc */
3840 | 		(void) hold_another_object(otmp, u.uswallow ?
3841 | 				       "Oops!  %s out of your reach!" :
3842 | 				       Is_airlevel(&u.uz) || u.uinwater ?
3843 | 				       "Oops!  %s away from you!" :
3844 | 				       "Oops!  %s to the floor!",
3845 | 				       The(aobjnam(otmp,
3846 | 					     Is_airlevel(&u.uz) || u.uinwater ?
3847 | 						   "slip" : "drop")),
3848 | 				       (const char *)0);
3849 | 	    u.ublesscnt += rn1(100,50);  /* the gods take notice */
3850 | 	}
3851 | }
3852 | 
3853 | #endif /*OVL2*/
3854 | 
3855 | /*zap.c*/