1 /* SCCS Id: @(#)hack.c 3.4 2003/04/30 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
8 STATIC_DCL void NDECL(maybe_wail);
10 STATIC_DCL int NDECL(moverock);
11 STATIC_DCL int FDECL(still_chewing,(XCHAR_P,XCHAR_P));
13 STATIC_DCL void NDECL(dosinkfall);
15 STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
16 STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
18 STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
20 #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
25 revive_nasty(x, y, msg)
29 register struct obj *otmp, *otmp2;
32 boolean revived = FALSE;
34 for(otmp = level.objects[x][y]; otmp; otmp = otmp2) {
35 otmp2 = otmp->nexthere;
36 if (otmp->otyp == CORPSE &&
37 (is_rider(&mons[otmp->corpsenm]) ||
38 otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
39 /* move any living monster already at that location */
40 if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data))
41 rloc_to(mtmp, cc.x, cc.y);
42 if(msg) Norep("%s", msg);
43 revived = revive_corpse(otmp);
47 /* this location might not be safe, if not, move revived monster */
50 if (mtmp && !goodpos(x, y, mtmp, 0) &&
51 enexto(&cc, x, y, mtmp->data)) {
52 rloc_to(mtmp, cc.x, cc.y);
54 /* else impossible? */
63 register xchar rx, ry, sx, sy;
64 register struct obj *otmp;
65 register struct trap *ttmp;
66 register struct monst *mtmp;
68 sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */
69 while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
70 /* make sure that this boulder is visible as the top object */
71 if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy);
73 rx = u.ux + 2 * u.dx; /* boulder destination position */
76 if (Levitation || Is_airlevel(&u.uz)) {
77 if (Blind) feel_location(sx, sy);
78 You("don't have enough leverage to push %s.", the(xname(otmp)));
79 /* Give them a chance to climb over it? */
82 if (verysmall(youmonst.data)
87 if (Blind) feel_location(sx, sy);
88 pline("You're too small to push that %s.", xname(otmp));
91 if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
92 levl[rx][ry].typ != IRONBARS &&
93 (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || (
95 !Is_rogue_level(&u.uz) &&
97 (levl[rx][ry].doormask & ~D_BROKEN) == D_NODOOR)) &&
98 !sobj_at(BOULDER, rx, ry)) {
102 /* KMH -- Sokoban doesn't let you push boulders diagonally */
103 if (In_sokoban(&u.uz) && u.dx && u.dy) {
104 if (Blind) feel_location(sx,sy);
105 pline("%s won't roll diagonally on this %s.",
106 The(xname(otmp)), surface(sx, sy));
110 if (revive_nasty(rx, ry, "You sense movement on the other side."))
113 if (mtmp && !noncorporeal(mtmp->data) &&
115 !(ttmp && ((ttmp->ttyp == PIT) ||
116 (ttmp->ttyp == SPIKED_PIT))))) {
117 if (Blind) feel_location(sx, sy);
118 if (canspotmon(mtmp))
119 pline("There's %s on the other side.", a_monnam(mtmp));
121 You_hear("a monster behind %s.", the(xname(otmp)));
122 map_invisible(rx, ry);
125 pline("Perhaps that's why %s cannot move it.",
127 u.usteed ? y_monnam(u.usteed) :
137 obj_extract_self(otmp);
138 place_object(otmp, rx, ry);
139 unblock_point(sx, sy);
141 pline("KAABLAMM!!! %s %s land mine.",
142 Tobjnam(otmp, "trigger"),
143 ttmp->madeby_u ? "your" : "a");
144 blow_up_landmine(ttmp);
145 /* if the boulder remains, it should fill the pit */
146 fill_pit(u.ux, u.uy);
147 if (cansee(rx,ry)) newsym(rx,ry);
153 obj_extract_self(otmp);
154 /* vision kludge to get messages right;
155 the pit will temporarily be seen even
156 if this is one among multiple boulders */
157 if (!Blind) viz_array[ry][rx] |= IN_SIGHT;
158 if (!flooreffects(otmp, rx, ry, "fall")) {
159 place_object(otmp, rx, ry);
161 if (mtmp && !Blind) newsym(rx, ry);
166 pline("Kerplunk! You no longer feel %s.",
169 pline("%s%s and %s a %s in the %s!",
171 (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"),
172 (ttmp->ttyp == TRAPDOOR) ? nul : " into",
173 otense(otmp, "plug"),
174 (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
179 if (cansee(rx,ry)) newsym(rx,ry);
185 pline("%s pushes %s and suddenly it disappears!",
186 upstart(y_monnam(u.usteed)), the(xname(otmp)));
189 You("push %s and suddenly it disappears!",
191 if (ttmp->ttyp == TELEP_TRAP)
194 int newlev = random_teleport_level();
197 if (newlev == depth(&u.uz) || In_endgame(&u.uz))
199 obj_extract_self(otmp);
200 add_to_migration(otmp);
201 get_level(&dest, newlev);
202 otmp->ox = dest.dnum;
203 otmp->oy = dest.dlevel;
204 otmp->owornmask = (long)MIGR_RANDOM;
209 if (closed_door(rx, ry))
211 if (boulder_hits_pool(otmp, rx, ry, TRUE))
214 * Re-link at top of fobj chain so that pile order is preserved
215 * when level is restored.
219 place_object(otmp, otmp->ox, otmp->oy);
223 #ifdef LINT /* static long lastmovetime; */
227 /* note: reset to zero after save/restore cycle */
228 static NEARDATA long lastmovetime;
233 if (moves > lastmovetime+2 || moves < lastmovetime)
234 pline("With %s effort you move %s.",
235 throws_rocks(youmonst.data) ? "little" : "great",
237 exercise(A_STR, TRUE);
240 pline("%s moves %s.",
241 upstart(y_monnam(u.usteed)), the(xname(otmp)));
243 lastmovetime = moves;
246 /* Move the boulder *after* the message. */
247 if (glyph_is_invisible(levl[rx][ry].glyph))
248 unmap_object(rx, ry);
249 movobj(otmp, rx, ry); /* does newsym(rx,ry) */
251 feel_location(rx,ry);
252 feel_location(sx, sy);
260 pline("%s tries to move %s, but cannot.",
261 upstart(y_monnam(u.usteed)), the(xname(otmp)));
264 You("try to move %s, but in vain.", the(xname(otmp)));
265 if (Blind) feel_location(sx, sy);
267 if (throws_rocks(youmonst.data)) {
269 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
270 You("aren't skilled enough to %s %s from %s.",
271 (flags.pickup && !In_sokoban(&u.uz))
272 ? "pick up" : "push aside",
273 the(xname(otmp)), y_monnam(u.usteed));
277 pline("However, you can easily %s.",
278 (flags.pickup && !In_sokoban(&u.uz))
279 ? "pick it up" : "push it aside");
280 if (In_sokoban(&u.uz))
281 change_luck(-1); /* Sokoban guilt */
291 (((!invent || inv_weight() <= -850) &&
292 (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
293 && IS_ROCK(levl[sx][u.uy].typ))))
294 || verysmall(youmonst.data))) {
295 pline("However, you can squeeze yourself into a small opening.");
296 if (In_sokoban(&u.uz))
297 change_luck(-1); /* Sokoban guilt */
309 * Chew on a wall, door, or boulder. Returns TRUE if still eating, FALSE
316 struct rm *lev = &levl[x][y];
317 struct obj *boulder = sobj_at(BOULDER,x,y);
318 const char *digtxt = (char *)0, *dmgtxt = (char *)0;
320 if (digging.down) /* not continuing previous dig (w/ pick-axe) */
321 (void) memset((genericptr_t)&digging, 0, sizeof digging);
323 if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) {
324 You("hurt your teeth on the %s.",
325 IS_TREE(lev->typ) ? "tree" : "hard stone");
328 } else if (digging.pos.x != x || digging.pos.y != y ||
329 !on_level(&digging.level, &u.uz)) {
330 digging.down = FALSE;
332 digging.warned = FALSE;
335 assign_level(&digging.level, &u.uz);
336 /* solid rock takes more work & time to dig through */
338 (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
339 You("start chewing %s %s.",
340 (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the",
341 boulder ? "boulder" :
342 IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door");
343 watch_dig((struct monst *)0, x, y, FALSE);
345 } else if ((digging.effort += (30 + u.udaminc)) <= 100) {
347 You("%s chewing on the %s.",
348 digging.chew ? "continue" : "begin",
349 boulder ? "boulder" :
350 IS_TREE(lev->typ) ? "tree" :
351 IS_ROCK(lev->typ) ? "rock" : "door");
353 watch_dig((struct monst *)0, x, y, FALSE);
357 /* Okay, you've chewed through something */
359 u.uhunger += rnd(20);
362 delobj(boulder); /* boulder goes bye-bye */
363 You("eat the boulder."); /* yum */
366 * The location could still block because of
367 * 1. More than one boulder
368 * 2. Boulder stuck in a wall/stone/door.
370 * [perhaps use does_block() below (from vision.c)]
372 if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) {
373 block_point(x,y); /* delobj will unblock the point */
374 /* reset dig state */
375 (void) memset((genericptr_t)&digging, 0, sizeof digging);
379 } else if (IS_WALL(lev->typ)) {
380 if (*in_rooms(x, y, SHOPBASE)) {
381 add_damage(x, y, 10L * ACURRSTR);
384 digtxt = "chew a hole in the wall.";
385 if (level.flags.is_maze_lev) {
387 } else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
391 lev->doormask = D_NODOOR;
393 } else if (IS_TREE(lev->typ)) {
394 digtxt = "chew through the tree.";
396 } else if (lev->typ == SDOOR) {
397 if (lev->doormask & D_TRAPPED) {
398 lev->doormask = D_NODOOR;
399 b_trapped("secret door", 0);
401 digtxt = "chew through the secret door.";
402 lev->doormask = D_BROKEN;
406 } else if (IS_DOOR(lev->typ)) {
407 if (*in_rooms(x, y, SHOPBASE)) {
408 add_damage(x, y, 400L);
411 if (lev->doormask & D_TRAPPED) {
412 lev->doormask = D_NODOOR;
413 b_trapped("door", 0);
415 digtxt = "chew through the door.";
416 lev->doormask = D_BROKEN;
419 } else { /* STONE or SCORR */
420 digtxt = "chew a passage through the rock.";
424 unblock_point(x, y); /* vision */
426 if (digtxt) You(digtxt); /* after newsym */
427 if (dmgtxt) pay_for_damage(dmgtxt, FALSE);
428 (void) memset((genericptr_t)&digging, 0, sizeof digging);
437 register struct obj *obj;
438 register xchar ox, oy;
440 /* optimize by leaving on the fobj chain? */
442 newsym(obj->ox, obj->oy);
443 place_object(obj, ox, oy);
448 static NEARDATA const char fell_on_sink[] = "fell onto a sink";
453 register struct obj *obj;
455 if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) {
456 You("wobble unsteadily for a moment.");
458 long save_ELev = ELevitation, save_HLev = HLevitation;
460 /* fake removal of levitation in advance so that final
461 disclosure will be right in case this turns out to
462 be fatal; fortunately the fact that rings and boots
463 are really still worn has no effect on bones data */
464 ELevitation = HLevitation = 0L;
465 You("crash to the floor!");
466 losehp(rn1(8, 25 - (int)ACURR(A_CON)),
467 fell_on_sink, NO_KILLER_PREFIX);
468 exercise(A_DEX, FALSE);
469 selftouch("Falling, you");
470 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
471 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
472 You("fell on %s.", doname(obj));
473 losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX);
474 exercise(A_CON, FALSE);
476 ELevitation = save_ELev;
477 HLevitation = save_HLev;
480 ELevitation &= ~W_ARTI;
481 HLevitation &= ~(I_SPECIAL|TIMEOUT);
483 if(uleft && uleft->otyp == RIN_LEVITATION) {
488 if(uright && uright->otyp == RIN_LEVITATION) {
493 if(uarmf && uarmf->otyp == LEVITATION_BOOTS) {
505 /* intended to be called only on ROCKs */
507 return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
508 (levl[x][y].wall_info & W_NONDIGGABLE)));
515 return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
516 (levl[x][y].wall_info & W_NONPASSWALL)));
524 struct permonst *mdat;
527 return((boolean) ((In_sokoban(&u.uz) && sobj_at(BOULDER,x,y)) ||
528 (IS_ROCK(levl[x][y].typ)
529 && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y))
530 && !(passes_walls(mdat) && may_passwall(x,y)))));
537 return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y));
543 /* return TRUE if (dx,dy) is an OK place to move
544 * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV
547 test_move(ux, uy, dx, dy, mode)
553 register struct rm *tmpr = &levl[x][y];
554 register struct rm *ust;
557 * Check for physical obstacles. First, the place we are going.
559 if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
560 if (Blind && mode == DO_MOVE) feel_location(x,y);
561 if (Passes_walls && may_passwall(x,y)) {
563 } else if (tmpr->typ == IRONBARS) {
564 if (!(Passes_walls || passes_bars(youmonst.data)))
566 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
568 if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
569 } else if (flags.autodig && !flags.run && !flags.nopick &&
570 uwep && is_pick(uwep)) {
571 /* MRKR: Automatic digging when wielding the appropriate tool */
573 (void) use_pick_axe2(uwep);
576 if (mode == DO_MOVE) {
577 if (Is_stronghold(&u.uz) && is_db_wall(x,y))
578 pline_The("drawbridge is up!");
579 if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz))
580 pline_The("Sokoban walls resist your ability.");
584 } else if (IS_DOOR(tmpr->typ)) {
585 if (closed_door(x,y)) {
586 if (Blind && mode == DO_MOVE) feel_location(x,y);
589 else if (can_ooze(&youmonst)) {
590 if (mode == DO_MOVE) You("ooze under the door.");
591 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
593 if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
595 if (mode == DO_MOVE) {
596 if (amorphous(youmonst.data))
597 You("try to ooze under the door, but can't squeeze your possessions through.");
598 else if (x == ux || y == uy) {
599 if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {
602 You_cant("lead %s through that closed door.",
607 pline("Ouch! You bump into a door.");
608 exercise(A_DEX, FALSE);
610 } else pline("That door is closed.");
612 } else if (mode == TEST_TRAV) goto testdiag;
617 if (dx && dy && !Passes_walls
618 && ((tmpr->doormask & ~D_BROKEN)
620 || Is_rogue_level(&u.uz)
622 || block_door(x,y))) {
623 /* Diagonal moves into a door are not allowed. */
624 if (Blind && mode == DO_MOVE)
631 && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) {
632 /* Move at a diagonal. */
633 if (In_sokoban(&u.uz)) {
635 You("cannot pass that way.");
638 if (bigmonst(youmonst.data)) {
640 Your("body is too large to fit through.");
643 if (invent && (inv_weight() + weight_cap() > 600)) {
645 You("are carrying too much to get through.");
649 /* Pick travel path that does not require crossing a trap.
650 * Avoid water and lava using the usual running rules.
651 * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
652 if (flags.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) {
653 struct trap* t = t_at(x, y);
655 if ((t && t->tseen) ||
656 (!Levitation && !Flying &&
657 !is_clinger(youmonst.data) &&
658 (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv))
664 /* Now see if other things block our way . . */
665 if (dx && dy && !Passes_walls
666 && (IS_DOOR(ust->typ) && ((ust->doormask & ~D_BROKEN)
668 || Is_rogue_level(&u.uz)
670 || block_entry(x, y))
672 /* Can't move at a diagonal out of a doorway with door. */
676 if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) {
677 if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV)
679 if (mode == DO_MOVE) {
680 /* tunneling monsters will chew before pushing */
681 if (tunnels(youmonst.data) && !needspick(youmonst.data) &&
682 !In_sokoban(&u.uz)) {
683 if (still_chewing(x,y)) return FALSE;
685 if (moverock() < 0) return FALSE;
686 } else if (mode == TEST_TRAV) {
689 /* don't pick two boulders in a row, unless there's a way thru */
690 if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) {
692 !(tunnels(youmonst.data) && !needspick(youmonst.data)) &&
693 !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) &&
694 !((obj = carrying(WAN_DIGGING)) &&
695 !objects[obj->otyp].oc_name_known))
699 /* assume you'll be able to push it when you get there... */
702 /* OK, it is a legal place to move. */
707 * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
708 * A shortest path is returned. If guess is TRUE, consider various
709 * inaccessible locations as valid intermediate path points.
710 * Returns TRUE if a path was found.
713 findtravelpath(guess)
716 /* if travel to adjacent, reachable location, use normal movement rules */
717 if (!guess && iflags.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1) {
719 if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) {
723 iflags.travelcc.x = iflags.travelcc.y = -1;
728 if (u.tx != u.ux || u.ty != u.uy) {
729 xchar travel[COLNO][ROWNO];
730 xchar travelstepx[2][COLNO*ROWNO];
731 xchar travelstepy[2][COLNO*ROWNO];
732 xchar tx, ty, ux, uy;
733 int n = 1; /* max offset in travelsteps */
734 int set = 0; /* two sets current and previous */
735 int radius = 1; /* search radius */
738 /* If guessing, first find an "obvious" goal location. The obvious
739 * goal is the position the player knows of, or might figure out
740 * (couldsee) that is closest to the target on a straight path.
743 tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty;
745 tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy;
749 (void) memset((genericptr_t)travel, 0, sizeof(travel));
750 travelstepx[0][0] = tx;
751 travelstepy[0][0] = ty;
756 for (i = 0; i < n; i++) {
758 int x = travelstepx[set][i];
759 int y = travelstepy[set][i];
760 static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
761 /* no diagonal movement for grid bugs */
762 int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8;
764 for (dir = 0; dir < dirmax; ++dir) {
765 int nx = x+xdir[ordered[dir]];
766 int ny = y+ydir[ordered[dir]];
768 if (!isok(nx, ny)) continue;
769 if ((!Passes_walls && !can_ooze(&youmonst) &&
770 closed_door(x, y)) || sobj_at(BOULDER, x, y)) {
771 /* closed doors and boulders usually
772 * cause a delay, so prefer another path */
773 if (travel[x][y] > radius-3) {
774 travelstepx[1-set][nn] = x;
775 travelstepy[1-set][nn] = y;
776 /* don't change travel matrix! */
781 if (test_move(x, y, nx-x, ny-y, TEST_TRAV) &&
782 (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) {
783 if (nx == ux && ny == uy) {
787 if (x == u.tx && y == u.ty) {
789 /* reset run so domove run checks work */
791 iflags.travelcc.x = iflags.travelcc.y = -1;
795 } else if (!travel[nx][ny]) {
796 travelstepx[1-set][nn] = nx;
797 travelstepy[1-set][nn] = ny;
798 travel[nx][ny] = radius;
810 /* if guessing, find best location in travel matrix and go there */
812 int px = tx, py = ty; /* pick location */
813 int dist, nxtdist, d2, nd2;
815 dist = distmin(ux, uy, tx, ty);
816 d2 = dist2(ux, uy, tx, ty);
817 for (tx = 1; tx < COLNO; ++tx)
818 for (ty = 0; ty < ROWNO; ++ty)
819 if (travel[tx][ty]) {
820 nxtdist = distmin(ux, uy, tx, ty);
821 if (nxtdist == dist && couldsee(tx, ty)) {
822 nd2 = dist2(ux, uy, tx, ty);
824 /* prefer non-zigzag path */
828 } else if (nxtdist < dist && couldsee(tx, ty)) {
831 d2 = dist2(ux, uy, tx, ty);
835 if (px == u.ux && py == u.uy) {
836 /* no guesses, just go in the general direction */
837 u.dx = sgn(u.tx - u.ux);
838 u.dy = sgn(u.ty - u.uy);
839 if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
865 register struct monst *mtmp;
866 register struct rm *tmpr;
871 xchar chainx, chainy, ballx, bally; /* ball&chain new positions */
872 int bc_control; /* control for ball&chain */
873 boolean cause_delay = FALSE; /* dragging ball will skip a move */
874 const char *predicament;
879 if (!findtravelpath(FALSE))
880 (void) findtravelpath(TRUE);
884 if(((wtcap = near_capacity()) >= OVERLOADED
885 || (wtcap > SLT_ENCUMBER &&
886 (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
887 : (u.uhp < 10 && u.uhp != u.uhpmax))))
888 && !Is_airlevel(&u.uz)) {
889 if(wtcap < OVERLOADED) {
890 You("don't have enough stamina to move.");
891 exercise(A_CON, FALSE);
893 You("collapse under your load.");
899 u.ux = x = u.ustuck->mx;
900 u.uy = y = u.ustuck->my;
903 if (Is_airlevel(&u.uz) && rn2(4) &&
904 !Levitation && !Flying) {
907 You("tumble in place.");
908 exercise(A_DEX, FALSE);
911 You_cant("control your movements very well."); break;
913 pline("It's hard to walk in thin air.");
914 exercise(A_DEX, TRUE);
920 /* check slippery ice */
921 on_ice = !Levitation && is_ice(u.ux, u.uy);
923 static int skates = 0;
924 if (!skates) skates = find_skates();
925 if ((uarmf && uarmf->otyp == skates)
926 || resists_cold(&youmonst) || Flying
927 || is_floater(youmonst.data) || is_clinger(youmonst.data)
928 || is_whirly(youmonst.data))
930 else if (!rn2(Cold_resistance ? 3 : 2)) {
931 HFumbling |= FROMOUTSIDE;
932 HFumbling &= ~TIMEOUT;
933 HFumbling += 1; /* slip on next move */
936 if (!on_ice && (HFumbling & FROMOUTSIDE))
937 HFumbling &= ~FROMOUTSIDE;
941 if(Stunned || (Confusion && !rn2(5))) {
942 register int tries = 0;
952 } while(!isok(x, y) || bad_rock(youmonst.data, x, y));
954 /* turbulence might alter your actual destination */
957 if (!u.dx && !u.dy) {
968 if (((trap = t_at(x, y)) && trap->tseen) ||
969 (Blind && !Levitation && !Flying &&
970 !is_clinger(youmonst.data) &&
971 (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) {
980 if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
981 if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
982 /* perhaps it fled (or was teleported or ... ) */
984 } else if (sticks(youmonst.data)) {
985 /* When polymorphed into a sticking monster,
986 * u.ustuck means it's stuck to you, not you to it.
988 You("release %s.", mon_nam(u.ustuck));
991 /* If holder is asleep or paralyzed:
992 * 37.5% chance of getting away,
993 * 12.5% chance of waking/releasing it;
995 * 7.5% chance of getting away.
996 * [strength ought to be a factor]
997 * If holder is tame and there is no conflict,
1000 switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
1001 case 0: case 1: case 2:
1003 You("pull free from %s.", mon_nam(u.ustuck));
1007 if (!u.ustuck->mcanmove) {
1008 /* it's free to move on next turn */
1009 u.ustuck->mfrozen = 1;
1010 u.ustuck->msleeping = 0;
1014 if (u.ustuck->mtame &&
1015 !Conflict && !u.ustuck->mconf)
1017 You("cannot escape from %s!", mon_nam(u.ustuck));
1026 /* Don't attack if you're running, and can see it */
1027 /* We should never get here if forcefight */
1029 ((!Blind && mon_visible(mtmp) &&
1030 ((mtmp->m_ap_type != M_AP_FURNITURE &&
1031 mtmp->m_ap_type != M_AP_OBJECT) ||
1032 Protection_from_shape_changers)) ||
1047 /* attack monster */
1050 /* only attack if we know it's there */
1051 /* or if we used the 'F' command to fight blindly */
1052 /* or if it hides_under, in which case we call attack() to print
1053 * the Wait! message.
1054 * This is different from ceiling hiders, who aren't handled in
1058 /* If they used a 'm' command, trying to move onto a monster
1059 * prints the below message and wastes a turn. The exception is
1060 * if the monster is unseen and the player doesn't remember an
1061 * invisible monster--then, we fall through to attack() and
1062 * attack_check(), which still wastes a turn, but prints a
1063 * different message and makes the player remember the monster. */
1065 (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
1066 if(mtmp->m_ap_type && !Protection_from_shape_changers
1068 stumble_onto_mimic(mtmp);
1069 else if (mtmp->mpeaceful && !Hallucination)
1070 pline("Pardon me, %s.", m_monnam(mtmp));
1072 You("move right into %s.", mon_nam(mtmp));
1075 if(flags.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
1076 ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
1077 !is_safepet(mtmp))){
1079 if(wtcap >= HVY_ENCUMBER && moves%3) {
1080 if (Upolyd && u.mh > 1) {
1082 } else if (!Upolyd && u.uhp > 1) {
1085 You("pass out from exertion!");
1086 exercise(A_CON, FALSE);
1087 fall_asleep(-10, FALSE);
1090 if(multi < 0) return; /* we just fainted */
1092 /* try to attack; note that it might evade */
1093 /* also, we don't attack tame when _safepet_ */
1094 if(attack(mtmp)) return;
1098 /* specifying 'F' with no monster wastes a turn */
1099 if (flags.forcefight ||
1100 /* remembered an 'I' && didn't use a move command */
1101 (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) {
1102 boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL));
1104 Sprintf(buf,"a vacant spot on the %s", surface(x,y));
1106 expl ? "explode at" : "attack",
1107 !Underwater ? "thin air" :
1108 is_pool(x,y) ? "empty water" : buf);
1109 unmap_object(x, y); /* known empty -- remove 'I' if present */
1113 u.mh = -1; /* dead in the current form */
1118 if (glyph_is_invisible(levl[x][y].glyph)) {
1122 /* not attacking an animal, so we try to move */
1124 if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) {
1125 pline("%s won't move!", upstart(y_monnam(u.usteed)));
1130 if(!youmonst.data->mmove) {
1131 You("are rooted %s.",
1132 Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
1133 "in place" : "to the ground");
1138 if(u.utraptype == TT_PIT) {
1139 if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) {
1140 Your("%s gets stuck in a crevice.", body_part(LEG));
1141 display_nhwindow(WIN_MESSAGE, FALSE);
1142 clear_nhwindow(WIN_MESSAGE);
1143 You("free your %s.", body_part(LEG));
1144 } else if (!(--u.utrap)) {
1145 You("%s to the edge of the pit.",
1146 (In_sokoban(&u.uz) && Levitation) ?
1147 "struggle against the air currents and float" :
1152 fill_pit(u.ux, u.uy);
1153 vision_full_recalc = 1; /* vision limits change */
1154 } else if (flags.verbose) {
1157 Norep("%s is still in a pit.",
1158 upstart(y_monnam(u.usteed)));
1161 Norep( (Hallucination && !rn2(5)) ?
1162 "You've fallen, and you can't get up." :
1163 "You are still in a pit." );
1165 } else if (u.utraptype == TT_LAVA) {
1167 predicament = "stuck in the lava";
1170 Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1174 Norep("You are %s.", predicament);
1178 if((u.utrap & 0xff) == 0) {
1181 You("lead %s to the edge of the lava.",
1182 y_monnam(u.usteed));
1185 You("pull yourself to the edge of the lava.");
1190 } else if (u.utraptype == TT_WEB) {
1191 if(uwep && uwep->oartifact == ART_STING) {
1193 pline("Sting cuts through the web!");
1198 predicament = "stuck to the web";
1201 Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1205 Norep("You are %s.", predicament);
1210 pline("%s breaks out of the web.",
1211 upstart(y_monnam(u.usteed)));
1214 You("disentangle yourself.");
1216 } else if (u.utraptype == TT_INFLOOR) {
1219 predicament = "stuck in the";
1222 Norep("%s is %s %s.",
1223 upstart(y_monnam(u.usteed)),
1224 predicament, surface(u.ux, u.uy));
1227 Norep("You are %s %s.", predicament,
1228 surface(u.ux, u.uy));
1233 pline("%s finally wiggles free.",
1234 upstart(y_monnam(u.usteed)));
1237 You("finally wiggle free.");
1241 predicament = "caught in a bear trap";
1244 Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1248 Norep("You are %s.", predicament);
1250 if((u.dx && u.dy) || !rn2(5)) u.utrap--;
1255 if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
1261 /* Move ball and chain. */
1263 if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
1264 &cause_delay, TRUE))
1267 /* Check regions entering/leaving */
1268 if (!in_out_region(x,y))
1271 /* now move the hero */
1276 /* Move your steed, too */
1278 u.usteed->mx = u.ux;
1279 u.usteed->my = u.uy;
1285 * If safepet at destination then move the pet to the hero's
1286 * previous location using the same conditions as in attack().
1287 * there are special extenuating circumstances:
1288 * (1) if the pet dies then your god angers,
1289 * (2) if the pet gets trapped then your god may disapprove,
1290 * (3) if the pet was already trapped and you attempt to free it
1291 * not only do you encounter the trap but you may frighten your
1292 * pet causing it to go wild! moral: don't abuse this privilege.
1294 * Ceiling-hiding pets are skipped by this section of code, to
1295 * be caught by the normal falling-monster code.
1297 if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
1298 /* if trapped, there's a chance the pet goes wild */
1299 if (mtmp->mtrapped) {
1300 if (!rn2(mtmp->mtame)) {
1301 mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
1302 if (mtmp->mleashed) m_unleash(mtmp, TRUE);
1308 mtmp->mundetected = 0;
1309 if (mtmp->m_ap_type) seemimic(mtmp);
1310 else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
1312 if (mtmp->mtrapped &&
1313 (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
1314 (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
1315 sobj_at(BOULDER, trap->tx, trap->ty)) {
1316 /* can't swap places with pet pinned in a pit by a boulder */
1317 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
1318 } else if (u.ux0 != x && u.uy0 != y &&
1319 bad_rock(mtmp->data, x, u.uy0) &&
1320 bad_rock(mtmp->data, u.ux0, y) &&
1321 (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
1322 /* can't swap places when pet won't fit thru the opening */
1323 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
1324 You("stop. %s won't fit through.", upstart(y_monnam(mtmp)));
1326 char pnambuf[BUFSZ];
1328 /* save its current description in case of polymorph */
1329 Strcpy(pnambuf, y_monnam(mtmp));
1331 remove_monster(x, y);
1332 place_monster(mtmp, u.ux0, u.uy0);
1334 /* check for displacing it into pools and traps */
1335 switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
1337 You("%s %s.", mtmp->mtame ? "displaced" : "frightened",
1340 case 1: /* trapped */
1341 case 3: /* changed levels */
1342 /* there's already been a trap message, reinforce it */
1347 /* it may have drowned or died. that's no way to
1348 * treat a pet! your god gets angry.
1351 You_feel("guilty about losing your pet like this.");
1356 /* you killed your pet by direct action.
1357 * minliquid and mintrap don't know to do this
1359 u.uconduct.killer++;
1362 pline("that's strange, unknown mintrap result!");
1368 reset_occupations();
1370 if ( flags.run < 8 )
1371 if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
1372 IS_FURNITURE(tmpr->typ))
1376 if (hides_under(youmonst.data))
1377 u.uundetected = OBJ_AT(u.ux, u.uy);
1378 else if (youmonst.data->mlet == S_EEL)
1379 u.uundetected = is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz);
1380 else if (u.dx || u.dy)
1384 * Mimics (or whatever) become noticeable if they move and are
1385 * imitating something that doesn't move. We could extend this
1386 * to non-moving monsters...
1388 if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
1389 || youmonst.m_ap_type == M_AP_FURNITURE))
1390 youmonst.m_ap_type = M_AP_NOTHING;
1392 check_leash(u.ux0,u.uy0);
1394 if(u.ux0 != u.ux || u.uy0 != u.uy) {
1396 /* Clean old position -- vision_recalc() will print our new one. */
1397 newsym(u.ux0,u.uy0);
1398 /* Since the hero has moved, adjust what can be seen/unseen. */
1399 vision_recalc(1); /* Do the work now in the recover time. */
1400 invocation_message();
1403 if (Punished) /* put back ball and chain */
1404 move_bc(0,bc_control,ballx,bally,chainx,chainy);
1408 /* delay next move because of ball dragging */
1409 /* must come after we finished picking up, in spoteffects() */
1415 if (flags.run && iflags.runmode != RUN_TPORT) {
1416 /* display every step or every 7th step depending upon mode */
1417 if (iflags.runmode != RUN_LEAP || !(moves % 7L)) {
1418 if (flags.time) flags.botl = 1;
1421 if (iflags.runmode == RUN_CRAWL) {
1432 invocation_message()
1434 /* a special clue-msg when on the Invocation position */
1435 if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
1437 struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
1439 nomul(0); /* stop running or travelling */
1441 if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed));
1444 if (Levitation || Flying) Strcpy(buf, "beneath you");
1445 else Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
1447 You_feel("a strange vibration %s.", buf);
1448 if (otmp && otmp->spe == 7 && otmp->lamplit)
1449 pline("%s %s!", The(xname(otmp)),
1450 Blind ? "throbs palpably" : "glows with a strange light");
1461 register struct monst *mtmp;
1466 if (!is_pool(u.ux,u.uy)) {
1467 if (Is_waterlevel(&u.uz))
1468 You("pop into an air bubble.");
1469 else if (is_lava(u.ux, u.uy))
1470 You("leave the water..."); /* oops! */
1472 You("are on solid %s again.",
1473 is_ice(u.ux, u.uy) ? "ice" : "land");
1475 else if (Is_waterlevel(&u.uz))
1477 else if (Levitation)
1478 You("pop out of the water like a cork!");
1480 You("fly out of the water.");
1482 You("slowly rise above the surface.");
1485 was_underwater = Underwater && !Is_waterlevel(&u.uz);
1486 u.uinwater = 0; /* leave the water */
1487 if (was_underwater) { /* restore vision */
1489 vision_full_recalc = 1;
1493 if (!Levitation && !u.ustuck && !Flying) {
1494 /* limit recursive calls through teleds() */
1495 if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
1497 if (u.usteed && !is_flyer(u.usteed->data) &&
1498 !is_floater(u.usteed->data) &&
1499 !is_clinger(u.usteed->data)) {
1500 dismount_steed(Underwater ?
1501 DISMOUNT_FELL : DISMOUNT_GENERIC);
1502 /* dismount_steed() -> float_down() -> pickup() */
1503 if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz))
1507 if (is_lava(u.ux, u.uy)) {
1508 if (lava_effects()) return;
1509 } else if (!Wwalking && drown())
1513 check_special_room(FALSE);
1515 if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
1518 if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
1519 struct trap *trap = t_at(u.ux, u.uy);
1521 pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT));
1523 dotrap(trap, 0); /* fall into pit */
1524 if (pick) (void) pickup(1);
1526 dotrap(trap, 0); /* fall into arrow trap, etc. */
1528 if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
1529 mtmp->mundetected = mtmp->msleeping = 0;
1530 switch(mtmp->data->mlet) {
1532 pline("%s suddenly drops from the %s!",
1533 Amonnam(mtmp), ceiling(u.ux,u.uy));
1534 if(mtmp->mtame) /* jumps to greet you, not attack */
1536 else if(uarmh && is_metallic(uarmh))
1537 pline("Its blow glances off your helmet.");
1538 else if (u.uac + 3 <= rnd(20))
1539 You("are almost hit by %s!",
1540 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1543 You("are hit by %s!",
1544 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1546 if(Half_physical_damage) dmg = (dmg+1) / 2;
1547 mdamageu(mtmp, dmg);
1550 default: /* monster surprises you. */
1552 pline("%s jumps near you from the %s.",
1553 Amonnam(mtmp), ceiling(u.ux,u.uy));
1554 else if(mtmp->mpeaceful) {
1556 Blind && !sensemon(mtmp) ?
1557 something : a_monnam(mtmp));
1558 mtmp->mpeaceful = 0;
1560 pline("%s attacks you by surprise!",
1564 mnexto(mtmp); /* have to move the monster */
1569 monstinroom(mdat,roomno)
1570 struct permonst *mdat;
1573 register struct monst *mtmp;
1575 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1576 if(!DEADMONSTER(mtmp) && mtmp->data == mdat &&
1577 index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
1583 in_rooms(x, y, typewanted)
1584 register xchar x, y;
1585 register int typewanted;
1588 char rno, *ptr = &buf[4];
1589 int typefound, min_x, min_y, max_x, max_y_offset, step;
1590 register struct rm *lev;
1592 #define goodtype(rno) (!typewanted || \
1593 ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \
1594 ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \
1596 switch (rno = levl[x][y].roomno) {
1605 default: /* i.e. a regular room # */
1623 max_y_offset -= step;
1625 if ((min_y + max_y_offset) >= ROWNO)
1626 max_y_offset -= step;
1628 for (x = min_x; x <= max_x; x += step) {
1629 lev = &levl[x][min_y];
1631 if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1632 !index(ptr, rno) && goodtype(rno))
1635 if (y > max_y_offset)
1637 if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1638 !index(ptr, rno) && goodtype(rno))
1641 if (y > max_y_offset)
1643 if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1644 !index(ptr, rno) && goodtype(rno))
1650 /* is (x,y) in a town? */
1655 s_level *slev = Is_special(&u.uz);
1656 register struct mkroom *sroom;
1657 boolean has_subrooms = FALSE;
1659 if (!slev || !slev->flags.town) return FALSE;
1662 * See if (x,y) is in a room with subrooms, if so, assume it's the
1663 * town. If there are no subrooms, the whole level is in town.
1665 for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
1666 if (sroom->nsubrooms > 0) {
1667 has_subrooms = TRUE;
1668 if (inside_room(sroom, x, y)) return TRUE;
1672 return !has_subrooms;
1677 register boolean newlev;
1679 char *ptr1, *ptr2, *ptr3, *ptr4;
1681 Strcpy(u.urooms0, u.urooms);
1682 Strcpy(u.ushops0, u.ushops);
1685 u.uentered[0] = '\0';
1687 u.ushops_entered[0] = '\0';
1688 Strcpy(u.ushops_left, u.ushops0);
1691 Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
1693 for (ptr1 = &u.urooms[0],
1694 ptr2 = &u.uentered[0],
1695 ptr3 = &u.ushops[0],
1696 ptr4 = &u.ushops_entered[0];
1698 if (!index(u.urooms0, *ptr1))
1700 if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
1702 if (!index(u.ushops0, *ptr1))
1710 /* filter u.ushops0 -> u.ushops_left */
1711 for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
1712 if (!index(u.ushops, *ptr1))
1718 check_special_room(newlev)
1719 register boolean newlev;
1721 register struct monst *mtmp;
1724 move_update(newlev);
1727 u_left_shop(u.ushops_left, newlev);
1729 if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */
1730 return; /* no entrance messages necessary */
1732 /* Did we just enter a shop? */
1733 if (*u.ushops_entered)
1734 u_entered_shop(u.ushops_entered);
1736 for (ptr = &u.uentered[0]; *ptr; ptr++) {
1737 register int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
1739 /* Did we just enter some other special room? */
1740 /* vault.c insists that a vault remain a VAULT,
1741 * and temples should remain TEMPLEs,
1742 * but everything else gives a message only the first time */
1745 pline("Welcome to David's treasure zoo!");
1748 pline("It %s rather %s down here.",
1749 Blind ? "feels" : "looks",
1750 Blind ? "humid" : "muddy");
1753 You("enter an opulent throne room!");
1756 You("enter a leprechaun hall!");
1760 const char *run = locomotion(youmonst.data, "Run");
1761 pline("%s away! %s away!", run, run);
1763 You("have an uncanny feeling...");
1766 You("enter a giant beehive!");
1769 You("enter a disgusting nest!");
1772 You("enter an anthole!");
1775 if(monstinroom(&mons[PM_SOLDIER], roomno) ||
1776 monstinroom(&mons[PM_SERGEANT], roomno) ||
1777 monstinroom(&mons[PM_LIEUTENANT], roomno) ||
1778 monstinroom(&mons[PM_CAPTAIN], roomno))
1779 You("enter a military barracks!");
1781 You("enter an abandoned barracks.");
1784 if(monstinroom(&mons[PM_ORACLE], roomno))
1785 verbalize("%s, %s, welcome to Delphi!",
1786 Hello((struct monst *) 0), plname);
1789 intemple(roomno + ROOMOFFSET);
1796 rooms[roomno].rtype = OROOM;
1797 if (!search_special(rt)) {
1798 /* No more room of that type */
1801 level.flags.has_court = 0;
1804 level.flags.has_swamp = 0;
1807 level.flags.has_morgue = 0;
1810 level.flags.has_zoo = 0;
1813 level.flags.has_barracks = 0;
1816 level.flags.has_temple = 0;
1819 level.flags.has_beehive = 0;
1823 if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
1824 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1825 if (!DEADMONSTER(mtmp) && !Stealth && !rn2(3)) mtmp->msleeping = 0;
1839 struct trap *traphere = t_at(u.ux, u.uy);
1840 /* awful kludge to work around parse()'s pre-decrement */
1841 count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
1842 multi = 0; /* always reset */
1843 /* uswallow case added by GAN 01/29/87 */
1845 if (!u.ustuck->minvent) {
1846 if (is_animal(u.ustuck->data)) {
1847 You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
1848 pline("But it's kind of slimy, so you drop it.");
1850 You("don't %s anything in here to pick up.",
1851 Blind ? "feel" : "see");
1854 int tmpcount = -count;
1855 return loot_mon(u.ustuck, &tmpcount, (boolean *)0);
1858 if(is_pool(u.ux, u.uy)) {
1859 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1860 || (Flying && !Breathless)) {
1861 You("cannot dive into the water to pick things up.");
1863 } else if (!Underwater) {
1864 You_cant("even see the bottom, let alone pick up %s.",
1869 if (is_lava(u.ux, u.uy)) {
1870 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1871 || (Flying && !Breathless)) {
1872 You_cant("reach the bottom to pick things up.");
1874 } else if (!likes_lava(youmonst.data)) {
1875 You("would burn to a crisp trying to pick things up.");
1879 if(!OBJ_AT(u.ux, u.uy)) {
1880 There("is nothing here to pick up.");
1883 if (!can_reach_floor()) {
1885 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1886 You("aren't skilled enough to reach from %s.",
1887 y_monnam(u.usteed));
1890 You("cannot reach the %s.", surface(u.ux,u.uy));
1894 if (traphere && traphere->tseen) {
1895 /* Allow pickup from holes and trap doors that you escaped from
1896 * because that stuff is teetering on the edge just like you, but
1897 * not pits, because there is an elevation discrepancy with stuff
1900 if ((traphere->ttyp == PIT || traphere->ttyp == SPIKED_PIT) &&
1901 (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) {
1902 You("cannot reach the bottom of the pit.");
1907 return (pickup(-count));
1913 /* stop running if we see something interesting */
1914 /* turn around a corner if that is the only way we can proceed */
1915 /* do not turn left or right twice */
1919 register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
1920 register int corrct = 0, noturn = 0;
1921 register struct monst *mtmp;
1922 register struct trap *trap;
1924 /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */
1925 /* they polymorphed while in the middle of a long move. */
1926 if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) {
1931 if(Blind || flags.run == 0) return;
1932 for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) {
1933 if(!isok(x,y)) continue;
1935 if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue;
1937 if(x == u.ux && y == u.uy) continue;
1939 if((mtmp = m_at(x,y)) &&
1940 mtmp->m_ap_type != M_AP_FURNITURE &&
1941 mtmp->m_ap_type != M_AP_OBJECT &&
1942 (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
1943 if((flags.run != 1 && !mtmp->mtame)
1944 || (x == u.ux+u.dx && y == u.uy+u.dy))
1948 if (levl[x][y].typ == STONE) continue;
1949 if (x == u.ux-u.dx && y == u.uy-u.dy) continue;
1951 if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) ||
1952 IS_AIR(levl[x][y].typ))
1954 else if (closed_door(x,y) ||
1955 (mtmp && mtmp->m_ap_type == M_AP_FURNITURE &&
1956 (mtmp->mappearance == S_hcdoor ||
1957 mtmp->mappearance == S_vcdoor))) {
1958 if(x != u.ux && y != u.uy) continue;
1959 if(flags.run != 1) goto stop;
1961 } else if (levl[x][y].typ == CORR) {
1963 if(levl[u.ux][u.uy].typ != ROOM) {
1964 if(flags.run == 1 || flags.run == 3 || flags.run == 8) {
1965 i = dist2(x,y,u.ux+u.dx,u.uy+u.dy);
1967 if(corrct == 1 && dist2(x,y,x0,y0) != 1)
1979 } else if ((trap = t_at(x,y)) && trap->tseen) {
1980 if(flags.run == 1) goto bcorr; /* if you must */
1981 if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
1983 } else if (is_pool(x,y) || is_lava(x,y)) {
1984 /* water and lava only stop you if directly in front, and stop
1985 * you even if you are running
1987 if(!Levitation && !Flying && !is_clinger(youmonst.data) &&
1988 x == u.ux+u.dx && y == u.uy+u.dy)
1989 /* No Wwalking check; otherwise they'd be able
1990 * to test boots by trying to SHIFT-direction
1991 * into a pool and seeing if the game allowed it
1995 } else { /* e.g. objects or trap or stairs */
1996 if(flags.run == 1) goto bcorr;
1997 if(flags.run == 8) continue;
1998 if(mtmp) continue; /* d */
1999 if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) ||
2000 ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
2006 } /* end for loops */
2008 if(corrct > 1 && flags.run == 2) goto stop;
2009 if((flags.run == 1 || flags.run == 3 || flags.run == 8) &&
2010 !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1)))
2012 /* make sure that we do not turn too far */
2014 if(u.dx == y0-u.uy && u.dy == u.ux-x0)
2015 i = 2; /* straight turn right */
2017 i = -2; /* straight turn left */
2018 } else if(u.dx && u.dy) {
2019 if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
2020 i = -1; /* half turn left */
2022 i = 1; /* half turn right */
2024 if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy))
2025 i = 1; /* half turn right */
2027 i = -1; /* half turn left */
2030 i += u.last_str_turn;
2031 if(i <= 2 && i >= -2) {
2032 u.last_str_turn = i;
2039 /* something like lookaround, but we are not running */
2040 /* react only to monsters that might hit us */
2045 register struct monst *mtmp;
2047 /* Also see the similar check in dochugw() in monmove.c */
2048 for(x = u.ux-1; x <= u.ux+1; x++)
2049 for(y = u.uy-1; y <= u.uy+1; y++) {
2050 if(!isok(x,y)) continue;
2051 if(x == u.ux && y == u.uy) continue;
2052 if((mtmp = m_at(x,y)) &&
2053 mtmp->m_ap_type != M_AP_FURNITURE &&
2054 mtmp->m_ap_type != M_AP_OBJECT &&
2055 (!mtmp->mpeaceful || Hallucination) &&
2056 (!is_hider(mtmp->data) || !mtmp->mundetected) &&
2057 !noattacks(mtmp->data) &&
2058 mtmp->mcanmove && !mtmp->msleeping && /* aplvax!jcn */
2059 !onscary(u.ux, u.uy, mtmp) &&
2070 if(multi < nval) return; /* This is a bug fix by ab@unido */
2071 u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */
2074 flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
2077 /* called when a non-movement, multi-turn action has completed */
2080 const char *msg_override;
2082 multi = 0; /* caller will usually have done this already */
2083 if (msg_override) nomovemsg = msg_override;
2084 else if (!nomovemsg) nomovemsg = You_can_move_again;
2085 if (*nomovemsg) pline(nomovemsg);
2088 if (afternmv) (*afternmv)();
2098 static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
2099 SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
2100 TELEPORT_CONTROL, STEALTH, FAST, INVIS };
2102 if (moves <= wailmsg + 50) return;
2105 if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
2109 who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
2110 urole.name.m : "Elf";
2112 pline("%s is about to die.", who);
2114 for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
2115 if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt;
2117 pline(powercnt >= 4 ? "%s, all your powers will be lost..."
2118 : "%s, your life force is running out.", who);
2121 You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
2122 : "the howling of the CwnAnnwn...");
2127 losehp(n, knam, k_format)
2129 register const char *knam;
2134 if (u.mhmax < u.mh) u.mhmax = u.mh;
2138 else if (n > 0 && u.mh*10 < u.mhmax && Unchanging)
2144 if(u.uhp > u.uhpmax)
2145 u.uhpmax = u.uhp; /* perhaps n was negative */
2148 killer_format = k_format;
2149 killer = knam; /* the thing that killed you */
2152 } else if (n > 0 && u.uhp*10 < u.uhpmax) {
2160 register long carrcap;
2162 carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50;
2164 /* consistent with can_carry() in mon.c */
2165 if (youmonst.data->mlet == S_NYMPH)
2166 carrcap = MAX_CARR_CAP;
2167 else if (!youmonst.data->cwt)
2168 carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN;
2169 else if (!strongmonst(youmonst.data)
2170 || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN)))
2171 carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN);
2174 if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */
2176 || (u.usteed && strongmonst(u.usteed->data))
2179 carrcap = MAX_CARR_CAP;
2181 if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
2183 if(EWounded_legs & LEFT_SIDE) carrcap -= 100;
2184 if(EWounded_legs & RIGHT_SIDE) carrcap -= 100;
2186 if (carrcap < 0) carrcap = 0;
2188 return((int) carrcap);
2191 static int wc; /* current weight_cap(); valid after call to inv_weight() */
2193 /* returns how far beyond the normal capacity the player is currently. */
2194 /* inv_weight() is negative if the player is below normal capacity. */
2198 register struct obj *otmp = invent;
2199 register int wt = 0;
2202 /* when putting stuff into containers, gold is inserted at the head
2203 of invent for easier manipulation by askchain & co, but it's also
2204 retained in u.ugold in order to keep the status line accurate; we
2205 mustn't add its weight in twice under that circumstance */
2206 wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 :
2207 (int)((u.ugold + 50L) / 100L);
2211 if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
2213 if (otmp->oclass == COIN_CLASS)
2214 wt += (int)(((long)otmp->quan + 50L) / 100L);
2215 else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
2225 * Returns 0 if below normal capacity, or the number of "capacity units"
2226 * over the normal capacity the player is loaded. Max is 5.
2229 calc_capacity(xtra_wt)
2232 int cap, wt = inv_weight() + xtra_wt;
2234 if (wt <= 0) return UNENCUMBERED;
2235 if (wc <= 1) return OVERLOADED;
2236 cap = (wt*2 / wc) + 1;
2237 return min(cap, OVERLOADED);
2243 return calc_capacity(0);
2249 int wt = inv_weight();
2251 return (wt - (2 * wc));
2258 if(near_capacity() >= EXT_ENCUMBER) {
2262 You_cant("do that while carrying so much stuff.");
2274 register struct obj *otmp = invent;
2275 register int ct = 0;
2285 /* Counts the money in an object chain. */
2286 /* Intended use is for your or some monsters inventory, */
2287 /* now that u.gold/m.gold is gone.*/
2288 /* Counting money in a container might be possible too. */
2294 /* Must change when silver & copper is implemented: */
2295 if (otmp->oclass == COIN_CLASS) return otmp->quan;