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