Home | History | Annotate | Line # | Download | only in hack
hack.zap.c revision 1.6
      1 /*	$NetBSD: hack.zap.c,v 1.6 2003/04/02 18:36:42 jsm 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.6 2003/04/02 18:36:42 jsm 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(mtmp, otmp)
     84 	struct monst   *mtmp;
     85 	struct obj     *otmp;
     86 {
     87 	wakeup(mtmp);
     88 	switch (otmp->otyp) {
     89 	case WAN_STRIKING:
     90 		if (u.uswallow || rnd(20) < 10 + mtmp->data->ac) {
     91 			int             tmp = d(2, 12);
     92 			hit("wand", mtmp, exclam(tmp));
     93 			mtmp->mhp -= tmp;
     94 			if (mtmp->mhp < 1)
     95 				killed(mtmp);
     96 		} else
     97 			miss("wand", mtmp);
     98 		break;
     99 	case WAN_SLOW_MONSTER:
    100 		mtmp->mspeed = MSLOW;
    101 		break;
    102 	case WAN_SPEED_MONSTER:
    103 		mtmp->mspeed = MFAST;
    104 		break;
    105 	case WAN_UNDEAD_TURNING:
    106 		if (strchr(UNDEAD, mtmp->data->mlet)) {
    107 			mtmp->mhp -= rnd(8);
    108 			if (mtmp->mhp < 1)
    109 				killed(mtmp);
    110 			else
    111 				mtmp->mflee = 1;
    112 		}
    113 		break;
    114 	case WAN_POLYMORPH:
    115 		if (newcham(mtmp, &mons[rn2(CMNUM)]))
    116 			objects[otmp->otyp].oc_name_known = 1;
    117 		break;
    118 	case WAN_CANCELLATION:
    119 		mtmp->mcan = 1;
    120 		break;
    121 	case WAN_TELEPORTATION:
    122 		rloc(mtmp);
    123 		break;
    124 	case WAN_MAKE_INVISIBLE:
    125 		mtmp->minvis = 1;
    126 		break;
    127 #ifdef WAN_PROBING
    128 	case WAN_PROBING:
    129 		mstatusline(mtmp);
    130 		break;
    131 #endif	/* WAN_PROBING */
    132 	default:
    133 		impossible("What an interesting wand (%u)", otmp->otyp);
    134 	}
    135 }
    136 
    137 int
    138 bhito(obj, otmp)		/* object obj was hit by the effect of wand
    139 				 * otmp */
    140 	struct obj     *obj, *otmp;	/* returns TRUE if sth was done */
    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()
    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(force)
    341 	int             force;
    342 {
    343 	/* force == 0 occurs e.g. with sleep ray */
    344 	/*
    345 	 * note that large force is usual with wands so that !! would require
    346 	 * information about hand/weapon/wand
    347 	 */
    348 	return ((force < 0) ? "?" : (force <= 4) ? "." : "!");
    349 }
    350 
    351 void
    352 hit(str, mtmp, force)
    353 	const char           *str;
    354 	struct monst   *mtmp;
    355 	const char           *force;	/* usually either "." or "!" */
    356 {
    357 	if (!cansee(mtmp->mx, mtmp->my))
    358 		pline("The %s hits it.", str);
    359 	else
    360 		pline("The %s hits %s%s", str, monnam(mtmp), force);
    361 }
    362 
    363 void
    364 miss(str, mtmp)
    365 	const char           *str;
    366 	struct monst   *mtmp;
    367 {
    368 	if (!cansee(mtmp->mx, mtmp->my))
    369 		pline("The %s misses it.", str);
    370 	else
    371 		pline("The %s misses %s.", str, monnam(mtmp));
    372 }
    373 
    374 /*
    375  * bhit: called when a weapon is thrown (sym = obj->olet) or when an
    376  * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range
    377  * or when a monster is hit; the monster is returned, and bhitpos is set to
    378  * the final position of the weapon thrown; the ray of a wand may affect
    379  * several objects and monsters on its path - for each of these an argument
    380  * function is called.
    381  */
    382 /* check !u.uswallow before calling bhit() */
    383 
    384 struct monst   *
    385 bhit(ddx, ddy, range, sym, fhitm, fhito, obj)
    386 	int             ddx, ddy, range;	/* direction and range */
    387 	char            sym;	/* symbol displayed on path */
    388 	/* fns called when mon/obj hit */
    389 	void          (*fhitm) __P((struct monst *, struct obj *));
    390 	int	      (*fhito) __P((struct obj *, struct obj *));
    391 	struct obj     *obj;	/* 2nd arg to fhitm/fhito */
    392 {
    393 	struct monst   *mtmp;
    394 	struct obj     *otmp;
    395 	int             typ;
    396 
    397 	bhitpos.x = u.ux;
    398 	bhitpos.y = u.uy;
    399 
    400 	if (sym)
    401 		tmp_at(-1, sym);/* open call */
    402 	while (range-- > 0) {
    403 		bhitpos.x += ddx;
    404 		bhitpos.y += ddy;
    405 		typ = levl[bhitpos.x][bhitpos.y].typ;
    406 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
    407 			if (sym) {
    408 				tmp_at(-1, -1);	/* close call */
    409 				return (mtmp);
    410 			}
    411 			(*fhitm) (mtmp, obj);
    412 			range -= 3;
    413 		}
    414 		if (fhito && (otmp = o_at(bhitpos.x, bhitpos.y))) {
    415 			if ((*fhito) (otmp, obj))
    416 				range--;
    417 		}
    418 		if (!ZAP_POS(typ)) {
    419 			bhitpos.x -= ddx;
    420 			bhitpos.y -= ddy;
    421 			break;
    422 		}
    423 		if (sym)
    424 			tmp_at(bhitpos.x, bhitpos.y);
    425 	}
    426 
    427 	/* leave last symbol unless in a pool */
    428 	if (sym)
    429 		tmp_at(-1, (levl[bhitpos.x][bhitpos.y].typ == POOL) ? -1 : 0);
    430 	return (0);
    431 }
    432 
    433 struct monst   *
    434 boomhit(int dx, int dy)
    435 {
    436 	int             i, ct;
    437 	struct monst   *mtmp;
    438 	char            sym = ')';
    439 
    440 	bhitpos.x = u.ux;
    441 	bhitpos.y = u.uy;
    442 
    443 	for (i = 0; i < 8; i++)
    444 		if (xdir[i] == dx && ydir[i] == dy)
    445 			break;
    446 	tmp_at(-1, sym);	/* open call */
    447 	for (ct = 0; ct < 10; ct++) {
    448 		if (i == 8)
    449 			i = 0;
    450 		sym = ')' + '(' - sym;
    451 		tmp_at(-2, sym);/* change let call */
    452 		dx = xdir[i];
    453 		dy = ydir[i];
    454 		bhitpos.x += dx;
    455 		bhitpos.y += dy;
    456 		if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != NULL) {
    457 			tmp_at(-1, -1);
    458 			return (mtmp);
    459 		}
    460 		if (!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ)) {
    461 			bhitpos.x -= dx;
    462 			bhitpos.y -= dy;
    463 			break;
    464 		}
    465 		if (bhitpos.x == u.ux && bhitpos.y == u.uy) {	/* ct == 9 */
    466 			if (rn2(20) >= 10 + u.ulevel) {	/* we hit ourselves */
    467 				(void) thitu(10, rnd(10), "boomerang");
    468 				break;
    469 			} else {/* we catch it */
    470 				tmp_at(-1, -1);
    471 				pline("Skillfully, you catch the boomerang.");
    472 				return (&youmonst);
    473 			}
    474 		}
    475 		tmp_at(bhitpos.x, bhitpos.y);
    476 		if (ct % 5 != 0)
    477 			i++;
    478 	}
    479 	tmp_at(-1, -1);		/* do not leave last symbol */
    480 	return (0);
    481 }
    482 
    483 char
    484 dirlet(dx, dy)
    485 	int dx, dy;
    486 {
    487 	return
    488 		(dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
    489 }
    490 
    491 /* type == -1: monster spitting fire at you */
    492 /* type == -1,-2,-3: bolts sent out by wizard */
    493 /* called with dx = dy = 0 with vertical bolts */
    494 void
    495 buzz(type, sx, sy, dx, dy)
    496 	int             type;
    497 	xchar           sx, sy;
    498 	int             dx, dy;
    499 {
    500 	int             abstype = abs(type);
    501 	const char     *fltxt = (type == -1) ? "blaze of fire" : fl[abstype];
    502 	struct rm      *lev;
    503 	xchar           range;
    504 	struct monst   *mon;
    505 
    506 	if (u.uswallow) {
    507 		int             tmp;
    508 
    509 		if (type < 0)
    510 			return;
    511 		tmp = zhit(u.ustuck, type);
    512 		pline("The %s rips into %s%s",
    513 		      fltxt, monnam(u.ustuck), exclam(tmp));
    514 		return;
    515 	}
    516 	if (type < 0)
    517 		pru();
    518 	range = rn1(7, 7);
    519 	Tmp_at(-1, dirlet(dx, dy));	/* open call */
    520 	while (range-- > 0) {
    521 		sx += dx;
    522 		sy += dy;
    523 		if ((lev = &levl[sx][sy])->typ)
    524 			Tmp_at(sx, sy);
    525 		else {
    526 			int             bounce = 0;
    527 			if (cansee(sx - dx, sy - dy))
    528 				pline("The %s bounces!", fltxt);
    529 			if (ZAP_POS(levl[sx][sy - dy].typ))
    530 				bounce = 1;
    531 			if (ZAP_POS(levl[sx - dx][sy].typ)) {
    532 				if (!bounce || rn2(2))
    533 					bounce = 2;
    534 			}
    535 			switch (bounce) {
    536 			case 0:
    537 				dx = -dx;
    538 				dy = -dy;
    539 				continue;
    540 			case 1:
    541 				dy = -dy;
    542 				sx -= dx;
    543 				break;
    544 			case 2:
    545 				dx = -dx;
    546 				sy -= dy;
    547 				break;
    548 			}
    549 			Tmp_at(-2, dirlet(dx, dy));
    550 			continue;
    551 		}
    552 		if (lev->typ == POOL && abstype == 1 /* fire */ ) {
    553 			range -= 3;
    554 			lev->typ = ROOM;
    555 			if (cansee(sx, sy)) {
    556 				mnewsym(sx, sy);
    557 				pline("The water evaporates.");
    558 			} else
    559 				pline("You hear a hissing sound.");
    560 		}
    561 		if ((mon = m_at(sx, sy)) &&
    562 		    (type != -1 || mon->data->mlet != 'D')) {
    563 			wakeup(mon);
    564 			if (rnd(20) < 18 + mon->data->ac) {
    565 				int             tmp = zhit(mon, abstype);
    566 				if (mon->mhp < 1) {
    567 					if (type < 0) {
    568 						if (cansee(mon->mx, mon->my))
    569 							pline("%s is killed by the %s!",
    570 							Monnam(mon), fltxt);
    571 						mondied(mon);
    572 					} else
    573 						killed(mon);
    574 				} else
    575 					hit(fltxt, mon, exclam(tmp));
    576 				range -= 2;
    577 			} else
    578 				miss(fltxt, mon);
    579 		} else if (sx == u.ux && sy == u.uy) {
    580 			nomul(0);
    581 			if (rnd(20) < 18 + u.uac) {
    582 				int             dam = 0;
    583 				range -= 2;
    584 				pline("The %s hits you!", fltxt);
    585 				switch (abstype) {
    586 				case 0:
    587 					dam = d(2, 6);
    588 					break;
    589 				case 1:
    590 					if (Fire_resistance)
    591 						pline("You don't feel hot!");
    592 					else
    593 						dam = d(6, 6);
    594 					if (!rn2(3))
    595 						burn_scrolls();
    596 					break;
    597 				case 2:
    598 					nomul(-rnd(25));	/* sleep ray */
    599 					break;
    600 				case 3:
    601 					if (Cold_resistance)
    602 						pline("You don't feel cold!");
    603 					else
    604 						dam = d(6, 6);
    605 					break;
    606 				case 4:
    607 					u.uhp = -1;
    608 				}
    609 				losehp(dam, fltxt);
    610 			} else
    611 				pline("The %s whizzes by you!", fltxt);
    612 			stop_occupation();
    613 		}
    614 		if (!ZAP_POS(lev->typ)) {
    615 			int             bounce = 0, rmn;
    616 			if (cansee(sx, sy))
    617 				pline("The %s bounces!", fltxt);
    618 			range--;
    619 			if (!dx || !dy || !rn2(20)) {
    620 				dx = -dx;
    621 				dy = -dy;
    622 			} else {
    623 				if (ZAP_POS(rmn = levl[sx][sy - dy].typ) &&
    624 				    (IS_ROOM(rmn) || ZAP_POS(levl[sx + dx][sy - dy].typ)))
    625 					bounce = 1;
    626 				if (ZAP_POS(rmn = levl[sx - dx][sy].typ) &&
    627 				    (IS_ROOM(rmn) || ZAP_POS(levl[sx - dx][sy + dy].typ)))
    628 					if (!bounce || rn2(2))
    629 						bounce = 2;
    630 
    631 				switch (bounce) {
    632 				case 0:
    633 					dy = -dy;
    634 					dx = -dx;
    635 					break;
    636 				case 1:
    637 					dy = -dy;
    638 					break;
    639 				case 2:
    640 					dx = -dx;
    641 					break;
    642 				}
    643 				Tmp_at(-2, dirlet(dx, dy));
    644 			}
    645 		}
    646 	}
    647 	Tmp_at(-1, -1);
    648 }
    649 
    650 int
    651 zhit(mon, type)			/* returns damage to mon */
    652 	struct monst   *mon;
    653 	int type;
    654 {
    655 	int             tmp = 0;
    656 
    657 	switch (type) {
    658 	case 0:		/* magic missile */
    659 		tmp = d(2, 6);
    660 		break;
    661 	case -1:		/* Dragon blazing fire */
    662 	case 1:		/* fire */
    663 		if (strchr("Dg", mon->data->mlet))
    664 			break;
    665 		tmp = d(6, 6);
    666 		if (strchr("YF", mon->data->mlet))
    667 			tmp += 7;
    668 		break;
    669 	case 2:		/* sleep */
    670 		mon->mfroz = 1;
    671 		break;
    672 	case 3:		/* cold */
    673 		if (strchr("YFgf", mon->data->mlet))
    674 			break;
    675 		tmp = d(6, 6);
    676 		if (mon->data->mlet == 'D')
    677 			tmp += 7;
    678 		break;
    679 	case 4:		/* death */
    680 		if (strchr(UNDEAD, mon->data->mlet))
    681 			break;
    682 		tmp = mon->mhp + 1;
    683 		break;
    684 	}
    685 	mon->mhp -= tmp;
    686 	return (tmp);
    687 }
    688 
    689 #define	CORPSE_I_TO_C(otyp)	(char) ((otyp >= DEAD_ACID_BLOB)\
    690 		     ?  'a' + (otyp - DEAD_ACID_BLOB)\
    691 		     :	'@' + (otyp - DEAD_HUMAN))
    692 int
    693 revive(obj)
    694 	struct obj     *obj;
    695 {
    696 	struct monst   *mtmp = NULL;
    697 
    698 	if (obj->olet == FOOD_SYM && obj->otyp > CORPSE) {
    699 		/* do not (yet) revive shopkeepers */
    700 		/*
    701 		 * Note: this might conceivably produce two monsters at the
    702 		 * same position - strange, but harmless
    703 		 */
    704 		mtmp = mkmon_at(CORPSE_I_TO_C(obj->otyp), obj->ox, obj->oy);
    705 		delobj(obj);
    706 	}
    707 	return (!!mtmp);	/* TRUE if some monster created */
    708 }
    709 
    710 void
    711 rloco(obj)
    712 	struct obj     *obj;
    713 {
    714 	int tx, ty, otx, oty;
    715 
    716 	otx = obj->ox;
    717 	oty = obj->oy;
    718 	do {
    719 		tx = rn1(COLNO - 3, 2);
    720 		ty = rn2(ROWNO);
    721 	} while (!goodpos(tx, ty));
    722 	obj->ox = tx;
    723 	obj->oy = ty;
    724 	if (cansee(otx, oty))
    725 		newsym(otx, oty);
    726 }
    727 
    728 void
    729 fracture_rock(obj)		/* fractured by pick-axe or wand of striking */
    730 	struct obj     *obj;	/* no texts here! */
    731 {
    732 	/* unpobj(obj); */
    733 	obj->otyp = ROCK;
    734 	obj->quan = 7 + rn2(60);
    735 	obj->owt = weight(obj);
    736 	obj->olet = WEAPON_SYM;
    737 	if (cansee(obj->ox, obj->oy))
    738 		prl(obj->ox, obj->oy);
    739 }
    740 
    741 void
    742 burn_scrolls()
    743 {
    744 	struct obj     *obj, *obj2;
    745 	int             cnt = 0;
    746 
    747 	for (obj = invent; obj; obj = obj2) {
    748 		obj2 = obj->nobj;
    749 		if (obj->olet == SCROLL_SYM) {
    750 			cnt++;
    751 			useup(obj);
    752 		}
    753 	}
    754 	if (cnt > 1) {
    755 		pline("Your scrolls catch fire!");
    756 		losehp(cnt, "burning scrolls");
    757 	} else if (cnt) {
    758 		pline("Your scroll catches fire!");
    759 		losehp(1, "burning scroll");
    760 	}
    761 }
    762