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