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