1 /* NetHack 3.6 hack.c $NHDT-Date: 1551137618 2019/02/25 23:33:38 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.208 $ */
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-2019 */
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)))) {
174 feel_location(sx, sy);
175 if (canspotmon(mtmp)) {
177 pline("There's %s on the other side.", a_monnam(mtmp));
179 pline("
\94½
\91Î
\91¤
\82É%s
\82ª
\82¢
\82é
\81D", a_monnam(mtmp));
182 You_hear("a monster behind %s.", the(xname(otmp)));
184 pline("%s
\82Ì
\94w
\8cã
\82É
\89ö
\95¨
\82Ì
\8bC
\94z
\82ª
\82·
\82é
\81D", the(xname(otmp)));
185 map_invisible(rx, ry);
189 pline("Perhaps that's why %s cannot move it.",
190 u.usteed ? y_monnam(u.usteed) : "you");
192 pline("
\82½
\82Ô
\82ñ
\82±
\82ê
\82ª
\81C
\8aâ
\82ð
\93®
\82©
\82¹
\82È
\82¢
\97\9d\97R
\82¾
\81D");
198 /* if a trap operates on the boulder, don't attempt
199 to move any others at this location; return -1
200 if another boulder is in hero's way, or 0 if he
201 should advance to the vacated boulder position */
202 switch (ttmp->ttyp) {
205 obj_extract_self(otmp);
206 place_object(otmp, rx, ry);
209 pline("KAABLAMM!!! %s %s land mine.",
210 Tobjnam(otmp, "trigger"),
211 ttmp->madeby_u ? "your" : "a");
213 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",
215 ttmp->madeby_u ? "
\82 \82È
\82½
\82Ì
\8ed
\8a|
\82¯
\82½" : "");
217 blow_up_landmine(ttmp);
218 /* if the boulder remains, it should fill the pit */
219 fill_pit(u.ux, u.uy);
222 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
227 obj_extract_self(otmp);
228 /* vision kludge to get messages right;
229 the pit will temporarily be seen even
230 if this is one among multiple boulders */
232 viz_array[ry][rx] |= IN_SIGHT;
234 if (!flooreffects(otmp, rx, ry, "fall")) {
236 if (!flooreffects(otmp, rx, ry, "
\97\8e\82¿
\82é")) {
237 place_object(otmp, rx, ry);
241 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
246 pline("Kerplunk! You no longer feel %s.",
248 pline("
\83h
\83T
\83b
\81I
\82 \82È
\82½
\82Í
\82à
\82¤%s
\82ð
\8a´
\82¶
\82ç
\82ê
\82È
\82¢
\81D",
252 pline("%s%s and %s a %s in the %s!",
253 Tobjnam(otmp, (ttmp->ttyp == TRAPDOOR)
256 (ttmp->ttyp == TRAPDOOR) ? "" : " into",
257 otense(otmp, "plug"),
258 (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
261 pline("%s
\82Í
\97\8e\82¿
\82Ä%s
\82Ì%s
\82ð
\96\84\82ß
\82½
\81I",
264 (ttmp->ttyp == TRAPDOOR) ? "
\97\8e\82µ
\94à" : "
\8c\8a");
269 levl[rx][ry].wall_info &= ~W_NONDIGGABLE;
270 levl[rx][ry].candig = 1;
273 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
276 int newlev = 0; /* lint suppression */
279 if (ttmp->ttyp == LEVEL_TELEP) {
280 newlev = random_teleport_level();
281 if (newlev == depth(&u.uz) || In_endgame(&u.uz))
282 /* trap didn't work; skip "disappears" message */
287 pline("%s pushes %s and suddenly it disappears!",
289 pline("%s
\82ª%s
\82ð
\89\9f\82·
\82Æ
\81C
\93Ë
\91R
\82»
\82ê
\82Í
\8fÁ
\96Å
\82µ
\82½
\81I",
290 upstart(y_monnam(u.usteed)), the(xname(otmp)));
293 You("push %s and suddenly it disappears!",
295 pline("
\82 \82È
\82½
\82ª%s
\82ð
\89\9f\82·
\82Æ
\81C
\93Ë
\91R
\82»
\82ê
\82Í
\8fÁ
\96Å
\82µ
\82½
\81I",
297 if (ttmp->ttyp == TELEP_TRAP) {
300 obj_extract_self(otmp);
301 add_to_migration(otmp);
302 get_level(&dest, newlev);
303 otmp->ox = dest.dnum;
304 otmp->oy = dest.dlevel;
305 otmp->owornmask = (long) MIGR_RANDOM;
308 return sobj_at(BOULDER, sx, sy) ? -1 : 0;
311 break; /* boulder not affected by this trap */
315 if (closed_door(rx, ry))
317 if (boulder_hits_pool(otmp, rx, ry, TRUE))
320 * Re-link at top of fobj chain so that pile order is preserved
321 * when level is restored.
325 place_object(otmp, otmp->ox, otmp->oy);
329 #ifdef LINT /* static long lastmovetime; */
333 /* note: reset to zero after save/restore cycle */
334 static NEARDATA long lastmovetime;
338 if (moves > lastmovetime + 2 || moves < lastmovetime)
340 pline("With %s effort you move %s.",
341 throws_rocks(youmonst.data) ? "little"
345 pline("%s
\97Í
\82ð
\82±
\82ß
\82Ä%s
\82ð
\89\9f\82µ
\82½
\81D",
346 throws_rocks(youmonst.data) ? "
\8f
\82µ" : "
\82©
\82È
\82è",
349 exercise(A_STR, TRUE);
352 pline("%s moves %s.", upstart(y_monnam(u.usteed)),
355 pline("%s
\82Í%s
\82ð
\93®
\82©
\82µ
\82½
\81D", upstart(y_monnam(u.usteed)),
358 lastmovetime = moves;
361 /* Move the boulder *after* the message. */
362 if (glyph_is_invisible(levl[rx][ry].glyph))
363 unmap_object(rx, ry);
364 movobj(otmp, rx, ry); /* does newsym(rx,ry) */
366 feel_location(rx, ry);
367 feel_location(sx, sy);
375 pline("%s tries to move %s, but cannot.",
376 upstart(y_monnam(u.usteed)), the(xname(otmp)));
378 pline("%s
\82Í%s
\82ð
\93®
\82©
\82»
\82¤
\82Æ
\82µ
\82½
\82ª
\8fo
\97\88\82È
\82©
\82Á
\82½
\81D",
379 upstart(y_monnam(u.usteed)), the(xname(otmp)));
383 You("try to move %s, but in vain.", the(xname(otmp)));
385 You("%s
\82ð
\93®
\82©
\82»
\82¤
\82Æ
\82µ
\82½
\82ª
\81C
\82¾
\82ß
\82¾
\82Á
\82½
\81D", the(xname(otmp)));
387 feel_location(sx, sy);
389 if (throws_rocks(youmonst.data)) {
391 canpickup = (!Sokoban
392 /* similar exception as in can_lift():
393 when poly'd into a giant, you can
394 pick up a boulder if you have a free
395 slot or into the overflow ('#') slot
396 unless already carrying at least one */
397 && (inv_cnt(FALSE) < 52 || !carrying(BOULDER))),
398 willpickup = (canpickup && autopick_testobj(otmp, TRUE));
400 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
402 You("aren't skilled enough to %s %s from %s.",
403 willpickup ? "pick up" : "push aside",
404 the(xname(otmp)), y_monnam(u.usteed));
406 You("%s
\82É%s
\82ð%s
\82é
\82Ù
\82Ç
\8bZ
\97Ê
\82ª
\82È
\82¢
\81D",
407 y_monnam(u.usteed), the(xname(otmp)),
408 willpickup ? "
\8fE
\82í
\82¹" : "
\89\9f\82³
\82¹");
412 * willpickup: you easily pick it up
413 * canpickup: you could easily pick it up
414 * otherwise: you easily push it aside
417 pline("However, you %seasily %s.",
418 (willpickup || !canpickup) ? "" : "could ",
419 (willpickup || canpickup) ? "pick it up"
422 pline("
\82µ
\82©
\82µ
\81C
\82 \82È
\82½
\82Í
\8aÈ
\92P
\82É
\82»
\82ê
\82ð%s
\81D",
423 (willpickup || canpickup) ?
424 "
\8fE
\82¦
\82½" : "
\95Ê
\82Ì
\95û
\82É
\89\9f\82¹
\82½");
433 && (((!invent || inv_weight() <= -850)
434 && (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
435 && IS_ROCK(levl[sx][u.uy].typ))))
436 || verysmall(youmonst.data))) {
439 "However, you can squeeze yourself into a small opening.");
441 "
\82µ
\82©
\82µ
\81C
\82 \82È
\82½
\82Í
\8f¬
\82³
\82¢
\8c\84\8aÔ
\82É
\82±
\82¶
\93ü
\82Á
\82½
\81D");
454 * Chew on a wall, door, or boulder. [What about statues?]
455 * Returns TRUE if still eating, FALSE when done.
461 struct rm *lev = &levl[x][y];
462 struct obj *boulder = sobj_at(BOULDER, x, y);
463 const char *digtxt = (char *) 0, *dmgtxt = (char *) 0;
465 if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */
466 (void) memset((genericptr_t) &context.digging, 0,
467 sizeof (struct dig_info));
470 && ((IS_ROCK(lev->typ) && !may_dig(x, y))
471 /* may_dig() checks W_NONDIGGABLE but doesn't handle iron bars */
472 || (lev->typ == IRONBARS && (lev->wall_info & W_NONDIGGABLE)))) {
474 You("hurt your teeth on the %s.",
475 (lev->typ == IRONBARS)
481 You("%s
\82Å
\8e\95\82ð
\92É
\82ß
\82½
\81D",
482 (lev->typ == IRONBARS)
490 } else if (context.digging.pos.x != x || context.digging.pos.y != y
491 || !on_level(&context.digging.level, &u.uz)) {
492 context.digging.down = FALSE;
493 context.digging.chew = TRUE;
494 context.digging.warned = FALSE;
495 context.digging.pos.x = x;
496 context.digging.pos.y = y;
497 assign_level(&context.digging.level, &u.uz);
498 /* solid rock takes more work & time to dig through */
499 context.digging.effort =
500 (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
502 You("start chewing %s %s.",
503 (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS)
512 : (lev->typ == IRONBARS)
516 You("%s%s
\82Í
\82¶
\82ß
\82½
\81D",
523 : lev->typ == IRONBARS
526 (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS)
528 : "
\82É
\8c\8a\82ð
\82 \82¯");
530 watch_dig((struct monst *) 0, x, y, FALSE);
532 } else if ((context.digging.effort += (30 + u.udaminc)) <= 100) {
535 You("%s chewing on the %s.",
536 context.digging.chew ? "continue" : "begin",
543 : (lev->typ == IRONBARS)
547 You("%s
\82ð
\8a\9a\82Ý%s
\81D",
554 : lev->typ == IRONBARS
557 context.digging.chew ? "
\91±
\82¯
\82½" : "
\82Í
\82¶
\82ß
\82½");
559 context.digging.chew = TRUE;
560 watch_dig((struct monst *) 0, x, y, FALSE);
564 /* Okay, you've chewed through something */
566 u.uhunger += rnd(20);
569 delobj(boulder); /* boulder goes bye-bye */
571 You("eat the boulder."); /* yum */
573 You("
\8aâ
\82ð
\90H
\82×
\82½
\81D"); /* yum */
577 * The location could still block because of
578 * 1. More than one boulder
579 * 2. Boulder stuck in a wall/stone/door.
581 * [perhaps use does_block() below (from vision.c)]
583 if (IS_ROCK(lev->typ) || closed_door(x, y)
584 || sobj_at(BOULDER, x, y)) {
585 block_point(x, y); /* delobj will unblock the point */
586 /* reset dig state */
587 (void) memset((genericptr_t) &context.digging, 0,
588 sizeof (struct dig_info));
592 } else if (IS_WALL(lev->typ)) {
593 if (*in_rooms(x, y, SHOPBASE)) {
594 add_damage(x, y, SHOP_WALL_DMG);
598 dmgtxt = "
\8f\9d\82Â
\82¯
\82é";
601 digtxt = "chew a hole in the wall.";
603 digtxt = "
\95Ç
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
604 if (level.flags.is_maze_lev) {
606 } else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
610 lev->doormask = D_NODOOR;
612 } else if (IS_TREE(lev->typ)) {
614 digtxt = "chew through the tree.";
616 digtxt = "
\96Ø
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
618 } else if (lev->typ == IRONBARS) {
620 digtxt = "eat through the bars.";
622 digtxt = "
\93S
\82Ì
\96_
\82É
\8c\8a\82ð
\8aJ
\82¯
\82½
\81D";
624 } else if (lev->typ == SDOOR) {
625 if (lev->doormask & D_TRAPPED) {
626 lev->doormask = D_NODOOR;
628 b_trapped("secret door", 0);
630 b_trapped("
\94é
\96§
\82Ì
\94à", 0);
633 digtxt = "chew through the secret door.";
635 digtxt = "
\94é
\96§
\82Ì
\94à
\82ð
\8a\9a\82Ý
\8dÓ
\82¢
\82½
\81D";
636 lev->doormask = D_BROKEN;
640 } else if (IS_DOOR(lev->typ)) {
641 if (*in_rooms(x, y, SHOPBASE)) {
642 add_damage(x, y, SHOP_DOOR_COST);
648 if (lev->doormask & D_TRAPPED) {
649 lev->doormask = D_NODOOR;
651 b_trapped("door", 0);
653 b_trapped("
\94à", 0);
656 digtxt = "chew through the door.";
658 digtxt = "
\94à
\82ð
\8dÓ
\82¢
\82½
\81D";
659 lev->doormask = D_BROKEN;
662 } else { /* STONE or SCORR */
664 digtxt = "chew a passage through the rock.";
666 digtxt = "
\8aâ
\82ð
\8a\9a\82Ý
\8dÓ
\82¢
\82Ä
\92Ê
\82è
\94²
\82¯
\82½
\81D";
670 unblock_point(x, y); /* vision */
673 You1(digtxt); /* after newsym */
675 pay_for_damage(dmgtxt, FALSE);
676 (void) memset((genericptr_t) &context.digging, 0,
677 sizeof (struct dig_info));
683 register struct obj *obj;
684 register xchar ox, oy;
686 /* optimize by leaving on the fobj chain? */
688 newsym(obj->ox, obj->oy);
689 place_object(obj, ox, oy);
694 static NEARDATA const char fell_on_sink[] = "fell onto a sink";
696 static NEARDATA const char fell_on_sink[] = "
\97¬
\82µ
\91ä
\82É
\97\8e\82¿
\82Ä";
701 register struct obj *obj;
703 boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS),
704 innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L),
705 /* to handle being chained to buried iron ball, trying to
706 levitate but being blocked, then moving onto adjacent sink;
707 no need to worry about being blocked by terrain because we
708 couldn't be over a sink at the same time */
709 blockd_lev = (BLevitation == I_SPECIAL),
710 ufall = (!innate_lev && !blockd_lev
711 && !(HFlying || EFlying)); /* BFlying */
715 You((innate_lev || blockd_lev) ? "wobble unsteadily for a moment."
717 You((innate_lev || blockd_lev) ? "
\82¿
\82å
\82Á
\82Æ
\82Ó
\82ç
\82Â
\82¢
\82½
\81D"
719 : "gain control of your flight.");
721 : "
\94ò
\8ds
\92\86\82Ì
\90§
\8cä
\82ð
\8eæ
\82è
\82à
\82Ç
\82µ
\82½
\81D");
723 long save_ELev = ELevitation, save_HLev = HLevitation;
725 /* fake removal of levitation in advance so that final
726 disclosure will be right in case this turns out to
727 be fatal; fortunately the fact that rings and boots
728 are really still worn has no effect on bones data */
729 ELevitation = HLevitation = 0L;
731 You("crash to the floor!");
733 You("
\8f°
\82É
\92@
\82«
\82Â
\82¯
\82ç
\82ê
\82½
\81I");
734 dmg = rn1(8, 25 - (int) ACURR(A_CON));
736 losehp(Maybe_Half_Phys(dmg), fell_on_sink, NO_KILLER_PREFIX);
738 losehp(Maybe_Half_Phys(dmg), fell_on_sink, KILLED_BY);
740 exercise(A_DEX, FALSE);
742 selftouch("Falling, you");
744 selftouch("
\97\8e\82¿
\82È
\82ª
\82ç
\81C
\82 \82È
\82½
\82Í");
745 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
746 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
748 You("fell on %s.", doname(obj));
750 You("%s
\82Ì
\8fã
\82É
\97\8e\82¿
\82½
\81D",doname(obj));
752 losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink,
755 losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink,
758 exercise(A_CON, FALSE);
760 ELevitation = save_ELev;
761 HLevitation = save_HLev;
765 * Interrupt multi-turn putting on/taking off of armor (in which
766 * case we reached the sink due to being teleported while busy;
767 * in 3.4.3, Boots_on()/Boots_off() [called via (*afternmv)() when
768 * 'multi' reaches 0] triggered a crash if we were donning/doffing
769 * levitation boots [because the Boots_off() below causes 'uarmf'
770 * to be null by the time 'afternmv' gets called]).
772 * Interrupt donning/doffing if we fall onto the sink, or if the
773 * code below is going to remove levitation boots even when we
774 * haven't fallen (innate floating or flying becoming unblocked).
776 if (ufall || lev_boots) {
777 (void) stop_donning(lev_boots ? uarmf : (struct obj *) 0);
778 /* recalculate in case uarmf just got set to null */
779 lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS);
782 /* remove worn levitation items */
783 ELevitation &= ~W_ARTI;
784 HLevitation &= ~(I_SPECIAL | TIMEOUT);
786 if (uleft && uleft->otyp == RIN_LEVITATION) {
791 if (uright && uright->otyp == RIN_LEVITATION) {
802 /* probably moot; we're either still levitating or went
803 through float_down(), but make sure BFlying is up to date */
807 /* intended to be called only on ROCKs or TREEs */
812 struct rm *lev = &levl[x][y];
814 return (boolean) !((IS_STWALL(lev->typ) || IS_TREE(lev->typ))
815 && (lev->wall_info & W_NONDIGGABLE));
822 return (boolean) !(IS_STWALL(levl[x][y].typ)
823 && (levl[x][y].wall_info & W_NONPASSWALL));
828 struct permonst *mdat;
831 return (boolean) ((Sokoban && sobj_at(BOULDER, x, y))
832 || (IS_ROCK(levl[x][y].typ)
833 && (!tunnels(mdat) || needspick(mdat)
835 && !(passes_walls(mdat) && may_passwall(x, y))));
838 /* caller has already decided that it's a tight diagonal; check whether a
839 monster--who might be the hero--can fit through, and if not then return
840 the reason why: 1: can't fit, 2: possessions won't fit, 3: sokoban
841 returns 0 if we can squeeze through */
843 cant_squeeze_thru(mon)
847 struct permonst *ptr = mon->data;
851 && !(amorphous(ptr) || is_whirly(ptr) || noncorporeal(ptr)
852 || slithy(ptr) || can_fog(mon)))
855 /* lugging too much junk? */
856 amt = (mon == &youmonst) ? inv_weight() + weight_cap()
857 : curr_mon_load(mon);
861 /* Sokoban restriction applies to hero only */
862 if (mon == &youmonst && Sokoban)
865 /* can squeeze through */
873 return (boolean) (Invocation_lev(&u.uz)
874 && x == inv_pos.x && y == inv_pos.y);
877 /* return TRUE if (dx,dy) is an OK place to move
878 * mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP
881 test_move(ux, uy, dx, dy, mode)
887 register struct rm *tmpr = &levl[x][y];
888 register struct rm *ust;
890 context.door_opened = FALSE;
892 * Check for physical obstacles. First, the place we are going.
894 if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
895 if (Blind && mode == DO_MOVE)
897 if (Passes_walls && may_passwall(x, y)) {
899 } else if (Underwater) {
900 /* note: if water_friction() changes direction due to
901 turbulence, new target destination will always be water,
902 so we won't get here, hence don't need to worry about
903 "there" being somewhere the player isn't sure of */
906 pline("There is an obstacle there.");
908 pline("
\8fá
\8aQ
\95¨
\82ª
\82 \82é
\81D");
910 } else if (tmpr->typ == IRONBARS) {
911 if ((dmgtype(youmonst.data, AD_RUST)
912 || dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE
913 && still_chewing(x, y)) {
916 if (!(Passes_walls || passes_bars(youmonst.data))) {
917 if (mode == DO_MOVE && iflags.mention_walls)
919 You("cannot pass through the bars.");
921 You("
\93S
\82Ì
\96_
\82ð
\92Ê
\82è
\94²
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
924 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
926 if (mode == DO_MOVE && still_chewing(x, y))
928 } else if (flags.autodig && !context.run && !context.nopick && uwep
930 /* MRKR: Automatic digging when wielding the appropriate tool */
932 (void) use_pick_axe2(uwep);
935 if (mode == DO_MOVE) {
936 if (is_db_wall(x, y))
938 pline("That drawbridge is up!");
940 pline("
\92µ
\82Ë
\8b´
\82Í
\8fã
\82Á
\82Ä
\82¢
\82é
\81I");
941 /* sokoban restriction stays even after puzzle is solved */
942 else if (Passes_walls && !may_passwall(x, y)
943 && In_sokoban(&u.uz))
945 pline_The("Sokoban walls resist your ability.");
947 pline_The("
\91q
\8cÉ
\94Ô
\82Ì
\95Ç
\82Í
\82 \82È
\82½
\82Ì
\94\
\97Í
\82É
\92ï
\8dR
\82µ
\82½
\81D");
948 else if (iflags.mention_walls)
951 (IS_WALL(tmpr->typ) || tmpr->typ == SDOOR) ? "a wall"
952 : IS_TREE(tmpr->typ) ? "a tree"
955 pline("
\82±
\82ê
\82Í%s
\82¾
\81D",
956 (IS_WALL(tmpr->typ) || tmpr->typ == SDOOR) ? "
\95Ç"
957 : IS_TREE(tmpr->typ) ? "
\96Ø"
963 } else if (IS_DOOR(tmpr->typ)) {
964 if (closed_door(x, y)) {
965 if (Blind && mode == DO_MOVE)
969 } else if (can_ooze(&youmonst)) {
972 You("ooze under the door.");
974 You("
\83h
\83A
\82Ì
\89º
\82©
\82ç
\82É
\82¶
\82Ý
\8fo
\82½
\81D");
975 } else if (Underwater) {
978 pline("There is an obstacle there.");
980 pline("
\8fá
\8aQ
\95¨
\82ª
\82 \82é
\81D");
982 } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
984 if (mode == DO_MOVE && still_chewing(x, y))
987 if (mode == DO_MOVE) {
988 if (amorphous(youmonst.data))
991 "try to ooze under the door, but can't squeeze your possessions through.");
993 "
\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");
994 if (flags.autoopen && !context.run && !Confusion
995 && !Stunned && !Fumbling) {
996 context.door_opened = context.move =
998 } else if (x == ux || y == uy) {
999 if (Blind || Stunned || ACURR(A_DEX) < 10
1003 You_cant("lead %s through that closed door.",
1005 You_cant("%s
\82É
\95Â
\82Ü
\82Á
\82½
\94à
\82ð
\92Ê
\89ß
\82³
\82¹
\82é
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D",
1006 y_monnam(u.usteed));
1009 pline("Ouch! You bump into a door.");
1011 pline("
\82¢
\82Ä
\82Á
\81I
\93ª
\82ð
\94à
\82É
\82Ô
\82Â
\82¯
\82½
\81D");
1012 exercise(A_DEX, FALSE);
1016 pline("That door is closed.");
1018 pline("
\94à
\82Í
\95Â
\82Ü
\82Á
\82Ä
\82¢
\82é
\81D");
1020 } else if (mode == TEST_TRAV || mode == TEST_TRAP)
1026 if (dx && dy && !Passes_walls
1027 && (!doorless_door(x, y) || block_door(x, y))) {
1028 /* Diagonal moves into a door are not allowed. */
1029 if (mode == DO_MOVE) {
1031 feel_location(x, y);
1032 if (Underwater || iflags.mention_walls)
1034 You_cant("move diagonally into an intact doorway.");
1036 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");
1042 if (dx && dy && bad_rock(youmonst.data, ux, y)
1043 && bad_rock(youmonst.data, x, uy)) {
1044 /* Move at a diagonal. */
1045 switch (cant_squeeze_thru(&youmonst)) {
1047 if (mode == DO_MOVE)
1049 You("cannot pass that way.");
1051 You("
\92Ê
\82è
\82Ê
\82¯
\82Å
\82«
\82È
\82¢
\81D");
1054 if (mode == DO_MOVE)
1056 You("are carrying too much to get through.");
1058 pline("
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\92Ê
\82è
\82Ê
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
1061 if (mode == DO_MOVE)
1063 Your("body is too large to fit through.");
1065 Your("
\91Ì
\82ª
\91å
\82«
\82·
\82¬
\82Ä
\92Ê
\82è
\82Ê
\82¯
\82ç
\82ê
\82È
\82¢
\81D");
1068 break; /* can squeeze through */
1070 } else if (dx && dy && worm_cross(ux, uy, x, y)) {
1071 /* consecutive long worm segments are at <ux,y> and <x,uy> */
1072 if (mode == DO_MOVE)
1074 pline("%s is in your way.", Monnam(m_at(ux, y)));
1076 pline("
\93¹
\82Ì
\93r
\92\86\82É%s
\82ª
\82¢
\82é
\81D", Monnam(m_at(ux, y)));
1079 /* Pick travel path that does not require crossing a trap.
1080 * Avoid water and lava using the usual running rules.
1081 * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
1082 if (context.run == 8 && (mode != DO_MOVE)
1083 && (x != u.ux || y != u.uy)) {
1084 struct trap *t = t_at(x, y);
1087 || (!Levitation && !Flying && !is_clinger(youmonst.data)
1088 && is_pool_or_lava(x, y) && levl[x][y].seenv))
1089 return (mode == TEST_TRAP);
1092 if (mode == TEST_TRAP)
1093 return FALSE; /* do not move through traps */
1095 ust = &levl[ux][uy];
1097 /* Now see if other things block our way . . */
1098 if (dx && dy && !Passes_walls && IS_DOOR(ust->typ)
1099 && (!doorless_door(ux, uy) || block_entry(x, y))) {
1100 /* Can't move at a diagonal out of a doorway with door. */
1101 if (mode == DO_MOVE && iflags.mention_walls)
1103 You_cant("move diagonally out of an intact doorway.");
1105 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");
1109 if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) {
1110 if (!(Blind || Hallucination) && (context.run >= 2)
1111 && mode != TEST_TRAV) {
1112 if (mode == DO_MOVE && iflags.mention_walls)
1114 pline("A boulder blocks your path.");
1116 pline("
\8b\90\8aâ
\82ª
\93¹
\82ð
\82Ó
\82³
\82¢
\82Å
\82¢
\82é
\81D");
1119 if (mode == DO_MOVE) {
1120 /* tunneling monsters will chew before pushing */
1121 if (tunnels(youmonst.data) && !needspick(youmonst.data)
1123 if (still_chewing(x, y))
1125 } else if (moverock() < 0)
1127 } else if (mode == TEST_TRAV) {
1130 /* never travel through boulders in Sokoban */
1134 /* don't pick two boulders in a row, unless there's a way thru */
1135 if (sobj_at(BOULDER, ux, uy) && !Sokoban) {
1137 && !(tunnels(youmonst.data) && !needspick(youmonst.data))
1138 && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK)
1139 && !((obj = carrying(WAN_DIGGING))
1140 && !objects[obj->otyp].oc_name_known))
1144 /* assume you'll be able to push it when you get there... */
1147 /* OK, it is a legal place to move. */
1152 * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
1153 * A shortest path is returned. If guess is TRUE, consider various
1154 * inaccessible locations as valid intermediate path points.
1155 * Returns TRUE if a path was found.
1158 findtravelpath(mode)
1161 /* if travel to adjacent, reachable location, use normal movement rules */
1162 if ((mode == TRAVP_TRAVEL || mode == TRAVP_VALID) && context.travel1
1163 && distmin(u.ux, u.uy, u.tx, u.ty) == 1
1164 && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) {
1166 if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) {
1167 if (mode == TRAVP_TRAVEL) {
1171 iflags.travelcc.x = iflags.travelcc.y = 0;
1175 if (mode == TRAVP_TRAVEL)
1178 if (u.tx != u.ux || u.ty != u.uy) {
1179 xchar travel[COLNO][ROWNO];
1180 xchar travelstepx[2][COLNO * ROWNO];
1181 xchar travelstepy[2][COLNO * ROWNO];
1182 xchar tx, ty, ux, uy;
1183 int n = 1; /* max offset in travelsteps */
1184 int set = 0; /* two sets current and previous */
1185 int radius = 1; /* search radius */
1188 /* If guessing, first find an "obvious" goal location. The obvious
1189 * goal is the position the player knows of, or might figure out
1190 * (couldsee) that is closest to the target on a straight path.
1192 if (mode == TRAVP_GUESS || mode == TRAVP_VALID) {
1205 (void) memset((genericptr_t) travel, 0, sizeof travel);
1206 travelstepx[0][0] = tx;
1207 travelstepy[0][0] = ty;
1212 for (i = 0; i < n; i++) {
1214 int x = travelstepx[set][i];
1215 int y = travelstepy[set][i];
1216 static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
1217 /* no diagonal movement for grid bugs */
1218 int dirmax = NODIAG(u.umonnum) ? 4 : 8;
1219 boolean alreadyrepeated = FALSE;
1221 for (dir = 0; dir < dirmax; ++dir) {
1222 int nx = x + xdir[ordered[dir]];
1223 int ny = y + ydir[ordered[dir]];
1226 * When guessing and trying to travel as close as possible
1227 * to an unreachable target space, don't include spaces
1228 * that would never be picked as a guessed target in the
1229 * travel matrix describing hero-reachable spaces.
1230 * This stops travel from getting confused and moving
1231 * the hero back and forth in certain degenerate
1232 * configurations of sight-blocking obstacles, e.g.
1234 * T 1. Dig this out and carry enough to not be
1235 * #### able to squeeze through diagonal gaps.
1236 * #--.--- Stand at @ and target travel at space T.
1240 * T 2. couldsee() marks spaces marked a and x
1241 * #### as eligible guess spaces to move the hero
1242 * a--.--- towards. Space a is closest to T, so it
1243 * @xxxxx gets chosen. Travel system moves @ right
1244 * |xxxxx to travel to space a.
1246 * T 3. couldsee() marks spaces marked b, c and x
1247 * #### as eligible guess spaces to move the hero
1248 * a--c--- towards. Since findtravelpath() is called
1249 * b@xxxx repeatedly during travel, it doesn't
1250 * |xxxxx remember that it wanted to go to space a,
1251 * so in comparing spaces b and c, b is
1252 * chosen, since it seems like the closest
1253 * eligible space to T. Travel system moves @
1254 * left to go to space b.
1258 * By limiting the travel matrix here, space a in the
1259 * example above is never included in it, preventing
1263 || ((mode == TRAVP_GUESS) && !couldsee(nx, ny)))
1265 if ((!Passes_walls && !can_ooze(&youmonst)
1266 && closed_door(x, y)) || sobj_at(BOULDER, x, y)
1267 || test_move(x, y, nx-x, ny-y, TEST_TRAP)) {
1268 /* closed doors and boulders usually
1269 * cause a delay, so prefer another path */
1270 if (travel[x][y] > radius - 3) {
1271 if (!alreadyrepeated) {
1272 travelstepx[1 - set][nn] = x;
1273 travelstepy[1 - set][nn] = y;
1274 /* don't change travel matrix! */
1276 alreadyrepeated = TRUE;
1281 if (test_move(x, y, nx - x, ny - y, TEST_TRAV)
1282 && (levl[nx][ny].seenv
1283 || (!Blind && couldsee(nx, ny)))) {
1284 if (nx == ux && ny == uy) {
1285 if (mode == TRAVP_TRAVEL || mode == TRAVP_VALID) {
1288 if (mode == TRAVP_TRAVEL
1289 && x == u.tx && y == u.ty) {
1291 /* reset run so domove run checks work */
1293 iflags.travelcc.x = iflags.travelcc.y = 0;
1297 } else if (!travel[nx][ny]) {
1298 travelstepx[1 - set][nn] = nx;
1299 travelstepy[1 - set][nn] = ny;
1300 travel[nx][ny] = radius;
1308 if (iflags.trav_debug) {
1309 /* Use of warning glyph is arbitrary. It stands out. */
1310 tmp_at(DISP_ALL, warning_to_glyph(1));
1311 for (i = 0; i < nn; ++i) {
1312 tmp_at(travelstepx[1 - set][i], travelstepy[1 - set][i]);
1315 if (flags.runmode == RUN_CRAWL) {
1319 tmp_at(DISP_END, 0);
1328 /* if guessing, find best location in travel matrix and go there */
1329 if (mode == TRAVP_GUESS) {
1330 int px = tx, py = ty; /* pick location */
1331 int dist, nxtdist, d2, nd2;
1333 dist = distmin(ux, uy, tx, ty);
1334 d2 = dist2(ux, uy, tx, ty);
1335 for (tx = 1; tx < COLNO; ++tx)
1336 for (ty = 0; ty < ROWNO; ++ty)
1337 if (travel[tx][ty]) {
1338 nxtdist = distmin(ux, uy, tx, ty);
1339 if (nxtdist == dist && couldsee(tx, ty)) {
1340 nd2 = dist2(ux, uy, tx, ty);
1342 /* prefer non-zigzag path */
1347 } else if (nxtdist < dist && couldsee(tx, ty)) {
1351 d2 = dist2(ux, uy, tx, ty);
1355 if (px == u.ux && py == u.uy) {
1356 /* no guesses, just go in the general direction */
1357 u.dx = sgn(u.tx - u.ux);
1358 u.dy = sgn(u.ty - u.uy);
1359 if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
1364 if (iflags.trav_debug) {
1365 /* Use of warning glyph is arbitrary. It stands out. */
1366 tmp_at(DISP_ALL, warning_to_glyph(2));
1369 if (flags.runmode == RUN_CRAWL) {
1375 tmp_at(DISP_END, 0);
1384 mode = TRAVP_TRAVEL;
1398 is_valid_travelpt(x,y)
1404 int g = glyph_at(x,y);
1405 if (x == u.ux && y == u.uy)
1407 if (isok(x,y) && glyph_is_cmap(g) && S_stone == glyph_to_cmap(g)
1408 && !levl[x][y].seenv)
1412 ret = findtravelpath(TRAVP_VALID);
1418 /* try to escape being stuck in a trapped state by walking out of it;
1419 return true iff moving should continue to intended destination
1420 (all failures and most successful escapes leave hero at original spot) */
1422 trapmove(x, y, desttrap)
1423 int x, y; /* targetted destination, <u.ux+u.dx,u.uy+u.dy> */
1424 struct trap *desttrap; /* nonnull if another trap at <x,y> */
1426 boolean anchored = FALSE;
1427 const char *predicament, *culprit;
1428 char *steedname = !u.usteed ? (char *) 0 : y_monnam(u.usteed);
1431 return TRUE; /* sanity check */
1434 * Note: caller should call reset_utrap() when we set u.utrap to 0.
1437 switch (u.utraptype) {
1439 if (flags.verbose) {
1441 predicament = "caught in a bear trap";
1443 predicament = "
\8cF
\82Ìã©
\82É
\82Â
\82©
\82Ü
\82Á
\82½";
1446 Norep("%s is %s.", upstart(steedname), predicament);
1448 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1451 Norep("You are %s.", predicament);
1453 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1455 /* [why does diagonal movement give quickest escape?] */
1456 if ((u.dx && u.dy) || !rn2(5))
1462 if (desttrap && desttrap->tseen
1463 && is_pit(desttrap->ttyp))
1464 return TRUE; /* move into adjacent pit */
1465 /* try to escape; position stays same regardless of success */
1469 if (uwep && uwep->oartifact == ART_STING) {
1470 /* escape trap but don't move and don't destroy it */
1471 u.utrap = 0; /* caller will call reset_utrap() */
1473 pline("Sting cuts through the web!");
1475 pline("
\83X
\83e
\83B
\83\93\83O
\82Í
\82
\82à
\82Ì
\91\83\82ð
\90Ø
\82è
\82³
\82¢
\82½
\81I");
1479 if (flags.verbose) {
1481 predicament = "stuck to the web";
1483 predicament = "
\82
\82à
\82Ì
\91\83\82É
\82Ð
\82Á
\82©
\82©
\82Á
\82½";
1486 Norep("%s is %s.", upstart(steedname), predicament);
1488 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1491 Norep("You are %s.", predicament);
1493 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1498 pline("%s breaks out of the web.", upstart(steedname));
1500 pline("%s
\82Í
\82
\82à
\82Ì
\91\83\82ð
\89ó
\82µ
\82½
\81D", upstart(steedname));
1503 You("disentangle yourself.");
1505 You("
\8e©
\95ª
\82Å
\82Ù
\82Ç
\82¢
\82½
\81D");
1509 if (flags.verbose) {
1511 predicament = "stuck in the lava";
1513 predicament = "
\97n
\8aâ
\82É
\82Í
\82Ü
\82Á
\82½";
1516 Norep("%s is %s.", upstart(steedname), predicament);
1518 Norep("%s
\82Í%s
\81D", upstart(steedname), predicament);
1521 Norep("You are %s.", predicament);
1523 Norep("
\82 \82È
\82½
\82Í%s
\81D", predicament);
1525 if (!is_lava(x, y)) {
1527 if ((u.utrap & 0xff) == 0) {
1531 You("lead %s to the edge of the %s.", steedname,
1534 You("%s
\82ð%s
\82Ì
\92[
\82Ü
\82Å
\93±
\82¢
\82½
\81D", steedname,
1535 hliquid("
\97n
\8aâ"));
1539 You("pull yourself to the edge of the %s.",
1542 You("%s
\82Ì
\92[
\82Ü
\82Å
\82©
\82ë
\82¤
\82¶
\82Ä
\81C
\82½
\82Ç
\82è
\82Â
\82¢
\82½
\81D",
1543 hliquid("
\97n
\8aâ"));
1551 anchored = (u.utraptype == TT_BURIEDBALL);
1555 cc.x = u.ux, cc.y = u.uy;
1556 /* can move normally within radius 1 of buried ball */
1557 if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) {
1558 /* ugly hack: we need to issue some message here
1559 in case "you are chained to the buried ball"
1560 was the most recent message given, otherwise
1561 our next attempt to move out of tether range
1562 after this successful move would have its
1563 can't-do-that message suppressed by Norep */
1566 Norep("You move within the chain's reach.");
1568 Norep("
\8d½
\82ª
\93Í
\82
\94Í
\88Í
\82É
\88Ú
\93®
\82Å
\82«
\82é
\81D");
1573 if (flags.verbose) {
1576 predicament = "chained to the";
1577 culprit = "buried ball";
1579 predicament = "
\82Æ
\82Â
\82È
\82ª
\82Á
\82Ä
\82¢
\82é";
1580 culprit = "
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é
\8b\85";
1584 predicament = "stuck in the";
1585 culprit = surface(u.ux, u.uy);
1587 predicament = "
\82É
\96\84\82Ü
\82Á
\82Ä
\82¢
\82é";
1588 culprit = surface(u.ux, u.uy);
1594 Norep("You and %s are %s %s.", steedname, predicament,
1597 Norep("
\82 \82È
\82½
\82Æ%s
\82Í%s%s
\81D", steedname, culprit,
1602 Norep("%s is %s %s.", upstart(steedname), predicament,
1605 Norep("%s
\82Í%s%s
\81D", steedname, culprit,
1610 Norep("You are %s %s.", predicament, culprit);
1612 Norep("
\82 \82È
\82½
\82Í%s
\82É%s
\81D", culprit, predicament);
1618 pline("%s finally %s free.", upstart(steedname),
1619 !anchored ? "lurches" : "wrenches the ball");
1621 pline("%s
\82Í%s
\82â
\82Á
\82Æ
\8e©
\97R
\82É
\82È
\82Á
\82½
\81D", upstart(steedname),
1622 !anchored ? "
\82à
\82ª
\82¢
\82Ä" : "
\93S
\8b\85\82ð
\82à
\82¬
\8eæ
\82Á
\82Ä");
1626 You("finally %s free.",
1627 !anchored ? "wriggle" : "wrench the ball");
1629 You("%s
\82â
\82Á
\82Æ
\8e©
\97R
\82É
\82È
\82Á
\82½
\81D",
1630 !anchored ? "
\82à
\82ª
\82¢
\82Ä" : "
\93S
\8b\85\82ð
\82à
\82¬
\8eæ
\82Á
\82Ä");
1633 buried_ball_to_punishment();
1637 impossible("trapmove: stuck in unknown trap? (%d)",
1647 if (!youmonst.data->mmove) {
1649 You("are rooted %s.",
1650 Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
1654 You("
\82»
\82Ì
\8fê
\82É
\97§
\82¿
\82·
\82
\82ñ
\82¾
\81D");
1665 int ux1 = u.ux, uy1 = u.uy;
1667 domove_succeeded = 0L;
1669 /* domove_succeeded is available for making assessments now */
1670 if ((domove_succeeded & (DOMOVE_RUSH | DOMOVE_WALK)) != 0)
1671 maybe_smudge_engr(ux1, uy1, u.ux, u.uy);
1672 domove_attempting = 0L;
1678 register struct monst *mtmp;
1679 register struct rm *tmpr;
1680 register xchar x, y;
1681 struct trap *trap = NULL;
1684 xchar chainx = 0, chainy = 0,
1685 ballx = 0, bally = 0; /* ball&chain new positions */
1686 int bc_control = 0; /* control for ball&chain */
1687 boolean cause_delay = FALSE; /* dragging ball will skip a move */
1689 if (context.travel) {
1690 if (!findtravelpath(FALSE))
1691 (void) findtravelpath(TRUE);
1692 context.travel1 = 0;
1695 if (((wtcap = near_capacity()) >= OVERLOADED
1696 || (wtcap > SLT_ENCUMBER
1697 && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
1698 : (u.uhp < 10 && u.uhp != u.uhpmax))))
1699 && !Is_airlevel(&u.uz)) {
1700 if (wtcap < OVERLOADED) {
1702 You("don't have enough stamina to move.");
1704 You("
\82Ö
\82Æ
\82Ö
\82Æ
\82Å
\93®
\82¯
\82È
\82¢
\81D");
1705 exercise(A_CON, FALSE);
1708 You("collapse under your load.");
1710 pline("
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\93|
\82ê
\82½
\81D");
1716 u.ux = x = u.ustuck->mx;
1717 u.uy = y = u.ustuck->my;
1720 if (Is_airlevel(&u.uz) && rn2(4) && !Levitation && !Flying) {
1724 You("tumble in place.");
1726 You("
\82»
\82Ì
\8fê
\82Å
\93|
\82ê
\82½
\81D");
1727 exercise(A_DEX, FALSE);
1731 You_cant("control your movements very well.");
1733 You("
\82¤
\82Ü
\82
\95à
\82¯
\82È
\82¢
\81D");
1737 pline("It's hard to walk in thin air.");
1739 pline("
\8bó
\92\86\82ð
\95à
\82
\82Ì
\82Í
\93ï
\82µ
\82¢
\81D");
1740 exercise(A_DEX, TRUE);
1746 /* check slippery ice */
1747 on_ice = !Levitation && is_ice(u.ux, u.uy);
1749 static int skates = 0;
1752 skates = find_skates();
1753 if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst)
1754 || Flying || is_floater(youmonst.data)
1755 || is_clinger(youmonst.data) || is_whirly(youmonst.data)) {
1757 } else if (!rn2(Cold_resistance ? 3 : 2)) {
1758 HFumbling |= FROMOUTSIDE;
1759 HFumbling &= ~TIMEOUT;
1760 HFumbling += 1; /* slip on next move */
1763 if (!on_ice && (HFumbling & FROMOUTSIDE))
1764 HFumbling &= ~FROMOUTSIDE;
1768 if (Stunned || (Confusion && !rn2(5))) {
1769 register int tries = 0;
1779 } while (!isok(x, y) || bad_rock(youmonst.data, x, y));
1781 /* turbulence might alter your actual destination */
1784 if (!u.dx && !u.dy) {
1791 /* are we trying to move out of water while carrying too much? */
1792 if (isok(x, y) && !is_pool(x, y) && !Is_waterlevel(&u.uz)
1793 && wtcap > (Swimming ? MOD_ENCUMBER : SLT_ENCUMBER)) {
1794 /* when escaping from drowning you need to be unencumbered
1795 in order to crawl out of water, but when not drowning,
1796 doing so while encumbered is feasible; if in an aquatic
1797 form, stressed or less is allowed; otherwise (magical
1798 breathing), only burdened is allowed */
1800 You("are carrying too much to climb out of the water.");
1802 You("
\90\85\82©
\82ç
\8fã
\82ª
\82é
\82É
\82Í
\89×
\95¨
\82ð
\8e\9d\82¿
\82·
\82¬
\82Ä
\82¢
\82é
\81D");
1811 if (((trap = t_at(x, y)) && trap->tseen)
1812 || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data)
1813 && is_pool_or_lava(x, y) && levl[x][y].seenv)) {
1814 if (context.run >= 2) {
1815 if (iflags.mention_walls) {
1816 if (trap && trap->tseen) {
1817 int tt = what_trap(trap->ttyp, rn2_on_display_rng);
1820 You("stop in front of %s.",
1822 You("%s
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
1823 an(defsyms[trap_to_defsym(tt)].explanation));
1824 } else if (is_pool_or_lava(x,y) && levl[x][y].seenv) {
1826 You("stop at the edge of the %s.",
1827 hliquid(is_pool(x,y) ? "water" : "lava"));
1829 You("%s
\82Ì
\92[
\82Å
\8e~
\82Ü
\82Á
\82½
\81D.",
1830 hliquid(is_pool(x,y) ? "
\90\85" : "
\97n
\8aâ"));
1841 if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
1842 if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
1843 /* perhaps it fled (or was teleported or ... ) */
1845 } else if (sticks(youmonst.data)) {
1846 /* When polymorphed into a sticking monster,
1847 * u.ustuck means it's stuck to you, not you to it.
1850 You("release %s.", mon_nam(u.ustuck));
1852 You("%s
\82ð
\95ú
\82µ
\82½
\81D", mon_nam(u.ustuck));
1855 /* If holder is asleep or paralyzed:
1856 * 37.5% chance of getting away,
1857 * 12.5% chance of waking/releasing it;
1859 * 7.5% chance of getting away.
1860 * [strength ought to be a factor]
1861 * If holder is tame and there is no conflict,
1862 * guaranteed escape.
1864 switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
1870 You("pull free from %s.", mon_nam(u.ustuck));
1872 You("%s
\82ð
\82Ð
\82«
\82Í
\82È
\82µ
\82½
\81D", mon_nam(u.ustuck));
1876 if (!u.ustuck->mcanmove) {
1877 /* it's free to move on next turn */
1878 u.ustuck->mfrozen = 1;
1879 u.ustuck->msleeping = 0;
1883 if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf)
1886 You("cannot escape from %s!", mon_nam(u.ustuck));
1888 You("%s
\82©
\82ç
\93¦
\82°
\82ç
\82ê
\82È
\82¢
\81I", mon_nam(u.ustuck));
1896 if (mtmp && !is_safepet(mtmp)) {
1897 /* Don't attack if you're running, and can see it */
1898 /* It's fine to displace pets, though */
1899 /* We should never get here if forcefight */
1900 if (context.run && ((!Blind && mon_visible(mtmp)
1901 && ((M_AP_TYPE(mtmp) != M_AP_FURNITURE
1902 && M_AP_TYPE(mtmp) != M_AP_OBJECT)
1903 || Protection_from_shape_changers))
1904 || sensemon(mtmp))) {
1918 /* attack monster */
1920 /* don't stop travel when displacing pets; if the
1921 displace fails for some reason, attack() in uhitm.c
1922 will stop travel rather than domove */
1923 if (!is_safepet(mtmp) || context.forcefight)
1925 /* only attack if we know it's there */
1926 /* or if we used the 'F' command to fight blindly */
1927 /* or if it hides_under, in which case we call attack() to print
1928 * the Wait! message.
1929 * This is different from ceiling hiders, who aren't handled in
1933 /* If they used a 'm' command, trying to move onto a monster
1934 * prints the below message and wastes a turn. The exception is
1935 * if the monster is unseen and the player doesn't remember an
1936 * invisible monster--then, we fall through to attack() and
1937 * attack_check(), which still wastes a turn, but prints a
1938 * different message and makes the player remember the monster.
1940 if (context.nopick && !context.travel
1941 && (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))) {
1942 if (M_AP_TYPE(mtmp) && !Protection_from_shape_changers
1944 stumble_onto_mimic(mtmp);
1945 else if (mtmp->mpeaceful && !Hallucination)
1946 /* m_monnam(): "dog" or "Fido", no "invisible dog" or "it" */
1948 pline("Pardon me, %s.", m_monnam(mtmp));
1950 pline("
\82¿
\82å
\82Á
\82Æ
\82²
\82ß
\82ñ
\82È
\82³
\82¢
\82æ
\81C%s
\82³
\82ñ
\81D", m_monnam(mtmp));
1953 You("move right into %s.", mon_nam(mtmp));
1955 You("%s
\82Ì
\82»
\82Î
\82É
\88Ú
\93®
\82µ
\82½
\81D", mon_nam(mtmp));
1958 if (context.forcefight || !mtmp->mundetected || sensemon(mtmp)
1959 || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)
1960 && !is_safepet(mtmp))) {
1961 /* try to attack; note that it might evade */
1962 /* also, we don't attack tame when _safepet_ */
1968 if (context.forcefight && levl[x][y].typ == IRONBARS && uwep) {
1969 struct obj *obj = uwep;
1971 if (breaktest(obj)) {
1973 obj = splitobj(obj, 1L);
1975 setuwep((struct obj *)0);
1978 hit_bars(&obj, u.ux, u.uy, x, y, TRUE, TRUE);
1982 /* specifying 'F' with no monster wastes a turn */
1983 if (context.forcefight
1984 /* remembered an 'I' && didn't use a move command */
1985 || (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) {
1986 struct obj *boulder = 0;
1987 boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)),
1988 solid = !accessible(x, y);
1989 int glyph = glyph_at(x, y); /* might be monster */
1993 boulder = sobj_at(BOULDER, x, y);
1994 /* if a statue is displayed at the target location,
1995 player is attempting to attack it [and boulder
1996 handling below is suitable for handling that] */
1997 if (glyph_is_statue(glyph)
1998 || (Hallucination && glyph_is_monster(glyph)))
1999 boulder = sobj_at(STATUE, x, y);
2001 /* force fight at boulder/statue or wall/door while wielding
2002 pick: start digging to break the boulder or wall */
2003 if (context.forcefight
2005 && uwep && dig_typ(uwep, x, y)
2006 /* should we dig? */
2007 && !glyph_is_invisible(glyph) && !glyph_is_monster(glyph)) {
2008 (void) use_pick_axe2(uwep);
2013 /* about to become known empty -- remove 'I' if present */
2016 map_object(boulder, TRUE);
2018 glyph = glyph_at(x, y); /* might have just changed */
2021 Strcpy(buf, ansimpleoname(boulder));
2022 } else if (Underwater && !is_pool(x, y)) {
2023 /* Underwater, targetting non-water; the map just shows blank
2024 because you don't see remembered terrain while underwater;
2025 although the hero can attack an adjacent monster this way,
2026 assume he can't reach out far enough to distinguish terrain */
2028 Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR)
2032 Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR)
2033 ? "
\8bó
\8bC
\82Ì
\96A"
2034 : "
\89½
\82à
\82È
\82¢
\82Æ
\82±
\82ë");
2037 /* glyph might indicate unseen terrain if hero is blind;
2038 unlike searching, this won't reveal what that terrain is
2039 (except for solid rock, where the glyph would otherwise
2040 yield ludicrous "dark part of a room") */
2042 Strcpy(buf, (levl[x][y].typ == STONE) ? "solid rock"
2043 : glyph_is_cmap(glyph)
2044 ? the(defsyms[glyph_to_cmap(glyph)].explanation)
2045 : (const char *) "an unknown obstacle");
2047 Strcpy(buf, (levl[x][y].typ == STONE) ? "
\90Î"
2048 : glyph_is_cmap(glyph)
2049 ? the(defsyms[glyph_to_cmap(glyph)].explanation)
2050 : (const char *) "
\95s
\96¾
\82È
\8fá
\8aQ
\95¨");
2052 /* note: 'solid' is misleadingly named and catches pools
2053 of water and lava as well as rock and walls */
2056 Strcpy(buf, "thin air");
2058 Strcpy(buf, "
\89½
\82à
\82È
\82¢
\8bó
\92\86");
2062 !(boulder || solid) ? "" : !explo ? "harmlessly " : "futilely ",
2063 explo ? "explode at" : "attack", buf);
2066 !(boulder || solid) ? "" : !explo ? "
\8cø
\89Ê
\82È
\82" : "
\82Þ
\82¾
\82É",
2067 buf, explo ? "
\82Å
\94\9a\94
\82µ
\82½" : "
\82ð
\8dU
\8c\82\82µ
\82½");
2073 u.mh = -1; /* dead in the current form */
2078 (void) unmap_invisible(x, y);
2079 /* not attacking an animal, so we try to move */
2080 if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) {
2089 boolean moved = trapmove(x, y, trap);
2092 reset_utrap(TRUE); /* might resume levitation or flight */
2093 /* might not have escaped, or did escape but remain in same spot */
2098 if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) {
2099 if (!context.door_opened) {
2106 /* Move ball and chain. */
2108 if (!drag_ball(x, y, &bc_control, &ballx, &bally, &chainx, &chainy,
2109 &cause_delay, TRUE))
2112 /* Check regions entering/leaving */
2113 if (!in_out_region(x, y))
2116 /* now move the hero */
2120 /* Move your steed, too */
2122 u.usteed->mx = u.ux;
2123 u.usteed->my = u.uy;
2128 * If safepet at destination then move the pet to the hero's
2129 * previous location using the same conditions as in attack().
2130 * there are special extenuating circumstances:
2131 * (1) if the pet dies then your god angers,
2132 * (2) if the pet gets trapped then your god may disapprove,
2133 * (3) if the pet was already trapped and you attempt to free it
2134 * not only do you encounter the trap but you may frighten your
2135 * pet causing it to go wild! moral: don't abuse this privilege.
2137 * Ceiling-hiding pets are skipped by this section of code, to
2138 * be caught by the normal falling-monster code.
2140 if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
2141 /* if trapped, there's a chance the pet goes wild */
2142 if (mtmp->mtrapped) {
2143 if (!rn2(mtmp->mtame)) {
2144 mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
2146 m_unleash(mtmp, TRUE);
2153 /* seemimic/newsym should be done before moving hero, otherwise
2154 the display code will draw the hero here before we possibly
2155 cancel the swap below (we can ignore steed mx,my here) */
2156 u.ux = u.ux0, u.uy = u.uy0;
2157 mtmp->mundetected = 0;
2158 if (M_AP_TYPE(mtmp))
2160 else if (!mtmp->mtame)
2161 newsym(mtmp->mx, mtmp->my);
2162 u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */
2164 if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0
2165 && is_pit(trap->ttyp)
2166 && sobj_at(BOULDER, trap->tx, trap->ty)) {
2167 /* can't swap places with pet pinned in a pit by a boulder */
2168 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
2170 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2171 } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
2172 /* can't swap places when pet can't move to your spot */
2173 u.ux = u.ux0, u.uy = u.uy0;
2175 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2177 You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp)));
2179 You("
\8e~
\82Ü
\82Á
\82½
\81D%s
\82Í
\8eÎ
\82ß
\82É
\93®
\82¯
\82È
\82¢
\81D", upstart(y_monnam(mtmp)));
2180 } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0)
2181 && bad_rock(mtmp->data, u.ux0, y)
2182 && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
2183 /* can't swap places when pet won't fit thru the opening */
2184 u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
2186 u.usteed->mx = u.ux, u.usteed->my = u.uy;
2188 You("stop. %s won't fit through.", upstart(y_monnam(mtmp)));
2190 You("
\8e~
\82Ü
\82Á
\82½
\81D%s
\82Í
\92Ê
\82è
\94²
\82¯
\82ç
\82ê
\82È
\82¢
\81D", upstart(y_monnam(mtmp)));
2192 char pnambuf[BUFSZ];
2194 /* save its current description in case of polymorph */
2195 Strcpy(pnambuf, y_monnam(mtmp));
2197 remove_monster(x, y);
2198 place_monster(mtmp, u.ux0, u.uy0);
2200 newsym(u.ux0, u.uy0);
2203 You("%s %s.", mtmp->mtame ? "swap places with" : "frighten",
2208 mtmp->mtame ? "
\82Æ
\8fê
\8f\8a\82ð
\93ü
\82ê
\8a·
\82í
\82Á" : "
\82ð
\95|
\82ª
\82ç
\82¹");
2211 /* check for displacing it into pools and traps */
2212 switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
2215 case 1: /* trapped */
2216 case 3: /* changed levels */
2217 /* there's already been a trap message, reinforce it */
2222 /* drowned or died...
2223 * you killed your pet by direct action, so get experience
2224 * and possibly penalties;
2225 * we want the level gain message, if it happens, to occur
2226 * before the guilt message below
2229 /* minliquid() and mintrap() call mondead() rather than
2230 killed() so we duplicate some of the latter here */
2233 u.uconduct.killer++;
2234 mndx = monsndx(mtmp->data);
2235 tmp = experience(mtmp, (int) mvitals[mndx].died);
2236 more_experienced(tmp, 0);
2237 newexplevel(); /* will decide if you go up */
2239 /* That's no way to treat a pet! Your god gets angry.
2241 * [This has always been pretty iffy. Why does your
2242 * patron deity care at all, let alone enough to get mad?]
2246 You_feel("guilty about losing your pet like this.");
2248 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");
2254 pline("that's strange, unknown mintrap result!");
2260 reset_occupations();
2262 if (context.run < 8)
2263 if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ)
2264 || IS_FURNITURE(tmpr->typ))
2268 if (hides_under(youmonst.data) || youmonst.data->mlet == S_EEL
2270 (void) hideunder(&youmonst);
2273 * Mimics (or whatever) become noticeable if they move and are
2274 * imitating something that doesn't move. We could extend this
2275 * to non-moving monsters...
2277 if ((u.dx || u.dy) && (U_AP_TYPE == M_AP_OBJECT
2278 || U_AP_TYPE == M_AP_FURNITURE))
2279 youmonst.m_ap_type = M_AP_NOTHING;
2281 check_leash(u.ux0, u.uy0);
2283 if (u.ux0 != u.ux || u.uy0 != u.uy) {
2284 /* let caller know so that an evaluation may take place */
2285 domove_succeeded |= (domove_attempting & (DOMOVE_RUSH | DOMOVE_WALK));
2287 /* Clean old position -- vision_recalc() will print our new one. */
2288 newsym(u.ux0, u.uy0);
2289 /* Since the hero has moved, adjust what can be seen/unseen. */
2290 vision_recalc(1); /* Do the work now in the recover time. */
2291 invocation_message();
2294 if (Punished) /* put back ball and chain */
2295 move_bc(0, bc_control, ballx, bally, chainx, chainy);
2300 /* delay next move because of ball dragging */
2301 /* must come after we finished picking up, in spoteffects() */
2305 multi_reason = "dragging an iron ball";
2307 multi_reason = "
\93S
\8b\85\82É
\88ø
\82«
\82¸
\82ç
\82ê
\82Ä
\82¢
\82é
\8e\9e\82É";
2311 if (context.run && flags.runmode != RUN_TPORT) {
2312 /* display every step or every 7th step depending upon mode */
2313 if (flags.runmode != RUN_LEAP || !(moves % 7L)) {
2318 if (flags.runmode == RUN_CRAWL) {
2329 maybe_smudge_engr(x1,y1,x2,y2)
2334 if (can_reach_floor(TRUE)) {
2335 if ((ep = engr_at(x1, y1)) && ep->engr_type != HEADSTONE)
2336 wipe_engr_at(x1, y1, rnd(5), FALSE);
2337 if ((x2 != x1 || y2 != y1)
2338 && (ep = engr_at(x2, y2)) && ep->engr_type != HEADSTONE)
2339 wipe_engr_at(x2, y2, rnd(5), FALSE);
2343 /* combat increases metabolism */
2347 /* this used to be part of domove() when moving to a monster's
2348 position, but is now called by attack() so that it doesn't
2349 execute if you decline to attack a peaceful monster */
2351 if ((moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) {
2352 int *hp = (!Upolyd ? &u.uhp : &u.mh);
2358 You("pass out from exertion!");
2360 You("
\8bC
\90â
\82µ
\82½
\81D");
2361 exercise(A_CON, FALSE);
2362 fall_asleep(-10, FALSE);
2365 return (boolean) (multi < 0); /* might have fainted (forced to sleep) */
2369 invocation_message()
2371 /* a special clue-msg when on the Invocation position */
2372 if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
2374 struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
2376 nomul(0); /* stop running or travelling */
2379 Sprintf(buf, "beneath %s", y_monnam(u.usteed));
2381 Sprintf(buf, "%s
\82Ì
\89º
\82É", y_monnam(u.usteed));
2382 else if (Levitation || Flying)
2384 Strcpy(buf, "beneath you");
2386 Strcpy(buf, "
\89º
\95û
\82É");
2389 Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
2391 Strcpy(buf, "
\91«
\8c³
\82É");
2394 You_feel("a strange vibration %s.", buf);
2396 You("%s
\8aï
\96
\82È
\90U
\93®
\82ð
\8a´
\82¶
\82½
\81D", buf);
2397 u.uevent.uvibrated = 1;
2398 if (otmp && otmp->spe == 7 && otmp->lamplit)
2400 pline("%s %s!", The(xname(otmp)),
2401 Blind ? "throbs palpably" : "glows with a strange light");
2403 pline("%s
\82Í%s
\82µ
\82½
\81I", The(xname(otmp)),
2404 Blind ? "
\82©
\82·
\82©
\82É
\90U
\93®" : "
\8aï
\96
\82È
\8cõ
\82ð
\94");
2409 /* moving onto different terrain;
2410 might be going into solid rock, inhibiting levitation or flight,
2411 or coming back out of such, reinstating levitation/flying */
2415 struct rm *lev = &levl[u.ux][u.uy];
2416 boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy)
2417 || (Is_waterlevel(&u.uz) && lev->typ == WATER)),
2418 was_levitating = !!Levitation, was_flying = !!Flying;
2421 /* called from spoteffects(), stop levitating but skip float_down() */
2424 You_cant("levitate in here.");
2426 You_cant("
\82±
\82±
\82Å
\82Í
\95\82\97V
\82Å
\82«
\82È
\82¢
\81D");
2427 BLevitation |= FROMOUTSIDE;
2428 } else if (BLevitation) {
2429 BLevitation &= ~FROMOUTSIDE;
2430 /* we're probably levitating now; if not, we must be chained
2431 to a buried iron ball so get float_up() feedback for that */
2432 if (Levitation || BLevitation)
2435 /* the same terrain that blocks levitation also blocks flight */
2439 You_cant("fly in here.");
2441 You_cant("
\82±
\82±
\82Å
\82Í
\94ò
\82×
\82È
\82¢
\81D");
2442 BFlying |= FROMOUTSIDE;
2443 } else if (BFlying) {
2444 BFlying &= ~FROMOUTSIDE;
2445 float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
2446 /* [minor bug: we don't know whether this is beginning flight or
2447 resuming it; that could be tracked so that this message could
2448 be adjusted to "resume flying", but isn't worth the effort...] */
2451 You("start flying.");
2453 You("
\94ò
\82Ñ
\82Í
\82¶
\82ß
\82½
\81D");
2455 if ((!Levitation ^ was_levitating) || (!Flying ^ was_flying))
2456 context.botl = TRUE; /* update Lev/Fly status condition */
2459 /* extracted from spoteffects; called by spoteffects to check for entering or
2460 leaving a pool of water/lava, and by moveloop to check for staying on one;
2461 returns true to skip rest of spoteffects */
2463 pooleffects(newspot)
2464 boolean newspot; /* true if called by spoteffects */
2466 /* check for leaving water */
2468 boolean still_inwater = FALSE; /* assume we're getting out */
2470 if (!is_pool(u.ux, u.uy)) {
2471 if (Is_waterlevel(&u.uz))
2473 You("pop into an air bubble.");
2475 You("
\82Ð
\82å
\82¢
\82Æ
\8bó
\8bC
\82Ì
\96A
\82É
\93ü
\82Á
\82½
\81D");
2476 else if (is_lava(u.ux, u.uy))
2478 You("leave the %s...", hliquid("water")); /* oops! */
2480 You("%s
\90\85\82©
\82ç
\94²
\82¯
\82¾
\82µ
\82½
\81D
\81D
\81D", hliquid("
\90\85")); /* oops! */
2484 You("are on solid %s again.",
2485 is_ice(u.ux, u.uy) ? "ice" : "land");
2487 You("
\8cÅ
\82¢%s
\82Ì
\8fã
\82É
\82Ü
\82½
\96ß
\82Á
\82½
\81D",
2488 is_ice(u.ux, u.uy) ? "
\95X" : "
\92n
\96Ê");
2490 } else if (Is_waterlevel(&u.uz)) {
2491 still_inwater = TRUE;
2492 } else if (Levitation) {
2494 You("pop out of the %s like a cork!", hliquid("water"));
2496 You("
\83R
\83\8b\83N
\82Ì
\82æ
\82¤
\82É%s
\82©
\82ç
\94ò
\82Ñ
\82¾
\82µ
\82½
\81I", hliquid("
\90\85"));
2497 } else if (Flying) {
2499 You("fly out of the %s.", hliquid("water"));
2501 You("%s
\82©
\82ç
\94ò
\82Ñ
\82¾
\82µ
\82½
\81D", hliquid("
\90\85"));
2502 } else if (Wwalking) {
2504 You("slowly rise above the surface.");
2506 You("
\82ä
\82Á
\82
\82è
\90\85\96Ê
\82Ü
\82Å
\8fã
\82ª
\82Á
\82½
\81D");
2508 still_inwater = TRUE;
2510 if (!still_inwater) {
2511 boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz));
2513 u.uinwater = 0; /* leave the water */
2514 if (was_underwater) { /* restore vision */
2516 vision_full_recalc = 1;
2521 /* check for entering water or lava */
2522 if (!u.ustuck && !Levitation && !Flying && is_pool_or_lava(u.ux, u.uy)) {
2524 && (is_flyer(u.usteed->data) || is_floater(u.usteed->data)
2525 || is_clinger(u.usteed->data))) {
2526 /* floating or clinging steed keeps hero safe (is_flyer() test
2527 is redundant; it can't be true since Flying yielded false) */
2529 } else if (u.usteed) {
2530 /* steed enters pool */
2531 dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC);
2532 /* dismount_steed() -> float_down() -> pickup()
2533 (float_down doesn't do autopickup on Air or Water) */
2534 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
2536 /* even if we actually end up at same location, float_down()
2537 has already done spoteffect()'s trap and pickup actions */
2539 check_special_room(FALSE); /* spoteffects */
2544 /* drown(),lava_effects() return true if hero changes
2545 location while surviving the problem */
2546 if (is_lava(u.ux, u.uy)) {
2549 } else if (!Wwalking
2550 && (newspot || !u.uinwater || !(Swimming || Amphibious))) {
2562 static int inspoteffects = 0;
2563 static coord spotloc;
2564 static int spotterrain;
2565 static struct trap *spottrap = (struct trap *) 0;
2566 static unsigned spottraptyp = NO_TRAP;
2569 struct trap *trap = t_at(u.ux, u.uy);
2570 int trapflag = iflags.failing_untrap ? FAILEDUNTRAP : 0;
2572 /* prevent recursion from affecting the hero all over again
2573 [hero poly'd to iron golem enters water here, drown() inflicts
2574 damage that triggers rehumanize() which calls spoteffects()...] */
2575 if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y
2576 /* except when reason is transformed terrain (ice -> water) */
2577 && spotterrain == levl[u.ux][u.uy].typ
2578 /* or transformed trap (land mine -> pit) */
2579 && (!spottrap || !trap || trap->ttyp == spottraptyp))
2583 spotterrain = levl[u.ux][u.uy].typ;
2584 spotloc.x = u.ux, spotloc.y = u.uy;
2586 /* moving onto different terrain might cause Lev or Fly to toggle */
2587 if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0))
2590 if (pooleffects(TRUE))
2593 check_special_room(FALSE);
2594 if (IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
2596 if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
2599 /* if levitation is due to time out at the end of this
2600 turn, allowing it to do so could give the perception
2601 that a trap here is being triggered twice, so adjust
2602 the timeout to prevent that */
2603 if (trap && (HLevitation & TIMEOUT) == 1L
2604 && !(ELevitation || (HLevitation & ~(I_SPECIAL | TIMEOUT)))) {
2605 if (rn2(2)) { /* defer timeout */
2606 incr_itimeout(&HLevitation, 1L);
2607 } else { /* timeout early */
2608 if (float_down(I_SPECIAL | TIMEOUT, 0L)) {
2609 /* levitation has ended; we've already triggered
2610 any trap and [usually] performed autopickup */
2617 * If not a pit, pickup before triggering trap.
2618 * If pit, trigger trap before pickup.
2620 pit = (trap && is_pit(trap->ttyp));
2626 * dotrap on a fire trap calls melt_ice() which triggers
2627 * spoteffects() (again) which can trigger the same fire
2628 * trap (again). Use static spottrap to prevent that.
2629 * We track spottraptyp because some traps morph
2630 * (landmine to pit) and any new trap type
2631 * should get triggered.
2633 if (!spottrap || spottraptyp != trap->ttyp) {
2635 spottraptyp = trap->ttyp;
2636 dotrap(trap, trapflag); /* fall into arrow trap, etc. */
2637 spottrap = (struct trap *) 0;
2638 spottraptyp = NO_TRAP;
2644 /* Warning alerts you to ice danger */
2645 if (Warning && is_ice(u.ux, u.uy)) {
2646 static const char *const icewarnings[] = {
2648 "The ice seems very soft and slushy.",
2649 "You feel the ice shift beneath you!",
2650 "The ice, is gonna BREAK!", /* The Dead Zone */
2652 "
\95X
\82Í
\82Æ
\82Ä
\82à
\93î
\82ç
\82©
\82
\82Ä
\97n
\82¯
\82»
\82¤
\82¾
\81D",
2653 "
\82 \82È
\82½
\82Ì
\89º
\82Ì
\95X
\82ª
\93®
\82¢
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I",
2654 "
\95X
\82ª
\89ó
\82ê
\82é
\82¼
\81I", /* The Dead Zone */
2657 long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY);
2659 if (time_left && time_left < 15L)
2660 pline("%s", icewarnings[(time_left < 5L) ? 2
2661 : (time_left < 10L) ? 1
2664 if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
2665 mtmp->mundetected = mtmp->msleeping = 0;
2666 switch (mtmp->data->mlet) {
2669 pline("%s suddenly drops from the %s!", Amonnam(mtmp),
2670 ceiling(u.ux, u.uy));
2672 pline("%s
\82ª
\93Ë
\91R%s
\82©
\82ç
\97\8e\82¿
\82Ä
\82«
\82½
\81I", Amonnam(mtmp),
2673 ceiling(u.ux,u.uy));
2675 if (mtmp->mtame) { /* jumps to greet you, not attack */
2677 } else if (uarmh && is_metallic(uarmh)) {
2679 pline("Its blow glances off your %s.",
2681 pline("
\8dU
\8c\82\82Í
\82 \82È
\82½
\82Ì%s
\82ð
\82©
\82·
\82ß
\82½
\82¾
\82¯
\82¾
\82Á
\82½
\81D",
2682 helm_simple_name(uarmh));
2683 } else if (u.uac + 3 <= rnd(20)) {
2685 You("are almost hit by %s!",
2686 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
2688 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",
2689 x_monnam(mtmp, ARTICLE_A, "", 0, TRUE));
2695 You("are hit by %s!",
2696 x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
2698 You("
\97\8e\82¿
\82Ä
\82«
\82½%s
\82É
\93\96\82½
\82Á
\82½
\81I",
2699 x_monnam(mtmp, ARTICLE_A, "", 0, TRUE));
2702 if (Half_physical_damage)
2703 dmg = (dmg + 1) / 2;
2704 mdamageu(mtmp, dmg);
2707 default: /* monster surprises you. */
2710 pline("%s jumps near you from the %s.", Amonnam(mtmp),
2711 ceiling(u.ux, u.uy));
2713 pline("%s
\82ª%s
\82©
\82ç
\82 \82È
\82½
\82Ì
\8bß
\82
\82É
\94ò
\82ñ
\82Å
\82«
\82½
\81D", Amonnam(mtmp),
2714 ceiling(u.ux,u.uy));
2716 else if (mtmp->mpeaceful) {
2720 You("%s
\82ð
\8bÁ
\82©
\82µ
\82½
\81I",
2721 Blind && !sensemon(mtmp) ? something : a_monnam(mtmp));
2722 mtmp->mpeaceful = 0;
2725 pline("%s attacks you by surprise!", Amonnam(mtmp));
2727 pline("%s
\82Í
\8bÁ
\82¢
\82Ä
\82 \82È
\82½
\82ð
\8dU
\8c\82\82µ
\82½
\81I", Amonnam(mtmp));
2730 mnexto(mtmp); /* have to move the monster */
2733 if (!--inspoteffects) {
2734 spotterrain = STONE; /* 0 */
2735 spotloc.x = spotloc.y = 0;
2740 /* returns first matching monster */
2741 STATIC_OVL struct monst *
2742 monstinroom(mdat, roomno)
2743 struct permonst *mdat;
2746 register struct monst *mtmp;
2748 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
2749 if (DEADMONSTER(mtmp))
2751 if (mtmp->data == mdat
2752 && index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
2755 return (struct monst *) 0;
2759 in_rooms(x, y, typewanted)
2760 register xchar x, y;
2761 register int typewanted;
2764 char rno, *ptr = &buf[4];
2765 int typefound, min_x, min_y, max_x, max_y_offset, step;
2766 register struct rm *lev;
2768 #define goodtype(rno) \
2770 || (typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted \
2771 || (typewanted == SHOPBASE && typefound > SHOPBASE))
2773 switch (rno = levl[x][y].roomno) {
2782 default: /* i.e. a regular room # */
2792 else if (x >= COLNO)
2799 max_y_offset -= step;
2800 } else if ((min_y + max_y_offset) >= ROWNO)
2801 max_y_offset -= step;
2803 for (x = min_x; x <= max_x; x += step) {
2804 lev = &levl[x][min_y];
2806 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2810 if (y > max_y_offset)
2812 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2816 if (y > max_y_offset)
2818 if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
2825 /* is (x,y) in a town? */
2830 s_level *slev = Is_special(&u.uz);
2831 register struct mkroom *sroom;
2832 boolean has_subrooms = FALSE;
2834 if (!slev || !slev->flags.town)
2838 * See if (x,y) is in a room with subrooms, if so, assume it's the
2839 * town. If there are no subrooms, the whole level is in town.
2841 for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
2842 if (sroom->nsubrooms > 0) {
2843 has_subrooms = TRUE;
2844 if (inside_room(sroom, x, y))
2849 return !has_subrooms;
2854 register boolean newlev;
2856 char *ptr1, *ptr2, *ptr3, *ptr4;
2858 Strcpy(u.urooms0, u.urooms);
2859 Strcpy(u.ushops0, u.ushops);
2862 u.uentered[0] = '\0';
2864 u.ushops_entered[0] = '\0';
2865 Strcpy(u.ushops_left, u.ushops0);
2868 Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
2870 for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0],
2871 ptr4 = &u.ushops_entered[0];
2873 if (!index(u.urooms0, *ptr1))
2875 if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
2877 if (!index(u.ushops0, *ptr1))
2885 /* filter u.ushops0 -> u.ushops_left */
2886 for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
2887 if (!index(u.ushops, *ptr1))
2892 /* possibly deliver a one-time room entry message */
2894 check_special_room(newlev)
2895 register boolean newlev;
2897 register struct monst *mtmp;
2900 move_update(newlev);
2903 u_left_shop(u.ushops_left, newlev);
2905 if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */
2906 return; /* no entrance messages necessary */
2908 /* Did we just enter a shop? */
2909 if (*u.ushops_entered)
2910 u_entered_shop(u.ushops_entered);
2912 for (ptr = &u.uentered[0]; *ptr; ptr++) {
2913 int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
2914 boolean msg_given = TRUE;
2916 /* Did we just enter some other special room? */
2917 /* vault.c insists that a vault remain a VAULT,
2918 * and temples should remain TEMPLEs,
2919 * but everything else gives a message only the first time */
2923 pline("Welcome to David's treasure zoo!");
2925 pline("
\83f
\83r
\83b
\83g
\95ó
\94 \93®
\95¨
\89\80\82É
\82æ
\82¤
\82±
\82»
\81I");
2929 pline("It %s rather %s down here.", Blind ? "feels" : "looks",
2930 Blind ? "humid" : "muddy");
2932 pline("
\82©
\82È
\82è%s
\81D",
2933 Blind ? "
\8e¼
\8bC
\82ª
\82 \82é
\8fê
\8f\8a\82Ì
\82æ
\82¤
\82¾"
2934 : "
\82Ç
\82ë
\82Ç
\82ë
\82µ
\82Ä
\82¢
\82é
\8fê
\8f\8a\82¾");
2939 You("enter an opulent throne room!");
2941 You("
\89Ø
\82â
\82©
\82È
\8bÊ
\8dÀ
\82Ì
\8aÔ
\82É
\93ü
\82Á
\82½
\81I");
2945 You("enter a leprechaun hall!");
2947 You("
\83\8c\83v
\83\89\83R
\81[
\83\93\83z
\81[
\83\8b\82É
\93ü
\82Á
\82½
\81I");
2952 const char *run = locomotion(youmonst.data, "Run");
2953 pline("%s away! %s away!", run, run);
2955 pline("
\93¦
\82°
\82ë
\81I
\93¦
\82°
\82ë
\81I");
2959 You("have an uncanny feeling...");
2961 You("
\95s
\8bC
\96¡
\82È
\8a´
\82¶
\82ª
\82µ
\82½
\81D
\81D
\81D");
2965 You("enter a giant beehive!");
2967 You("
\8b\90\91å
\82È
\96I
\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
2971 You("enter a disgusting nest!");
2973 You("
\82Þ
\82Á
\82Æ
\82·
\82é
\8fL
\82¢
\82Ì
\82·
\82é
\92¹
\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
2977 You("enter an anthole!");
2979 You("
\83A
\83\8a\82Ì
\91\83\82É
\93ü
\82Á
\82½
\81I");
2982 if (monstinroom(&mons[PM_SOLDIER], roomno)
2983 || monstinroom(&mons[PM_SERGEANT], roomno)
2984 || monstinroom(&mons[PM_LIEUTENANT], roomno)
2985 || monstinroom(&mons[PM_CAPTAIN], roomno))
2987 You("enter a military barracks!");
2989 You("
\8cR
\91à
\82Ì
\95ºäq
\82É
\93ü
\82Á
\82½
\81I");
2992 You("enter an abandoned barracks.");
2994 You("
\95ú
\92u
\82³
\82ê
\82½
\82Ü
\82Ü
\82Ì
\95ºäq
\82É
\93ü
\82Á
\82½
\81D");
2997 struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno);
2999 if (!oracle->mpeaceful)
3001 verbalize("You're in Delphi, %s.", plname);
3003 verbalize("
\82¨
\82Ü
\82¦
\82Í
\83f
\83\8b\83t
\83@
\83C
\82Ì
\90_
\91õ
\8f\8a\82É
\82¢
\82é
\81D");
3006 verbalize("%s, %s, welcome to Delphi!",
3007 Hello((struct monst *) 0), plname);
3009 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",
3017 intemple(roomno + ROOMOFFSET);
3020 msg_given = (rt == TEMPLE);
3025 room_discovered(roomno);
3028 rooms[roomno].rtype = OROOM;
3029 if (!search_special(rt)) {
3030 /* No more room of that type */
3033 level.flags.has_court = 0;
3036 level.flags.has_swamp = 0;
3039 level.flags.has_morgue = 0;
3042 level.flags.has_zoo = 0;
3045 level.flags.has_barracks = 0;
3048 level.flags.has_temple = 0;
3051 level.flags.has_beehive = 0;
3055 if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
3056 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
3057 if (DEADMONSTER(mtmp))
3059 if (!Stealth && !rn2(3))
3060 mtmp->msleeping = 0;
3069 1 = cannot pickup, time taken
3070 0 = cannot pickup, no time taken
3071 -1 = do normal pickup
3072 -2 = loot the monster */
3076 /* uswallow case added by GAN 01/29/87 */
3078 if (!u.ustuck->minvent) {
3079 if (is_animal(u.ustuck->data)) {
3081 You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
3083 You("%s
\82Ì
\90ã
\82ð
\8fE
\82Á
\82½
\81D", mon_nam(u.ustuck));
3085 pline("But it's kind of slimy, so you drop it.");
3087 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");
3090 You("don't %s anything in here to pick up.",
3091 Blind ? "feel" : "see");
3093 pline("
\82±
\82±
\82É
\82Í
\8fE
\82¦
\82é
\82à
\82Ì
\82ª
\82È
\82¢%s
\81D",
3094 Blind ? "
\82æ
\82¤
\82¾" : "");
3098 return -2; /* loot the monster inventory */
3101 if (is_pool(u.ux, u.uy)) {
3102 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
3103 || (Flying && !Breathless)) {
3105 You("cannot dive into the %s to pick things up.",
3108 You("
\95¨
\82ð
\8fE
\82¢
\82 \82°
\82é
\82½
\82ß
\82É%s
\82É
\94ò
\82Ñ
\82±
\82ß
\82È
\82¢
\81D",
3112 } else if (!Underwater) {
3114 You_cant("even see the bottom, let alone pick up %s.", something);
3116 pline("
\92ê
\82³
\82¦
\8c©
\82¦
\82È
\82¢
\81C
\8fE
\82¤
\82Ì
\82Í
\82â
\82ß
\82æ
\82¤
\81D");
3120 if (is_lava(u.ux, u.uy)) {
3121 if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
3122 || (Flying && !Breathless)) {
3124 You_cant("reach the bottom to pick things up.");
3126 You_cant("
\95¨
\82ð
\8fE
\82¢
\8fã
\82°
\82é
\82½
\82ß
\82É
\92ê
\82Ü
\82Å
\82¢
\82¯
\82È
\82¢
\81D");
3128 } else if (!likes_lava(youmonst.data)) {
3130 You("would burn to a crisp trying to pick things up.");
3132 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");
3136 if (!OBJ_AT(u.ux, u.uy)) {
3137 register struct rm *lev = &levl[u.ux][u.uy];
3139 if (IS_THRONE(lev->typ))
3141 pline("It must weigh%s a ton!", lev->looted ? " almost" : "");
3143 pline("
\82±
\82ê
\82Í%s
\8fd
\82¢
\81I", lev->looted ? "
\82©
\82È
\82è" : "
\82·
\82²
\82");
3144 else if (IS_SINK(lev->typ))
3146 pline_The("plumbing connects it to the floor.");
3148 pline_The("
\94z
\8aÇ
\82Í
\8f°
\82É
\82Â
\82È
\82ª
\82Á
\82Ä
\82¢
\82é
\81D");
3149 else if (IS_GRAVE(lev->typ))
3151 You("don't need a gravestone. Yet.");
3153 pline("
\82 \82È
\82½
\82É
\82Í
\95æ
\90Î
\82Í
\95s
\97v
\82¾
\81D
\81D
\81D
\8d¡
\82Ì
\82Æ
\82±
\82ë
\81D");
3154 else if (IS_FOUNTAIN(lev->typ))
3156 You("could drink the %s...", hliquid("water"));
3158 You("%s
\82ð
\88ù
\82ß
\82È
\82¢
\81D
\81D
\81D", hliquid("
\90\85"));
3159 else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
3161 pline("It won't come off the hinges.");
3163 pline("
\83q
\83\93\83W
\82ð
\8aO
\82¹
\82È
\82¢
\81D");
3164 else if (IS_ALTAR(lev->typ))
3165 pline("Moving the altar would be a very bad idea.");
3166 else if (lev->typ == STAIRS)
3167 pline_The("stairs are solidly fixed to the %s.",
3168 surface(u.ux, u.uy));
3171 There("is nothing here to pick up.");
3173 pline("
\82±
\82±
\82É
\82Í
\8fE
\82¦
\82é
\82à
\82Ì
\82Í
\82È
\82¢
\81D");
3176 if (!can_reach_floor(TRUE)) {
3177 struct trap *traphere = t_at(u.ux, u.uy);
3178 if (traphere && uteetering_at_seen_pit(traphere))
3180 You("cannot reach the bottom of the pit.");
3182 You("
\97\8e\82µ
\8c\8a\82Ì
\92ê
\82É%s
\82ª
\93Í
\82©
\82È
\82©
\82Á
\82½
\81D", body_part(HAND));
3183 else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
3185 else if (Blind && !can_reach_floor(TRUE))
3187 You("cannot reach anything here.");
3189 You("
\89½
\82É
\82à
\93Í
\82©
\82È
\82¢
\81D");
3192 You("cannot reach the %s.", surface(u.ux, u.uy));
3194 You("%s
\82É
\82½
\82Ç
\82è
\82Â
\82
\82±
\82Æ
\82ª
\82Å
\82«
\82È
\82¢
\81D", surface(u.ux, u.uy));
3197 return -1; /* can do normal pickup */
3200 /* the ',' command */
3204 int count, tmpcount, ret;
3206 /* awful kludge to work around parse()'s pre-decrement */
3207 count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup)))
3209 multi = 0; /* always reset */
3211 if ((ret = pickup_checks() >= 0))
3213 else if (ret == -2) {
3215 return loot_mon(u.ustuck, &tmpcount, (boolean *) 0);
3216 } /* else ret == -1 */
3218 return pickup(-count);
3221 /* stop running if we see something interesting */
3222 /* turn around a corner if that is the only way we can proceed */
3223 /* do not turn left or right twice */
3228 int i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
3229 int corrct = 0, noturn = 0;
3233 /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */
3234 /* they polymorphed while in the middle of a long move. */
3235 if (NODIAG(u.umonnum) && u.dx && u.dy) {
3237 You("cannot move diagonally.");
3239 You("
\8eÎ
\82ß
\82É
\88Ú
\93®
\82Å
\82«
\82È
\82¢
\81D");
3244 if (Blind || context.run == 0)
3246 for (x = u.ux - 1; x <= u.ux + 1; x++)
3247 for (y = u.uy - 1; y <= u.uy + 1; y++) {
3248 if (!isok(x, y) || (x == u.ux && y == u.uy))
3250 if (NODIAG(u.umonnum) && x != u.ux && y != u.uy)
3253 if ((mtmp = m_at(x, y)) != 0
3254 && M_AP_TYPE(mtmp) != M_AP_FURNITURE
3255 && M_AP_TYPE(mtmp) != M_AP_OBJECT
3256 && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
3257 if ((context.run != 1 && !mtmp->mtame)
3258 || (x == u.ux + u.dx && y == u.uy + u.dy
3259 && !context.travel)) {
3260 if (iflags.mention_walls)
3262 pline("%s blocks your path.", upstart(a_monnam(mtmp)));
3264 pline("%s
\82ª
\93¹
\82ð
\82Ó
\82³
\82¢
\82Å
\82¢
\82é
\81D", a_monnam(mtmp));
3269 if (levl[x][y].typ == STONE)
3271 if (x == u.ux - u.dx && y == u.uy - u.dy)
3274 if (IS_ROCK(levl[x][y].typ) || levl[x][y].typ == ROOM
3275 || IS_AIR(levl[x][y].typ)) {
3277 } else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) {
3278 if (x != u.ux && y != u.uy)
3280 if (context.run != 1) {
3281 if (iflags.mention_walls)
3283 You("stop in front of the door.");
3285 You("
\94à
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D");
3289 } else if (levl[x][y].typ == CORR) {
3291 if (levl[u.ux][u.uy].typ != ROOM) {
3292 if (context.run == 1 || context.run == 3
3293 || context.run == 8) {
3294 i = dist2(x, y, u.ux + u.dx, u.uy + u.dy);
3297 if (corrct == 1 && dist2(x, y, x0, y0) != 1)
3309 } else if ((trap = t_at(x, y)) && trap->tseen) {
3310 if (context.run == 1)
3311 goto bcorr; /* if you must */
3312 if (x == u.ux + u.dx && y == u.uy + u.dy) {
3313 if (iflags.mention_walls) {
3314 int tt = what_trap(trap->ttyp, rn2_on_display_rng);
3316 You("stop in front of %s.",
3318 You("%s
\82Ì
\8eè
\91O
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
3319 an(defsyms[trap_to_defsym(tt)].explanation));
3324 } else if (is_pool_or_lava(x, y)) {
3325 /* water and lava only stop you if directly in front, and stop
3326 * you even if you are running
3328 if (!Levitation && !Flying && !is_clinger(youmonst.data)
3329 && x == u.ux + u.dx && y == u.uy + u.dy) {
3330 /* No Wwalking check; otherwise they'd be able
3331 * to test boots by trying to SHIFT-direction
3332 * into a pool and seeing if the game allowed it
3334 if (iflags.mention_walls)
3336 You("stop at the edge of the %s.",
3337 hliquid(is_pool(x,y) ? "water" : "lava"));
3339 You("%s
\82Ì
\92[
\82Å
\8e~
\82Ü
\82Á
\82½
\81D",
3340 hliquid(is_pool(x,y) ? "
\90\85" : "
\97n
\8aâ"));
3345 } else { /* e.g. objects or trap or stairs */
3346 if (context.run == 1)
3348 if (context.run == 8)
3352 if (((x == u.ux - u.dx) && (y != u.uy + u.dy))
3353 || ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
3359 } /* end for loops */
3361 if (corrct > 1 && context.run == 2) {
3362 if (iflags.mention_walls)
3364 pline_The("corridor widens here.");
3366 pline("
\92Ê
\98H
\82Í
\82±
\82±
\82Å
\8dL
\82
\82È
\82Á
\82Ä
\82¢
\82é
\81D");
3369 if ((context.run == 1 || context.run == 3 || context.run == 8) && !noturn
3370 && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) {
3371 /* make sure that we do not turn too far */
3373 if (u.dx == y0 - u.uy && u.dy == u.ux - x0)
3374 i = 2; /* straight turn right */
3376 i = -2; /* straight turn left */
3377 } else if (u.dx && u.dy) {
3378 if ((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
3379 i = -1; /* half turn left */
3381 i = 1; /* half turn right */
3383 if ((x0 - u.ux == y0 - u.uy && !u.dy)
3384 || (x0 - u.ux != y0 - u.uy && u.dy))
3385 i = 1; /* half turn right */
3387 i = -1; /* half turn left */
3390 i += u.last_str_turn;
3391 if (i <= 2 && i >= -2) {
3392 u.last_str_turn = i;
3399 /* check for a doorway which lacks its door (NODOOR or BROKEN) */
3404 struct rm *lev_p = &levl[x][y];
3406 if (!IS_DOOR(lev_p->typ))
3408 /* all rogue level doors are doorless but disallow diagonal access, so
3409 we treat them as if their non-existant doors were actually present */
3410 if (Is_rogue_level(&u.uz))
3412 return !(lev_p->doormask & ~(D_NODOOR | D_BROKEN));
3415 /* used by drown() to check whether hero can crawl from water to <x,y> */
3417 crawl_destination(x, y)
3420 /* is location ok in general? */
3421 if (!goodpos(x, y, &youmonst, 0))
3424 /* orthogonal movement is unrestricted when destination is ok */
3425 if (x == u.ux || y == u.uy)
3428 /* diagonal movement has some restrictions */
3429 if (NODIAG(u.umonnum))
3430 return FALSE; /* poly'd into a grid bug... */
3432 return TRUE; /* or a xorn... */
3433 /* pool could be next to a door, conceivably even inside a shop */
3434 if (IS_DOOR(levl[x][y].typ) && (!doorless_door(x, y) || block_door(x, y)))
3436 /* finally, are we trying to squeeze through a too-narrow gap? */
3437 return !(bad_rock(youmonst.data, u.ux, y)
3438 && bad_rock(youmonst.data, x, u.uy));
3441 /* something like lookaround, but we are not running */
3442 /* react only to monsters that might hit us */
3447 register struct monst *mtmp;
3449 /* Also see the similar check in dochugw() in monmove.c */
3450 for (x = u.ux - 1; x <= u.ux + 1; x++)
3451 for (y = u.uy - 1; y <= u.uy + 1; y++) {
3452 if (!isok(x, y) || (x == u.ux && y == u.uy))
3454 if ((mtmp = m_at(x, y)) && M_AP_TYPE(mtmp) != M_AP_FURNITURE
3455 && M_AP_TYPE(mtmp) != M_AP_OBJECT
3456 && (!mtmp->mpeaceful || Hallucination)
3457 && (!is_hider(mtmp->data) || !mtmp->mundetected)
3458 && !noattacks(mtmp->data) && mtmp->mcanmove
3459 && !mtmp->msleeping /* aplvax!jcn */
3460 && !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp))
3471 return; /* This is a bug fix by ab@unido */
3472 u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */
3476 multi_reason = NULL;
3477 context.travel = context.travel1 = context.mv = context.run = 0;
3480 /* called when a non-movement, multi-turn action has completed */
3483 const char *msg_override;
3485 multi = 0; /* caller will usually have done this already */
3487 nomovemsg = msg_override;
3488 else if (!nomovemsg)
3489 nomovemsg = You_can_move_again;
3491 pline("%s", nomovemsg);
3494 multi_reason = NULL;
3496 int NDECL((*f)) = afternmv;
3498 /* clear afternmv before calling it (to override the
3499 encumbrance hack for levitation--see weight_cap()) */
3500 afternmv = (int NDECL((*))) 0;
3502 /* for finishing Armor/Boots/&c_on() */
3510 static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
3511 SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
3512 TELEPORT_CONTROL, STEALTH, FAST, INVIS };
3514 if (moves <= wailmsg + 50)
3518 if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
3523 who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m
3526 who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m
3531 pline("%s is about to die.", who);
3533 pline("%s
\82Í
\8e\80\82É
\82©
\82¯
\82Ä
\82¢
\82é
\81D", who);
3535 for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
3536 if (u.uprops[powers[i]].intrinsic & INTRINSIC)
3540 pline((powercnt >= 4) ? "%s, all your powers will be lost..."
3542 pline((powercnt >= 4) ? "%s
\81C
\82 \82È
\82½
\82Ì
\91S
\82Ä
\82Ì
\97Í
\82Í
\8e¸
\82í
\82ê
\82Â
\82Â
\82 \82é
\81D
\81D
\81D"
3544 : "%s, your life force is running out.",
3546 : "%s
\81C
\82 \82È
\82½
\82Ì
\90¶
\96½
\97Í
\82Í
\90s
\82«
\82æ
\82¤
\82Æ
\82µ
\82Ä
\82¢
\82é
\81D
\81D
\81D",
3551 You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
3553 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"
3555 : "the howling of the CwnAnnwn...");
3557 : "
\83N
\81[
\83\93\81E
\83A
\83\93\83k
\81[
\83\93\82Ì
\89\93\96i
\82ª
\95·
\82±
\82¦
\82é
\81D
\81D
\81D");
3562 losehp(n, knam, k_format)
3564 register const char *knam;
3574 else if (n > 0 && u.mh * 10 < u.mhmax && Unchanging)
3580 if (u.uhp > u.uhpmax)
3581 u.uhpmax = u.uhp; /* perhaps n was negative */
3583 context.travel = context.travel1 = context.mv = context.run = 0;
3586 killer.format = k_format;
3587 if (killer.name != knam) /* the thing that killed you */
3588 Strcpy(killer.name, knam ? knam : "");
3592 pline("
\82 \82È
\82½
\82Í
\8e\80\82É
\82Ü
\82µ
\82½
\81D
\81D
\81D");
3594 } else if (n > 0 && u.uhp * 10 < u.uhpmax) {
3602 long carrcap, save_ELev = ELevitation, save_BLev = BLevitation;
3604 /* boots take multiple turns to wear but any properties they
3605 confer are enabled at the start rather than the end; that
3606 causes message sequencing issues for boots of levitation
3607 so defer their encumbrance benefit until they're fully worn */
3608 if (afternmv == Boots_on && (ELevitation & W_ARMF) != 0L) {
3609 ELevitation &= ~W_ARMF;
3610 float_vs_flight(); /* in case Levitation is blocking Flying */
3612 /* levitation is blocked by being trapped in the floor, but it still
3613 functions enough in that situation to enhance carrying capacity */
3614 BLevitation &= ~I_SPECIAL;
3616 carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50;
3618 /* consistent with can_carry() in mon.c */
3619 if (youmonst.data->mlet == S_NYMPH)
3620 carrcap = MAX_CARR_CAP;
3621 else if (!youmonst.data->cwt)
3622 carrcap = (carrcap * (long) youmonst.data->msize) / MZ_HUMAN;
3623 else if (!strongmonst(youmonst.data)
3624 || (strongmonst(youmonst.data)
3625 && (youmonst.data->cwt > WT_HUMAN)))
3626 carrcap = (carrcap * (long) youmonst.data->cwt / WT_HUMAN);
3629 if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */
3630 || (u.usteed && strongmonst(u.usteed->data))) {
3631 carrcap = MAX_CARR_CAP;
3633 if (carrcap > MAX_CARR_CAP)
3634 carrcap = MAX_CARR_CAP;
3636 if (EWounded_legs & LEFT_SIDE)
3638 if (EWounded_legs & RIGHT_SIDE)
3645 if (ELevitation != save_ELev || BLevitation != save_BLev) {
3646 ELevitation = save_ELev;
3647 BLevitation = save_BLev;
3651 return (int) carrcap;
3654 static int wc; /* current weight_cap(); valid after call to inv_weight() */
3656 /* returns how far beyond the normal capacity the player is currently. */
3657 /* inv_weight() is negative if the player is below normal capacity. */
3661 register struct obj *otmp = invent;
3662 register int wt = 0;
3665 if (otmp->oclass == COIN_CLASS)
3666 wt += (int) (((long) otmp->quan + 50L) / 100L);
3667 else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
3676 * Returns 0 if below normal capacity, or the number of "capacity units"
3677 * over the normal capacity the player is loaded. Max is 5.
3680 calc_capacity(xtra_wt)
3683 int cap, wt = inv_weight() + xtra_wt;
3686 return UNENCUMBERED;
3689 cap = (wt * 2 / wc) + 1;
3690 return min(cap, OVERLOADED);
3696 return calc_capacity(0);
3702 int wt = inv_weight();
3704 return (wt - (2 * wc));
3711 if (near_capacity() >= EXT_ENCUMBER) {
3716 You_cant("do that while carrying so much stuff.");
3718 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");
3728 register struct obj *otmp = invent;
3729 register int ct = 0;
3732 if (incl_gold || otmp->invlet != GOLD_SYM)
3739 /* Counts the money in an object chain. */
3740 /* Intended use is for your or some monster's inventory, */
3741 /* now that u.gold/m.gold is gone.*/
3742 /* Counting money in a container might be possible too. */
3748 /* Must change when silver & copper is implemented: */
3749 if (otmp->oclass == COIN_CLASS)