From 07b1d9d396c50582d8acd9d1e3f963d5d84f27f2 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 16 Oct 2021 09:54:08 -0700 Subject: [PATCH] travelling through boulders If the hero can move to a boulder's location via m, 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 | 101 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/src/hack.c b/src/hack.c index b5abee6cb..f5f4e309e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -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 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 void maybe_smudge_engr(int, int, int, int); +static struct monst *monstinroom(struct permonst *, int); +static void move_update(boolean); +static int pickup_checks(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 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 */ - } 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 */ } 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 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 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;