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