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 $ */
7 static void movobj(struct obj *, int, int);
9 static bool rroom(int, int);
11 static int inv_cnt(void);
13 /* called on movement:
14 * 1. when throwing ball+chain far away
16 * 3. when walking out of a lit room
29 for (x = u.ux - 1; x < u.ux + 2; x++)
30 for (y = u.uy - 1; y < u.uy + 2; y++) {
34 if (!lev->lit && lev->scrsym == '.') {
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
50 * 1 to redo @, 0 to leave them *//* 1 means
51 * misc movement, 0 means blindness
59 if (u.udispl && mode) {
61 levl[u.udisx][u.udisy].scrsym = news0(u.udisx, u.udisy);
69 for (x = u.ux - 1; x < u.ux + 2; x++)
70 for (y = u.uy - 1; y < u.uy + 2; y++) {
74 if (!lev->lit && lev->scrsym == '.')
84 struct monst *mtmp = NULL;
85 struct rm *tmpr, *ust;
86 struct trap *trap = NULL;
91 if (inv_weight() > 0) {
92 pline("You collapse under your load.");
104 } while (!isok(u.ux + u.dx, u.uy + u.dy) ||
105 IS_ROCK(levl[u.ux + u.dx][u.uy + u.dy].typ));
107 if (!isok(u.ux + u.dx, u.uy + u.dy)) {
113 ust = &levl[u.ux][u.uy];
117 (trap = t_at(u.ux + u.dx, u.uy + u.dy)) && trap->tseen)
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 ... ) */
126 pline("You cannot escape from it!");
128 pline("You cannot escape from %s!",
134 if (u.uswallow || (mtmp = m_at(u.ux + u.dx, u.uy + u.dy))) {
139 if (multi < 0) /* we just fainted */
142 /* try to attack; note that it might evade */
143 if (attack(u.uswallow ? u.ustuck : mtmp))
146 /* not attacking an animal, so we try to move */
148 if (u.utraptype == TT_PIT) {
149 pline("You are still in a pit.");
152 pline("You are caught in a beartrap.");
153 if ((u.dx && u.dy) || !rn2(5))
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))) {
165 while ((otmp = sobj_at(ENORMOUS_ROCK, u.ux + u.dx, u.uy + u.dy)) != NULL) {
167 xchar rx = u.ux + 2 * u.dx, ry = u.uy + 2 * u.dy;
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)) {
173 pline("You hear a monster behind the rock.");
174 pline("Perhaps that's why you cannot move it.");
177 if ((ttmp = t_at(rx, ry)) != NULL)
178 switch (ttmp->ttyp) {
180 pline("You push the rock into a pit!");
183 pline("It completely fills the pit!");
186 pline("You push the rock and suddenly it disappears!");
190 if (levl[rx][ry].typ == POOL) {
191 levl[rx][ry].typ = ROOM;
194 pline("You push the rock into the water.");
195 pline("Now you can cross the water!");
202 atl(rx, ry, otmp->olet);
204 newsym(u.ux + u.dx, u.uy + u.dy);
207 static long lastmovetime;
208 /* note: this var contains garbage initially and
210 if (moves > lastmovetime + 2 || moves < lastmovetime)
211 pline("With great effort you move the enormous rock.");
212 lastmovetime = moves;
215 pline("You try to move the enormous rock, but in vain.");
217 if ((!invent || inv_weight() + 90 <= 0) &&
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.");
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.");
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);
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);
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 " : "");
254 movobj(uball, uchain->ox, uchain->oy);
255 unpobj(uball); /* BAH %% */
265 if (tmpr->typ == DOOR ||
266 (xupstair == u.ux && yupstair == u.uy) ||
267 (xdnstair == u.ux && ydnstair == u.uy))
271 if (tmpr->typ == POOL && !Levitation)
272 drown(); /* not necessarily fatal */
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);
286 prl1(u.ux + u.dx, u.uy + u.dy);
292 prl1(u.ux + u.dx, u.uy + u.dy);
293 if (tmpr->typ == DOOR) {
303 nose1(oldx - u.dx, oldy - u.dy);
311 dotrap(trap); /* fall into pit, arrow trap, etc. */
314 read_engr_at(u.ux, u.uy);
318 movobj(struct obj *obj, int ox, int oy)
320 /* Some dirty programming to get display right */
332 if (!g_at(u.ux, u.uy) && !o_at(u.ux, u.uy)) {
333 pline("There is nothing here to pick up.");
337 pline("You cannot reach the floor.");
348 struct obj *obj, *obj2;
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;
364 /* check for more than one object */
368 for (obj = fobj; obj; obj = obj->nobj)
369 if (obj->ox == u.ux && obj->oy == u.uy)
370 if (!Punished || obj != uchain)
375 pline("There are several objects here.");
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) {
384 /* do not pick up uchain */
385 if (Punished && obj == uchain)
391 pline("Pick up %s ? [ynaq]", doname(obj));
392 while (!strchr("ynaq ", (c = readchar())))
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";
409 if (obj->otyp == SCR_SCARE_MONSTER) {
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.");
423 wt = inv_weight() + obj->owt;
426 /* see how many we can lift */
427 int savequan = obj->quan;
428 int iw = inv_weight();
430 for (qq = 1; qq < savequan; qq++) {
432 if (iw + weight(obj) > 0)
435 obj->quan = savequan;
437 /* we can carry qq of them */
440 pline("You can only carry %s of the %s lying here.",
441 (qq == 1) ? "one" : "some",
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);
452 pline("There %s %s here, but %s.",
453 (obj->quan == 1) ? "is" : "are",
455 !invent ? "it is too heavy for you to lift"
456 : "you cannot carry anymore");
460 if (inv_cnt() >= 52) {
461 pline("Your knapsack cannot accommodate anymore items.");
465 pline("You have a little trouble lifting");
469 addtobill(obj); /* sets obj->unpaid if necessary */
471 int pickquan = obj->quan;
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() */
480 obj->quan = mergquan;
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 */
492 int x, y, i, x0, y0, m0, i0 = 9;
493 int corrct = 0, noturn = 0;
496 /* suppress "used before set" message */
498 if (Blind || flags.run == 0)
500 if (flags.run == 1 && levl[u.ux][u.uy].typ == ROOM)
503 if (u.ux0 == u.ux + u.dx && u.uy0 == u.uy + u.dy)
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)
512 if ((mtmp = m_at(x, y)) && !mtmp->mimic &&
513 (!mtmp->minvis || See_invisible)) {
515 (x == u.ux + u.dx && y == u.uy + u.dy))
517 } else /* invisible M cannot influence us */
519 if (x == u.ux - u.dx && y == u.uy - u.dy)
521 switch (levl[x][y].scrsym) {
528 if (x != u.ux && y != u.uy)
532 /* fall into next case */
535 if (flags.run == 1 || flags.run == 3) {
536 i = DIST(x, y, u.ux + u.dx, u.uy + u.dy);
540 DIST(x, y, x0, y0) != 1)
552 if (flags.run == 1) /* if you must */
554 if (x == u.ux + u.dx && y == u.uy + u.dy)
557 default: /* e.g. objects or trap or stairs */
568 if (corrct > 0 && (flags.run == 4 || flags.run == 5))
571 if (corrct > 1 && flags.run == 2)
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 */
577 if (u.dx == y0 - u.uy && u.dy == u.ux - x0)
578 i = 2; /* straight turn right */
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 */
586 i = 1; /* half turn right */
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 */
592 i = -1; /* half turn left */
594 i += u.last_str_turn;
595 if (i <= 2 && i >= -2) {
597 u.dx = x0 - u.ux, u.dy = y0 - u.uy;
602 /* something like lookaround, but we are not running */
603 /* react only to monsters that might hit us */
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)
615 if ((mtmp = m_at(x, y)) && !mtmp->mimic &&
618 !strchr("Ea", mtmp->data->mlet) &&
619 !mtmp->mfroz && !mtmp->msleep && /* aplvax!jcn */
620 (!mtmp->minvis || See_invisible))
628 cansee(xchar x, xchar y)
630 int dx, dy, adx, ady, sdx, sdy, dmax, d;
639 if (d > u.uhorizon * u.uhorizon)
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))
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))
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)))
675 return (IS_ROOM(levl[u.ux + x][u.uy + y].typ));
681 cansee(xchar x, xchar y)
683 if (Blind || u.uswallow)
687 if (levl[x][y].lit && seelx <= x && x <= seehx && seely <= y &&
697 return ((a > 0) ? 1 : (a == 0) ? 0 : -1);
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++) {
728 if (!levl[u.ux][u.uy].lit) {
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++) ;
739 for (y = seely; y <= seehy; y++)
740 for (x = seelx; x <= seehx; x++)
743 if (!levl[u.ux][u.uy].lit) /* seems necessary elsewhere */
747 for (x = u.ux - 1; x <= u.ux + 1; x++)
750 for (x = u.ux - 1; x <= u.ux + 1; x++)
753 for (y = u.uy - 1; y <= u.uy + 1; y++)
756 for (y = u.uy - 1; y <= u.uy + 1; y++)
768 flags.mv = flags.run = 0;
780 else if (u.ustr < 17)
782 else if (u.ustr < 69) /* up to 18/50 */
784 else if (u.ustr < 118)
795 else if (u.ustr < 16)
797 else if (u.ustr < 18)
799 else if (u.ustr == 18) /* up to 18 */
801 else if (u.ustr < 94) /* up to 18/75 */
803 else if (u.ustr < 109) /* up to 18/90 */
805 else if (u.ustr < 118) /* up to 18/99 */
811 /* may kill you; cause may be poison or monster like 'A' */
825 losehp(int n, const char *knam)
828 if (u.uhp > u.uhpmax)
829 u.uhpmax = u.uhp; /* perhaps n was negative */
832 killer = knam; /* the thing that killed you */
838 losehp_m(int n, struct monst *mtmp)
847 losexp(void) /* hit by V or W */
852 pline("Goodbye level %u.", u.ulevel--);
865 struct obj *otmp = invent;
866 int wt = (u.ugold + 500) / 1000;
869 if (Levitation) /* pugh@cornell */
870 carrcap = MAX_CARR_CAP;
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)
877 if (Wounded_legs & RIGHT_SIDE)
884 return (wt - carrcap);
890 struct obj *otmp = invent;
903 return (10 * (1L << (u.ulevel - 1)));