Home | History | Annotate | Line # | Download | only in hack
hack.c revision 1.6
      1 /*	$NetBSD: hack.c,v 1.6 2003/04/02 18:36:35 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.c,v 1.6 2003/04/02 18:36:35 jsm Exp $");
     67 #endif				/* not lint */
     68 
     69 #include "hack.h"
     70 #include "extern.h"
     71 
     72 /*
     73  * called on movement: 1. when throwing ball+chain far away 2. when
     74  * teleporting 3. when walking out of a lit room
     75  */
     76 void
     77 unsee()
     78 {
     79 	int x, y;
     80 	struct rm *lev;
     81 
     82 	/*
     83 		if(u.udispl){
     84 			u.udispl = 0;
     85 			newsym(u.udisx, u.udisy);
     86 		}
     87 	*/
     88 #ifndef QUEST
     89 	if (seehx) {
     90 		seehx = 0;
     91 	} else
     92 #endif	/* QUEST */
     93 		for (x = u.ux - 1; x < u.ux + 2; x++)
     94 			for (y = u.uy - 1; y < u.uy + 2; y++) {
     95 				if (!isok(x, y))
     96 					continue;
     97 				lev = &levl[x][y];
     98 				if (!lev->lit && lev->scrsym == '.') {
     99 					lev->scrsym = ' ';
    100 					lev->new = 1;
    101 					on_scr(x, y);
    102 				}
    103 			}
    104 }
    105 
    106 /*
    107  * called: in hack.eat.c: seeoff(0) - blind after eating rotten food in
    108  * hack.mon.c: seeoff(0) - blinded by a yellow light in hack.mon.c: seeoff(1)
    109  * - swallowed in hack.do.c:  seeoff(0) - blind after drinking potion in
    110  * hack.do.c:  seeoff(1) - go up or down the stairs in hack.trap.c:seeoff(1)
    111  * - fall through trapdoor
    112  */
    113 void
    114 seeoff(mode)
    115 	int mode;		/* 1 to redo @, 0 to leave them *//* 1 means
    116 				 * misc movement, 0 means blindness */
    117 {
    118 	int x, y;
    119 	struct rm *lev;
    120 
    121 	if (u.udispl && mode) {
    122 		u.udispl = 0;
    123 		levl[u.udisx][u.udisy].scrsym = news0(u.udisx, u.udisy);
    124 	}
    125 #ifndef QUEST
    126 	if (seehx) {
    127 		seehx = 0;
    128 	} else
    129 #endif	/* QUEST */
    130 	if (!mode) {
    131 		for (x = u.ux - 1; x < u.ux + 2; x++)
    132 			for (y = u.uy - 1; y < u.uy + 2; y++) {
    133 				if (!isok(x, y))
    134 					continue;
    135 				lev = &levl[x][y];
    136 				if (!lev->lit && lev->scrsym == '.')
    137 					lev->seen = 0;
    138 			}
    139 	}
    140 }
    141 
    142 void
    143 domove()
    144 {
    145 	xchar           oldx, oldy;
    146 	struct monst *mtmp = NULL;
    147 	struct rm *tmpr, *ust;
    148 	struct trap    *trap = NULL;
    149 	struct obj *otmp = NULL;
    150 
    151 	u_wipe_engr(rnd(5));
    152 
    153 	if (inv_weight() > 0) {
    154 		pline("You collapse under your load.");
    155 		nomul(0);
    156 		return;
    157 	}
    158 	if (u.uswallow) {
    159 		u.dx = u.dy = 0;
    160 		u.ux = u.ustuck->mx;
    161 		u.uy = u.ustuck->my;
    162 	} else {
    163 		if (Confusion) {
    164 			do {
    165 				confdir();
    166 			} while (!isok(u.ux + u.dx, u.uy + u.dy) ||
    167 			       IS_ROCK(levl[u.ux + u.dx][u.uy + u.dy].typ));
    168 		}
    169 		if (!isok(u.ux + u.dx, u.uy + u.dy)) {
    170 			nomul(0);
    171 			return;
    172 		}
    173 	}
    174 
    175 	ust = &levl[u.ux][u.uy];
    176 	oldx = u.ux;
    177 	oldy = u.uy;
    178 	if (!u.uswallow && (trap = t_at(u.ux + u.dx, u.uy + u.dy)) && trap->tseen)
    179 		nomul(0);
    180 	if (u.ustuck && !u.uswallow && (u.ux + u.dx != u.ustuck->mx ||
    181 					u.uy + u.dy != u.ustuck->my)) {
    182 		if (dist(u.ustuck->mx, u.ustuck->my) > 2) {
    183 			/* perhaps it fled (or was teleported or ... ) */
    184 			u.ustuck = 0;
    185 		} else {
    186 			if (Blind)
    187 				pline("You cannot escape from it!");
    188 			else
    189 				pline("You cannot escape from %s!",
    190 				      monnam(u.ustuck));
    191 			nomul(0);
    192 			return;
    193 		}
    194 	}
    195 	if (u.uswallow || (mtmp = m_at(u.ux + u.dx, u.uy + u.dy))) {
    196 		/* attack monster */
    197 
    198 		nomul(0);
    199 		gethungry();
    200 		if (multi < 0)
    201 			return;	/* we just fainted */
    202 
    203 		/* try to attack; note that it might evade */
    204 		if (attack(u.uswallow ? u.ustuck : mtmp))
    205 			return;
    206 	}
    207 	/* not attacking an animal, so we try to move */
    208 	if (u.utrap) {
    209 		if (u.utraptype == TT_PIT) {
    210 			pline("You are still in a pit.");
    211 			u.utrap--;
    212 		} else {
    213 			pline("You are caught in a beartrap.");
    214 			if ((u.dx && u.dy) || !rn2(5))
    215 				u.utrap--;
    216 		}
    217 		return;
    218 	}
    219 	tmpr = &levl[u.ux + u.dx][u.uy + u.dy];
    220 	if (IS_ROCK(tmpr->typ) ||
    221 	    (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))) {
    222 		flags.move = 0;
    223 		nomul(0);
    224 		return;
    225 	}
    226 	while ((otmp = sobj_at(ENORMOUS_ROCK, u.ux + u.dx, u.uy + u.dy)) != NULL){
    227 		xchar  rx = u.ux + 2 * u.dx, ry = u.uy + 2 * u.dy;
    228 		struct trap *ttmp;
    229 		nomul(0);
    230 		if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ) &&
    231 		    (levl[rx][ry].typ != DOOR || !(u.dx && u.dy)) &&
    232 		    !sobj_at(ENORMOUS_ROCK, rx, ry)) {
    233 			if (m_at(rx, ry)) {
    234 				pline("You hear a monster behind the rock.");
    235 				pline("Perhaps that's why you cannot move it.");
    236 				goto cannot_push;
    237 			}
    238 			if ((ttmp = t_at(rx, ry)) != NULL)
    239 				switch (ttmp->ttyp) {
    240 				case PIT:
    241 					pline("You push the rock into a pit!");
    242 					deltrap(ttmp);
    243 					delobj(otmp);
    244 					pline("It completely fills the pit!");
    245 					continue;
    246 				case TELEP_TRAP:
    247 					pline("You push the rock and suddenly it disappears!");
    248 					delobj(otmp);
    249 					continue;
    250 				}
    251 			if (levl[rx][ry].typ == POOL) {
    252 				levl[rx][ry].typ = ROOM;
    253 				mnewsym(rx, ry);
    254 				prl(rx, ry);
    255 				pline("You push the rock into the water.");
    256 				pline("Now you can cross the water!");
    257 				delobj(otmp);
    258 				continue;
    259 			}
    260 			otmp->ox = rx;
    261 			otmp->oy = ry;
    262 			/* pobj(otmp); */
    263 			if (cansee(rx, ry))
    264 				atl(rx, ry, otmp->olet);
    265 			if (Invisible)
    266 				newsym(u.ux + u.dx, u.uy + u.dy);
    267 
    268 			{
    269 				static long     lastmovetime;
    270 				/*
    271 				 * note: this var contains garbage initially
    272 				 * and after a restore
    273 				 */
    274 				if (moves > lastmovetime + 2 || moves < lastmovetime)
    275 					pline("With great effort you move the enormous rock.");
    276 				lastmovetime = moves;
    277 			}
    278 		} else {
    279 			pline("You try to move the enormous rock, but in vain.");
    280 	cannot_push:
    281 			if ((!invent || inv_weight() + 90 <= 0) &&
    282 			    (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][u.uy + u.dy].typ)
    283 				&& IS_ROCK(levl[u.ux + u.dx][u.uy].typ)))) {
    284 				pline("However, you can squeeze yourself into a small opening.");
    285 				break;
    286 			} else
    287 				return;
    288 		}
    289 	}
    290 	if (u.dx && u.dy && IS_ROCK(levl[u.ux][u.uy + u.dy].typ) &&
    291 	    IS_ROCK(levl[u.ux + u.dx][u.uy].typ) &&
    292 	    invent && inv_weight() + 40 > 0) {
    293 		pline("You are carrying too much to get through.");
    294 		nomul(0);
    295 		return;
    296 	}
    297 	if (Punished &&
    298 	    DIST(u.ux + u.dx, u.uy + u.dy, uchain->ox, uchain->oy) > 2) {
    299 		if (carried(uball)) {
    300 			movobj(uchain, u.ux, u.uy);
    301 			goto nodrag;
    302 		}
    303 		if (DIST(u.ux + u.dx, u.uy + u.dy, uball->ox, uball->oy) < 3) {
    304 			/* leave ball, move chain under/over ball */
    305 			movobj(uchain, uball->ox, uball->oy);
    306 			goto nodrag;
    307 		}
    308 		if (inv_weight() + (int) uball->owt / 2 > 0) {
    309 			pline("You cannot %sdrag the heavy iron ball.",
    310 			      invent ? "carry all that and also " : "");
    311 			nomul(0);
    312 			return;
    313 		}
    314 		movobj(uball, uchain->ox, uchain->oy);
    315 		unpobj(uball);	/* BAH %% */
    316 		uchain->ox = u.ux;
    317 		uchain->oy = u.uy;
    318 		nomul(-2);
    319 		nomovemsg = "";
    320 nodrag:	;
    321 	}
    322 	u.ux += u.dx;
    323 	u.uy += u.dy;
    324 	if (flags.run) {
    325 		if (tmpr->typ == DOOR ||
    326 		    (xupstair == u.ux && yupstair == u.uy) ||
    327 		    (xdnstair == u.ux && ydnstair == u.uy))
    328 			nomul(0);
    329 	}
    330 	if (tmpr->typ == POOL && !Levitation)
    331 		drown();	/* not necessarily fatal */
    332 
    333 	/*
    334 		if(u.udispl) {
    335 			u.udispl = 0;
    336 			newsym(oldx,oldy);
    337 		}
    338 	*/
    339 	if (!Blind) {
    340 #ifdef QUEST
    341 		setsee();
    342 #else
    343 		if (ust->lit) {
    344 			if (tmpr->lit) {
    345 				if (tmpr->typ == DOOR)
    346 					prl1(u.ux + u.dx, u.uy + u.dy);
    347 				else if (ust->typ == DOOR)
    348 					nose1(oldx - u.dx, oldy - u.dy);
    349 			} else {
    350 				unsee();
    351 				prl1(u.ux + u.dx, u.uy + u.dy);
    352 			}
    353 		} else {
    354 			if (tmpr->lit)
    355 				setsee();
    356 			else {
    357 				prl1(u.ux + u.dx, u.uy + u.dy);
    358 				if (tmpr->typ == DOOR) {
    359 					if (u.dy) {
    360 						prl(u.ux - 1, u.uy);
    361 						prl(u.ux + 1, u.uy);
    362 					} else {
    363 						prl(u.ux, u.uy - 1);
    364 						prl(u.ux, u.uy + 1);
    365 					}
    366 				}
    367 			}
    368 			nose1(oldx - u.dx, oldy - u.dy);
    369 		}
    370 #endif	/* QUEST */
    371 	} else {
    372 		pru();
    373 	}
    374 	if (!flags.nopick)
    375 		pickup(1);
    376 	if (trap)
    377 		dotrap(trap);	/* fall into pit, arrow trap, etc. */
    378 	(void) inshop();
    379 	if (!Blind)
    380 		read_engr_at(u.ux, u.uy);
    381 }
    382 
    383 void
    384 movobj(obj, ox, oy)
    385 	struct obj *obj;
    386 	int    ox, oy;
    387 {
    388 	/* Some dirty programming to get display right */
    389 	freeobj(obj);
    390 	unpobj(obj);
    391 	obj->nobj = fobj;
    392 	fobj = obj;
    393 	obj->ox = ox;
    394 	obj->oy = oy;
    395 }
    396 
    397 int
    398 dopickup()
    399 {
    400 	if (!g_at(u.ux, u.uy) && !o_at(u.ux, u.uy)) {
    401 		pline("There is nothing here to pick up.");
    402 		return (0);
    403 	}
    404 	if (Levitation) {
    405 		pline("You cannot reach the floor.");
    406 		return (1);
    407 	}
    408 	pickup(0);
    409 	return (1);
    410 }
    411 
    412 void
    413 pickup(int all)
    414 {
    415 	struct gold *gold;
    416 	struct obj *obj, *obj2;
    417 	int    wt;
    418 
    419 	if (Levitation)
    420 		return;
    421 	while ((gold = g_at(u.ux, u.uy)) != NULL) {
    422 		pline("%ld gold piece%s.", gold->amount, plur(gold->amount));
    423 		u.ugold += gold->amount;
    424 		flags.botl = 1;
    425 		freegold(gold);
    426 		if (flags.run)
    427 			nomul(0);
    428 		if (Invisible)
    429 			newsym(u.ux, u.uy);
    430 	}
    431 
    432 	/* check for more than one object */
    433 	if (!all) {
    434 		int    ct = 0;
    435 
    436 		for (obj = fobj; obj; obj = obj->nobj)
    437 			if (obj->ox == u.ux && obj->oy == u.uy)
    438 				if (!Punished || obj != uchain)
    439 					ct++;
    440 		if (ct < 2)
    441 			all++;
    442 		else
    443 			pline("There are several objects here.");
    444 	}
    445 	for (obj = fobj; obj; obj = obj2) {
    446 		obj2 = obj->nobj;	/* perhaps obj will be picked up */
    447 		if (obj->ox == u.ux && obj->oy == u.uy) {
    448 			if (flags.run)
    449 				nomul(0);
    450 
    451 			/* do not pick up uchain */
    452 			if (Punished && obj == uchain)
    453 				continue;
    454 
    455 			if (!all) {
    456 				char            c;
    457 
    458 				pline("Pick up %s ? [ynaq]", doname(obj));
    459 				while (!strchr("ynaq ", (c = readchar())))
    460 					bell();
    461 				if (c == 'q')
    462 					return;
    463 				if (c == 'n')
    464 					continue;
    465 				if (c == 'a')
    466 					all = 1;
    467 			}
    468 			if (obj->otyp == DEAD_COCKATRICE && !uarmg) {
    469 				pline("Touching the dead cockatrice is a fatal mistake.");
    470 				pline("You turn to stone.");
    471 				killer = "cockatrice cadaver";
    472 				done("died");
    473 			}
    474 			if (obj->otyp == SCR_SCARE_MONSTER) {
    475 				if (!obj->spe)
    476 					obj->spe = 1;
    477 				else {
    478 					/*
    479 					 * Note: perhaps the 1st pickup
    480 					 * failed: you cannot carry anymore,
    481 					 * and so we never dropped it - let's
    482 					 * assume that treading on it twice
    483 					 * also destroys the scroll
    484 					 */
    485 					pline("The scroll turns to dust as you pick it up.");
    486 					delobj(obj);
    487 					continue;
    488 				}
    489 			}
    490 			wt = inv_weight() + obj->owt;
    491 			if (wt > 0) {
    492 				if (obj->quan > 1) {
    493 					/* see how many we can lift */
    494 					int             savequan = obj->quan;
    495 					int             iw = inv_weight();
    496 					int             qq;
    497 					for (qq = 1; qq < savequan; qq++) {
    498 						obj->quan = qq;
    499 						if (iw + weight(obj) > 0)
    500 							break;
    501 					}
    502 					obj->quan = savequan;
    503 					qq--;
    504 					/* we can carry qq of them */
    505 					if (!qq)
    506 						goto too_heavy;
    507 					pline("You can only carry %s of the %s lying here.",
    508 					      (qq == 1) ? "one" : "some",
    509 					      doname(obj));
    510 					(void) splitobj(obj, qq);
    511 					/*
    512 					 * note: obj2 is set already, so
    513 					 * we'll never encounter the other
    514 					 * half; if it should be otherwise
    515 					 * then write obj2 =
    516 					 * splitobj(obj,qq);
    517 					 */
    518 					goto lift_some;
    519 				}
    520 		too_heavy:
    521 				pline("There %s %s here, but %s.",
    522 				      (obj->quan == 1) ? "is" : "are",
    523 				      doname(obj),
    524 				 !invent ? "it is too heavy for you to lift"
    525 				      : "you cannot carry anymore");
    526 				break;
    527 			}
    528 	lift_some:
    529 			if (inv_cnt() >= 52) {
    530 				pline("Your knapsack cannot accomodate anymore items.");
    531 				break;
    532 			}
    533 			if (wt > -5)
    534 				pline("You have a little trouble lifting");
    535 			freeobj(obj);
    536 			if (Invisible)
    537 				newsym(u.ux, u.uy);
    538 			addtobill(obj);	/* sets obj->unpaid if necessary */
    539 			{
    540 				int             pickquan = obj->quan;
    541 				int             mergquan;
    542 				if (!Blind)
    543 					obj->dknown = 1;	/* this is done by
    544 								 * prinv(), but addinv()
    545 								 * needs it already for
    546 								 * merging */
    547 				obj = addinv(obj);	/* might merge it with
    548 							 * other objects */
    549 				mergquan = obj->quan;
    550 				obj->quan = pickquan;	/* to fool prinv() */
    551 				prinv(obj);
    552 				obj->quan = mergquan;
    553 			}
    554 		}
    555 	}
    556 }
    557 
    558 /* stop running if we see something interesting */
    559 /* turn around a corner if that is the only way we can proceed */
    560 /* do not turn left or right twice */
    561 void
    562 lookaround()
    563 {
    564 	int    x, y, i, x0 = 0, y0 = 0, m0 = 0, i0 = 9;
    565 	int    corrct = 0, noturn = 0;
    566 	struct monst *mtmp;
    567 	if (Blind || flags.run == 0)
    568 		return;
    569 	if (flags.run == 1 && levl[u.ux][u.uy].typ == ROOM)
    570 		return;
    571 #ifdef QUEST
    572 	if (u.ux0 == u.ux + u.dx && u.uy0 == u.uy + u.dy)
    573 		goto stop;
    574 #endif	/* QUEST */
    575 	for (x = u.ux - 1; x <= u.ux + 1; x++)
    576 		for (y = u.uy - 1; y <= u.uy + 1; y++) {
    577 			if (x == u.ux && y == u.uy)
    578 				continue;
    579 			if (!levl[x][y].typ)
    580 				continue;
    581 			if ((mtmp = m_at(x, y)) && !mtmp->mimic &&
    582 			    (!mtmp->minvis || See_invisible)) {
    583 				if (!mtmp->mtame || (x == u.ux + u.dx && y == u.uy + u.dy))
    584 					goto stop;
    585 			} else
    586 				mtmp = 0;	/* invisible M cannot
    587 						 * influence us */
    588 			if (x == u.ux - u.dx && y == u.uy - u.dy)
    589 				continue;
    590 			switch (levl[x][y].scrsym) {
    591 			case '|':
    592 			case '-':
    593 			case '.':
    594 			case ' ':
    595 				break;
    596 			case '+':
    597 				if (x != u.ux && y != u.uy)
    598 					break;
    599 				if (flags.run != 1)
    600 					goto stop;
    601 				/* fall into next case */
    602 			case CORR_SYM:
    603 		corr:
    604 				if (flags.run == 1 || flags.run == 3) {
    605 					i = DIST(x, y, u.ux + u.dx, u.uy + u.dy);
    606 					if (i > 2)
    607 						break;
    608 					if (corrct == 1 && DIST(x, y, x0, y0) != 1)
    609 						noturn = 1;
    610 					if (i < i0) {
    611 						i0 = i;
    612 						x0 = x;
    613 						y0 = y;
    614 						m0 = mtmp ? 1 : 0;
    615 					}
    616 				}
    617 				corrct++;
    618 				break;
    619 			case '^':
    620 				if (flags.run == 1)
    621 					goto corr;	/* if you must */
    622 				if (x == u.ux + u.dx && y == u.uy + u.dy)
    623 					goto stop;
    624 				break;
    625 			default:	/* e.g. objects or trap or stairs */
    626 				if (flags.run == 1)
    627 					goto corr;
    628 				if (mtmp)
    629 					break;	/* d */
    630 		stop:
    631 				nomul(0);
    632 				return;
    633 			}
    634 		}
    635 #ifdef QUEST
    636 	if (corrct > 0 && (flags.run == 4 || flags.run == 5))
    637 		goto stop;
    638 #endif	/* QUEST */
    639 	if (corrct > 1 && flags.run == 2)
    640 		goto stop;
    641 	if ((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
    642 	    (corrct == 1 || (corrct == 2 && i0 == 1))) {
    643 		/* make sure that we do not turn too far */
    644 		if (i0 == 2) {
    645 			if (u.dx == y0 - u.uy && u.dy == u.ux - x0)
    646 				i = 2;	/* straight turn right */
    647 			else
    648 				i = -2;	/* straight turn left */
    649 		} else if (u.dx && u.dy) {
    650 			if ((u.dx == u.dy && y0 == u.uy) ||
    651 			    (u.dx != u.dy && y0 != u.uy))
    652 				i = -1;	/* half turn left */
    653 			else
    654 				i = 1;	/* half turn right */
    655 		} else {
    656 			if ((x0 - u.ux == y0 - u.uy && !u.dy) ||
    657 			    (x0 - u.ux != y0 - u.uy && u.dy))
    658 				i = 1;	/* half turn right */
    659 			else
    660 				i = -1;	/* half turn left */
    661 		}
    662 		i += u.last_str_turn;
    663 		if (i <= 2 && i >= -2) {
    664 			u.last_str_turn = i;
    665 			u.dx = x0 - u.ux, u.dy = y0 - u.uy;
    666 		}
    667 	}
    668 }
    669 
    670 /* something like lookaround, but we are not running */
    671 /* react only to monsters that might hit us */
    672 int
    673 monster_nearby()
    674 {
    675 	int    x, y;
    676 	struct monst *mtmp;
    677 	if (!Blind)
    678 		for (x = u.ux - 1; x <= u.ux + 1; x++)
    679 			for (y = u.uy - 1; y <= u.uy + 1; y++) {
    680 				if (x == u.ux && y == u.uy)
    681 					continue;
    682 				if ((mtmp = m_at(x, y)) && !mtmp->mimic && !mtmp->mtame &&
    683 				    !mtmp->mpeaceful && !strchr("Ea", mtmp->data->mlet) &&
    684 				    !mtmp->mfroz && !mtmp->msleep &&	/* aplvax!jcn */
    685 				    (!mtmp->minvis || See_invisible))
    686 					return (1);
    687 			}
    688 	return (0);
    689 }
    690 
    691 #ifdef QUEST
    692 int
    693 cansee(x, y)
    694 	xchar           x, y;
    695 {
    696 	int    dx, dy, adx, ady, sdx, sdy, dmax, d;
    697 	if (Blind)
    698 		return (0);
    699 	if (!isok(x, y))
    700 		return (0);
    701 	d = dist(x, y);
    702 	if (d < 3)
    703 		return (1);
    704 	if (d > u.uhorizon * u.uhorizon)
    705 		return (0);
    706 	if (!levl[x][y].lit)
    707 		return (0);
    708 	dx = x - u.ux;
    709 	adx = abs(dx);
    710 	sdx = sgn(dx);
    711 	dy = y - u.uy;
    712 	ady = abs(dy);
    713 	sdy = sgn(dy);
    714 	if (dx == 0 || dy == 0 || adx == ady) {
    715 		dmax = (dx == 0) ? ady : adx;
    716 		for (d = 1; d <= dmax; d++)
    717 			if (!rroom(sdx * d, sdy * d))
    718 				return (0);
    719 		return (1);
    720 	} else if (ady > adx) {
    721 		for (d = 1; d <= ady; d++) {
    722 			if (!rroom(sdx * ((d * adx) / ady), sdy * d) ||
    723 			    !rroom(sdx * ((d * adx - 1) / ady + 1), sdy * d))
    724 				return (0);
    725 		}
    726 		return (1);
    727 	} else {
    728 		for (d = 1; d <= adx; d++) {
    729 			if (!rroom(sdx * d, sdy * ((d * ady) / adx)) ||
    730 			    !rroom(sdx * d, sdy * ((d * ady - 1) / adx + 1)))
    731 				return (0);
    732 		}
    733 		return (1);
    734 	}
    735 }
    736 
    737 int
    738 rroom(x, y)
    739 	int    x, y;
    740 {
    741 	return (IS_ROOM(levl[u.ux + x][u.uy + y].typ));
    742 }
    743 
    744 #else
    745 
    746 int
    747 cansee(x, y)
    748 	xchar           x, y;
    749 {
    750 	if (Blind || u.uswallow)
    751 		return (0);
    752 	if (dist(x, y) < 3)
    753 		return (1);
    754 	if (levl[x][y].lit && seelx <= x && x <= seehx && seely <= y &&
    755 	    y <= seehy)
    756 		return (1);
    757 	return (0);
    758 }
    759 #endif	/* QUEST */
    760 
    761 int
    762 sgn(a)
    763 	int    a;
    764 {
    765 	return ((a > 0) ? 1 : (a == 0) ? 0 : -1);
    766 }
    767 
    768 #ifdef QUEST
    769 void
    770 setsee()
    771 {
    772 	int	x, y;
    773 
    774 	if (Blind) {
    775 		pru();
    776 		return;
    777 	}
    778 	for (y = u.uy - u.uhorizon; y <= u.uy + u.uhorizon; y++)
    779 		for (x = u.ux - u.uhorizon; x <= u.ux + u.uhorizon; x++) {
    780 			if (cansee(x, y))
    781 				prl(x, y);
    782 		}
    783 }
    784 
    785 #else
    786 
    787 void
    788 setsee()
    789 {
    790 	int x, y;
    791 
    792 	if (Blind) {
    793 		pru();
    794 		return;
    795 	}
    796 	if (!levl[u.ux][u.uy].lit) {
    797 		seelx = u.ux - 1;
    798 		seehx = u.ux + 1;
    799 		seely = u.uy - 1;
    800 		seehy = u.uy + 1;
    801 	} else {
    802 		for (seelx = u.ux; levl[seelx - 1][u.uy].lit; seelx--);
    803 		for (seehx = u.ux; levl[seehx + 1][u.uy].lit; seehx++);
    804 		for (seely = u.uy; levl[u.ux][seely - 1].lit; seely--);
    805 		for (seehy = u.uy; levl[u.ux][seehy + 1].lit; seehy++);
    806 	}
    807 	for (y = seely; y <= seehy; y++)
    808 		for (x = seelx; x <= seehx; x++) {
    809 			prl(x, y);
    810 		}
    811 	if (!levl[u.ux][u.uy].lit)
    812 		seehx = 0;	/* seems necessary elsewhere */
    813 	else {
    814 		if (seely == u.uy)
    815 			for (x = u.ux - 1; x <= u.ux + 1; x++)
    816 				prl(x, seely - 1);
    817 		if (seehy == u.uy)
    818 			for (x = u.ux - 1; x <= u.ux + 1; x++)
    819 				prl(x, seehy + 1);
    820 		if (seelx == u.ux)
    821 			for (y = u.uy - 1; y <= u.uy + 1; y++)
    822 				prl(seelx - 1, y);
    823 		if (seehx == u.ux)
    824 			for (y = u.uy - 1; y <= u.uy + 1; y++)
    825 				prl(seehx + 1, y);
    826 	}
    827 }
    828 #endif	/* QUEST */
    829 
    830 void
    831 nomul(nval)
    832 	int nval;
    833 {
    834 	if (multi < 0)
    835 		return;
    836 	multi = nval;
    837 	flags.mv = flags.run = 0;
    838 }
    839 
    840 int
    841 abon()
    842 {
    843 	if (u.ustr == 3)
    844 		return (-3);
    845 	else if (u.ustr < 6)
    846 		return (-2);
    847 	else if (u.ustr < 8)
    848 		return (-1);
    849 	else if (u.ustr < 17)
    850 		return (0);
    851 	else if (u.ustr < 69)
    852 		return (1);	/* up to 18/50 */
    853 	else if (u.ustr < 118)
    854 		return (2);
    855 	else
    856 		return (3);
    857 }
    858 
    859 int
    860 dbon()
    861 {
    862 	if (u.ustr < 6)
    863 		return (-1);
    864 	else if (u.ustr < 16)
    865 		return (0);
    866 	else if (u.ustr < 18)
    867 		return (1);
    868 	else if (u.ustr == 18)
    869 		return (2);	/* up to 18 */
    870 	else if (u.ustr < 94)
    871 		return (3);	/* up to 18/75 */
    872 	else if (u.ustr < 109)
    873 		return (4);	/* up to 18/90 */
    874 	else if (u.ustr < 118)
    875 		return (5);	/* up to 18/99 */
    876 	else
    877 		return (6);
    878 }
    879 
    880 void
    881 losestr(num)			/* may kill you; cause may be poison or */
    882 	int num;		/* monster like 'A' */
    883 {
    884 	u.ustr -= num;
    885 	while (u.ustr < 3) {
    886 		u.ustr++;
    887 		u.uhp -= 6;
    888 		u.uhpmax -= 6;
    889 	}
    890 	flags.botl = 1;
    891 }
    892 
    893 void
    894 losehp(n, knam)
    895 	int n;
    896 	const char  *knam;
    897 {
    898 	u.uhp -= n;
    899 	if (u.uhp > u.uhpmax)
    900 		u.uhpmax = u.uhp;	/* perhaps n was negative */
    901 	flags.botl = 1;
    902 	if (u.uhp < 1) {
    903 		killer = knam;	/* the thing that killed you */
    904 		done("died");
    905 	}
    906 }
    907 
    908 void
    909 losehp_m(n, mtmp)
    910 	int n;
    911 	struct monst *mtmp;
    912 {
    913 	u.uhp -= n;
    914 	flags.botl = 1;
    915 	if (u.uhp < 1)
    916 		done_in_by(mtmp);
    917 }
    918 
    919 void
    920 losexp()
    921 {				/* hit by V or W */
    922 	int num;
    923 
    924 	if (u.ulevel > 1)
    925 		pline("Goodbye level %u.", u.ulevel--);
    926 	else
    927 		u.uhp = -1;
    928 	num = rnd(10);
    929 	u.uhp -= num;
    930 	u.uhpmax -= num;
    931 	u.uexp = newuexp();
    932 	flags.botl = 1;
    933 }
    934 
    935 int
    936 inv_weight()
    937 {
    938 	struct obj *otmp = invent;
    939 	int    wt = (u.ugold + 500) / 1000;
    940 	int    carrcap;
    941 	if (Levitation)		/* pugh@cornell */
    942 		carrcap = MAX_CARR_CAP;
    943 	else {
    944 		carrcap = 5 * (((u.ustr > 18) ? 20 : u.ustr) + u.ulevel);
    945 		if (carrcap > MAX_CARR_CAP)
    946 			carrcap = MAX_CARR_CAP;
    947 		if (Wounded_legs & LEFT_SIDE)
    948 			carrcap -= 10;
    949 		if (Wounded_legs & RIGHT_SIDE)
    950 			carrcap -= 10;
    951 	}
    952 	while (otmp) {
    953 		wt += otmp->owt;
    954 		otmp = otmp->nobj;
    955 	}
    956 	return (wt - carrcap);
    957 }
    958 
    959 int
    960 inv_cnt()
    961 {
    962 	struct obj *otmp = invent;
    963 	int    ct = 0;
    964 	while (otmp) {
    965 		ct++;
    966 		otmp = otmp->nobj;
    967 	}
    968 	return (ct);
    969 }
    970 
    971 long
    972 newuexp()
    973 {
    974 	return (10 * (1L << (u.ulevel - 1)));
    975 }
    976