1 /* NetHack 3.6 hack.c $NHDT-Date: 1576638500 2019/12/18 03:08:20 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.220 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Derek S. Ray, 2015. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022 */
9 /* JNetHack may be freely redistributed. See license for details. */
13 /* #define DEBUG */ /* uncomment for debugging */
15 STATIC_DCL void NDECL(maybe_wail);
16 STATIC_DCL int NDECL(moverock);
17 STATIC_DCL int FDECL(still_chewing, (XCHAR_P, XCHAR_P));
18 STATIC_DCL void NDECL(dosinkfall);
19 STATIC_DCL boolean FDECL(findtravelpath, (int));
20 STATIC_DCL boolean FDECL(trapmove, (int, int, struct trap *));
21 STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *, int));
22 STATIC_DCL boolean FDECL(doorless_door, (int, int));
23 STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
24 STATIC_DCL void FDECL(maybe_smudge_engr, (int, int, int, int));
25 STATIC_DCL void NDECL(domove_core);
27 #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
29 /* mode values for findtravelpath() */
30 #define TRAVP_TRAVEL 0
34 static anything tmp_anything;
40 tmp_anything = zeroany;
41 tmp_anything.a_uint = ui;
49 tmp_anything = zeroany;
50 tmp_anything.a_long = lng;
58 tmp_anything = zeroany;
59 tmp_anything.a_monst = mtmp;
67 tmp_anything = zeroany;
68 tmp_anything.a_obj = obj;
73 revive_nasty(x, y, msg)
77 register struct obj *otmp, *otmp2;
80 boolean revived = FALSE;
82 for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
83 otmp2 = otmp->nexthere;
84 if (otmp->otyp == CORPSE
85 && (is_rider(&mons[otmp->corpsenm])
86 || otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
87 /* move any living monster already at that location */
88 if ((mtmp = m_at(x, y)) && enexto(&cc, x, y, mtmp->data))
89 rloc_to(mtmp, cc.x, cc.y);
92 revived = revive_corpse(otmp);
96 /* this location might not be safe, if not, move revived monster */
99 if (mtmp && !goodpos(x, y, mtmp, 0)
100 && enexto(&cc, x, y, mtmp->data)) {
101 rloc_to(mtmp, cc.x, cc.y);
103 /* else impossible? */
112 register xchar rx, ry, sx, sy;
113 register struct obj *otmp;
114 register struct trap *ttmp;
115 register struct monst *mtmp;
117 sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */
118 while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
119 /* make sure that this boulder is visible as the top object */
120 if (otmp != level.objects[sx][sy])
121 movobj(otmp, sx, sy);
123 rx = u.ux + 2 * u.dx; /* boulder destination position */
124 ry = u.uy + 2 * u.dy;
126 if (Levitation || Is_airlevel(&u.uz)) {
128 feel_location(sx, sy);
130 You("don't have enough leverage to push %s.", the(xname(otmp)));
132 You("
\91Ì
\82ª
\95\82\82¢
\82Ä
\82¢
\82é
\82Ì
\82Å%s
\82ð
\89\9f\82¹
\82È
\82¢
\81D", the(xname(otmp)));
133 /* Give them a chance to climb over it? */
136 if (verysmall(youmonst.data) && !u.usteed) {
138 feel_location(sx, sy);
140 pline("You're too small to push that %s.", xname(otmp));
142 You("
\8f¬
\82³
\82·
\82¬
\82Ä%s
\82ð
\89\9f\82¹
\82È
\82¢
\81D",xname(otmp));
145 if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ)
146 && levl[rx][ry].typ != IRONBARS
147 && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy)
148 || doorless_door(rx, ry)) && !sobj_at(BOULDER, rx, ry)) {
152 /* KMH -- Sokoban doesn't let you push boulders diagonally */
153 if (Sokoban && u.dx && u.dy) {
155 feel_location(sx, sy);
157 pline("%s won't roll diagonally on this %s.",
159 pline("%s
\82Ì
\8fã
\82Å
\82Í%s
\82Í
\8eÎ
\82ß
\82É
\89\9f\82¹
\82È
\82¢
\81D",
160 The(xname(otmp)), surface(sx, sy));
165 if (revive_nasty(rx, ry, "You sense movement on the other side."))
167 if (revive_nasty(rx, ry, "
\94½
\91Î
\91¤
\82É
\93®
\82«
\82ð
\8a´
\82¶
\82½
\81D"))
170 if (mtmp && !noncorporeal(mtmp->data)
172 || !(ttmp && is_pit(ttmp->ttyp)))) {
173 boolean deliver_part1 = FALSE;
176 feel_location(sx, sy);
177 if (canspotmon(mtmp)) {
179 pline("There's %s on the other side.", a_monnam(mtmp));
181 pline("
\94½
\91Î
\91¤
\82É%s
\82ª
\82¢
\82é
\81D", a_monnam(mtmp));
182 deliver_part1 = TRUE;
185 You_hear("a monster behind %s.", the(xname(otmp)));
187 pline("%s
\82Ì
\94w
\8cã
\82É
\89ö
\95¨
\82Ì
\8bC
\94z
\82ª
\82·
\82é
\81D", the(xname(otmp)));
189 deliver_part1 = TRUE;
190 map_invisible(rx, ry);
193 char you_or_steed[BUFSZ];
197 u.usteed ? y_monnam(u.usteed) : "you");
200 u.usteed ? y_monnam(u.usteed) : "
\82 \82È
\82½");
203 pline("%s%s cannot move %s.",
205 ? "Perhaps that's why "
209 : upstart(you_or_steed),
214 /* "Perhaps that's why (you_or_steed) cannot move it."*/
215 /* "(You_or_steed) cannot move (otmp)."*/
217 pline("
\82½
\82Ô
\82ñ
\82±
\82ê
\82ª
\81C%s
\82ª
\82»
\82ê
\82ð
\93®
\82©
\82¹
\82È
\82¢
\97\9d\97R
\82¾
\81D",
220 pline("%s
\82Í%s
\82ð
\93®
\82©
\82¹
\82È
\82¢
\81D",
221 you_or_steed, xname(otmp));
229 /* if a trap operates on the boulder, don't attempt
230 to move any others at this location; return -1
231 if another boulder is in hero's way, or 0 if he
232 should advance to the vacated boulder position */
233 switch (ttmp->ttyp) {
236 obj_extract_self(otmp);
237 place_object(otmp, rx, ry);
240 pline("KAABLAMM!!! %s %s land mine.",
241 Tobjnam(otmp, "trigger"),
242 ttmp->madeby_u ? "your" : "a");
244 pline("
\82¿
\82ã
\82Ç
\81[
\82ñ
\81I
\81I%s
\82Å%s
\92n
\97\8b\82Ì
\8bN
\94\9a\83X
\83C
\83b
\83`
\82ª
\93ü
\82Á
\82½
\81D",
246 ttmp->madeby_u ? "
\82 \82È
\82½
\82Ì
\8ed
\8a|
\82¯
\82½" : "");
248 blow_up_landmine(ttmp);
249 /* if the boulder remains, it should fill the pit */
250 fill_pit(u.ux, u.uy);
253 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
258 obj_extract_self(otmp);
259 /* vision kludge to get messages right;
260 the pit will temporarily be seen even
261 if this is one among multiple boulders */
263 viz_array[ry][rx] |= IN_SIGHT;
265 if (!flooreffects(otmp, rx, ry, "fall")) {
267 if (!flooreffects(otmp, rx, ry, "
\97\8e\82¿
\82é")) {
268 place_object(otmp, rx, ry);
272 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
277 pline("Kerplunk! You no longer feel %s.",
279 pline("
\83h
\83T
\83b
\81I
\82 \82È
\82½
\82Í
\82à
\82¤%s
\82ð
\8a´
\82¶
\82ç
\82ê
\82È
\82¢
\81D",
283 pline("%s%s and %s a %s in the %s!",
284 Tobjnam(otmp, (ttmp->ttyp == TRAPDOOR)
287 (ttmp->ttyp == TRAPDOOR) ? "" : " into",
288 otense(otmp, "plug"),
289 (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
292 pline("%s
\82Í
\97\8e\82¿
\82Ä%s
\82Ì%s
\82ð
\96\84\82ß
\82½
\81I",
295 (ttmp->ttyp == TRAPDOOR) ? "
\97\8e\82µ
\94à" : "
\8c\8a");
300 levl[rx][ry].wall_info &= ~W_NONDIGGABLE;
301 levl[rx][ry].candig = 1;
304 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
307 int newlev = 0; /* lint suppression */
310 if (ttmp->ttyp == LEVEL_TELEP) {
311 newlev = random_teleport_level();
312 if (newlev == depth(&u.uz) || In_endgame(&u.uz))
313 /* trap didn't work; skip "disappears" message */
318 pline("%s pushes %s and suddenly it disappears!",
320 pline("%s
\82ª%s
\82ð
\89\9f\82·
\82Æ
\81C
\93Ë
\91R
\82»
\82ê
\82Í
\8fÁ
\96Å
\82µ
\82½
\81I",
321 upstart(y_monnam(u.usteed)), the(xname(otmp)));
324 You("push %s and suddenly it disappears!",
326 pline("
\82 \82È
\82½
\82ª%s
\82ð
\89\9f\82·
\82Æ
\81C
\93Ë
\91R
\82»
\82ê
\82Í
\8fÁ
\96Å
\82µ
\82½
\81I",
328 if (ttmp->ttyp == TELEP_TRAP) {
331 obj_extract_self(otmp);
332 add_to_migration(otmp);
333 get_level(&dest, newlev);
334 otmp->ox = dest.dnum;
335 otmp->oy = dest.dlevel;
336 otmp->owornmask = (long) MIGR_RANDOM;
339 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
342 break; /* boulder not affected by this trap */
346 if (closed_door(rx, ry))
348 if (boulder_hits_pool(otmp, rx, ry, TRUE))
351 * Re-link at top of fobj chain so that pile order is preserved
352 * when level is restored.
356 place_object(otmp, otmp->ox, otmp->oy);
360 #ifdef LINT /* static long lastmovetime; */
364 /* note: reset to zero after save/restore cycle */
365 static NEARDATA long lastmovetime;
369 if (moves > lastmovetime + 2 || moves < lastmovetime)
371 pline("With %s effort you move %s.",
372 throws_rocks(youmonst.data) ? "little"
376 pline("%s
\97Í
\82ð
\82±
\82ß
\82Ä%s
\82ð
\89\9f\82µ
\82½
\81D",
377 throws_rocks(youmonst.data) ? "
\8f
\82µ" : "
\82©
\82È
\82è",
380 exercise(A_STR, TRUE);
383 pline("%s moves %s.", upstart(y_monnam(u.usteed)),
386 pline("%s
\82Í%s
\82ð
\93®
\82©
\82µ
\82½
\81D", upstart(y_monnam(u.usteed)),
389 lastmovetime = moves;
392 /* Move the boulder *after* the message. */
393 if (glyph_is_invisible(levl[rx][ry].glyph))
394 unmap_object(rx, ry);
395 movobj(otmp, rx, ry); /* does newsym(rx,ry) */
397 feel_location(rx, ry);
398 feel_location(sx, sy);
406 pline("%s tries to move %s, but cannot.",
407 upstart(y_monnam(u.usteed)), the(xname(otmp)));
409 pline("%s
\82Í%s
\82ð
\93®
\82©
\82»
\82¤
\82Æ
\82µ
\82½
\82ª
\8fo
\97\88\82È
\82©
\82Á
\82½
\81D",
410 upstart(y_monnam(u.usteed)), the(xname(otmp)));
414 You("try to move %s, but in vain.", the(xname(otmp)));
416 You("%s
\82ð
\93®
\82©
\82»
\82¤
\82Æ
\82µ
\82½
\82ª
\81C
\82¾
\82ß
\82¾
\82Á
\82½
\81D", the(xname(otmp)));
418 feel_location(sx, sy);
420 if (throws_rocks(youmonst.data)) {
422 canpickup = (!Sokoban
423 /* similar exception as in can_lift():
424 when poly'd into a giant, you can
425 pick up a boulder if you have a free
426 slot or into the overflow ('#') slot
427 unless already carrying at least one */
428 && (inv_cnt(FALSE) < 52 || !carrying(BOULDER))),
429 willpickup = (canpickup && autopick_testobj(otmp, TRUE));
431 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
433 You("aren't skilled enough to %s %s from %s.",
434 willpickup ? "pick up" : "push aside",
435 the(xname(otmp)), y_monnam(u.usteed));
437 You("%s
\82É%s
\82ð%s
\82é
\82Ù
\82Ç
\8bZ
\97Ê
\82ª
\82È
\82¢
\81D",
438 y_monnam(u.usteed), the(xname(otmp)),
439 willpickup ? "
\8fE
\82í
\82¹" : "
\89\9f\82³
\82¹");
443 * willpickup: you easily pick it up
444 * canpickup: you could easily pick it up
445 * otherwise: you easily push it aside
448 pline("However, you %seasily %s.",
449 (willpickup || !canpickup) ? "" : "could ",
450 (willpickup || canpickup) ? "pick it up"
453 pline("
\82µ
\82©
\82µ
\81C
\82 \82È
\82½
\82Í
\8aÈ
\92P
\82É
\82»
\82ê
\82ð%s
\81D",
454 (willpickup || canpickup) ?
455 "
\8fE
\82¦
\82½" : "
\95Ê
\82Ì
\95û
\82É
\89\9f\82¹
\82½");
464 && (((!invent || inv_weight() <= -850)
465 && (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
466 && IS_ROCK(levl[sx][u.uy].typ))))
467 || verysmall(youmonst.data))) {
470 "However, you can squeeze yourself into a small opening.");
472 "
\82µ
\82©
\82µ
\81C
\82 \82È
\82½
\82Í
\8f¬
\82³
\82¢
\8c\84\8aÔ
\82É
\82±
\82¶
\93ü
\82Á
\82½
\81D");
485 * Chew on a wall, door, or boulder. [What about statues?]
486 * Returns TRUE if still eating, FALSE when done.
492 struct rm *lev = &levl[x][y];
493 struct obj *boulder = sobj_at(BOULDER, x, y);
494 const char *digtxt = (char *) 0, *dmgtxt = (char *) 0;
496 if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */
497 (void) memset((genericptr_t) &context.digging, 0,
498 sizeof (struct dig_info));
501 && ((IS_ROCK(lev->typ) && !may_dig(x, y))
502 /* may_dig() checks W_NONDIGGABLE but doesn't handle iron bars */
503 || (lev->typ == IRONBARS && (lev->wall_info & W_NONDIGGABLE)))) {
505 You("hurt your teeth on the %s.",
506 (lev->typ == IRONBARS)
512 You("%s
\82Å
\8e\95\82ð
\92É
\82ß
\82½
\81D",
513 (lev->typ == IRONBARS)
521 } else if (context.digging.pos.x != x || context.digging.pos.y != y
522 || !on_level(&context.digging.level, &u.uz)) {
523 context.digging.down = FALSE;
524 context.digging.chew = TRUE;
525 context.digging.warned = FALSE;
526 context.digging.pos.x = x;
527 context.digging.pos.y = y;
528 assign_level(&context.digging.level, &u.uz);
529 /* solid rock takes more work & time to dig through */
530 context.digging.effort =
531 (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
533 You("start chewing %s %s.",
534 (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS)
543 : (lev->typ == IRONBARS)
547 You("%s%s
\82Í
\82¶
\82ß
\82½
\81D",
554 : lev->typ == IRONBARS
557 (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS)
559 : "
\82É
\8c\8a\82ð
\82 \82¯");
561 watch_dig((struct monst *) 0, x, y, FALSE);
563 } else if ((context.digging.effort += (30 + u.udaminc)) <= 100) {
566 You("%s chewing on the %s.",
567 context.digging.chew ? "continue" : "begin",
574 : (lev->typ == IRONBARS)
578 You("%s
\82ð
\8a\9a\82Ý%s
\81D",
585 : lev->typ == IRONBARS
588 context.digging.chew ? "
\91±
\82¯
\82½" : "
\82Í
\82¶
\82ß
\82½");
590 context.digging.chew = TRUE;
591 watch_dig((struct monst *) 0, x, y, FALSE);
595 /* Okay, you've chewed through something */
597 u.uhunger += rnd(20);
600 delobj(boulder); /* boulder goes bye-bye */
602 You("eat the boulder."); /* yum */
604 You("
\8aâ
\82ð
\90H
\82×
\82½
\81D"); /* yum */
608 * The location could still block because of
609 * 1. More than one boulder
610 * 2. Boulder stuck in a wall/stone/door.
612 * [perhaps use does_block() below (from vision.c)]
614 if (IS_ROCK(lev->typ) || closed_door(x, y)
615 || sobj_at(BOULDER, x, y)) {
616 block_point(x, y); /* delobj will unblock the point */
617 /* reset dig state */
618 (void) memset((genericptr_t) &context.digging, 0,
619 sizeof (struct dig_info));
623 } else if (IS_WALL(lev->typ)) {
624 if (*in_rooms(x, y, SHOPBASE)) {
625 add_damage(x, y, SHOP_WALL_DMG);
629 dmgtxt = "
\8f\9d\82Â
\82¯
\82é";
632 digtxt = "chew a hole in the wall.";
634 digtxt = "
\95Ç
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
635 if (level.flags.is_maze_lev) {
637 } else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
641 lev->doormask = D_NODOOR;
643 } else if (IS_TREE(lev->typ)) {
645 digtxt = "chew through the tree.";
647 digtxt = "
\96Ø
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
649 } else if (lev->typ == IRONBARS) {
651 digtxt = "eat through the bars.";
653 digtxt = "
\93S
\82Ì
\96_
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
655 } else if (lev->typ == SDOOR) {
656 if (lev->doormask & D_TRAPPED) {
657 lev->doormask = D_NODOOR;
659 b_trapped("secret door", 0);
661 b_trapped("
\94é
\96§
\82Ì
\94à", 0);
664 digtxt = "chew through the secret door.";
666 digtxt = "
\94é
\96§
\82Ì
\94à
\82ð
\8a\9a\82Ý
\8dÓ
\82¢
\82½
\81D";
667 lev->doormask = D_BROKEN;
671 } else if (IS_DOOR(lev->typ)) {
672 if (*in_rooms(x, y, SHOPBASE)) {
673 add_damage(x, y, SHOP_DOOR_COST);
679 if (lev->doormask & D_TRAPPED) {
680 lev->doormask = D_NODOOR;
682 b_trapped("door", 0);
684 b_trapped("
\94à", 0);
687 digtxt = "chew through the door.";
689 digtxt = "
\94à
\82ð
\8dÓ
\82¢
\82½
\81D";
690 lev->doormask = D_BROKEN;
693 } else { /* STONE or SCORR */
695 digtxt = "chew a passage through the rock.";
697 digtxt = "
\8aâ
\82ð
\8a\9a\82Ý
\8dÓ
\82¢
\82Ä
\92Ê
\82è
\94²
\82¯
\82½
\81D";
701 unblock_point(x, y); /* vision */
704 You1(digtxt); /* after newsym */
706 pay_for_damage(dmgtxt, FALSE);
707 (void) memset((genericptr_t) &context.digging, 0,
708 sizeof (struct dig_info));
714 register struct obj *obj;
715 register xchar ox, oy;
717 /* optimize by leaving on the fobj chain? */
719 newsym(obj->ox, obj->oy);
720 place_object(obj, ox, oy);
725 static NEARDATA const char fell_on_sink[] = "fell onto a sink";
727 static NEARDATA const char fell_on_sink[] = "
\97¬
\82µ
\91ä
\82É
\97\8e\82¿
\82Ä";
732 register struct obj *obj;
734 boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS),
735 innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L),
736 /* to handle being chained to buried iron ball, trying to
737 levitate but being blocked, then moving onto adjacent sink;
738 no need to worry about being blocked by terrain because we
739 couldn't be over a sink at the same time */
740 blockd_lev = (BLevitation == I_SPECIAL),
741 ufall = (!innate_lev && !blockd_lev
742 && !(HFlying || EFlying)); /* BFlying */
746 You((innate_lev || blockd_lev) ? "wobble unsteadily for a moment."
748 You((innate_lev || blockd_lev) ? "
\82¿
\82å
\82Á
\82Æ
\82Ó
\82ç
\82Â
\82¢
\82½
\81D"
750 : "gain control of your flight.");
752 : "
\94ò
\8ds
\92\86\82Ì
\90§
\8cä
\82ð
\8eæ
\82è
\82à
\82Ç
\82µ
\82½
\81D");
754 long save_ELev = ELevitation, save_HLev = HLevitation;
756 /* fake removal of levitation in advance so that final
757 disclosure will be right in case this turns out to
758 be fatal; fortunately the fact that rings and boots
759 are really still worn has no effect on bones data */
760 ELevitation = HLevitation = 0L;
762 You("crash to the floor!");
764 You("
\8f°
\82É
\92@
\82«
\82Â
\82¯
\82ç
\82ê
\82½
\81I");
765 dmg = rn1(8, 25 - (int) ACURR(A_CON));
767 losehp(Maybe_Half_Phys(dmg), fell_on_sink, NO_KILLER_PREFIX);
769 losehp(Maybe_Half_Phys(dmg), fell_on_sink, KILLED_BY);
771 exercise(A_DEX, FALSE);
773 selftouch("Falling, you");
775 selftouch("
\97\8e\82¿
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í");
776 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
777 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
779 You("fell on %s.", doname(obj));
781 You("%s
\82Ì
\8fã
\82É
\97\8e\82¿
\82½
\81D",doname(obj));
783 losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink,
786 losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink,
789 exercise(A_CON, FALSE);
791 ELevitation = save_ELev;
792 HLevitation = save_HLev;
796 * Interrupt multi-turn putting on/taking off of armor (in which
797 * case we reached the sink due to being teleported while busy;
798 * in 3.4.3, Boots_on()/Boots_off() [called via (*afternmv)() when
799 * 'multi' reaches 0] triggered a crash if we were donning/doffing
800 * levitation boots [because the Boots_off() below causes 'uarmf'
801 * to be null by the time 'afternmv' gets called]).
803 * Interrupt donning/doffing if we fall onto the sink, or if the
804 * code below is going to remove levitation boots even when we
805 * haven't fallen (innate floating or flying becoming unblocked).
807 if (ufall || lev_boots) {
808 (void) stop_donning(lev_boots ? uarmf : (struct obj *) 0);
809 /* recalculate in case uarmf just got set to null */
810 lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS);
813 /* remove worn levitation items */
814 ELevitation &= ~W_ARTI;
815 HLevitation &= ~(I_SPECIAL | TIMEOUT);
817 if (uleft && uleft->otyp == RIN_LEVITATION) {
822 if (uright && uright->otyp == RIN_LEVITATION) {
833 /* probably moot; we're either still levitating or went
834 through float_down(), but make sure BFlying is up to date */
838 /* intended to be called only on ROCKs or TREEs */
843 struct rm *lev = &levl[x][y];
845 return (boolean) !((IS_STWALL(lev->typ) || IS_TREE(lev->typ))
846 && (lev->wall_info & W_NONDIGGABLE));
853 return (boolean) !(IS_STWALL(levl[x][y].typ)
854 && (levl[x][y].wall_info & W_NONPASSWALL));
859 struct permonst *mdat;
862 return (boolean) ((Sokoban && sobj_at(BOULDER, x, y))
863 || (IS_ROCK(levl[x][y].typ)
864 && (!tunnels(mdat) || needspick(mdat)
866 && !(passes_walls(mdat) && may_passwall(x, y))));
869 /* caller has already decided that it's a tight diagonal; check whether a
870 monster--who might be the hero--can fit through, and if not then return
871 the reason why: 1: can't fit, 2: possessions won't fit, 3: sokoban
872 returns 0 if we can squeeze through */
874 cant_squeeze_thru(mon)
878 struct permonst *ptr = mon->data;
882 && !(amorphous(ptr) || is_whirly(ptr) || noncorporeal(ptr)
883 || slithy(ptr) || can_fog(mon)))
886 /* lugging too much junk? */
887 amt = (mon == &youmonst) ? inv_weight() + weight_cap()
888 : curr_mon_load(mon);
892 /* Sokoban restriction applies to hero only */
893 if (mon == &youmonst && Sokoban)
896 /* can squeeze through */
904 return (boolean) (Invocation_lev(&u.uz)
905 && x == inv_pos.x && y == inv_pos.y);
908 /* return TRUE if (dx,dy) is an OK place to move
909 * mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP
912 test_move(ux, uy, dx, dy, mode)
918 register struct rm *tmpr = &levl[x][y];
919 register struct rm *ust;
921 context.door_opened = FALSE;
923 * Check for physical obstacles. First, the place we are going.
925 if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
926 if (Blind && mode == DO_MOVE)
928 if (Passes_walls && may_passwall(x, y)) {
930 } else if (Underwater) {
931 /* note: if water_friction() changes direction due to
932 turbulence, new target destination will always be water,
933 so we won't get here, hence don't need to worry about
934 "there" being somewhere the player isn't sure of */
937 pline("There is an obstacle there.");
939 pline("
\8fá
\8aQ
\95¨
\82ª
\82 \82é
\81D");
941 } else if (tmpr->typ == IRONBARS) {
942 if ((dmgtype(youmonst.data, AD_RUST)
943 || dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE
944 && still_chewing(x, y)) {
947 if (!(Passes_walls || passes_bars(youmonst.data))) {
948 if (mode == DO_MOVE && iflags.mention_walls)
950 You("cannot pass through the bars.");
952 You("
\93S
\82Ì
\96_
\82ð
\92Ê
\82è
\94²
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
955 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
957 if (mode == DO_MOVE && still_chewing(x, y))
959 } else if (flags.autodig && !context.run && !context.nopick && uwep
961 /* MRKR: Automatic digging when wielding the appropriate tool */
963 (void) use_pick_axe2(uwep);
966 if (mode == DO_MOVE) {
967 if (is_db_wall(x, y))
969 pline("That drawbridge is up!");
971 pline("
\92µ
\82Ë
\8b´
\82Í
\8fã
\82Á
\82Ä
\82¢
\82é
\81I");
972 /* sokoban restriction stays even after puzzle is solved */
973 else if (Passes_walls && !may_passwall(x, y)
974 && In_sokoban(&u.uz))
976 pline_The("Sokoban walls resist your ability.");
978 pline_The("
\91q
\8cÉ
\94Ô
\82Ì
\95Ç
\82Í
\82 \82È
\82½
\82Ì
\94\
\97Í
\82É
\92ï
\8dR
\82µ
\82½
\81D");
979 else if (iflags.mention_walls)
982 (IS_WALL(tmpr->typ) || tmpr->typ == SDOOR) ? "a wall"
983 : IS_TREE(tmpr->typ) ? "a tree"
986 pline("
\82±
\82ê
\82Í%s
\82¾
\81D",
987 (IS_WALL(tmpr->typ) || tmpr->typ == SDOOR) ? "
\95Ç"
988 : IS_TREE(tmpr->typ) ? "
\96Ø"
994 } else if (IS_DOOR(tmpr->typ)) {
995 if (closed_door(x, y)) {
996 if (Blind && mode == DO_MOVE)
1000 } else if (can_ooze(&youmonst)) {
1001 if (mode == DO_MOVE)
1003 You("ooze under the door.");
1005 You("
\83h
\83A
\82Ì
\89º
\82©
\82ç
\82É
\82¶
\82Ý
\8fo
\82½
\81D");
1006 } else if (Underwater) {
1007 if (mode == DO_MOVE)
1009 pline("There is an obstacle there.");
1011 pline("
\8fá
\8aQ
\95¨
\82ª
\82 \82é
\81D");
1013 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
1015 if (mode == DO_MOVE && still_chewing(x, y))
1018 if (mode == DO_MOVE) {
1019 if (amorphous(youmonst.data))
1022 "try to ooze under the door, but can't squeeze your possessions through.");
1024 "
\83h
\83A
\82Ì
\89º
\82©
\82ç
\82É
\82¶
\82Ý
\8fo
\82æ
\82¤
\82Æ
\82µ
\82½
\81C
\82µ
\82©
\82µ
\8e\9d\82¿
\95¨
\82Í
\82»
\82¤
\82Í
\82¢
\82©
\82È
\82¢
\81D");
1025 if (flags.autoopen && !context.run && !Confusion
1026 && !Stunned && !Fumbling) {
1027 context.door_opened = context.move =
1029 } else if (x == ux || y == uy) {
1030 if (Blind || Stunned || ACURR(A_DEX) < 10
1034 You_cant("lead %s through that closed door.",
1036 You_cant("%s
\82É
\95Â
\82Ü
\82Á
\82½
\94à
\82ð
\92Ê
\89ß
\82³
\82¹
\82é
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D",
1037 y_monnam(u.usteed));
1040 pline("Ouch! You bump into a door.");
1042 pline("
\82¢
\82Ä
\82Á
\81I
\93ª
\82ð
\94à
\82É
\82Ô
\82Â
\82¯
\82½
\81D");
1043 exercise(A_DEX, FALSE);
1047 pline("That door is closed.");
1049 pline("
\94à
\82Í
\95Â
\82Ü
\82Á
\82Ä
\82¢
\82é
\81D");
1051 } else if (mode == TEST_TRAV || mode == TEST_TRAP)
1057 if (dx && dy && !Passes_walls
1058 && (!doorless_door(x, y) || block_door(x, y))) {
1059 /* Diagonal moves into a door are not allowed. */
1060 if (mode == DO_MOVE) {
1062 feel_location(x, y);
1063 if (Underwater || iflags.mention_walls)
1065 You_cant("move diagonally into an intact doorway.");
1067 You_cant("
\89ó
\82ê
\82Ä
\82¢
\82È
\82¢
\94à
\82É
\8eÎ
\82ß
\82É
\88Ú
\93®
\82·
\82é
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D");
1073 if (dx && dy && bad_rock(youmonst.data, ux, y)
1074 && bad_rock(youmonst.data, x, uy)) {
1075 /* Move at a diagonal. */
1076 switch (cant_squeeze_thru(&youmonst)) {
1078 if (mode == DO_MOVE)
1080 You("cannot pass that way.");
1082 You("
\92Ê
\82è
\82Ê
\82¯
\82Å
\82«
\82È
\82¢
\81D");
1085 if (mode == DO_MOVE)
1087 You("are carrying too much to get through.");
1089 pline("
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\92Ê
\82è
\82Ê
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
1092 if (mode == DO_MOVE)
1094 Your("body is too large to fit through.");
1096 Your("
\91Ì
\82ª
\91å
\82«
\82·
\82¬
\82Ä
\92Ê
\82è
\82Ê
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
1099 break; /* can squeeze through */
1101 } else if (dx && dy && worm_cross(ux, uy, x, y)) {
1102 /* consecutive long worm segments are at <ux,y> and <x,uy> */
1103 if (mode == DO_MOVE)
1105 pline("%s is in your way.", Monnam(m_at(ux, y)));
1107 pline("
\93¹
\82Ì
\93r
\92\86\82É%s
\82ª
\82¢
\82é
\81D", Monnam(m_at(ux, y)));
1110 /* Pick travel path that does not require crossing a trap.
1111 * Avoid water and lava using the usual running rules.
1112 * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
1113 if (context.run == 8 && (mode != DO_MOVE)
1114 && (x != u.ux || y != u.uy)) {
1115 struct trap *t = t_at(x, y);
1118 || (!Levitation && !Flying && !is_clinger(youmonst.data)
1119 && is_pool_or_lava(x, y) && levl[x][y].seenv))
1120 return (mode == TEST_TRAP);
1123 if (mode == TEST_TRAP)
1124 return FALSE; /* do not move through traps */
1126 ust = &levl[ux][uy];
1128 /* Now see if other things block our way . . */
1129 if (dx && dy && !Passes_walls && IS_DOOR(ust->typ)
1130 && (!doorless_door(ux, uy) || block_entry(x, y))) {
1131 /* Can't move at a diagonal out of a doorway with door. */
1132 if (mode == DO_MOVE && iflags.mention_walls)
1134 You_cant("move diagonally out of an intact doorway.");
1136 You_cant("
\89ó
\82ê
\82Ä
\82¢
\82È
\82¢
\94à
\82©
\82ç
\8eÎ
\82ß
\82É
\88Ú
\93®
\82·
\82é
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D");
1140 if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) {
1141 if (!(Blind || Hallucination) && (context.run >= 2)
1142 && mode != TEST_TRAV) {
1143 if (mode == DO_MOVE && iflags.mention_walls)
1145 pline("A boulder blocks your path.");
1147 pline("
\8b\90\8aâ
\82ª
\93¹
\82ð
\82Ó
\82³
\82¢
\82Å
\82¢
\82é
\81D");
1150 if (mode == DO_MOVE) {
1151 /* tunneling monsters will chew before pushing */
1152 if (tunnels(youmonst.data) && !needspick(youmonst.data)
1154 if (still_chewing(x, y))
1156 } else if (moverock() < 0)
1158 } else if (mode == TEST_TRAV) {
1161 /* never travel through boulders in Sokoban */
1165 /* don't pick two boulders in a row, unless there's a way thru */
1166 if (sobj_at(BOULDER, ux, uy) && !Sokoban) {
1168 && !(tunnels(youmonst.data) && !needspick(youmonst.data))
1169 && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK)
1170 && !((obj = carrying(WAN_DIGGING))
1171 && !objects[obj->otyp].oc_name_known))
1175 /* assume you'll be able to push it when you get there... */
1178 /* OK, it is a legal place to move. */
1183 * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
1184 * A shortest path is returned. If guess is TRUE, consider various
1185 * inaccessible locations as valid intermediate path points.
1186 * Returns TRUE if a path was found.
1189 findtravelpath(mode)
1192 /* if travel to adjacent, reachable location, use normal movement rules */
1193 if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && context.travel1
1194 && distmin(u.ux, u.uy, u.tx, u.ty) == 1
1195 && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) {
1197 if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) {
1198 if (mode == TRAVP_TRAVEL) {
1202 iflags.travelcc.x = iflags.travelcc.y = 0;
1206 if (mode == TRAVP_TRAVEL)
1209 if (u.tx != u.ux || u.ty != u.uy) {
1210 xchar travel[COLNO][ROWNO];
1211 xchar travelstepx[2][COLNO * ROWNO];
1212 xchar travelstepy[2][COLNO * ROWNO];
1213 xchar tx, ty, ux, uy;
1214 int n = 1; /* max offset in travelsteps */
1215 int set = 0; /* two sets current and previous */
1216 int radius = 1; /* search radius */
1219 /* If guessing, first find an "obvious" goal location. The obvious
1220 * goal is the position the player knows of, or might figure out
1221 * (couldsee) that is closest to the target on a straight path.
1223 if (mode == TRAVP_GUESS || mode == TRAVP_VALID) {
1236 (void) memset((genericptr_t) travel, 0, sizeof travel);
1237 travelstepx[0][0] = tx;
1238 travelstepy[0][0] = ty;
1243 for (i = 0; i < n; i++) {
1245 int x = travelstepx[set][i];
1246 int y = travelstepy[set][i];
1247 static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
1248 /* no diagonal movement for grid bugs */
1249 int dirmax = NODIAG(u.umonnum) ? 4 : 8;
1250 boolean alreadyrepeated = FALSE;
1252 for (dir = 0; dir < dirmax; ++dir) {
1253 int nx = x + xdir[ordered[dir]];
1254 int ny = y + ydir[ordered[dir]];
1257 * When guessing and trying to travel as close as possible
1258 * to an unreachable target space, don't include spaces
1259 * that would never be picked as a guessed target in the
1260 * travel matrix describing hero-reachable spaces.
1261 * This stops travel from getting confused and moving
1262 * the hero back and forth in certain degenerate
1263 * configurations of sight-blocking obstacles, e.g.
1265 * T 1. Dig this out and carry enough to not be
1266 * #### able to squeeze through diagonal gaps.
1267 * #--.--- Stand at @ and target travel at space T.
1271 * T 2. couldsee() marks spaces marked a and x
1272 * #### as eligible guess spaces to move the hero
1273 * a--.--- towards. Space a is closest to T, so it
1274 * @xxxxx gets chosen. Travel system moves @ right
1275 * |xxxxx to travel to space a.
1277 * T 3. couldsee() marks spaces marked b, c and x
1278 * #### as eligible guess spaces to move the hero
1279 * a--c--- towards. Since findtravelpath() is called
1280 * b@xxxx repeatedly during travel, it doesn't
1281 * |xxxxx remember that it wanted to go to space a,
1282 * so in comparing spaces b and c, b is
1283 * chosen, since it seems like the closest
1284 * eligible space to T. Travel system moves @
1285 * left to go to space b.
1289 * By limiting the travel matrix here, space a in the
1290 * example above is never included in it, preventing
1294 || ((mode == TRAVP_GUESS) && !couldsee(nx, ny)))
1296 if ((!Passes_walls && !can_ooze(&youmonst)
1297 && closed_door(x, y)) || sobj_at(BOULDER, x, y)
1298 || test_move(x, y, nx-x, ny-y, TEST_TRAP)) {
1299 /* closed doors and boulders usually
1300 * cause a delay, so prefer another path */
1301 if (travel[x][y] > radius - 3) {
1302 if (!alreadyrepeated) {
1303 travelstepx[1 - set][nn] = x;
1304 travelstepy[1 - set][nn] = y;
1305 /* don't change travel matrix! */
1307 alreadyrepeated = TRUE;
1312 if (test_move(x, y, nx - x, ny - y, TEST_TRAV)
1313 && (levl[nx][ny].seenv
1314 || (!Blind && couldsee(nx, ny)))) {
1315 if (nx == ux && ny == uy) {
1316 if (mode == TRAVP_TRAVEL || mode == TRAVP_VALID) {
1319 if (mode == TRAVP_TRAVEL
1320 && x == u.tx && y == u.ty) {
1322 /* reset run so domove run checks work */
1324 iflags.travelcc.x = iflags.travelcc.y = 0;
1328 } else if (!travel[nx][ny]) {
1329 travelstepx[1 - set][nn] = nx;
1330 travelstepy[1 - set][nn] = ny;
1331 travel[nx][ny] = radius;
1339 if (iflags.trav_debug) {
1340 /* Use of warning glyph is arbitrary. It stands out. */
1341 tmp_at(DISP_ALL, warning_to_glyph(1));
1342 for (i = 0; i < nn; ++i) {
1343 tmp_at(travelstepx[1 - set][i], travelstepy[1 - set][i]);
1346 if (flags.runmode == RUN_CRAWL) {
1350 tmp_at(DISP_END, 0);
1359 /* if guessing, find best location in travel matrix and go there */
1360 if (mode == TRAVP_GUESS) {
1361 int px = tx, py = ty; /* pick location */
1362 int dist, nxtdist, d2, nd2;
1364 dist = distmin(ux, uy, tx, ty);
1365 d2 = dist2(ux, uy, tx, ty);
1366 for (tx = 1; tx < COLNO; ++tx)
1367 for (ty = 0; ty < ROWNO; ++ty)
1368 if (travel[tx][ty]) {
1369 nxtdist = distmin(ux, uy, tx, ty);
1370 if (nxtdist == dist && couldsee(tx, ty)) {
1371 nd2 = dist2(ux, uy, tx, ty);
1373 /* prefer non-zigzag path */
1378 } else if (nxtdist < dist && couldsee(tx, ty)) {
1382 d2 = dist2(ux, uy, tx, ty);
1386 if (px == u.ux && py == u.uy) {
1387 /* no guesses, just go in the general direction */
1388 u.dx = sgn(u.tx - u.ux);
1389 u.dy = sgn(u.ty - u.uy);
1390 if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
1395 if (iflags.trav_debug) {
1396 /* Use of warning glyph is arbitrary. It stands out. */
1397 tmp_at(DISP_ALL, warning_to_glyph(2));
1400 if (flags.runmode == RUN_CRAWL) {
1406 tmp_at(DISP_END, 0);
1415 mode = TRAVP_TRAVEL;
1429 is_valid_travelpt(x,y)
1435 int g = glyph_at(x,y);
1437 if (x == u.ux && y == u.uy)
1439 if (isok(x,y) && glyph_is_cmap(g) && S_stone == glyph_to_cmap(g)
1440 && !levl[x][y].seenv)
1444 ret = findtravelpath(TRAVP_VALID);
1450 /* try to escape being stuck in a trapped state by walking out of it;
1451 return true iff moving should continue to intended destination
1452 (all failures and most successful escapes leave hero at original spot) */
1454 trapmove(x, y, desttrap)
1455 int x, y; /* targetted destination, <u.ux+u.dx,u.uy+u.dy> */
1456 struct trap *desttrap; /* nonnull if another trap at <x,y> */
1458 boolean anchored = FALSE;
1459 const char *predicament, *culprit;
1460 char *steedname = !u.usteed ? (char *) 0 : y_monnam(u.usteed);
1463 return TRUE; /* sanity check */
1466 * Note: caller should call reset_utrap() when we set u.utrap to 0.
1469 switch (u.utraptype) {
1471 if (flags.verbose) {
1473 predicament = "caught in a bear trap";
1475 predicament = "
\8cF
\82Ìã©
\82É
\82Â
\82©
\82Ü
\82Á
\82½";
1478 Norep("%s is %s.", upstart(steedname), predicament);
1480 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1483 Norep("You are %s.", predicament);
1485 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1487 /* [why does diagonal movement give quickest escape?] */
1488 if ((u.dx && u.dy) || !rn2(5))
1494 if (desttrap && desttrap->tseen
1495 && is_pit(desttrap->ttyp))
1496 return TRUE; /* move into adjacent pit */
1497 /* try to escape; position stays same regardless of success */
1501 if (uwep && uwep->oartifact == ART_STING) {
1502 /* escape trap but don't move and don't destroy it */
1503 u.utrap = 0; /* caller will call reset_utrap() */
1505 pline("Sting cuts through the web!");
1507 pline("
\83X
\83e
\83B
\83\93\83O
\82Í
\82
\82à
\82Ì
\91\83\82ð
\90Ø
\82è
\82³
\82¢
\82½
\81I");
1511 if (flags.verbose) {
1513 predicament = "stuck to the web";
1515 predicament = "
\82
\82à
\82Ì
\91\83\82É
\82Ð
\82Á
\82©
\82©
\82Á
\82½";
1518 Norep("%s is %s.", upstart(steedname), predicament);
1520 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1523 Norep("You are %s.", predicament);
1525 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1530 pline("%s breaks out of the web.", upstart(steedname));
1532 pline("%s
\82Í
\82
\82à
\82Ì
\91\83\82ð
\89ó
\82µ
\82½
\81D", upstart(steedname));
1535 You("disentangle yourself.");
1537 You("
\8e©
\95ª
\82Å
\82Ù
\82Ç
\82¢
\82½
\81D");
1541 if (flags.verbose) {
1543 predicament = "stuck in the lava";
1545 predicament = "
\97n
\8aâ
\82É
\82Í
\82Ü
\82Á
\82½";
1548 Norep("%s is %s.", upstart(steedname), predicament);
1550 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1553 Norep("You are %s.", predicament);
1555 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1557 if (!is_lava(x, y)) {
1559 if ((u.utrap & 0xff) == 0) {
1563 You("lead %s to the edge of the %s.", steedname,
1566 You("%s
\82ð%s
\82Ì
\92[
\82Ü
\82Å
\93±
\82¢
\82½
\81D", steedname,
1567 hliquid("
\97n
\8aâ"));
1571 You("pull yourself to the edge of the %s.",
1574 You("%s
\82Ì
\92[
\82Ü
\82Å
\82©
\82ë
\82¤
\82¶
\82Ä
\81C
\82½
\82Ç
\82è
\82Â
\82¢
\82½
\81D",
1575 hliquid("
\97n
\8aâ"));
1583 anchored = (u.utraptype == TT_BURIEDBALL);
1587 cc.x = u.ux, cc.y = u.uy;
1588 /* can move normally within radius 1 of buried ball */
1589 if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) {
1590 /* ugly hack: we need to issue some message here
1591 in case "you are chained to the buried ball"
1592 was the most recent message given, otherwise
1593 our next attempt to move out of tether range
1594 after this successful move would have its
1595 can't-do-that message suppressed by Norep */
1598 Norep("You move within the chain's reach.");
1600 Norep("
\8d½
\82ª
\93Í
\82
\94Í
\88Í
\82É
\88Ú
\93®
\82Å
\82«
\82é
\81D");
1605 if (flags.verbose) {
1608 predicament = "chained to the";
1609 culprit = "buried ball";
1611 predicament = "
\82Æ
\82Â
\82È
\82ª
\82Á
\82Ä
\82¢
\82é";
1612 culprit = "
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é
\8b\85";
1616 predicament = "stuck in the";
1617 culprit = surface(u.ux, u.uy);
1619 predicament = "
\82É
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é";
1620 culprit = surface(u.ux, u.uy);
1626 Norep("You and %s are %s %s.", steedname, predicament,
1629 Norep("
\82 \82È
\82½
\82Æ%s
\82Í%s%s
\81D", steedname, culprit,
1634 Norep("%s is %s %s.", upstart(steedname), predicament,
1637 Norep("%s
\82Í%s%s
\81D", steedname, culprit,
1642 Norep("You are %s %s.", predicament, culprit);
1644 Norep("
\82 \82È
\82½
\82Í%s
\82É%s
\81D", culprit, predicament);
1650 pline("%s finally %s free.", upstart(steedname),
1651 !anchored ? "lurches" : "wrenches the ball");
1653 pline("%s
\82Í%s
\82â
\82Á
\82Æ
\8e©
\97R
\82É
\82È
\82Á
\82½
\81D", upstart(steedname),
1654 !anchored ? "
\82à
\82ª
\82¢
\82Ä" : "
\93S
\8b\85\82ð
\82à
\82¬
\8eæ
\82Á
\82Ä");
1658 You("finally %s free.",
1659 !anchored ? "wriggle" : "wrench the ball");
1661 You("%s
\82â
\82Á
\82Æ
\8e©
\97R
\82É
\82È
\82Á
\82½
\81D",
1662 !anchored ? "
\82à
\82ª
\82¢
\82Ä" : "
\93S
\8b\85\82ð
\82à
\82¬
\8eæ
\82Á
\82Ä");
1665 buried_ball_to_punishment();
1669 impossible("trapmove: stuck in unknown trap? (%d)",
1679 if (!youmonst.data->mmove) {
1681 You("are rooted %s.",
1682 Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
1686 You("
\82»
\82Ì
\8fê
\82É
\97§
\82¿
\82·
\82
\82ñ
\82¾
\81D");
1697 int ux1 = u.ux, uy1 = u.uy;
1699 domove_succeeded = 0L;
1701 /* domove_succeeded is available for making assessments now */
1702 if ((domove_succeeded & (DOMOVE_RUSH | DOMOVE_WALK)) != 0)
1703 maybe_smudge_engr(ux1, uy1, u.ux, u.uy);
1704 domove_attempting = 0L;
1710 register struct monst *mtmp;
1711 register struct rm *tmpr;
1712 register xchar x, y;
1713 struct trap *trap = NULL;
1716 xchar chainx = 0, chainy = 0,
1717 ballx = 0, bally = 0; /* ball&chain new positions */
1718 int bc_control = 0; /* control for ball&chain */
1719 boolean cause_delay = FALSE, /* dragging ball will skip a move */
1720 u_with_boulder = (sobj_at(BOULDER, u.ux, u.uy) != 0);
1722 if (context.travel) {
1723 if (!findtravelpath(FALSE))
1724 (void) findtravelpath(TRUE);
1725 context.travel1 = 0;
1728 if (((wtcap = near_capacity()) >= OVERLOADED
1729 || (wtcap > SLT_ENCUMBER
1730 && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
1731 : (u.uhp < 10 && u.uhp != u.uhpmax))))
1732 && !Is_airlevel(&u.uz)) {
1733 if (wtcap < OVERLOADED) {
1735 You("don't have enough stamina to move.");
1737 You("
\82Ö
\82Æ
\82Ö
\82Æ
\82Å
\93®
\82¯
\82È
\82¢
\81D");
1738 exercise(A_CON, FALSE);
1741 You("collapse under your load.");
1743 pline("
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\93|
\82ê
\82½
\81D");
1749 u.ux = x = u.ustuck->mx;
1750 u.uy = y = u.ustuck->my;
1753 if (Is_airlevel(&u.uz) && rn2(4) && !Levitation && !Flying) {
1757 You("tumble in place.");
1759 You("
\82»
\82Ì
\8fê
\82Å
\93|
\82ê
\82½
\81D");
1760 exercise(A_DEX, FALSE);
1764 You_cant("control your movements very well.");
1766 You("
\82¤
\82Ü
\82
\95à
\82¯
\82È
\82¢
\81D");
1770 pline("It's hard to walk in thin air.");
1772 pline("
\8bó
\92\86\82ð
\95à
\82
\82Ì
\82Í
\93ï
\82µ
\82¢
\81D");
1773 exercise(A_DEX, TRUE);
1779 /* check slippery ice */
1780 on_ice = !Levitation && is_ice(u.ux, u.uy);
1782 static int skates = 0;
1785 skates = find_skates();
1786 if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst)
1787 || Flying || is_floater(youmonst.data)
1788 || is_clinger(youmonst.data) || is_whirly(youmonst.data)) {
1790 } else if (!rn2(Cold_resistance ? 3 : 2)) {
1791 HFumbling |= FROMOUTSIDE;
1792 HFumbling &= ~TIMEOUT;
1793 HFumbling += 1; /* slip on next move */
1796 if (!on_ice && (HFumbling & FROMOUTSIDE))
1797 HFumbling &= ~FROMOUTSIDE;
1801 if (Stunned || (Confusion && !rn2(5))) {
1802 register int tries = 0;
1812 } while (!isok(x, y) || bad_rock(youmonst.data, x, y));
1814 /* turbulence might alter your actual destination */
1817 if (!u.dx && !u.dy) {
1824 /* are we trying to move out of water while carrying too much? */
1825 if (isok(x, y) && !is_pool(x, y) && !Is_waterlevel(&u.uz)
1826 && wtcap > (Swimming ? MOD_ENCUMBER : SLT_ENCUMBER)) {
1827 /* when escaping from drowning you need to be unencumbered
1828 in order to crawl out of water, but when not drowning,
1829 doing so while encumbered is feasible; if in an aquatic
1830 form, stressed or less is allowed; otherwise (magical
1831 breathing), only burdened is allowed */
1833 You("are carrying too much to climb out of the water.");
1835 You("
\90\85\82©
\82ç
\8fã
\82ª
\82é
\82É
\82Í
\89×
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\82¢
\82é
\81D");
1841 if (iflags.mention_walls) {
1842 int dx = u.dx, dy = u.dy;
1844 if (dx && dy) { /* diagonal */
1845 /* only as far as possible diagonally if in very
1846 corner; otherwise just report whichever of the
1847 cardinal directions has reached its limit */
1850 else if (isok(u.ux, y))
1854 You("have already gone as far %s as possible.",
1855 directionname(xytod(dx, dy)));
1857 You("
\82·
\82Å
\82É
\82Å
\82«
\82é
\82¾
\82¯%s
\82É
\93®
\82¢
\82Ä
\82¢
\82é
\81D",
1858 directionname(xytod(dx, dy)));
1864 if (((trap = t_at(x, y)) && trap->tseen)
1865 || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data)
1866 && is_pool_or_lava(x, y) && levl[x][y].seenv)) {
1867 if (context.run >= 2) {
1868 if (iflags.mention_walls) {
1869 if (trap && trap->tseen) {
1870 int tt = what_trap(trap->ttyp, rn2_on_display_rng);
1873 You("stop in front of %s.",
1875 You("%s
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
1876 an(defsyms[trap_to_defsym(tt)].explanation));
1877 } else if (is_pool_or_lava(x,y) && levl[x][y].seenv) {
1879 You("stop at the edge of the %s.",
1880 hliquid(is_pool(x,y) ? "water" : "lava"));
1882 You("%s
\82Ì
\92[
\82Å
\8e~
\82Ü
\82Á
\82½
\81D.",
1883 hliquid(is_pool(x,y) ? "
\90\85" : "
\97n
\8aâ"));
1894 if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
1895 if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
1896 /* perhaps it fled (or was teleported or ... ) */
1898 } else if (sticks(youmonst.data)) {
1899 /* When polymorphed into a sticking monster,
1900 * u.ustuck means it's stuck to you, not you to it.
1903 You("release %s.", mon_nam(u.ustuck));
1905 You("%s
\82ð
\95ú
\82µ
\82½
\81D", mon_nam(u.ustuck));
1908 /* If holder is asleep or paralyzed:
1909 * 37.5% chance of getting away,
1910 * 12.5% chance of waking/releasing it;
1912 * 7.5% chance of getting away.
1913 * [strength ought to be a factor]
1914 * If holder is tame and there is no conflict,
1915 * guaranteed escape.
1917 switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
1923 You("pull free from %s.", mon_nam(u.ustuck));
1925 You("%s
\82ð
\82Ð
\82«
\82Í
\82È
\82µ
\82½
\81D", mon_nam(u.ustuck));
1929 if (!u.ustuck->mcanmove) {
1930 /* it's free to move on next turn */
1931 u.ustuck->mfrozen = 1;
1932 u.ustuck->msleeping = 0;
1936 if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf)
1939 You("cannot escape from %s!", mon_nam(u.ustuck));
1941 You("%s
\82©
\82ç
\93¦
\82°
\82ç
\82ê
\82È
\82¢
\81I", mon_nam(u.ustuck));
1949 if (mtmp && !is_safepet(mtmp)) {
1950 /* Don't attack if you're running, and can see it */
1951 /* It's fine to displace pets, though */
1952 /* We should never get here if forcefight */
1953 if (context.run && ((!Blind && mon_visible(mtmp)
1954 && ((M_AP_TYPE(mtmp) != M_AP_FURNITURE
1955 && M_AP_TYPE(mtmp) != M_AP_OBJECT)
1956 || Protection_from_shape_changers))
1957 || sensemon(mtmp))) {
1971 /* attack monster */
1973 /* don't stop travel when displacing pets; if the
1974 displace fails for some reason, attack() in uhitm.c
1975 will stop travel rather than domove */
1976 if (!is_safepet(mtmp) || context.forcefight)
1978 /* only attack if we know it's there */
1979 /* or if we used the 'F' command to fight blindly */
1980 /* or if it hides_under, in which case we call attack() to print
1981 * the Wait! message.
1982 * This is different from ceiling hiders, who aren't handled in
1986 /* If they used a 'm' command, trying to move onto a monster
1987 * prints the below message and wastes a turn. The exception is
1988 * if the monster is unseen and the player doesn't remember an
1989 * invisible monster--then, we fall through to attack() and
1990 * attack_check(), which still wastes a turn, but prints a
1991 * different message and makes the player remember the monster.
1993 if (context.nopick && !context.travel
1994 && (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))) {
1995 if (M_AP_TYPE(mtmp) && !Protection_from_shape_changers
1997 stumble_onto_mimic(mtmp);
1998 else if (mtmp->mpeaceful && !Hallucination)
1999 /* m_monnam(): "dog" or "Fido", no "invisible dog" or "it" */
2001 pline("Pardon me, %s.", m_monnam(mtmp));
2003 pline("
\82¿
\82å
\82Á
\82Æ
\82²
\82ß
\82ñ
\82È
\82³
\82¢
\82æ
\81C%s
\82³
\82ñ
\81D", m_monnam(mtmp));
2006 You("move right into %s.", mon_nam(mtmp));
2008 You("%s
\82Ì
\82»
\82Î
\82É
\88Ú
\93®
\82µ
\82½
\81D", mon_nam(mtmp));
2011 if (context.forcefight || !mtmp->mundetected || sensemon(mtmp)
2012 || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)
2013 && !is_safepet(mtmp))) {
2014 /* try to attack; note that it might evade */
2015 /* also, we don't attack tame when _safepet_ */
2021 if (context.forcefight && levl[x][y].typ == IRONBARS && uwep) {
2022 struct obj *obj = uwep;
2024 if (breaktest(obj)) {
2026 obj = splitobj(obj, 1L);
2028 setuwep((struct obj *)0);
2031 hit_bars(&obj, u.ux, u.uy, x, y, TRUE, TRUE);
2035 /* specifying 'F' with no monster wastes a turn */
2036 if (context.forcefight
2037 /* remembered an 'I' && didn't use a move command */
2038 || (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) {
2039 struct obj *boulder = 0;
2040 boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)),
2041 solid = !accessible(x, y);
2042 int glyph = glyph_at(x, y); /* might be monster */
2046 boulder = sobj_at(BOULDER, x, y);
2047 /* if a statue is displayed at the target location,
2048 player is attempting to attack it [and boulder
2049 handling below is suitable for handling that] */
2050 if (glyph_is_statue(glyph)
2051 || (Hallucination && glyph_is_monster(glyph)))
2052 boulder = sobj_at(STATUE, x, y);
2054 /* force fight at boulder/statue or wall/door while wielding
2055 pick: start digging to break the boulder or wall */
2056 if (context.forcefight
2058 && uwep && dig_typ(uwep, x, y)
2059 /* should we dig? */
2060 && !glyph_is_invisible(glyph) && !glyph_is_monster(glyph)) {
2061 (void) use_pick_axe2(uwep);
2066 /* about to become known empty -- remove 'I' if present */
2069 map_object(boulder, TRUE);
2071 glyph = glyph_at(x, y); /* might have just changed */
2074 Strcpy(buf, ansimpleoname(boulder));
2075 } else if (Underwater && !is_pool(x, y)) {
2076 /* Underwater, targetting non-water; the map just shows blank
2077 because you don't see remembered terrain while underwater;
2078 although the hero can attack an adjacent monster this way,
2079 assume he can't reach out far enough to distinguish terrain */
2081 Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR)
2085 Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR)
2086 ? "
\8bó
\8bC
\82Ì
\96A"
2087 : "
\89½
\82à
\82È
\82¢
\82Æ
\82±
\82ë");
2090 /* glyph might indicate unseen terrain if hero is blind;
2091 unlike searching, this won't reveal what that terrain is
2092 (except for solid rock, where the glyph would otherwise
2093 yield ludicrous "dark part of a room") */
2095 Strcpy(buf, (levl[x][y].typ == STONE) ? "solid rock"
2096 : glyph_is_cmap(glyph)
2097 ? the(defsyms[glyph_to_cmap(glyph)].explanation)
2098 : (const char *) "an unknown obstacle");
2100 Strcpy(buf, (levl[x][y].typ == STONE) ? "
\90Î"
2101 : glyph_is_cmap(glyph)
2102 ? the(defsyms[glyph_to_cmap(glyph)].explanation)
2103 : (const char *) "
\95s
\96¾
\82È
\8fá
\8aQ
\95¨");
2105 /* note: 'solid' is misleadingly named and catches pools
2106 of water and lava as well as rock and walls */
2109 Strcpy(buf, "thin air");
2111 Strcpy(buf, "
\89½
\82à
\82È
\82¢
\8bó
\92\86");
2115 !(boulder || solid) ? "" : !explo ? "harmlessly " : "futilely ",
2116 explo ? "explode at" : "attack", buf);
2119 !(boulder || solid) ? "" : !explo ? "
\8cø
\89Ê
\82È
\82" : "
\82Þ
\82¾
\82É",
2120 buf, explo ? "
\82Å
\94\9a\94
\82µ
\82½" : "
\82ð
\8dU
\8c\82\82µ
\82½");
2126 u.mh = -1; /* dead in the current form */
2131 (void) unmap_invisible(x, y);
2132 /* not attacking an animal, so we try to move */
2133 if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) {
2142 boolean moved = trapmove(x, y, trap);
2145 reset_utrap(TRUE); /* might resume levitation or flight */
2146 /* might not have escaped, or did escape but remain in same spot */
2151 if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) {
2152 if (!context.door_opened) {
2159 /* Move ball and chain. */
2161 if (!drag_ball(x, y, &bc_control, &ballx, &bally, &chainx, &chainy,
2162 &cause_delay, TRUE))
2165 /* Check regions entering/leaving */
2166 if (!in_out_region(x, y))
2169 /* now move the hero */
2173 /* Move your steed, too */
2175 u.usteed->mx = u.ux;
2176 u.usteed->my = u.uy;
2181 * If safepet at destination then move the pet to the hero's
2182 * previous location using the same conditions as in attack().
2183 * there are special extenuating circumstances:
2184 * (1) if the pet dies then your god angers,
2185 * (2) if the pet gets trapped then your god may disapprove,
2186 * (3) if the pet was already trapped and you attempt to free it
2187 * not only do you encounter the trap but you may frighten your
2188 * pet causing it to go wild! moral: don't abuse this privilege.
2190 * Ceiling-hiding pets are skipped by this section of code, to
2191 * be caught by the normal falling-monster code.
2193 if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
2194 /* if trapped, there's a chance the pet goes wild */
2195 if (mtmp->mtrapped) {
2196 if (!rn2(mtmp->mtame)) {
2197 mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
2199 m_unleash(mtmp, TRUE);
2206 /* seemimic/newsym should be done before moving hero, otherwise
2207 the display code will draw the hero here before we possibly
2208 cancel the swap below (we can ignore steed mx,my here) */
2209 u.ux = u.ux0, u.uy = u.uy0;
2210 mtmp->mundetected = 0;
2211 if (M_AP_TYPE(mtmp))
2213 else if (!mtmp->mtame)
2214 newsym(mtmp->mx, mtmp->my);
2215 u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */
2217 if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0
2218 && is_pit(trap->ttyp)
2219 && sobj_at(BOULDER, trap->tx, trap->ty)) {
2220 /* can't swap places with pet pinned in a pit by a boulder */
2221 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
2223 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2224 } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
2225 /* can't swap places when pet can't move to your spot */
2226 u.ux = u.ux0, u.uy = u.uy0;
2228 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2230 You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp)));
2232 You("
\8e~
\82Ü
\82Á
\82½
\81D%s
\82Í
\8eÎ
\82ß
\82É
\93®
\82¯
\82È
\82¢
\81D", upstart(y_monnam(mtmp)));
2233 } else if (u_with_boulder
2234 && !(verysmall(mtmp->data)
2235 && (!mtmp->minvent || (curr_mon_load(mtmp) <= 600)))) {
2236 /* can't swap places when pet won't fit there with the boulder */
2237 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
2239 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2241 You("stop. %s won't fit into the same spot that you're at.",
2242 upstart(y_monnam(mtmp)));
2244 You("
\8e~
\82Ü
\82Á
\82½
\81D%s
\82Í
\82 \82È
\82½
\82Ì
\82¢
\82é
\82Ì
\82Æ
\93¯
\82¶
\8fê
\8f\8a\82É
\82Í
\8eû
\82Ü
\82ç
\82È
\82¢
\81D",
2247 } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0)
2248 && bad_rock(mtmp->data, u.ux0, y)
2249 && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
2250 /* can't swap places when pet won't fit thru the opening */
2251 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
2253 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2255 You("stop. %s won't fit through.", upstart(y_monnam(mtmp)));
2257 You("
\8e~
\82Ü
\82Á
\82½
\81D%s
\82Í
\92Ê
\82è
\94²
\82¯
\82ç
\82ê
\82È
\82¢
\81D", upstart(y_monnam(mtmp)));
2259 char pnambuf[BUFSZ];
2261 /* save its current description in case of polymorph */
2262 Strcpy(pnambuf, y_monnam(mtmp));
2264 remove_monster(x, y);
2265 place_monster(mtmp, u.ux0, u.uy0);
2267 newsym(u.ux0, u.uy0);
2270 You("%s %s.", mtmp->mtame ? "swap places with" : "frighten",
2275 mtmp->mtame ? "
\82Æ
\8fê
\8f\8a\82ð
\93ü
\82ê
\8a·
\82í
\82Á" : "
\82ð
\95|
\82ª
\82ç
\82¹");
2278 /* check for displacing it into pools and traps */
2279 switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
2282 case 1: /* trapped */
2283 case 3: /* changed levels */
2284 /* there's already been a trap message, reinforce it */
2289 /* drowned or died...
2290 * you killed your pet by direct action, so get experience
2291 * and possibly penalties;
2292 * we want the level gain message, if it happens, to occur
2293 * before the guilt message below
2296 /* minliquid() and mintrap() call mondead() rather than
2297 killed() so we duplicate some of the latter here */
2300 u.uconduct.killer++;
2301 mndx = monsndx(mtmp->data);
2302 tmp = experience(mtmp, (int) mvitals[mndx].died);
2303 more_experienced(tmp, 0);
2304 newexplevel(); /* will decide if you go up */
2306 /* That's no way to treat a pet! Your god gets angry.
2308 * [This has always been pretty iffy. Why does your
2309 * patron deity care at all, let alone enough to get mad?]
2313 You_feel("guilty about losing your pet like this.");
2315 pline("
\82±
\82Ì
\82æ
\82¤
\82È
\8c`
\82Å
\83y
\83b
\83g
\82ð
\8e¸
\82¤
\82Æ
\82Í
\8dß
\90[
\82¢
\82±
\82Æ
\82¾
\82Æ
\8ev
\82Á
\82½
\81D");
2321 pline("that's strange, unknown mintrap result!");
2327 reset_occupations();
2329 if (context.run < 8)
2330 if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ)
2331 || IS_FURNITURE(tmpr->typ))
2335 if (hides_under(youmonst.data) || youmonst.data->mlet == S_EEL
2337 (void) hideunder(&youmonst);
2340 * Mimics (or whatever) become noticeable if they move and are
2341 * imitating something that doesn't move. We could extend this
2342 * to non-moving monsters...
2344 if ((u.dx || u.dy) && (U_AP_TYPE == M_AP_OBJECT
2345 || U_AP_TYPE == M_AP_FURNITURE))
2346 youmonst.m_ap_type = M_AP_NOTHING;
2348 check_leash(u.ux0, u.uy0);
2350 if (u.ux0 != u.ux || u.uy0 != u.uy) {
2351 /* let caller know so that an evaluation may take place */
2352 domove_succeeded |= (domove_attempting & (DOMOVE_RUSH | DOMOVE_WALK));
2354 /* Clean old position -- vision_recalc() will print our new one. */
2355 newsym(u.ux0, u.uy0);
2356 /* Since the hero has moved, adjust what can be seen/unseen. */
2357 vision_recalc(1); /* Do the work now in the recover time. */
2358 invocation_message();
2361 if (Punished) /* put back ball and chain */
2362 move_bc(0, bc_control, ballx, bally, chainx, chainy);
2367 /* delay next move because of ball dragging */
2368 /* must come after we finished picking up, in spoteffects() */
2372 multi_reason = "dragging an iron ball";
2374 multi_reason = "
\93S
\8b\85\82É
\88ø
\82«
\82¸
\82ç
\82ê
\82Ä
\82¢
\82é
\8e\9e\82É";
2378 if (context.run && flags.runmode != RUN_TPORT) {
2379 /* display every step or every 7th step depending upon mode */
2380 if (flags.runmode != RUN_LEAP || !(moves % 7L)) {
2385 if (flags.runmode == RUN_CRAWL) {
2396 maybe_smudge_engr(x1,y1,x2,y2)
2401 if (can_reach_floor(TRUE)) {
2402 if ((ep = engr_at(x1, y1)) && ep->engr_type != HEADSTONE)
2403 wipe_engr_at(x1, y1, rnd(5), FALSE);
2404 if ((x2 != x1 || y2 != y1)
2405 && (ep = engr_at(x2, y2)) && ep->engr_type != HEADSTONE)
2406 wipe_engr_at(x2, y2, rnd(5), FALSE);
2410 /* combat increases metabolism */
2414 /* this used to be part of domove() when moving to a monster's
2415 position, but is now called by attack() so that it doesn't
2416 execute if you decline to attack a peaceful monster */
2418 if ((moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) {
2419 int *hp = (!Upolyd ? &u.uhp : &u.mh);
2425 You("pass out from exertion!");
2427 You("
\8bC
\90â
\82µ
\82½
\81D");
2428 exercise(A_CON, FALSE);
2429 fall_asleep(-10, FALSE);
2432 return (boolean) (multi < 0); /* might have fainted (forced to sleep) */
2436 invocation_message()
2438 /* a special clue-msg when on the Invocation position */
2439 if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
2441 struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
2443 nomul(0); /* stop running or travelling */
2446 Sprintf(buf, "beneath %s", y_monnam(u.usteed));
2448 Sprintf(buf, "%s
\82Ì
\89º
\82É", y_monnam(u.usteed));
2449 else if (Levitation || Flying)
2451 Strcpy(buf, "beneath you");
2453 Strcpy(buf, "
\89º
\95û
\82É");
2456 Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
2458 Strcpy(buf, "
\91«
\8c³
\82É");
2461 You_feel("a strange vibration %s.", buf);
2463 You("%s
\8aï
\96
\82È
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D", buf);
2464 u.uevent.uvibrated = 1;
2465 if (otmp && otmp->spe == 7 && otmp->lamplit)
2467 pline("%s %s!", The(xname(otmp)),
2468 Blind ? "throbs palpably" : "glows with a strange light");
2470 pline("%s
\82Í%s
\82µ
\82½
\81I", The(xname(otmp)),
2471 Blind ? "
\82©
\82·
\82©
\82É
\90U
\93®" : "
\8aï
\96
\82È
\8cõ
\82ð
\94");
2476 /* moving onto different terrain;
2477 might be going into solid rock, inhibiting levitation or flight,
2478 or coming back out of such, reinstating levitation/flying */
2482 struct rm *lev = &levl[u.ux][u.uy];
2483 boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy)
2484 || (Is_waterlevel(&u.uz) && lev->typ == WATER)),
2485 was_levitating = !!Levitation, was_flying = !!Flying;
2488 /* called from spoteffects(), stop levitating but skip float_down() */
2491 You_cant("levitate in here.");
2493 You_cant("
\82±
\82±
\82Å
\82Í
\95\82\97V
\82Å
\82«
\82È
\82¢
\81D");
2494 BLevitation |= FROMOUTSIDE;
2495 } else if (BLevitation) {
2496 BLevitation &= ~FROMOUTSIDE;
2497 /* we're probably levitating now; if not, we must be chained
2498 to a buried iron ball so get float_up() feedback for that */
2499 if (Levitation || BLevitation)
2502 /* the same terrain that blocks levitation also blocks flight */
2506 You_cant("fly in here.");
2508 You_cant("
\82±
\82±
\82Å
\82Í
\94ò
\82×
\82È
\82¢
\81D");
2509 BFlying |= FROMOUTSIDE;
2510 } else if (BFlying) {
2511 BFlying &= ~FROMOUTSIDE;
2512 float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
2513 /* [minor bug: we don't know whether this is beginning flight or
2514 resuming it; that could be tracked so that this message could
2515 be adjusted to "resume flying", but isn't worth the effort...] */
2518 You("start flying.");
2520 You("
\94ò
\82Ñ
\82Í
\82¶
\82ß
\82½
\81D");
2522 if ((!Levitation ^ was_levitating) || (!Flying ^ was_flying))
2523 context.botl = TRUE; /* update Lev/Fly status condition */
2526 /* extracted from spoteffects; called by spoteffects to check for entering or
2527 leaving a pool of water/lava, and by moveloop to check for staying on one;
2528 returns true to skip rest of spoteffects */
2530 pooleffects(newspot)
2531 boolean newspot; /* true if called by spoteffects */
2533 /* check for leaving water */
2535 boolean still_inwater = FALSE; /* assume we're getting out */
2537 if (!is_pool(u.ux, u.uy)) {
2538 if (Is_waterlevel(&u.uz))
2540 You("pop into an air bubble.");
2542 You("
\82Ð
\82å
\82¢
\82Æ
\8bó
\8bC
\82Ì
\96A
\82É
\93ü
\82Á
\82½
\81D");
2543 else if (is_lava(u.ux, u.uy))
2545 You("leave the %s...", hliquid("water")); /* oops! */
2547 You("%s
\90\85\82©
\82ç
\94²
\82¯
\82¾
\82µ
\82½
\81D
\81D
\81D", hliquid("
\90\85")); /* oops! */
2551 You("are on solid %s again.",
2552 is_ice(u.ux, u.uy) ? "ice" : "land");
2554 You("
\8cÅ
\82¢%s
\82Ì
\8fã
\82É
\82Ü
\82½
\96ß
\82Á
\82½
\81D",
2555 is_ice(u.ux, u.uy) ? "
\95X" : "
\92n
\96Ê");
2557 } else if (Is_waterlevel(&u.uz)) {
2558 still_inwater = TRUE;
2559 } else if (Levitation) {
2561 You("pop out of the %s like a cork!", hliquid("water"));
2563 You("
\83R
\83\8b\83N
\82Ì
\82æ
\82¤
\82É%s
\82©
\82ç
\94ò
\82Ñ
\82¾
\82µ
\82½
\81I", hliquid("
\90\85"));
2564 } else if (Flying) {
2566 You("fly out of the %s.", hliquid("water"));
2568 You("%s
\82©
\82ç
\94ò
\82Ñ
\82¾
\82µ
\82½
\81D", hliquid("
\90\85"));
2569 } else if (Wwalking) {
2571 You("slowly rise above the surface.");
2573 You("
\82ä
\82Á
\82
\82è
\90\85\96Ê
\82Ü
\82Å
\8fã
\82ª
\82Á
\82½
\81D");
2575 still_inwater = TRUE;
2577 if (!still_inwater) {
2578 boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz));
2580 u.uinwater = 0; /* leave the water */
2581 if (was_underwater) { /* restore vision */
2583 vision_full_recalc = 1;
2588 /* check for entering water or lava */
2589 if (!u.ustuck && !Levitation && !Flying && is_pool_or_lava(u.ux, u.uy)) {
2591 && (is_flyer(u.usteed->data) || is_floater(u.usteed->data)
2592 || is_clinger(u.usteed->data))) {
2593 /* floating or clinging steed keeps hero safe (is_flyer() test
2594 is redundant; it can't be true since Flying yielded false) */
2596 } else if (u.usteed) {
2597 /* steed enters pool */
2598 dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC);
2599 /* dismount_steed() -> float_down() -> pickup()
2600 (float_down doesn't do autopickup on Air or Water) */
2601 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
2603 /* even if we actually end up at same location, float_down()
2604 has already done spoteffect()'s trap and pickup actions */
2606 check_special_room(FALSE); /* spoteffects */
2611 /* if hiding on ceiling then don't automatically enter pool */
2612 if (Upolyd && ceiling_hider(&mons[u.umonnum]) && u.uundetected)
2615 /* drown(),lava_effects() return true if hero changes
2616 location while surviving the problem */
2617 if (is_lava(u.ux, u.uy)) {
2620 } else if (!Wwalking
2621 && (newspot || !u.uinwater || !(Swimming || Amphibious))) {
2633 static int inspoteffects = 0;
2634 static coord spotloc;
2635 static int spotterrain;
2636 static struct trap *spottrap = (struct trap *) 0;
2637 static unsigned spottraptyp = NO_TRAP;
2640 struct trap *trap = t_at(u.ux, u.uy);
2641 int trapflag = iflags.failing_untrap ? FAILEDUNTRAP : 0;
2643 /* prevent recursion from affecting the hero all over again
2644 [hero poly'd to iron golem enters water here, drown() inflicts
2645 damage that triggers rehumanize() which calls spoteffects()...] */
2646 if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y
2647 /* except when reason is transformed terrain (ice -> water) */
2648 && spotterrain == levl[u.ux][u.uy].typ
2649 /* or transformed trap (land mine -> pit) */
2650 && (!spottrap || !trap || trap->ttyp == spottraptyp))
2654 spotterrain = levl[u.ux][u.uy].typ;
2655 spotloc.x = u.ux, spotloc.y = u.uy;
2657 /* moving onto different terrain might cause Lev or Fly to toggle */
2658 if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0))
2661 if (pooleffects(TRUE))
2664 check_special_room(FALSE);
2665 if (IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
2667 if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
2670 /* if levitation is due to time out at the end of this
2671 turn, allowing it to do so could give the perception
2672 that a trap here is being triggered twice, so adjust
2673 the timeout to prevent that */
2674 if (trap && (HLevitation & TIMEOUT) == 1L
2675 && !(ELevitation || (HLevitation & ~(I_SPECIAL | TIMEOUT)))) {
2676 if (rn2(2)) { /* defer timeout */
2677 incr_itimeout(&HLevitation, 1L);
2678 } else { /* timeout early */
2679 if (float_down(I_SPECIAL | TIMEOUT, 0L)) {
2680 /* levitation has ended; we've already triggered
2681 any trap and [usually] performed autopickup */
2688 * If not a pit, pickup before triggering trap.
2689 * If pit, trigger trap before pickup.
2691 pit = (trap && is_pit(trap->ttyp));
2697 * dotrap on a fire trap calls melt_ice() which triggers
2698 * spoteffects() (again) which can trigger the same fire
2699 * trap (again). Use static spottrap to prevent that.
2700 * We track spottraptyp because some traps morph
2701 * (landmine to pit) and any new trap type
2702 * should get triggered.
2704 if (!spottrap || spottraptyp != trap->ttyp) {
2706 spottraptyp = trap->ttyp;
2707 dotrap(trap, trapflag); /* fall into arrow trap, etc. */
2708 spottrap = (struct trap *) 0;
2709 spottraptyp = NO_TRAP;
2715 /* Warning alerts you to ice danger */
2716 if (Warning && is_ice(u.ux, u.uy)) {
2717 static const char *const icewarnings[] = {
2719 "The ice seems very soft and slushy.",
2720 "You feel the ice shift beneath you!",
2721 "The ice, is gonna BREAK!", /* The Dead Zone */
2723 "
\95X
\82Í
\82Æ
\82Ä
\82à
\93î
\82ç
\82©
\82
\82Ä
\97n
\82¯
\82»
\82¤
\82¾
\81D",
2724 "
\82 \82È
\82½
\82Ì
\89º
\82Ì
\95X
\82ª
\93®
\82¢
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I",
2725 "
\95X
\82ª
\89ó
\82ê
\82é
\82¼
\81I", /* The Dead Zone */
2728 long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY);
2730 if (time_left && time_left < 15L)
2731 pline("%s", icewarnings[(time_left < 5L) ? 2
2732 : (time_left < 10L) ? 1
2735 if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
2736 mtmp->mundetected = mtmp->msleeping = 0;
2737 switch (mtmp->data->mlet) {
2740 pline("%s suddenly drops from the %s!", Amonnam(mtmp),
2741 ceiling(u.ux, u.uy));
2743 pline("%s
\82ª
\93Ë
\91R%s
\82©
\82ç
\97\8e\82¿
\82Ä
\82«
\82½
\81I", Amonnam(mtmp),
2744 ceiling(u.ux,u.uy));
2746 if (mtmp->mtame) { /* jumps to greet you, not attack */
2748 } else if (uarmh && is_metallic(uarmh)) {
2750 pline("Its blow glances off your %s.",
2752 pline("
\8dU
\8c\82\82Í
\82 \82È
\82½
\82Ì%s
\82ð
\82©
\82·
\82ß
\82½
\82¾
\82¯
\82¾
\82Á
\82½
\81D",
2753 helm_simple_name(uarmh));
2754 } else if (u.uac + 3 <= rnd(20)) {
2756 You("are almost hit by %s!",
2757 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
2759 You("
\97\8e\82¿
\82Ä
\82«
\82½%s
\82É
\82à
\82¤
\8f
\82µ
\82Å
\93\96\82½
\82é
\82Æ
\82±
\82ë
\82¾
\82Á
\82½
\81D",
2760 x_monnam(mtmp, ARTICLE_A, "", 0, TRUE));
2766 You("are hit by %s!",
2767 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
2769 You("
\97\8e\82¿
\82Ä
\82«
\82½%s
\82É
\93\96\82½
\82Á
\82½
\81I",
2770 x_monnam(mtmp, ARTICLE_A, "", 0, TRUE));
2773 if (Half_physical_damage)
2774 dmg = (dmg + 1) / 2;
2775 mdamageu(mtmp, dmg);
2778 default: /* monster surprises you. */
2781 pline("%s jumps near you from the %s.", Amonnam(mtmp),
2782 ceiling(u.ux, u.uy));
2784 pline("%s
\82ª%s
\82©
\82ç
\82 \82È
\82½
\82Ì
\8bß
\82
\82É
\94ò
\82ñ
\82Å
\82«
\82½
\81D", Amonnam(mtmp),
2785 ceiling(u.ux,u.uy));
2787 else if (mtmp->mpeaceful) {
2791 You("%s
\82ð
\8bÁ
\82©
\82µ
\82½
\81I",
2792 Blind && !sensemon(mtmp) ? something : a_monnam(mtmp));
2793 mtmp->mpeaceful = 0;
2796 pline("%s attacks you by surprise!", Amonnam(mtmp));
2798 pline("%s
\82Í
\8bÁ
\82¢
\82Ä
\82 \82È
\82½
\82ð
\8dU
\8c\82\82µ
\82½
\81I", Amonnam(mtmp));
2801 mnexto(mtmp); /* have to move the monster */
2804 if (!--inspoteffects) {
2805 spotterrain = STONE; /* 0 */
2806 spotloc.x = spotloc.y = 0;
2811 /* returns first matching monster */
2812 STATIC_OVL struct monst *
2813 monstinroom(mdat, roomno)
2814 struct permonst *mdat;
2817 register struct monst *mtmp;
2819 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
2820 if (DEADMONSTER(mtmp))
2822 if (mtmp->data == mdat
2823 && index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
2826 return (struct monst *) 0;
2830 in_rooms(x, y, typewanted)
2831 register xchar x, y;
2832 register int typewanted;
2835 char rno, *ptr = &buf[4];
2836 int typefound, min_x, min_y, max_x, max_y_offset, step;
2837 register struct rm *lev;
2839 #define goodtype(rno) \
2841 || (typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted \
2842 || (typewanted == SHOPBASE && typefound > SHOPBASE))
2844 switch (rno = levl[x][y].roomno) {
2853 default: /* i.e. a regular room # */
2863 else if (x >= COLNO)
2870 max_y_offset -= step;
2871 } else if ((min_y + max_y_offset) >= ROWNO)
2872 max_y_offset -= step;
2874 for (x = min_x; x <= max_x; x += step) {
2875 lev = &levl[x][min_y];
2877 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2881 if (y > max_y_offset)
2883 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2887 if (y > max_y_offset)
2889 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2896 /* is (x,y) in a town? */
2901 s_level *slev = Is_special(&u.uz);
2902 register struct mkroom *sroom;
2903 boolean has_subrooms = FALSE;
2905 if (!slev || !slev->flags.town)
2909 * See if (x,y) is in a room with subrooms, if so, assume it's the
2910 * town. If there are no subrooms, the whole level is in town.
2912 for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
2913 if (sroom->nsubrooms > 0) {
2914 has_subrooms = TRUE;
2915 if (inside_room(sroom, x, y))
2920 return !has_subrooms;
2925 register boolean newlev;
2927 char *ptr1, *ptr2, *ptr3, *ptr4;
2929 Strcpy(u.urooms0, u.urooms);
2930 Strcpy(u.ushops0, u.ushops);
2933 u.uentered[0] = '\0';
2935 u.ushops_entered[0] = '\0';
2936 Strcpy(u.ushops_left, u.ushops0);
2939 Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
2941 for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0],
2942 ptr4 = &u.ushops_entered[0];
2944 if (!index(u.urooms0, *ptr1))
2946 if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
2948 if (!index(u.ushops0, *ptr1))
2956 /* filter u.ushops0 -> u.ushops_left */
2957 for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
2958 if (!index(u.ushops, *ptr1))
2963 /* possibly deliver a one-time room entry message */
2965 check_special_room(newlev)
2966 register boolean newlev;
2968 register struct monst *mtmp;
2971 move_update(newlev);
2974 u_left_shop(u.ushops_left, newlev);
2976 if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */
2977 return; /* no entrance messages necessary */
2979 /* Did we just enter a shop? */
2980 if (*u.ushops_entered)
2981 u_entered_shop(u.ushops_entered);
2983 for (ptr = &u.uentered[0]; *ptr; ptr++) {
2984 int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
2985 boolean msg_given = TRUE;
2987 /* Did we just enter some other special room? */
2988 /* vault.c insists that a vault remain a VAULT,
2989 * and temples should remain TEMPLEs,
2990 * but everything else gives a message only the first time */
2994 pline("Welcome to David's treasure zoo!");
2996 pline("
\83f
\83r
\83b
\83g
\95ó
\94 \93®
\95¨
\89\80\82É
\82æ
\82¤
\82±
\82»
\81I");
3000 pline("It %s rather %s down here.", Blind ? "feels" : "looks",
3001 Blind ? "humid" : "muddy");
3003 pline("
\82©
\82È
\82è%s
\81D",
3004 Blind ? "
\8e¼
\8bC
\82ª
\82 \82é
\8fê
\8f\8a\82Ì
\82æ
\82¤
\82¾"
3005 : "
\82Ç
\82ë
\82Ç
\82ë
\82µ
\82Ä
\82¢
\82é
\8fê
\8f\8a\82¾");
3010 You("enter an opulent throne room!");
3012 You("
\89Ø
\82â
\82©
\82È
\8bÊ
\8dÀ
\82Ì
\8aÔ
\82É
\93ü
\82Á
\82½
\81I");
3016 You("enter a leprechaun hall!");
3018 You("
\83\8c\83v
\83\89\83R
\81[
\83\93\83z
\81[
\83\8b\82É
\93ü
\82Á
\82½
\81I");
3023 const char *run = locomotion(youmonst.data, "Run");
3024 pline("%s away! %s away!", run, run);
3026 pline("
\93¦
\82°
\82ë
\81I
\93¦
\82°
\82ë
\81I");
3030 You("have an uncanny feeling...");
3032 You("
\95s
\8bC
\96¡
\82È
\8a´
\82¶
\82ª
\82µ
\82½
\81D
\81D
\81D");
3036 You("enter a giant beehive!");
3038 You("
\8b\90\91å
\82È
\96I
\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
3042 You("enter a disgusting nest!");
3044 You("
\82Þ
\82Á
\82Æ
\82·
\82é
\8fL
\82¢
\82Ì
\82·
\82é
\92¹
\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
3048 You("enter an anthole!");
3050 You("
\83A
\83\8a\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
3053 if (monstinroom(&mons[PM_SOLDIER], roomno)
3054 || monstinroom(&mons[PM_SERGEANT], roomno)
3055 || monstinroom(&mons[PM_LIEUTENANT], roomno)
3056 || monstinroom(&mons[PM_CAPTAIN], roomno))
3058 You("enter a military barracks!");
3060 You("
\8cR
\91à
\82Ì
\95ºäq
\82É
\93ü
\82Á
\82½
\81I");
3063 You("enter an abandoned barracks.");
3065 You("
\95ú
\92u
\82³
\82ê
\82½
\82Ü
\82Ü
\82Ì
\95ºäq
\82É
\93ü
\82Á
\82½
\81D");
3068 struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno);
3070 if (!oracle->mpeaceful)
3072 verbalize("You're in Delphi, %s.", plname);
3074 verbalize("
\82¨
\82Ü
\82¦
\82Í
\83f
\83\8b\83t
\83@
\83C
\82Ì
\90_
\91õ
\8f\8a\82É
\82¢
\82é
\81D");
3077 verbalize("%s, %s, welcome to Delphi!",
3078 Hello((struct monst *) 0), plname);
3080 verbalize("
\82¨
\82¨%s
\81C
\83f
\83\8b\83t
\83@
\83C
\82Ì
\90_
\91õ
\8f\8a\82É
\82æ
\82
\82¼
\82Ü
\82¢
\82ç
\82ê
\82½
\81I",
3088 intemple(roomno + ROOMOFFSET);
3091 msg_given = (rt == TEMPLE);
3096 room_discovered(roomno);
3099 rooms[roomno].rtype = OROOM;
3100 if (!search_special(rt)) {
3101 /* No more room of that type */
3104 level.flags.has_court = 0;
3107 level.flags.has_swamp = 0;
3110 level.flags.has_morgue = 0;
3113 level.flags.has_zoo = 0;
3116 level.flags.has_barracks = 0;
3119 level.flags.has_temple = 0;
3122 level.flags.has_beehive = 0;
3126 if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
3127 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
3128 if (DEADMONSTER(mtmp))
3130 if (!Stealth && !rn2(3))
3131 mtmp->msleeping = 0;
3140 1 = cannot pickup, time taken
3141 0 = cannot pickup, no time taken
3142 -1 = do normal pickup
3143 -2 = loot the monster */
3147 /* uswallow case added by GAN 01/29/87 */
3149 if (!u.ustuck->minvent) {
3150 if (is_animal(u.ustuck->data)) {
3152 You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
3154 You("%s
\82Ì
\90ã
\82ð
\8fE
\82Á
\82½
\81D", mon_nam(u.ustuck));
3156 pline("But it's kind of slimy, so you drop it.");
3158 pline("
\82µ
\82©
\82µ
\81C
\82»
\82ê
\82Í
\82Ê
\82é
\82Ê
\82é
\82µ
\82Ä
\95s
\89õ
\82¾
\82Á
\82½
\82Ì
\82Å
\8eÌ
\82Ä
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
3161 You("don't %s anything in here to pick up.",
3162 Blind ? "feel" : "see");
3164 pline("
\82±
\82±
\82É
\82Í
\8fE
\82¦
\82é
\82à
\82Ì
\82ª
\82È
\82¢%s
\81D",
3165 Blind ? "
\82æ
\82¤
\82¾" : "");
3169 return -2; /* loot the monster inventory */
3172 if (is_pool(u.ux, u.uy)) {
3173 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
3174 || (Flying && !Breathless)) {
3176 You("cannot dive into the %s to pick things up.",
3179 You("
\95¨
\82ð
\8fE
\82¢
\82 \82°
\82é
\82½
\82ß
\82É%s
\82É
\94ò
\82Ñ
\82±
\82ß
\82È
\82¢
\81D",
3183 } else if (!Underwater) {
3185 You_cant("even see the bottom, let alone pick up %s.", something);
3187 pline("
\92ê
\82³
\82¦
\8c©
\82¦
\82È
\82¢
\81C
\8fE
\82¤
\82Ì
\82Í
\82â
\82ß
\82æ
\82¤
\81D");
3191 if (is_lava(u.ux, u.uy)) {
3192 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
3193 || (Flying && !Breathless)) {
3195 You_cant("reach the bottom to pick things up.");
3197 You_cant("
\95¨
\82ð
\8fE
\82¢
\8fã
\82°
\82é
\82½
\82ß
\82É
\92ê
\82Ü
\82Å
\82¢
\82¯
\82È
\82¢
\81D");
3199 } else if (!likes_lava(youmonst.data)) {
3201 You("would burn to a crisp trying to pick things up.");
3203 You("
\8fE
\82¢
\8fã
\82°
\82æ
\82¤
\82Æ
\82µ
\82½
\82ç
\8aÛ
\8fÅ
\82°
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82¤
\82¾
\82ë
\82¤
\81D");
3207 if (!OBJ_AT(u.ux, u.uy)) {
3208 register struct rm *lev = &levl[u.ux][u.uy];
3210 if (IS_THRONE(lev->typ))
3212 pline("It must weigh%s a ton!", lev->looted ? " almost" : "");
3214 pline("
\82±
\82ê
\82Í%s
\8fd
\82¢
\81I", lev->looted ? "
\82©
\82È
\82è" : "
\82·
\82²
\82");
3215 else if (IS_SINK(lev->typ))
3217 pline_The("plumbing connects it to the floor.");
3219 pline_The("
\94z
\8aÇ
\82Í
\8f°
\82É
\82Â
\82È
\82ª
\82Á
\82Ä
\82¢
\82é
\81D");
3220 else if (IS_GRAVE(lev->typ))
3222 You("don't need a gravestone. Yet.");
3224 pline("
\82 \82È
\82½
\82É
\82Í
\95æ
\90Î
\82Í
\95s
\97v
\82¾
\81D
\81D
\81D
\8d¡
\82Ì
\82Æ
\82±
\82ë
\81D");
3225 else if (IS_FOUNTAIN(lev->typ))
3227 You("could drink the %s...", hliquid("water"));
3229 You("%s
\82ð
\88ù
\82ß
\82È
\82¢
\81D
\81D
\81D", hliquid("
\90\85"));
3230 else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
3232 pline("It won't come off the hinges.");
3234 pline("
\83q
\83\93\83W
\82ð
\8aO
\82¹
\82È
\82¢
\81D");
3235 else if (IS_ALTAR(lev->typ))
3237 pline("Moving the altar would be a very bad idea.");
3239 pline("
\8dÕ
\92d
\82ð
\93®
\82©
\82·
\82Ì
\82Í
\82Æ
\82Ä
\82à
\88«
\82¢
\8dl
\82¦
\82¾
\81D");
3240 else if (lev->typ == STAIRS)
3242 pline_The("stairs are solidly fixed to the %s.",
3243 surface(u.ux, u.uy));
3245 pline_The("
\8aK
\92i
\82Í%s
\82É
\82µ
\82Á
\82©
\82è
\82Æ
\8cÅ
\92è
\82³
\82ê
\82Ä
\82¢
\82é
\81D",
3246 surface(u.ux, u.uy));
3250 There("is nothing here to pick up.");
3252 pline("
\82±
\82±
\82É
\82Í
\8fE
\82¦
\82é
\82à
\82Ì
\82Í
\82È
\82¢
\81D");
3255 if (!can_reach_floor(TRUE)) {
3256 struct trap *traphere = t_at(u.ux, u.uy);
3258 && (uteetering_at_seen_pit(traphere) || uescaped_shaft(traphere)))
3260 You("cannot reach the bottom of the %s.",
3261 is_pit(traphere->ttyp) ? "pit" : "abyss");
3263 You("%s
\82Ì
\92ê
\82É
\93Í
\82©
\82È
\82©
\82Á
\82½
\81D",
3264 is_pit(traphere->ttyp) ? "
\97\8e\82µ
\8c\8a" : "
\93Þ
\97\8e");
3266 else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
3268 else if (Blind && !can_reach_floor(TRUE))
3270 You("cannot reach anything here.");
3272 You("
\89½
\82É
\82à
\93Í
\82©
\82È
\82¢
\81D");
3275 You("cannot reach the %s.", surface(u.ux, u.uy));
3277 You("%s
\82É
\82½
\82Ç
\82è
\82Â
\82
\82±
\82Æ
\82ª
\82Å
\82«
\82È
\82¢
\81D", surface(u.ux, u.uy));
3280 return -1; /* can do normal pickup */
3283 /* the ',' command */
3287 int count, tmpcount, ret;
3289 /* awful kludge to work around parse()'s pre-decrement */
3290 count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup)))
3292 multi = 0; /* always reset */
3294 if ((ret = pickup_checks()) >= 0) {
3296 } else if (ret == -2) {
3298 return loot_mon(u.ustuck, &tmpcount, (boolean *) 0);
3299 } /* else ret == -1 */
3301 return pickup(-count);
3304 /* stop running if we see something interesting */
3305 /* turn around a corner if that is the only way we can proceed */
3306 /* do not turn left or right twice */
3311 int i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
3312 int corrct = 0, noturn = 0;
3316 /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */
3317 /* they polymorphed while in the middle of a long move. */
3318 if (NODIAG(u.umonnum) && u.dx && u.dy) {
3320 You("cannot move diagonally.");
3322 You("
\8eÎ
\82ß
\82É
\88Ú
\93®
\82Å
\82«
\82È
\82¢
\81D");
3327 if (Blind || context.run == 0)
3329 for (x = u.ux - 1; x <= u.ux + 1; x++)
3330 for (y = u.uy - 1; y <= u.uy + 1; y++) {
3331 if (!isok(x, y) || (x == u.ux && y == u.uy))
3333 if (NODIAG(u.umonnum) && x != u.ux && y != u.uy)
3336 if ((mtmp = m_at(x, y)) != 0
3337 && M_AP_TYPE(mtmp) != M_AP_FURNITURE
3338 && M_AP_TYPE(mtmp) != M_AP_OBJECT
3339 && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
3340 if ((context.run != 1 && !mtmp->mtame)
3341 || (x == u.ux + u.dx && y == u.uy + u.dy
3342 && !context.travel)) {
3343 if (iflags.mention_walls)
3345 pline("%s blocks your path.", upstart(a_monnam(mtmp)));
3347 pline("%s
\82ª
\93¹
\82ð
\82Ó
\82³
\82¢
\82Å
\82¢
\82é
\81D", a_monnam(mtmp));
3352 if (levl[x][y].typ == STONE)
3354 if (x == u.ux - u.dx && y == u.uy - u.dy)
3357 if (IS_ROCK(levl[x][y].typ) || levl[x][y].typ == ROOM
3358 || IS_AIR(levl[x][y].typ)) {
3360 } else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) {
3361 if (x != u.ux && y != u.uy)
3363 if (context.run != 1) {
3364 if (iflags.mention_walls)
3366 You("stop in front of the door.");
3368 You("
\94à
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D");
3372 } else if (levl[x][y].typ == CORR) {
3374 if (levl[u.ux][u.uy].typ != ROOM) {
3375 if (context.run == 1 || context.run == 3
3376 || context.run == 8) {
3377 i = dist2(x, y, u.ux + u.dx, u.uy + u.dy);
3380 if (corrct == 1 && dist2(x, y, x0, y0) != 1)
3392 } else if ((trap = t_at(x, y)) && trap->tseen) {
3393 if (context.run == 1)
3394 goto bcorr; /* if you must */
3395 if (x == u.ux + u.dx && y == u.uy + u.dy) {
3396 if (iflags.mention_walls) {
3397 int tt = what_trap(trap->ttyp, rn2_on_display_rng);
3400 You("stop in front of %s.",
3402 You("%s
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
3403 an(defsyms[trap_to_defsym(tt)].explanation));
3408 } else if (is_pool_or_lava(x, y)) {
3409 /* water and lava only stop you if directly in front, and stop
3410 * you even if you are running
3412 if (!Levitation && !Flying && !is_clinger(youmonst.data)
3413 && x == u.ux + u.dx && y == u.uy + u.dy) {
3414 /* No Wwalking check; otherwise they'd be able
3415 * to test boots by trying to SHIFT-direction
3416 * into a pool and seeing if the game allowed it
3418 if (iflags.mention_walls)
3420 You("stop at the edge of the %s.",
3421 hliquid(is_pool(x,y) ? "water" : "lava"));
3423 You("%s
\82Ì
\92[
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
3424 hliquid(is_pool(x,y) ? "
\90\85" : "
\97n
\8aâ"));
3429 } else { /* e.g. objects or trap or stairs */
3430 if (context.run == 1)
3432 if (context.run == 8)
3436 if (((x == u.ux - u.dx) && (y != u.uy + u.dy))
3437 || ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
3443 } /* end for loops */
3445 if (corrct > 1 && context.run == 2) {
3446 if (iflags.mention_walls)
3448 pline_The("corridor widens here.");
3450 pline("
\92Ê
\98H
\82Í
\82±
\82±
\82Å
\8dL
\82
\82È
\82Á
\82Ä
\82¢
\82é
\81D");
3453 if ((context.run == 1 || context.run == 3 || context.run == 8) && !noturn
3454 && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) {
3455 /* make sure that we do not turn too far */
3457 if (u.dx == y0 - u.uy && u.dy == u.ux - x0)
3458 i = 2; /* straight turn right */
3460 i = -2; /* straight turn left */
3461 } else if (u.dx && u.dy) {
3462 if ((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
3463 i = -1; /* half turn left */
3465 i = 1; /* half turn right */
3467 if ((x0 - u.ux == y0 - u.uy && !u.dy)
3468 || (x0 - u.ux != y0 - u.uy && u.dy))
3469 i = 1; /* half turn right */
3471 i = -1; /* half turn left */
3474 i += u.last_str_turn;
3475 if (i <= 2 && i >= -2) {
3476 u.last_str_turn = i;
3483 /* check for a doorway which lacks its door (NODOOR or BROKEN) */
3488 struct rm *lev_p = &levl[x][y];
3490 if (!IS_DOOR(lev_p->typ))
3492 /* all rogue level doors are doorless but disallow diagonal access, so
3493 we treat them as if their non-existent doors were actually present */
3494 if (Is_rogue_level(&u.uz))
3496 return !(lev_p->doormask & ~(D_NODOOR | D_BROKEN));
3499 /* used by drown() to check whether hero can crawl from water to <x,y> */
3501 crawl_destination(x, y)
3504 /* is location ok in general? */
3505 if (!goodpos(x, y, &youmonst, 0))
3508 /* orthogonal movement is unrestricted when destination is ok */
3509 if (x == u.ux || y == u.uy)
3512 /* diagonal movement has some restrictions */
3513 if (NODIAG(u.umonnum))
3514 return FALSE; /* poly'd into a grid bug... */
3516 return TRUE; /* or a xorn... */
3517 /* pool could be next to a door, conceivably even inside a shop */
3518 if (IS_DOOR(levl[x][y].typ) && (!doorless_door(x, y) || block_door(x, y)))
3520 /* finally, are we trying to squeeze through a too-narrow gap? */
3521 return !(bad_rock(youmonst.data, u.ux, y)
3522 && bad_rock(youmonst.data, x, u.uy));
3525 /* something like lookaround, but we are not running */
3526 /* react only to monsters that might hit us */
3531 register struct monst *mtmp;
3533 /* Also see the similar check in dochugw() in monmove.c */
3534 for (x = u.ux - 1; x <= u.ux + 1; x++)
3535 for (y = u.uy - 1; y <= u.uy + 1; y++) {
3536 if (!isok(x, y) || (x == u.ux && y == u.uy))
3538 if ((mtmp = m_at(x, y)) && M_AP_TYPE(mtmp) != M_AP_FURNITURE
3539 && M_AP_TYPE(mtmp) != M_AP_OBJECT
3540 && (!mtmp->mpeaceful || Hallucination)
3541 && (!is_hider(mtmp->data) || !mtmp->mundetected)
3542 && !noattacks(mtmp->data) && mtmp->mcanmove
3543 && !mtmp->msleeping /* aplvax!jcn */
3544 && !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp))
3555 return; /* This is a bug fix by ab@unido */
3556 u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */
3560 multi_reason = NULL;
3561 context.travel = context.travel1 = context.mv = context.run = 0;
3564 /* called when a non-movement, multi-turn action has completed */
3567 const char *msg_override;
3569 multi = 0; /* caller will usually have done this already */
3571 nomovemsg = msg_override;
3572 else if (!nomovemsg)
3573 nomovemsg = You_can_move_again;
3575 pline("%s", nomovemsg);
3576 /* follow "you survived that attempt on your life" with a message
3577 about current form if it's not the default; primarily for
3578 life-saving while turning into green slime but is also a reminder
3579 if life-saved while poly'd and Unchanging (explore or wizard mode
3580 declining to die since can't be both Unchanging and Lifesaved) */
3582 if (Upolyd && !strncmpi(nomovemsg, "You survived that ", 18))
3583 You("are %s.", an(mons[u.umonnum].mname)); /* (ignore Hallu) */
3585 if (Upolyd && !STRNCMP2(nomovemsg, "
\82 \82È
\82½
\82Í
\90¶
\82«
\82È
\82ª
\82ç"))
3586 You("%s
\82¾
\81D", mons[u.umonnum].mname); /* (ignore Hallu) */
3591 multi_reason = NULL;
3593 int NDECL((*f)) = afternmv;
3595 /* clear afternmv before calling it (to override the
3596 encumbrance hack for levitation--see weight_cap()) */
3597 afternmv = (int NDECL((*))) 0;
3599 /* for finishing Armor/Boots/&c_on() */
3607 static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
3608 SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
3609 TELEPORT_CONTROL, STEALTH, FAST, INVIS };
3611 if (moves <= wailmsg + 50)
3615 if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
3620 who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m
3623 who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m
3628 pline("%s is about to die.", who);
3630 pline("%s
\82Í
\8e\80\82É
\82©
\82¯
\82Ä
\82¢
\82é
\81D", who);
3632 for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
3633 if (u.uprops[powers[i]].intrinsic & INTRINSIC)
3637 pline((powercnt >= 4) ? "%s, all your powers will be lost..."
3639 pline((powercnt >= 4) ? "%s
\81C
\82 \82È
\82½
\82Ì
\91S
\82Ä
\82Ì
\97Í
\82Í
\8e¸
\82í
\82ê
\82Â
\82Â
\82 \82é
\81D
\81D
\81D"
3641 : "%s, your life force is running out.",
3643 : "%s
\81C
\82 \82È
\82½
\82Ì
\90¶
\96½
\97Í
\82Í
\90s
\82«
\82æ
\82¤
\82Æ
\82µ
\82Ä
\82¢
\82é
\81D
\81D
\81D",
3648 You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
3650 You_hear(u.uhp == 1 ? "
\83o
\83\93\83V
\81[
\82Ì
\82·
\82·
\82è
\8b\83\82«
\82ª
\95·
\82±
\82¦
\82é
\81D
\81D
\81D"
3652 : "the howling of the CwnAnnwn...");
3654 : "
\83N
\81[
\83\93\81E
\83A
\83\93\83k
\81[
\83\93\82Ì
\89\93\96i
\82ª
\95·
\82±
\82¦
\82é
\81D
\81D
\81D");
3659 losehp(n, knam, k_format)
3661 register const char *knam;
3671 else if (n > 0 && u.mh * 10 < u.mhmax && Unchanging)
3677 if (u.uhp > u.uhpmax)
3678 u.uhpmax = u.uhp; /* perhaps n was negative */
3680 context.travel = context.travel1 = context.mv = context.run = 0;
3683 killer.format = k_format;
3684 if (killer.name != knam) /* the thing that killed you */
3685 Strcpy(killer.name, knam ? knam : "");
3689 pline("
\82 \82È
\82½
\82Í
\8e\80\82É
\82Ü
\82µ
\82½
\81D
\81D
\81D");
3691 } else if (n > 0 && u.uhp * 10 < u.uhpmax) {
3699 long carrcap, save_ELev = ELevitation, save_BLev = BLevitation;
3701 /* boots take multiple turns to wear but any properties they
3702 confer are enabled at the start rather than the end; that
3703 causes message sequencing issues for boots of levitation
3704 so defer their encumbrance benefit until they're fully worn */
3705 if (afternmv == Boots_on && (ELevitation & W_ARMF) != 0L) {
3706 ELevitation &= ~W_ARMF;
3707 float_vs_flight(); /* in case Levitation is blocking Flying */
3709 /* levitation is blocked by being trapped in the floor, but it still
3710 functions enough in that situation to enhance carrying capacity */
3711 BLevitation &= ~I_SPECIAL;
3713 carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50;
3715 /* consistent with can_carry() in mon.c */
3716 if (youmonst.data->mlet == S_NYMPH)
3717 carrcap = MAX_CARR_CAP;
3718 else if (!youmonst.data->cwt)
3719 carrcap = (carrcap * (long) youmonst.data->msize) / MZ_HUMAN;
3720 else if (!strongmonst(youmonst.data)
3721 || (strongmonst(youmonst.data)
3722 && (youmonst.data->cwt > WT_HUMAN)))
3723 carrcap = (carrcap * (long) youmonst.data->cwt / WT_HUMAN);
3726 if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */
3727 || (u.usteed && strongmonst(u.usteed->data))) {
3728 carrcap = MAX_CARR_CAP;
3730 if (carrcap > MAX_CARR_CAP)
3731 carrcap = MAX_CARR_CAP;
3733 if (EWounded_legs & LEFT_SIDE)
3735 if (EWounded_legs & RIGHT_SIDE)
3742 if (ELevitation != save_ELev || BLevitation != save_BLev) {
3743 ELevitation = save_ELev;
3744 BLevitation = save_BLev;
3748 return (int) carrcap;
3751 static int wc; /* current weight_cap(); valid after call to inv_weight() */
3753 /* returns how far beyond the normal capacity the player is currently. */
3754 /* inv_weight() is negative if the player is below normal capacity. */
3758 register struct obj *otmp = invent;
3759 register int wt = 0;
3762 if (otmp->oclass == COIN_CLASS)
3763 wt += (int) (((long) otmp->quan + 50L) / 100L);
3764 else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
3773 * Returns 0 if below normal capacity, or the number of "capacity units"
3774 * over the normal capacity the player is loaded. Max is 5.
3777 calc_capacity(xtra_wt)
3780 int cap, wt = inv_weight() + xtra_wt;
3783 return UNENCUMBERED;
3786 cap = (wt * 2 / wc) + 1;
3787 return min(cap, OVERLOADED);
3793 return calc_capacity(0);
3799 int wt = inv_weight();
3801 return (wt - (2 * wc));
3808 if (near_capacity() >= EXT_ENCUMBER) {
3813 You_cant("do that while carrying so much stuff.");
3815 You("
\91ò
\8eR
\82à
\82Ì
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\82¢
\82é
\82Ì
\82Å
\81C
\82»
\82ñ
\82È
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D");
3825 register struct obj *otmp = invent;
3826 register int ct = 0;
3829 if (incl_gold || otmp->invlet != GOLD_SYM)
3836 /* Counts the money in an object chain. */
3837 /* Intended use is for your or some monster's inventory, */
3838 /* now that u.gold/m.gold is gone.*/
3839 /* Counting money in a container might be possible too. */
3845 /* Must change when silver & copper is implemented: */
3846 if (otmp->oclass == COIN_CLASS)