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