Home | History | Annotate | Line # | Download | only in hack
hack.zap.c revision 1.8
      1 /*	$NetBSD: hack.zap.c,v 1.8 2009/06/07 18:30:39 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
      5  * Amsterdam
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions are
     10  * met:
     11  *
     12  * - Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * - Redistributions in binary form must reproduce the above copyright
     16  * notice, this list of conditions and the following disclaimer in the
     17  * documentation and/or other materials provided with the distribution.
     18  *
     19  * - Neither the name of the Stichting Centrum voor Wiskunde en
     20  * Informatica, nor the names of its contributors may be used to endorse or
     21  * promote products derived from this software without specific prior
     22  * written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  */
     36 
     37 /*
     38  * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org>
     39  * All rights reserved.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. The name of the author may not be used to endorse or promote products
     50  *    derived from this software without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
     55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 __RCSID("$NetBSD: hack.zap.c,v 1.8 2009/06/07 18:30:39 dholland Exp $");
     67 #endif				/* not lint */
     68 
     69 #include "hack.h"
     70 #include "extern.h"
     71 
     72 const char           *const fl[] = {
     73 	"magic missile",
     74 	"bolt of fire",
     75 	"sleep ray",
     76 	"bolt of cold",
     77 	"death ray"
     78 };
     79 
     80 /* Routines for IMMEDIATE wands. */
     81 /* bhitm: monster mtmp was hit by the effect of wand otmp */
     82 void
     83 bhitm(struct monst *mtmp, struct obj *otmp)
     84 {
     85 	wakeup(mtmp);
     86 	switch (otmp->otyp) {
     87 	case WAN_STRIKING:
     88 		if (u.uswallow || rnd(20) < 10 + mtmp->data->ac) {
     89 			int             tmp = d(2, 12);
     90 			hit("wand", mtmp, exclam(tmp));
     91 			mtmp->mhp -= tmp;
     92 			if (mtmp->mhp < 1)
     93 				killed(mtmp);
     94 		} else
     95 			miss("wand", mtmp);
     96 		break;
     97 	case WAN_SLOW_MONSTER:
     98 		mtmp->mspeed = MSLOW;
     99 		break;
    100 	case WAN_SPEED_MONSTER:
    101 		mtmp->mspeed = MFAST;
    102 		break;
    103 	case WAN_UNDEAD_TURNING:
    104 		if (strchr(UNDEAD, mtmp->data->mlet)) {
    105 			mtmp->mhp -= rnd(8);
    106 			if (mtmp->mhp < 1)
    107 				killed(mtmp);
    108 			else
    109 				mtmp->mflee = 1;
    110 		}
    111 		break;
    112 	case WAN_POLYMORPH:
    113 		if (newcham(mtmp, &mons[rn2(CMNUM)]))
    114 			objects[otmp->otyp].oc_name_known = 1;
    115 		break;
    116 	case WAN_CANCELLATION:
    117 		mtmp->mcan = 1;
    118 		break;
    119 	case WAN_TELEPORTATION:
    120 		rloc(mtmp);
    121 		break;
    122 	case WAN_MAKE_INVISIBLE:
    123 		mtmp->minvis = 1;
    124 		break;
    125 #ifdef WAN_PROBING
    126 	case WAN_PROBING:
    127 		mstatusline(mtmp);
    128 		break;
    129 #endif	/* WAN_PROBING */
    130 	default:
    131 		impossible("What an interesting wand (%u)", otmp->otyp);
    132 	}
    133 }
    134 
    135 /*
    136  * object obj was hit by the effect of wand otmp
    137  * returns TRUE if sth was done
    138  */
    139 int
    140 bhito(struct obj *obj, struct obj *otmp)
    141 {
    142 	int             res = TRUE;
    143 
    144 	if (obj == uball || obj == uchain)
    145 		res = FALSE;
    146 	else
    147 		switch (otmp->otyp) {
    148 		case WAN_POLYMORPH:
    149 			/*
    150 			 * preserve symbol and quantity, but turn rocks into
    151 			 * gems
    152 			 */
    153 			mkobj_at((obj->otyp == ROCK || obj->otyp == ENORMOUS_ROCK)
    154 				 ? GEM_SYM : obj->olet,
    155 				 obj->ox, obj->oy)->quan = obj->quan;
    156 			delobj(obj);
    157 			break;
    158 		case WAN_STRIKING:
    159 			if (obj->otyp == ENORMOUS_ROCK)
    160 				fracture_rock(obj);
    161 			else
    162 				res = FALSE;
    163 			break;
    164 		case WAN_CANCELLATION:
    165 			if (obj->spe && obj->olet != AMULET_SYM) {
    166 				obj->known = 0;
    167 				obj->spe = 0;
    168 			}
    169 			break;
    170 		case WAN_TELEPORTATION:
    171 			rloco(obj);
    172 			break;
    173 		case WAN_MAKE_INVISIBLE:
    174 			obj->oinvis = 1;
    175 			break;
    176 		case WAN_UNDEAD_TURNING:
    177 			res = revive(obj);
    178 			break;
    179 		case WAN_SLOW_MONSTER:	/* no effect on objects */
    180 		case WAN_SPEED_MONSTER:
    181 #ifdef WAN_PROBING
    182 		case WAN_PROBING:
    183 #endif	/* WAN_PROBING */
    184 			res = FALSE;
    185 			break;
    186 		default:
    187 			impossible("What an interesting wand (%u)", otmp->otyp);
    188 		}
    189 	return (res);
    190 }
    191 
    192 int
    193 dozap(void)
    194 {
    195 	struct obj     *obj;
    196 	xchar           zx, zy;
    197 
    198 	obj = getobj("/", "zap");
    199 	if (!obj)
    200 		return (0);
    201 	if (obj->spe < 0 || (obj->spe == 0 && rn2(121))) {
    202 		pline("Nothing Happens.");
    203 		return (1);
    204 	}
    205 	if (obj->spe == 0)
    206 		pline("You wrest one more spell from the worn-out wand.");
    207 	if (!(objects[obj->otyp].bits & NODIR) && !getdir(1))
    208 		return (1);	/* make him pay for knowing !NODIR */
    209 	obj->spe--;
    210 	if (objects[obj->otyp].bits & IMMEDIATE) {
    211 		if (u.uswallow)
    212 			bhitm(u.ustuck, obj);
    213 		else if (u.dz) {
    214 			if (u.dz > 0) {
    215 				struct obj     *otmp = o_at(u.ux, u.uy);
    216 				if (otmp)
    217 					(void) bhito(otmp, obj);
    218 			}
    219 		} else
    220 			(void) bhit(u.dx, u.dy, rn1(8, 6), 0, bhitm, bhito, obj);
    221 	} else {
    222 		switch (obj->otyp) {
    223 		case WAN_LIGHT:
    224 			litroom(TRUE);
    225 			break;
    226 		case WAN_SECRET_DOOR_DETECTION:
    227 			if (!findit())
    228 				return (1);
    229 			break;
    230 		case WAN_CREATE_MONSTER:
    231 			{
    232 				int             cnt = 1;
    233 				if (!rn2(23))
    234 					cnt += rn2(7) + 1;
    235 				while (cnt--)
    236 					(void) makemon((struct permonst *) 0, u.ux, u.uy);
    237 			}
    238 			break;
    239 		case WAN_WISHING:
    240 			{
    241 				char            buf[BUFSZ];
    242 				struct obj     *otmp;
    243 				if (u.uluck + rn2(5) < 0) {
    244 					pline("Unfortunately, nothing happens.");
    245 					break;
    246 				}
    247 				pline("You may wish for an object. What do you want? ");
    248 				getlin(buf);
    249 				if (buf[0] == '\033')
    250 					buf[0] = 0;
    251 				otmp = readobjnam(buf);
    252 				otmp = addinv(otmp);
    253 				prinv(otmp);
    254 				break;
    255 			}
    256 		case WAN_DIGGING:
    257 			/*
    258 			 * Original effect (approximately): from CORR: dig
    259 			 * until we pierce a wall from ROOM: piece wall and
    260 			 * dig until we reach an ACCESSIBLE place. Currently:
    261 			 * dig for digdepth positions; also down on request
    262 			 * of Lennart Augustsson.
    263 			 */
    264 			{
    265 				struct rm      *room;
    266 				int             digdepth;
    267 				if (u.uswallow) {
    268 					struct monst   *mtmp = u.ustuck;
    269 
    270 					pline("You pierce %s's stomach wall!",
    271 					      monnam(mtmp));
    272 					mtmp->mhp = 1;	/* almost dead */
    273 					unstuck(mtmp);
    274 					mnexto(mtmp);
    275 					break;
    276 				}
    277 				if (u.dz) {
    278 					if (u.dz < 0) {
    279 						pline("You loosen a rock from the ceiling.");
    280 						pline("It falls on your head!");
    281 						losehp(1, "falling rock");
    282 						mksobj_at(ROCK, u.ux, u.uy);
    283 						fobj->quan = 1;
    284 						stackobj(fobj);
    285 						if (Invisible)
    286 							newsym(u.ux, u.uy);
    287 					} else {
    288 						dighole();
    289 					}
    290 					break;
    291 				}
    292 				zx = u.ux + u.dx;
    293 				zy = u.uy + u.dy;
    294 				digdepth = 8 + rn2(18);
    295 				Tmp_at(-1, '*');	/* open call */
    296 				while (--digdepth >= 0) {
    297 					if (!isok(zx, zy))
    298 						break;
    299 					room = &levl[zx][zy];
    300 					Tmp_at(zx, zy);
    301 					if (!xdnstair) {
    302 						if (zx < 3 || zx > COLNO - 3 ||
    303 						    zy < 3 || zy > ROWNO - 3)
    304 							break;
    305 						if (room->typ == HWALL ||
    306 						    room->typ == VWALL) {
    307 							room->typ = ROOM;
    308 							break;
    309 						}
    310 					} else if (room->typ == HWALL || room->typ == VWALL ||
    311 						   room->typ == SDOOR || room->typ == LDOOR) {
    312 						room->typ = DOOR;
    313 						digdepth -= 2;
    314 					} else if (room->typ == SCORR || !room->typ) {
    315 						room->typ = CORR;
    316 						digdepth--;
    317 					}
    318 					mnewsym(zx, zy);
    319 					zx += u.dx;
    320 					zy += u.dy;
    321 				}
    322 				mnewsym(zx, zy);	/* not always necessary */
    323 				Tmp_at(-1, -1);	/* closing call */
    324 				break;
    325 			}
    326 		default:
    327 			buzz((int) obj->otyp - WAN_MAGIC_MISSILE,
    328 			     u.ux, u.uy, u.dx, u.dy);
    329 			break;
    330 		}
    331 		if (!objects[obj->otyp].oc_name_known) {
    332 			objects[obj->otyp].oc_name_known = 1;
    333 			more_experienced(0, 10);
    334 		}
    335 	}
    336 	return (1);
    337 }
    338 
    339 const char           *
    340 exclam(int force)
    341 {
    342 	/* force == 0 occurs e.g. with sleep ray */
    343 	/*
    344 	 * note that large force is usual with wands so that !! would require
    345 	 * information about hand/weapon/wand
    346 	 */
    347 	return ((force < 0) ? "?" : (force <= 4) ? "." : "!");
    348 }
    349 
    350 void
    351 hit(const char *str, struct monst *mtmp, const char *force)
    352 {
    353 	/* force is usually either "." or "!" */
    354 
    355 	if (!cansee(mtmp->mx, mtmp->my))
    356 		pline("The %s hits it.", str);
    357 	else
    358 		pline("The %s hits %s%s", str, monnam(mtmp), force);
    359 }
    360 
    361 void
    362 miss(const char *str, struct monst *mtmp)
    363 {
    364 	if (!cansee(mtmp->mx, mtmp->my))
    365 		pline("The %s misses it.", str);
    366 	else
    367 		pline("The %s misses %s.", str, monnam(mtmp));
    368 }
    369 
    370 /*
    371  * bhit: called when a weapon is thrown (sym = obj->olet) or when an
    372  * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range
    373  * or when a monster is hit; the monster is returned, and bhitpos is set to
    374  * the final position of the weapon thrown; the ray of a wand may affect
    375  * several objects and monsters on its path - for each of these an argument
    376  * function is called.
    377  */
    378 /* check !u.uswallow before calling bhit() */
    379 
    380 struct monst   *
    381 bhit(int ddx, int ddy, int range,	/* direction and range */
    382      int sym,				/* symbol displayed on path */
    383      					/* fns called when mon/obj hit */
    384      void (*fhitm)(struct monst *, struct obj *),
    385      int (*fhito)(struct obj *, struct obj *),
    386      struct obj *obj)			/* 2nd arg to fhitm/fhito */
    387 {
    388 	struct monst   *mtmp;
    389 	struct obj     *otmp;
    390 	int             typ;
    391 
    392 	bhitpos.x = u.ux;
    393 	bhitpos.y = u.uy;
    394 
    395 	if (sym)
    396 		tmp_at(-1, sym);/* open call */
    397 	while (range-- > 0) {
    398 		bhitpos.x += ddx;
    399 		bhitpos.y += ddy;
    400 		typ = levl[bhitpos.x][bhitpos.y].typ;
    401 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
    402 			if (sym) {
    403 				tmp_at(-1, -1);	/* close call */
    404 				return (mtmp);
    405 			}
    406 			(*fhitm) (mtmp, obj);
    407 			range -= 3;
    408 		}
    409 		if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) {
    410 			if ((*fhito) (otmp, obj))
    411 				range--;
    412 		}
    413 		if (!ZAP_POS(typ)) {
    414 			bhitpos.x -= ddx;
    415 			bhitpos.y -= ddy;
    416 			break;
    417 		}
    418 		if (sym)
    419 			tmp_at(bhitpos.x, bhitpos.y);
    420 	}
    421 
    422 	/* leave last symbol unless in a pool */
    423 	if (sym)
    424 		tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0);
    425 	return (0);
    426 }
    427 
    428 struct monst   *
    429 boomhit(int dx, int dy)
    430 {
    431 	int             i, ct;
    432 	struct monst   *mtmp;
    433 	char            sym = ')';
    434 
    435 	bhitpos.x = u.ux;
    436 	bhitpos.y = u.uy;
    437 
    438 	for (i = 0; i < 8; i++)
    439 		if (xdir[i] == dx && ydir[i] == dy)
    440 			break;
    441 	tmp_at(-1, sym);	/* open call */
    442 	for (ct = 0; ct < 10; ct++) {
    443 		if (i == 8)
    444 			i = 0;
    445 		sym = ')' + '(' - sym;
    446 		tmp_at(-2, sym);/* change let call */
    447 		dx = xdir[i];
    448 		dy = ydir[i];
    449 		bhitpos.x += dx;
    450 		bhitpos.y += dy;
    451 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
    452 			tmp_at(-1, -1);
    453 			return (mtmp);
    454 		}
    455 		if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) {
    456 			bhitpos.x -= dx;
    457 			bhitpos.y -= dy;
    458 			break;
    459 		}
    460 		if (bhitpos.x == u.ux && bhitpos.y == u.uy) {	/* ct == 9 */
    461 			if (rn2(20) >= 10 + u.ulevel) {	/* we hit ourselves */
    462 				(void) thitu(10, rnd(10), "boomerang");
    463 				break;
    464 			} else {/* we catch it */
    465 				tmp_at(-1, -1);
    466 				pline("Skillfully, you catch the boomerang.");
    467 				return (&youmonst);
    468 			}
    469 		}
    470 		tmp_at(bhitpos.x, bhitpos.y);
    471 		if (ct % 5 != 0)
    472 			i++;
    473 	}
    474 	tmp_at(-1, -1);		/* do not leave last symbol */
    475 	return (0);
    476 }
    477 
    478 char
    479 dirlet(int dx, int dy)
    480 {
    481 	return
    482 		(dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
    483 }
    484 
    485 /* type == -1: monster spitting fire at you */
    486 /* type == -1,-2,-3: bolts sent out by wizard */
    487 /* called with dx = dy = 0 with vertical bolts */
    488 void
    489 buzz(int type, xchar sx, xchar sy, int dx, int dy)
    490 {
    491 	int             abstype = abs(type);
    492 	const char     *fltxt = (type == -1) ? "blaze of fire" : fl[abstype];
    493 	struct rm      *lev;
    494 	xchar           range;
    495 	struct monst   *mon;
    496 
    497 	if (u.uswallow) {
    498 		int             tmp;
    499 
    500 		if (type < 0)
    501 			return;
    502 		tmp = zhit(u.ustuck, type);
    503 		pline("The %s rips into %s%s",
    504 		      fltxt, monnam(u.ustuck), exclam(tmp));
    505 		return;
    506 	}
    507 	if (type < 0)
    508 		pru();
    509 	range = rn1(7, 7);
    510 	Tmp_at(-1, dirlet(dx, dy));	/* open call */
    511 	while (range-- > 0) {
    512 		sx += dx;
    513 		sy += dy;
    514 		if ((lev = &levl[sx][sy])->typ)
    515 			Tmp_at(sx, sy);
    516 		else {
    517 			int             bounce = 0;
    518 			if (cansee(sx - dx, sy - dy))
    519 				pline("The %s bounces!", fltxt);
    520 			if (ZAP_POS(levl[sx][sy - dy].typ))
    521 				bounce = 1;
    522 			if (ZAP_POS(levl[sx - dx][sy].typ)) {
    523 				if (!bounce || rn2(2))
    524 					bounce = 2;
    525 			}
    526 			switch (bounce) {
    527 			case 0:
    528 				dx = -dx;
    529 				dy = -dy;
    530 				continue;
    531 			case 1:
    532 				dy = -dy;
    533 				sx -= dx;
    534 				break;
    535 			case 2:
    536 				dx = -dx;
    537 				sy -= dy;
    538 				break;
    539 			}
    540 			Tmp_at(-2, dirlet(dx, dy));
    541 			continue;
    542 		}
    543 		if (lev->typ == POOL && abstype == 1 /* fire */ ) {
    544 			range -= 3;
    545 			lev->typ = ROOM;
    546 			if (cansee(sx, sy)) {
    547 				mnewsym(sx, sy);
    548 				pline("The water evaporates.");
    549 			} else
    550 				pline("You hear a hissing sound.");
    551 		}
    552 		if ((mon = m_at(sx, sy)) &&
    553 		    (type != -1 || mon->data->mlet != 'D')) {
    554 			wakeup(mon);
    555 			if (rnd(20) < 18 + mon->data->ac) {
    556 				int             tmp = zhit(mon, abstype);
    557 				if (mon->mhp < 1) {
    558 					if (type < 0) {
    559 						if (cansee(mon->mx, mon->my))
    560 							pline("%s is killed by the %s!",
    561 							Monnam(mon), fltxt);
    562 						mondied(mon);
    563 					} else
    564 						killed(mon);
    565 				} else
    566 					hit(fltxt, mon, exclam(tmp));
    567 				range -= 2;
    568 			} else
    569 				miss(fltxt, mon);
    570 		} else if (sx == u.ux && sy == u.uy) {
    571 			nomul(0);
    572 			if (rnd(20) < 18 + u.uac) {
    573 				int             dam = 0;
    574 				range -= 2;
    575 				pline("The %s hits you!", fltxt);
    576 				switch (abstype) {
    577 				case 0:
    578 					dam = d(2, 6);
    579 					break;
    580 				case 1:
    581 					if (Fire_resistance)
    582 						pline("You don't feel hot!");
    583 					else
    584 						dam = d(6, 6);
    585 					if (!rn2(3))
    586 						burn_scrolls();
    587 					break;
    588 				case 2:
    589 					nomul(-rnd(25));	/* sleep ray */
    590 					break;
    591 				case 3:
    592 					if (Cold_resistance)
    593 						pline("You don't feel cold!");
    594 					else
    595 						dam = d(6, 6);
    596 					break;
    597 				case 4:
    598 					u.uhp = -1;
    599 				}
    600 				losehp(dam, fltxt);
    601 			} else
    602 				pline("The %s whizzes by you!", fltxt);
    603 			stop_occupation();
    604 		}
    605 		if (!ZAP_POS(lev->typ)) {
    606 			int             bounce = 0, rmn;
    607 			if (cansee(sx, sy))
    608 				pline("The %s bounces!", fltxt);
    609 			range--;
    610 			if (!dx || !dy || !rn2(20)) {
    611 				dx = -dx;
    612 				dy = -dy;
    613 			} else {
    614 				if (ZAP_POS(rmn = levl[sx][sy - dy].typ) &&
    615 				    (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ)))
    616 					bounce = 1;
    617 				if (ZAP_POS(rmn = levl[sx - dx][sy].typ) &&
    618 				    (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ)))
    619 					if (!bounce || rn2(2))
    620 						bounce = 2;
    621 
    622 				switch (bounce) {
    623 				case 0:
    624 					dy = -dy;
    625 					dx = -dx;
    626 					break;
    627 				case 1:
    628 					dy = -dy;
    629 					break;
    630 				case 2:
    631 					dx = -dx;
    632 					break;
    633 				}
    634 				Tmp_at(-2, dirlet(dx, dy));
    635 			}
    636 		}
    637 	}
    638 	Tmp_at(-1, -1);
    639 }
    640 
    641 int
    642 zhit(struct monst *mon, int type)		/* returns damage to mon */
    643 {
    644 	int             tmp = 0;
    645 
    646 	switch (type) {
    647 	case 0:		/* magic missile */
    648 		tmp = d(2, 6);
    649 		break;
    650 	case -1:		/* Dragon blazing fire */
    651 	case 1:		/* fire */
    652 		if (strchr("Dg", mon->data->mlet))
    653 			break;
    654 		tmp = d(6, 6);
    655 		if (strchr("YF", mon->data->mlet))
    656 			tmp += 7;
    657 		break;
    658 	case 2:		/* sleep */
    659 		mon->mfroz = 1;
    660 		break;
    661 	case 3:		/* cold */
    662 		if (strchr("YFgf", mon->data->mlet))
    663 			break;
    664 		tmp = d(6, 6);
    665 		if (mon->data->mlet == 'D')
    666 			tmp += 7;
    667 		break;
    668 	case 4:		/* death */
    669 		if (strchr(UNDEAD, mon->data->mlet))
    670 			break;
    671 		tmp = mon->mhp + 1;
    672 		break;
    673 	}
    674 	mon->mhp -= tmp;
    675 	return (tmp);
    676 }
    677 
    678 #define	CORPSE_I_TO_C(otyp)	(char) ((otyp >= DEAD_ACID_BLOB)\
    679 		     ?  'a' + (otyp - DEAD_ACID_BLOB)\
    680 		     :	'@' + (otyp - DEAD_HUMAN))
    681 int
    682 revive(struct obj *obj)
    683 {
    684 	struct monst   *mtmp = NULL;
    685 
    686 	if (obj->olet == FOOD_SYM && obj->otyp > CORPSE) {
    687 		/* do not (yet) revive shopkeepers */
    688 		/*
    689 		 * Note: this might conceivably produce two monsters at the
    690 		 * same position - strange, but harmless
    691 		 */
    692 		mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp), obj->ox, obj->oy);
    693 		delobj(obj);
    694 	}
    695 	return (!!mtmp);	/* TRUE if some monster created */
    696 }
    697 
    698 void
    699 rloco(struct obj *obj)
    700 {
    701 	int tx, ty, otx, oty;
    702 
    703 	otx = obj->ox;
    704 	oty = obj->oy;
    705 	do {
    706 		tx = rn1(COLNO - 3, 2);
    707 		ty = rn2(ROWNO);
    708 	} while (!goodpos(tx, ty));
    709 	obj->ox = tx;
    710 	obj->oy = ty;
    711 	if (cansee(otx, oty))
    712 		newsym(otx, oty);
    713 }
    714 
    715 /* fractured by pick-axe or wand of striking */
    716 /* no texts here! */
    717 void
    718 fracture_rock(struct obj *obj)
    719 {
    720 	/* unpobj(obj); */
    721 	obj->otyp = ROCK;
    722 	obj->quan = 7 + rn2(60);
    723 	obj->owt = weight(obj);
    724 	obj->olet = WEAPON_SYM;
    725 	if (cansee(obj->ox, obj->oy))
    726 		prl(obj->ox, obj->oy);
    727 }
    728 
    729 void
    730 burn_scrolls(void)
    731 {
    732 	struct obj     *obj, *obj2;
    733 	int             cnt = 0;
    734 
    735 	for (obj = invent; obj; obj = obj2) {
    736 		obj2 = obj->nobj;
    737 		if (obj->olet == SCROLL_SYM) {
    738 			cnt++;
    739 			useup(obj);
    740 		}
    741 	}
    742 	if (cnt > 1) {
    743 		pline("Your scrolls catch fire!");
    744 		losehp(cnt, "burning scrolls");
    745 	} else if (cnt) {
    746 		pline("Your scroll catches fire!");
    747 		losehp(1, "burning scroll");
    748 	}
    749 }
    750