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".
This commit is contained in:
PatR
2024-03-08 13:08:28 -08:00
parent 76826744d7
commit cb50fbb2ce
2 changed files with 62 additions and 15 deletions

View File

@@ -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 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: field turned it into a blank spellbook, the novel's title would stick:
"{spellbook of blank paper|plain spellbook} named <Discworld title>" "{spellbook of blank paper|plain spellbook} named <Discworld title>"
walking on ice can make you slide in a random direction 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 Fixes to 3.7.0-x General Problems Exposed Via git Repository

View File

@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2012. */ /*-Copyright (c) Michael Allison, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -8,6 +8,7 @@
static boolean rm_waslit(void); static boolean rm_waslit(void);
static void mkcavepos(coordxy, coordxy, int, boolean, boolean); static void mkcavepos(coordxy, coordxy, int, boolean, boolean);
static void mkcavearea(boolean); static void mkcavearea(boolean);
static boolean pick_can_reach(struct obj *, coordxy, coordxy) NONNULLARG1;
static int dig(void); static int dig(void);
static void dig_up_grave(coord *); static void dig_up_grave(coord *);
static boolean watchman_canseeu(struct monst *) NONNULLARG1; static boolean watchman_canseeu(struct monst *) NONNULLARG1;
@@ -135,6 +136,34 @@ mkcavearea(boolean rockit)
gv.vision_full_recalc = 1; /* everything changed */ 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 <x,y>, what are you actually digging into? */ /* When digging into location <x,y>, what are you actually digging into? */
int int
dig_typ(struct obj *otmp, coordxy x, coordxy y) 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)) if (!ispick && !is_axe(otmp))
return DIGTYP_UNDIGGABLE; 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 ? DIGTYP_STATUE
: (ispick && sobj_at(BOULDER, x, y)) : (ispick && sobj_at(BOULDER, x, y)
&& pick_can_reach(otmp, x, y))
? DIGTYP_BOULDER ? DIGTYP_BOULDER
: closed_door(x, y) : closed_door(x, y)
? DIGTYP_DOOR ? DIGTYP_DOOR
@@ -1112,6 +1143,8 @@ use_pick_axe2(struct obj *obj)
return ECMD_TIME; return ECMD_TIME;
dig_target = dig_typ(obj, rx, ry); dig_target = dig_typ(obj, rx, ry);
if (dig_target == DIGTYP_UNDIGGABLE) { if (dig_target == DIGTYP_UNDIGGABLE) {
struct obj *boulder;
/* ACCESSIBLE or POOL */ /* ACCESSIBLE or POOL */
trap = t_at(rx, ry); trap = t_at(rx, ry);
if (trap && trap->ttyp == WEB) { if (trap && trap->ttyp == WEB) {
@@ -1137,17 +1170,28 @@ use_pick_axe2(struct obj *obj)
You("need an axe to cut down a tree."); You("need an axe to cut down a tree.");
} else if (IS_ROCK(lev->typ)) { } else if (IS_ROCK(lev->typ)) {
You("need a pick to dig rock."); You("need a pick to dig rock.");
} else if (!ispick && (sobj_at(STATUE, rx, ry) } else if ((boulder = sobj_at(BOULDER, rx, ry)) != 0
|| sobj_at(BOULDER, rx, ry))) { || sobj_at(STATUE, rx, ry)) {
boolean vibrate = !rn2(3); /* 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", if (!ispick) {
sobj_at(STATUE, rx, ry) ? "statue" : "boulder", boolean vibrate = !rn2(3);
vibrate ? " The axe-handle vibrates violently!" : "");
if (vibrate) pline("Sparks fly as you whack the %s.%s", what,
losehp(Maybe_Half_Phys(2), "axing a hard object", vibrate ? " The axe-handle vibrates violently!"
KILLED_BY); : "");
wake_nearby(); 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 } else if (u.utrap && u.utraptype == TT_PIT && trap
&& (trap_with_u = t_at(u.ux, u.uy)) && (trap_with_u = t_at(u.ux, u.uy))
&& is_pit(trap->ttyp) && is_pit(trap->ttyp)
@@ -1177,7 +1221,8 @@ use_pick_axe2(struct obj *obj)
gd.did_dig_msg = FALSE; gd.did_dig_msg = FALSE;
gc.context.digging.quiet = 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) || !on_level(&gc.context.digging.level, &u.uz)
|| gc.context.digging.down) { || gc.context.digging.down) {
if (flags.autodig && dig_target == DIGTYP_ROCK if (flags.autodig && dig_target == DIGTYP_ROCK