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