]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.c
mention hex numbers
[bsdgames-darwin.git] / hack / hack.c
1 /* $NetBSD: hack.c,v 1.11 2011/08/07 06:03:45 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.11 2011/08/07 06:03:45 dholland 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
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
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
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
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
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
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
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
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
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
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
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
761 sgn(int a)
762 {
763 return ((a > 0) ? 1 : (a == 0) ? 0 : -1);
764 }
765
766 #ifdef QUEST
767 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
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
829 nomul(int nval)
830 {
831 if (multi < 0)
832 return;
833 multi = nval;
834 flags.mv = flags.run = 0;
835 }
836
837 int
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
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
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
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
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
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
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
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
966 newuexp(void)
967 {
968 return (10 * (1L << (u.ulevel - 1)));
969 }