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