]> granicus.if.org Git - nethack/commitdiff
'$' vs #jump
authorPatR <rankin@nethack.org>
Tue, 21 Jun 2016 09:39:21 +0000 (02:39 -0700)
committerPatR <rankin@nethack.org>
Tue, 21 Jun 2016 09:39:21 +0000 (02:39 -0700)
Hero poly'd into xorn can wear jumping boots or cast jump spell, so
some target destinations which were excluded by '$' (to show valid
destinations during getpos) shouldn't have been.  Doubly so if
wearing the Eyes of the Overworld where xorn'd hero can jump through
walls rather than just into them.

This attempts to deal with diagonal moves vs open doorways sanely,
including allowing knight's move jumps in or out of them when
appropriate.

Also, need to check isok(x,y) before cansee(x,y) instead of after.

doc/fixes36.1
src/apply.c
src/dothrow.c

index 34ceec7fc5b80df3097644e688d078fa7d907b7a..e731a1de39c8cdfc5b09b3fa050c7d9ac2c35a04 100644 (file)
@@ -316,6 +316,7 @@ catch up win/Qt/qt_win.cpp on 18-Dec-2015 change to formatkiller()
 fix for long lines in config file (28-Jan-2016) made 'O' command's 'list' and
        'remove' menu choices in interactive handling for menu colorings,
        message types, and autopickup exceptions subject to buffer overflow
+when picking a destination for #jump, '$' to show valid dest. is more accurate
 
 
 Platform- and/or Interface-Specific Fixes
index e00557a5593eaef06c8f3a5ae32540fb05bbe44e..8d64620a85e1aa2c9a2b269b8e2ba98f0863aad8 100644 (file)
@@ -36,6 +36,7 @@ STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *,
                                                     coord *, BOOLEAN_P));
 STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
 STATIC_DCL void FDECL(setapplyclasses, (char *));
+STATIC_PTR boolean FDECL(check_jump, (genericptr_t, int, int));
 STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P));
 STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int));
 
@@ -1450,7 +1451,48 @@ dojump()
     return jump(0);
 }
 
-boolean
+enum jump_trajectory {
+    jAny  = 0, /* any direction => magical jump */
+    jHorz = 1,
+    jVert = 2,
+    jDiag = 3  /* jHorz|jVert */
+};
+
+/* callback routine for walk_path() */
+STATIC_PTR boolean
+check_jump(arg, x, y)
+genericptr arg;
+int x, y;
+{
+    int traj = *(int *) arg;
+    struct rm *lev = &levl[x][y];
+
+    if (Passes_walls)
+        return TRUE;
+    if (IS_STWALL(lev->typ))
+        return FALSE;
+    if (IS_DOOR(lev->typ)) {
+        if (closed_door(x, y))
+            return FALSE;
+        if ((lev->doormask & D_ISOPEN) != 0 && traj != jAny
+            /* reject diagonal jump into or out-of or through open door */
+            && (traj == jDiag
+                /* reject horizontal jump through horizontal open door
+                   and non-horizontal (ie, vertical) jump through
+                   non-horizontal (vertical) open door */
+                || ((traj & jHorz) != 0) == (lev->horizontal != 0)))
+            return FALSE;
+        /* empty doorways aren't restricted */
+    }
+    /* let giants jump over boulders (what about Flying?
+       and is there really enough head room for giants to jump
+       at all, let alone over something tall?) */
+    if (sobj_at(BOULDER, x, y) && !throws_rocks(youmonst.data))
+        return FALSE;
+    return TRUE;
+}
+
+STATIC_OVL boolean
 is_valid_jump_pos(x, y, magic, showmsg)
 int x, y, magic;
 boolean showmsg;
@@ -1466,14 +1508,54 @@ boolean showmsg;
         if (showmsg)
             pline("Too far!");
         return FALSE;
-    } else if (!cansee(x, y)) {
-        if (showmsg)
-            You("cannot see where to land!");
-        return FALSE;
     } else if (!isok(x, y)) {
         if (showmsg)
             You("cannot jump there!");
         return FALSE;
+    } else if (!cansee(x, y)) {
+        if (showmsg)
+            You("cannot see where to land!");
+        return FALSE;
+    } else {
+        coord uc, tc;
+        struct rm *lev = &levl[u.ux][u.uy];
+        /* we want to categorize trajectory for use in determining
+           passage through doorways: horizonal, vertical, or diagonal;
+           since knight's jump and other irregular directions are
+           possible, we flatten those out to simplify door checks */
+        int diag, traj,
+            dx = x - u.ux, dy = y - u.uy,
+            ax = abs(dx), ay = abs(dy);
+
+        /* diag: any non-orthogonal destination classifed as diagonal */
+        diag = (magic || Passes_walls || (!dx && !dy)) ? jAny
+               : !dy ? jHorz : !dx ? jVert : jDiag;
+        /* traj: flatten out the trajectory => some diagonals re-classified */
+        if (ax >= 2 * ay)
+            ay = 0;
+        else if (ay >= 2 * ax)
+            ax = 0;
+        traj = (magic || Passes_walls || (!ax && !ay)) ? jAny
+               : !ay ? jHorz : !ax ? jVert : jDiag;
+        /* walk_path doesn't process the starting spot;
+           this is iffy:  if you're starting on a closed door spot,
+           you _can_ jump diagonally from doorway (without needing
+           Passes_walls); that's intentional but is it correct? */
+        if (diag == jDiag && IS_DOOR(lev->typ)
+            && (lev->doormask & D_ISOPEN) != 0
+            && (traj == jDiag
+                || ((traj & jHorz) != 0) == (lev->horizontal != 0))) {
+            if (showmsg)
+                You_cant("jump diagonally out of a doorway.");
+            return FALSE;
+        }
+        uc.x = u.ux, uc.y = u.uy;
+        tc.x = x, tc.y = y; /* target */
+        if (!walk_path(&uc, &tc, check_jump, (genericptr_t) &traj)) {
+            if (showmsg)
+                There("is an obstacle preventing that jump.");
+            return FALSE;
+        }
     }
     return TRUE;
 }
@@ -1493,7 +1575,8 @@ int state;
             for (dy = -4; dy <= 4; dy++) {
                 x = dx + (int) u.ux;
                 y = dy + (int) u.uy;
-                if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
+                if (isok(x, y)
+                    && (ACCESSIBLE(levl[x][y].typ) || Passes_walls)
                     && is_valid_jump_pos(x, y, jumping_is_magic, FALSE))
                     tmp_at(x, y);
             }
index b8a3778b5eeefdea16fbc393aad801e68c5c804a..70496ef7a0369ebfa72985f7dedee3a1ce358fbf 100644 (file)
@@ -547,8 +547,8 @@ int x, y;
         boolean odoor_diag = (IS_DOOR(levl[x][y].typ)
                               && (levl[x][y].doormask & D_ISOPEN)
                               && (u.ux - x) && (u.uy - y));
-        if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)
-            || odoor_diag) {
+
+        if (IS_ROCK(levl[x][y].typ) || closed_door(x, y) || odoor_diag) {
             const char *s;
 
             if (odoor_diag)