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