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