From d5785f287e0b855f14e243f13f67076ebc24d636 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 23 Jul 2024 01:06:24 -0400 Subject: [PATCH] GitHub issue #1254 > If there's a trap on a no-dig level, the floor beneath it will always be "too hard to dig into", making it impossible to remove the trap. > > As you can still dig pits in these levels (just not holes), the floor under the trap itself resisting to become a pit seems inconsistent. > > Steps to reproduce: > > Go to no-dig level like Mine's End > Make a trap > Dig a pit next to it -> works > Dig on the trap -> does not work Return more information about the dig_check() results to caller (was just a boolean). Move the messaging that was in dig_check() into a separate digcheck_fail_message() function that uses the expanded return information. Resolves #1254 . --- include/extern.h | 4 +- include/hack.h | 22 ++++++++ src/apply.c | 2 +- src/dig.c | 134 ++++++++++++++++++++++++++++++++++------------- 4 files changed, 123 insertions(+), 39 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8476b017b..0be195583 100644 --- a/include/extern.h +++ b/include/extern.h @@ -498,7 +498,9 @@ extern int wiz_mgender(void); extern int dig_typ(struct obj *, coordxy, coordxy); extern boolean is_digging(void); extern int holetime(void); -extern boolean dig_check(struct monst *, boolean, coordxy, coordxy); +extern enum digcheck_result dig_check(struct monst *, coordxy, coordxy); +extern void digcheck_fail_message(enum digcheck_result, struct monst *, + coordxy, coordxy); extern void digactualhole(coordxy, coordxy, struct monst *, int); extern boolean dighole(boolean, boolean, coord *); extern int use_pick_axe(struct obj *) NONNULLARG1; diff --git a/include/hack.h b/include/hack.h index 1a08246fb..fdd7740a4 100644 --- a/include/hack.h +++ b/include/hack.h @@ -327,6 +327,28 @@ struct _create_particular_data { boolean sleeping, saddled, invisible, hidden; }; +/* dig_check() results */ + +enum digcheck_result { + DIGCHECK_PASSED = 1, + DIGCHECK_PASSED_DESTROY_TRAP = 2, + DIGCHECK_PASSED_PITONLY = 3, + DIGCHECK_FAILED = 4, + DIGCHECK_FAIL_ONSTAIRS = DIGCHECK_FAILED, + DIGCHECK_FAIL_ONLADDER, + DIGCHECK_FAIL_THRONE, + DIGCHECK_FAIL_ALTAR, + DIGCHECK_FAIL_AIRLEVEL, + DIGCHECK_FAIL_WATERLEVEL, + DIGCHECK_FAIL_TOOHARD, + DIGCHECK_FAIL_UNDESTROYABLETRAP, + DIGCHECK_FAIL_CANTDIG, + DIGCHECK_FAIL_BOULDER, + DIGCHECK_FAIL_OBJ_POOL_OR_TRAP +}; + + + /* Dismount: causes for why you are no longer riding */ enum dismount_types { DISMOUNT_GENERIC = 0, diff --git a/src/apply.c b/src/apply.c index 32a9b14ad..bf867c3e5 100644 --- a/src/apply.c +++ b/src/apply.c @@ -3945,7 +3945,7 @@ do_break_wand(struct obj *obj) if (obj->otyp == WAN_DIGGING) { schar typ; - if (dig_check(BY_OBJECT, FALSE, x, y)) { + if (dig_check(BY_OBJECT, x, y) < DIGCHECK_FAILED) { if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { /* normally, pits and holes don't anger guards, but they * do if it's a wall or door that's being dug */ diff --git a/src/dig.c b/src/dig.c index 26b327c99..dfa23dc5e 100644 --- a/src/dig.c +++ b/src/dig.c @@ -205,59 +205,97 @@ is_digging(void) #define BY_YOU (&gy.youmonst) #define BY_OBJECT ((struct monst *) 0) -boolean -dig_check(struct monst *madeby, boolean verbose, coordxy x, coordxy y) +enum digcheck_result +dig_check(struct monst *madeby, coordxy x, coordxy y) { struct trap *ttmp = t_at(x, y); - const char *verb = - (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { stairway *stway = stairway_at(x, y); if (stway->isladder) { - if (verbose) - pline_The("ladder resists your effort."); - } else if (verbose) - pline_The("stairs are too hard to %s.", verb); - return FALSE; + return DIGCHECK_FAIL_ONLADDER; + } else { + return DIGCHECK_FAIL_ONSTAIRS; + } } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) { - if (verbose) - pline_The("throne is too hard to break apart."); - return FALSE; + return DIGCHECK_FAIL_THRONE; } else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT || (altarmask_at(x, y) & AM_SANCTUM) != 0)) { - if (verbose) - pline_The("altar is too hard to break apart."); - return FALSE; + return DIGCHECK_FAIL_ALTAR; } else if (Is_airlevel(&u.uz)) { - if (verbose) - You("cannot %s thin air.", verb); - return FALSE; + return DIGCHECK_FAIL_AIRLEVEL; } else if (Is_waterlevel(&u.uz)) { - if (verbose) - pline_The("%s splashes and subsides.", hliquid("water")); - return FALSE; + return DIGCHECK_FAIL_WATERLEVEL; } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR - && (levl[x][y].wall_info & W_NONDIGGABLE) != 0) - || (ttmp - && (undestroyable_trap(ttmp->ttyp) - || (!Can_dig_down(&u.uz) && !levl[x][y].candig)))) { - if (verbose) - pline_The("%s here is too hard to %s.", surface(x, y), verb); - return FALSE; + && (levl[x][y].wall_info & W_NONDIGGABLE) != 0)) { + return DIGCHECK_FAIL_TOOHARD; + } else if (ttmp && undestroyable_trap(ttmp->ttyp)) { + return DIGCHECK_FAIL_UNDESTROYABLETRAP; + } else if (!Can_dig_down(&u.uz) && !levl[x][y].candig) { + if (ttmp) { + if (ttmp->ttyp != HOLE && !is_pit(ttmp->ttyp)) + return DIGCHECK_PASSED_DESTROY_TRAP; + else + return DIGCHECK_FAIL_CANTDIG; + } else { + return DIGCHECK_PASSED_PITONLY; + } } else if (sobj_at(BOULDER, x, y)) { - if (verbose) - There("isn't enough room to %s here.", verb); - return FALSE; + return DIGCHECK_FAIL_BOULDER; } else if (madeby == BY_OBJECT /* the block against existing traps is mainly to prevent broken wands from turning holes into pits */ && (ttmp || is_pool_or_lava(x, y))) { /* digging by player handles pools separately */ - return FALSE; + return DIGCHECK_FAIL_OBJ_POOL_OR_TRAP; + } + return DIGCHECK_PASSED; +} + +void +digcheck_fail_message(enum digcheck_result digresult, struct monst *madeby, + coordxy x, coordxy y) +{ + const char *verb = + (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; + + if (digresult < DIGCHECK_FAILED) + return; + + switch (digresult) { + case DIGCHECK_FAIL_AIRLEVEL: + You("cannot %s thin air.", verb); + break; + case DIGCHECK_FAIL_ALTAR: + pline_The("altar is too hard to break apart."); + break; + case DIGCHECK_FAIL_BOULDER: + There("isn't enough room to %s here.", verb); + break; + case DIGCHECK_FAIL_ONLADDER: + pline_The("ladder resists your effort."); + break; + case DIGCHECK_FAIL_ONSTAIRS: + pline_The("stairs are too hard to %s.", verb); + break; + case DIGCHECK_FAIL_THRONE: + pline_The("throne is too hard to break apart."); + break; + case DIGCHECK_FAIL_CANTDIG: + case DIGCHECK_FAIL_TOOHARD: + pline_The("%s here is too hard to %s.", surface(x, y), verb); + break; + case DIGCHECK_FAIL_UNDESTROYABLETRAP: + case DIGCHECK_FAIL_WATERLEVEL: + pline_The("%s splashes and subsides.", hliquid("water")); + break; + case DIGCHECK_FAIL_OBJ_POOL_OR_TRAP: + case DIGCHECK_PASSED: + case DIGCHECK_PASSED_PITONLY: + case DIGCHECK_PASSED_DESTROY_TRAP: + break; } - return TRUE; } staticfn int @@ -267,6 +305,7 @@ dig(void) coordxy dpx = svc.context.digging.pos.x, dpy = svc.context.digging.pos.y; boolean ispick = uwep && is_pick(uwep); const char *verb = (!uwep || is_pick(uwep)) ? "dig into" : "chop through"; + enum digcheck_result dcresult = DIGCHECK_PASSED; lev = &levl[dpx][dpy]; /* perhaps a nymph stole your pick-axe while you were busy digging */ @@ -278,8 +317,11 @@ dig(void) return 0; if (svc.context.digging.down) { - if (!dig_check(BY_YOU, TRUE, u.ux, u.uy)) + dcresult = dig_check(BY_YOU, u.ux, u.uy); + if (dcresult >= DIGCHECK_FAILED) { + digcheck_fail_message(dcresult, BY_YOU, u.ux, u.uy); return 0; + } } else { /* !svc.context.digging.down */ if (IS_TREE(lev->typ) && !may_dig(dpx, dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) { @@ -370,6 +412,17 @@ dig(void) /* we haven't made any progress toward a pit yet */ svc.context.digging.effort = 0; return 0; + } else if (ttmp && dcresult == DIGCHECK_PASSED_DESTROY_TRAP) { + const char *ttmpname = trapname(ttmp->ttyp, FALSE); + + if (ispick) + You("destroy %s with %s.", + ttmp->tseen ? the(ttmpname) : an(ttmpname), + yobjnam(uwep, (const char *) 0)); + deltrap(ttmp); + /* we haven't made any progress toward a pit yet */ + svc.context.digging.effort = 0; + return 0; } if (IS_ALTAR(lev->typ)) { @@ -637,6 +690,7 @@ digactualhole(coordxy x, coordxy y, struct monst *madeby, int ttyp) } shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE); oldobjs = svl.level.objects[x][y]; + ttmp = maketrap(x, y, ttyp); if (!ttmp) return; @@ -836,7 +890,8 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) schar typ, old_typ; coordxy dig_x, dig_y; boolean nohole, retval = FALSE; - + enum digcheck_result dig_check_result; + if (!cc) { dig_x = u.ux; dig_y = u.uy; @@ -849,7 +904,10 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) ttmp = t_at(dig_x, dig_y); lev = &levl[dig_x][dig_y]; - nohole = (!Can_dig_down(&u.uz) && !lev->candig); + dig_check_result = dig_check(BY_YOU, dig_x, dig_y); + /* nohole = (!Can_dig_down(&u.uz) && !lev->candig); */ + nohole = (dig_check_result == DIGCHECK_FAIL_CANTDIG + || dig_check_result == DIGCHECK_FAIL_TOOHARD); old_typ = lev->typ; if ((ttmp && (undestroyable_trap(ttmp->ttyp) || nohole)) @@ -952,7 +1010,9 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) } /* finally we get to make a hole */ - if (nohole || pit_only) + if (nohole || pit_only + || dig_check_result == DIGCHECK_PASSED_DESTROY_TRAP + || dig_check_result == DIGCHECK_PASSED_PITONLY) digactualhole(dig_x, dig_y, BY_YOU, PIT); else digactualhole(dig_x, dig_y, BY_YOU, HOLE);