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