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