From cb50fbb2ce8ebe91edcff906cb7eaf4a04cac985 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 8 Mar 2024 13:08:28 -0800 Subject: [PATCH] fix for breaking unreachable statue Reported almost 9 years ago: if an adjacent statue was in a pit, you could use a pick-axe to break it even though if you managed to move to the pit location without falling in, you wouldn't be able to reach objects there including the statue. Allow a pick to reach if hero is in a conjoined pit, or if it is a mattock rather than an ordinary pick-axe. Otherwise you'll get the "you swing at thin air" result. Similarly when hero is in a pit and and adjacent statue or boulder is on the floor: mattock will work but pick-axe now yields "you can't reach". --- doc/fixes3-7-0.txt | 4 ++- src/dig.c | 73 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 46cfffe9a..7424ecb3c 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1393 $ $NHDT-Date: 1709388534 2024/03/02 14:08:54 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1396 $ $NHDT-Date: 1709928001 2024/03/08 20:00:01 $ General Fixes and Modified Features ----------------------------------- @@ -1371,6 +1371,8 @@ when a spellbook was polymorphed into a novel and then incrementing spestudied field turned it into a blank spellbook, the novel's title would stick: "{spellbook of blank paper|plain spellbook} named " walking on ice can make you slide in a random direction +if an adjacent statue was a in a pit, you could break it with a pick-axe even + though you're conceptually at the wrong elevation to reach it Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dig.c b/src/dig.c index 288bbbe7b..2d65e93fa 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dig.c $NHDT-Date: 1702206282 2023/12/10 11:04:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.204 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1709928001 2024/03/08 20:00:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.211 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,6 +8,7 @@ static boolean rm_waslit(void); static void mkcavepos(coordxy, coordxy, int, boolean, boolean); static void mkcavearea(boolean); +static boolean pick_can_reach(struct obj *, coordxy, coordxy) NONNULLARG1; static int dig(void); static void dig_up_grave(coord *); static boolean watchman_canseeu(struct monst *) NONNULLARG1; @@ -135,6 +136,34 @@ mkcavearea(boolean rockit) gv.vision_full_recalc = 1; /* everything changed */ } +/* called when attempting to break a statue or boulder with a pick */ +static boolean +pick_can_reach(struct obj *pick, coordxy x, coordxy y) +{ + struct trap *t = t_at(x, y); + /* tseen: pit only affects item positioning when it is known */ + boolean target_in_pit = t && is_pit(t->ttyp) && t->tseen; + + /* if hero is in a pit, pick can only reach if the statue is too and + the two pits are conjoined or the statue isn't and pick is two-handed; + this applies to hero in pit trying to reach an adjcacent boulder too */ + if (u.utrap && u.utraptype == TT_PIT) { + if (target_in_pit) + return conjoined_pits(t, t_at(u.ux, u.uy), FALSE); + return bimanual(pick); + } + + /* when hero isn't in a pit, a mattock or flying hero w/ pick can reach + whether or not the statue is in a pit */ + if (bimanual(pick) || Flying) + return TRUE; + /* one-handed pick-axe can reach if statue isn't in a pit */ + if (!target_in_pit) + return TRUE; + + return FALSE; +} + /* When digging into location , what are you actually digging into? */ int dig_typ(struct obj *otmp, coordxy x, coordxy y) @@ -147,9 +176,11 @@ dig_typ(struct obj *otmp, coordxy x, coordxy y) if (!ispick && !is_axe(otmp)) return DIGTYP_UNDIGGABLE; - return ((ispick && sobj_at(STATUE, x, y)) + return ((ispick && sobj_at(STATUE, x, y) + && pick_can_reach(otmp, x, y)) ? DIGTYP_STATUE - : (ispick && sobj_at(BOULDER, x, y)) + : (ispick && sobj_at(BOULDER, x, y) + && pick_can_reach(otmp, x, y)) ? DIGTYP_BOULDER : closed_door(x, y) ? DIGTYP_DOOR @@ -1112,6 +1143,8 @@ use_pick_axe2(struct obj *obj) return ECMD_TIME; dig_target = dig_typ(obj, rx, ry); if (dig_target == DIGTYP_UNDIGGABLE) { + struct obj *boulder; + /* ACCESSIBLE or POOL */ trap = t_at(rx, ry); if (trap && trap->ttyp == WEB) { @@ -1137,17 +1170,28 @@ use_pick_axe2(struct obj *obj) You("need an axe to cut down a tree."); } else if (IS_ROCK(lev->typ)) { You("need a pick to dig rock."); - } else if (!ispick && (sobj_at(STATUE, rx, ry) - || sobj_at(BOULDER, rx, ry))) { - boolean vibrate = !rn2(3); + } else if ((boulder = sobj_at(BOULDER, rx, ry)) != 0 + || sobj_at(STATUE, rx, ry)) { + /* if both boulders and statues are present, the topmost + boulder will be shown on the map so treat it as target */ + const char *what = boulder ? "boulder" : "statue"; - pline("Sparks fly as you whack the %s.%s", - sobj_at(STATUE, rx, ry) ? "statue" : "boulder", - vibrate ? " The axe-handle vibrates violently!" : ""); - if (vibrate) - losehp(Maybe_Half_Phys(2), "axing a hard object", - KILLED_BY); - wake_nearby(); + if (!ispick) { + boolean vibrate = !rn2(3); + + pline("Sparks fly as you whack the %s.%s", what, + vibrate ? " The axe-handle vibrates violently!" + : ""); + if (vibrate) + losehp(Maybe_Half_Phys(2), "axing a hard object", + KILLED_BY); + wake_nearby(); + } else { + /* using a pick but dig_target is DIGTYPE_UNDIGGABLE + and there is at least one boulder or statue or both + present; pick_can_reach() returned false */ + You_cant("reach the %s.", what); + } } else if (u.utrap && u.utraptype == TT_PIT && trap && (trap_with_u = t_at(u.ux, u.uy)) && is_pit(trap->ttyp) @@ -1177,7 +1221,8 @@ use_pick_axe2(struct obj *obj) gd.did_dig_msg = FALSE; gc.context.digging.quiet = FALSE; - if (gc.context.digging.pos.x != rx || gc.context.digging.pos.y != ry + if (gc.context.digging.pos.x != rx + || gc.context.digging.pos.y != ry || !on_level(&gc.context.digging.level, &u.uz) || gc.context.digging.down) { if (flags.autodig && dig_target == DIGTYP_ROCK