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