xref: /netbsd/games/hack/hack.c (revision bf9ec67e)
1 /*	$NetBSD: hack.c,v 1.5 2001/03/25 20:43:59 jsm 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.5 2001/03/25 20:43:59 jsm 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(int 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 	const 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