]> granicus.if.org Git - nethack/commitdiff
travelling through boulders
authorPatR <rankin@nethack.org>
Sat, 16 Oct 2021 16:54:08 +0000 (09:54 -0700)
committerPatR <rankin@nethack.org>
Sat, 16 Oct 2021 16:54:08 +0000 (09:54 -0700)
If the hero can move to a boulder's location via m<dir>, allow travel
to do so too.  You will always stop on the boulder spot rather than
keep going toward the destination because of change in visibility at
a boulder spot.

Giants should be able to see over boulders, and doing that for poly'd
hero would probably be straightforward, but when not poly'd, seeing a
giant beyond a boulder and vice versa seems like it would be a can of
giant-sized worms.

A couple of other miscellaneous changes are mixed in with this.

src/hack.c

index b5abee6cbd6adf7347924a8a685daf8d94682ba1..f5f4e309e6aa090f2d8bd9ff0466284eb737011d 100644 (file)
@@ -7,18 +7,19 @@
 
 /* #define DEBUG */ /* uncomment for debugging */
 
-static void maybe_wail(void);
+static boolean could_move_onto_boulder(int, int);
 static int moverock(void);
 static void dosinkfall(void);
 static boolean findtravelpath(int);
 static boolean trapmove(int, int, struct trap *);
+static void check_buried_zombies(xchar, xchar);
+static void domove_core(void);
+static void maybe_smudge_engr(int, int, int, int);
 static struct monst *monstinroom(struct permonst *, int);
-static boolean doorless_door(int, int);
 static void move_update(boolean);
 static int pickup_checks(void);
-static void maybe_smudge_engr(int, int, int, int);
-static void check_buried_zombies(xchar, xchar);
-static void domove_core(void);
+static boolean doorless_door(int, int);
+static void maybe_wail(void);
 
 #define IS_SHOP(x) (g.rooms[x].rtype >= SHOPBASE)
 
@@ -96,6 +97,29 @@ revive_nasty(int x, int y, const char *msg)
 
 #define squeezeablylightinvent() (!g.invent || inv_weight() <= -850)
 
+/* can hero move onto a spot containing one or more boulders?
+   used for m<dir> and travel and during boulder push failure */
+static boolean
+could_move_onto_boulder(int sx, int sy)
+{
+    /* can if able to phaze through rock (must be poly'd, so not riding) */
+    if (Passes_walls)
+        return TRUE;
+    /* can't when riding */
+    if (u.usteed)
+        return FALSE;
+    /* can if a giant, unless doing so allows hero to pass into a
+       diagonal squeeze at the same time */
+    if (throws_rocks(g.youmonst.data))
+        return (!u.dx || !u.dy || !(IS_ROCK(levl[u.ux][sy].typ)
+                                    && IS_ROCK(levl[sx][u.uy].typ)));
+    /* can if tiny (implies carrying very little else couldn't move at all) */
+    if (verysmall(g.youmonst.data))
+        return TRUE;
+    /* can squeeze to spot if carrying extremely little, otherwise can't */
+    return squeezeablylightinvent();
+}
+
 static int
 moverock(void)
 {
@@ -144,9 +168,9 @@ moverock(void)
                 /* ["over" seems weird on air level but what else to say?] */
                 sokoban_guilt();
                 res = 0; /* move to <sx,sy> */
-            } else if (!u.usteed && (squeezeablylightinvent()
-                                     || verysmall(g.youmonst.data))) {
-                You("squeeze yourself against the boulder.");
+            } else if (could_move_onto_boulder(sx, sy)) {
+                You("squeeze yourself %s the boulder.",
+                    Flying ? "over" : "against");
                 sokoban_guilt();
                 res = 0; /* move to <sx,sy> */
             } else {
@@ -200,8 +224,7 @@ moverock(void)
             }
 
             if (mtmp && !noncorporeal(mtmp->data)
-                && (!mtmp->mtrapped
-                    || !(ttmp && is_pit(ttmp->ttyp)))) {
+                && (!mtmp->mtrapped || !(ttmp && is_pit(ttmp->ttyp)))) {
                 boolean deliver_part1 = FALSE;
 
                 if (Blind)
@@ -221,15 +244,10 @@ moverock(void)
                     Strcpy(you_or_steed,
                            u.usteed ? y_monnam(u.usteed) : "you");
                     pline("%s%s cannot move %s.",
-                          deliver_part1
-                              ? "Perhaps that's why "
-                              : "",
-                          deliver_part1
-                              ? you_or_steed
-                              : upstart(you_or_steed),
-                          deliver_part1
-                              ? "it"
-                              : the(xname(otmp)));
+                          deliver_part1 ? "Perhaps that's why " : "",
+                          deliver_part1 ? you_or_steed
+                                        : upstart(you_or_steed),
+                          deliver_part1 ? "it" : the(xname(otmp)));
                 }
                 goto cannot_push;
             }
@@ -248,7 +266,16 @@ moverock(void)
                         obj_extract_self(otmp);
                         place_object(otmp, rx, ry);
                         newsym(sx, sy);
-                        pline("KAABLAMM!!!  %s %s land mine.",
+                        pline("%s!  %s %s land mine.",
+                              /* "kablam" is a variation of "ka-boom" or
+                                 "kablooey", rather cartoonish descriptions
+                                 of the sound of an explosion, but give it
+                                 even when deaf if hero sees the explosion */
+                              (!Deaf || !Blind) ? "KAABLAMM!!"
+                              /* use an alternate exclamation when feeling
+                                 the floor/ground/whatever shake (or maybe
+                                 a weak shockwave if levitating or flying) */
+                                                : "Gadzooks",
                               Tobjnam(otmp, "trigger"),
                               ttmp->madeby_u ? "your" : "a");
                         blow_up_landmine(ttmp);
@@ -431,13 +458,7 @@ moverock(void)
                 break;
             }
 
-            /* similar to m<dir> above, but that doesn't care if you're
-               moving orthogonally or toward a diagonal squeeze */
-            if (!u.usteed && ((squeezeablylightinvent()
-                               && (!u.dx || !u.dy
-                                   || (IS_ROCK(levl[u.ux][sy].typ)
-                                       && IS_ROCK(levl[sx][u.uy].typ))))
-                              || verysmall(g.youmonst.data))) {
+            if (could_move_onto_boulder(sx, sy)) {
                 pline(
                    "However, you can squeeze yourself into a small opening.");
                 sokoban_guilt();
@@ -636,7 +657,7 @@ still_chewing(xchar x, xchar y)
 }
 
 void
-movobj(register struct obj *obj, register xchar ox, register xchar oy)
+movobj(struct obj *obj, xchar ox, xchar oy)
 {
     /* optimize by leaving on the fobj chain? */
     remove_object(obj);
@@ -646,12 +667,11 @@ movobj(register struct obj *obj, register xchar ox, register xchar oy)
     newsym(ox, oy);
 }
 
-static NEARDATA const char fell_on_sink[] = "fell onto a sink";
-
 static void
 dosinkfall(void)
 {
-    register struct obj *obj;
+    static const char fell_on_sink[] = "fell onto a sink";
+    struct obj *obj;
     int dmg;
     boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS),
             innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L),
@@ -806,7 +826,7 @@ test_move(int ux, int uy, int dx, int dy, int mode)
     int x = ux + dx;
     int y = uy + dy;
     register struct rm *tmpr = &levl[x][y];
-    register struct rm *ust;
+    struct rm *ust;
 
     g.context.door_opened = FALSE;
     /*
@@ -985,8 +1005,8 @@ test_move(int ux, int uy, int dx, int dy, int mode)
     }
 
     if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) {
-        if (!(Blind || Hallucination) && (g.context.run >= 2)
-            && mode != TEST_TRAV) {
+        if (mode != TEST_TRAV && g.context.run >= 2
+            && !(Blind || Hallucination) && !could_move_onto_boulder(x, y)) {
             if (mode == DO_MOVE && flags.mention_walls)
                 pline("A boulder blocks your path.");
             return FALSE;
@@ -1009,6 +1029,7 @@ test_move(int ux, int uy, int dx, int dy, int mode)
             /* don't pick two boulders in a row, unless there's a way thru */
             if (sobj_at(BOULDER, ux, uy) && !Sokoban) {
                 if (!Passes_walls
+                    && !could_move_onto_boulder(ux, uy)
                     && !(tunnels(g.youmonst.data)
                          && !needspick(g.youmonst.data))
                     && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK)
@@ -1139,10 +1160,14 @@ findtravelpath(int mode)
                         || ((mode == TRAVP_GUESS) && !couldsee(nx, ny)))
                         continue;
                     if ((!Passes_walls && !can_ooze(&g.youmonst)
-                         && closed_door(x, y)) || sobj_at(BOULDER, x, y)
+                         && closed_door(x, y))
+                        || (sobj_at(BOULDER, x, y)
+                            && !could_move_onto_boulder(x, y))
                         || test_move(x, y, nx - x, ny - y, TEST_TRAP)) {
-                        /* closed doors and boulders usually
-                         * cause a delay, so prefer another path */
+                        /* closed doors and boulders usually cause a delay,
+                           so prefer another path; however, giants and tiny
+                           creatures can use m<dir> to move onto a boulder's
+                           spot without pushing, so allow boulders for them */
                         if (travel[x][y] > radius - 3) {
                             if (!alreadyrepeated) {
                                 travelstepx[1 - set][nn] = x;