diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 7e5d658d3..eb8fa876b 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1323,6 +1323,11 @@ change [master] mind flayer, the Wizard, and the riders to bright magenta walking into a shopkeeper tries to pay the bill show billed items in a menu when paying with non-traditional menustyle prioritize paying shopkeeper next to you even if multiple are detected +avoid impossible "trapped without a trap (fmon)" from 'sanity_check' when a + drum of earthquake made a pit at a monster's spot and pit creation + caused adjacent pool/moat/lava to flood that spot; if a non-floater, + non-flyer monster survived that it got marked as trapped even though + flooding deleted the trap Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dig.c b/src/dig.c index 17fba710a..a6a1f98f5 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dig.c $NHDT-Date: 1596498156 2020/08/03 23:42:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1702206282 2023/12/10 11:04:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.204 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -747,19 +747,32 @@ digactualhole(coordxy x, coordxy y, struct monst *madeby, int ttyp) DISABLE_WARNING_FORMAT_NONLITERAL /* - * Called from dighole(), but also from do_break_wand() - * in apply.c. + * Called from dighole(); also from do_break_wand() in apply.c + * and do_earthquake() in music.c. */ void -liquid_flow(coordxy x, coordxy y, schar typ, struct trap *ttmp, - const char *fillmsg) +liquid_flow( + coordxy x, coordxy y, + schar typ, + struct trap *ttmp, + const char *fillmsg) { struct obj *objchain; struct monst *mon; boolean u_spot = u_at(x, y); + /* caller should have changed levl[x][y].typ to POOL, MOAT, or LAVA */ + if (!is_pool_or_lava(x, y)) { + if (iflags.sanity_check) { + impossible("Insane liquid_flow(%d,%d,%s,%s).", x, y, + ttmp ? trapname(ttmp->ttyp, TRUE) : "no trap", + fillmsg ? fillmsg : "no mesg"); + } + return; + } + if (ttmp) - (void) delfloortrap(ttmp); + (void) delfloortrap(ttmp); /* will untrap monster is one is here */ /* if any objects were frozen here, they're released now */ unearth_objs(x, y); diff --git a/src/music.c b/src/music.c index 2703f2f0a..a1f4b6086 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 music.c $NHDT-Date: 1646688067 2022/03/07 21:21:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */ +/* NetHack 3.7 music.c $NHDT-Date: 1702206294 2023/12/10 11:04:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.101 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -337,8 +337,11 @@ do_earthquake(int force) wand of digging if you alter this sequence. */ filltype = fillholetyp(x, y, FALSE); if (filltype != ROOM) { - levl[x][y].typ = filltype; /* flags set via doormask */ + set_levltyp(x, y, filltype); /* levl[x][y] = filltype; */ liquid_flow(x, y, filltype, chasm, (char *) 0); + /* liquid_flow() deletes trap, might kill mtmp */ + if ((chasm = t_at(x, y)) == NULL) + break; /* from switch, not loop */ } mtmp = m_at(x, y); /* (redundant?) */ @@ -353,8 +356,8 @@ do_earthquake(int force) break; /* from switch, not loop */ } - /* We have to check whether monsters or player - falls in a chasm... */ + /* We have to check whether monsters or hero falls into a + new pit.... Note: if we get here, chasm is non-Null. */ if (mtmp) { if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) { boolean m_already_trapped = mtmp->mtrapped; @@ -427,7 +430,7 @@ do_earthquake(int force) exercise(A_DEX, TRUE); else selftouch((Upolyd && (slithy(gy.youmonst.data) - || nolimbs(gy.youmonst.data))) + || nolimbs(gy.youmonst.data))) ? "Shaken, you" : "Falling down, you"); } diff --git a/src/pickup.c b/src/pickup.c index 7b7781116..01e272103 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -41,6 +41,7 @@ static void explain_container_prompt(boolean); static int traditional_loot(boolean); static int menu_loot(int, boolean); static int tip_ok(struct obj *); +static int choose_tip_container_menu(void); static struct obj *tipcontainer_gettarget(struct obj *, boolean *); static int tipcontainer_checks(struct obj *, struct obj *, boolean); static char in_or_out_menu(const char *, struct obj *, boolean, boolean, @@ -3376,6 +3377,67 @@ tip_ok(struct obj *obj) return GETOBJ_DOWNPLAY; } +/* show a menu of containers under hero, + and one extra entry for choosing an inventory. + returns ECMD_CANCEL if menu was canceled, + ECMD_TIME if a container was picked, + otherwise returns ECMD_OK. */ +static int +choose_tip_container_menu(void) +{ + int n, i; + winid win; + anything any; + menu_item *pick_list = (menu_item *) 0; + struct obj dummyobj, *otmp; + int clr = NO_COLOR; + + any = cg.zeroany; + win = create_nhwindow(NHW_MENU); + start_menu(win, MENU_BEHAVE_STANDARD); + + for (otmp = gl.level.objects[u.ux][u.uy], i = 0; otmp; + otmp = otmp->nexthere) + if (Is_container(otmp)) { + ++i; + any.a_obj = otmp; + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, + clr, doname(otmp), MENU_ITEMFLAGS_NONE); + } + if (gi.invent) { + add_menu_str(win, ""); + any.a_obj = &dummyobj; + /* use 'i' for inventory unless there are so many + containers that it's already being used */ + i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0; + add_menu(win, &nul_glyphinfo, &any, i, 0, ATR_NONE, + clr, "tip something being carried", + MENU_ITEMFLAGS_SELECTED); + } + end_menu(win, "Tip which container?"); + n = select_menu(win, PICK_ONE, &pick_list); + destroy_nhwindow(win); + /* + * Deal with quirk of preselected item in pick-one menu: + * n == 0 => picked preselected entry, toggling it off; + * n == 1 => accepted preselected choice via SPACE or RETURN; + * n == 2 => picked something other than preselected entry; + * n == -1 => cancelled via ESC; + */ + otmp = (n <= 0) ? (struct obj *) 0 : pick_list[0].item.a_obj; + if (n > 1 && otmp == &dummyobj) + otmp = pick_list[1].item.a_obj; + if (pick_list) + free((genericptr_t) pick_list); + if (otmp && otmp != &dummyobj) { + tipcontainer(otmp); + return ECMD_TIME; + } + if (n == -1) + return ECMD_CANCEL; + return ECMD_OK; +} + /* #tip command -- empty container contents onto floor */ int dotip(void) @@ -3412,57 +3474,10 @@ dotip(void) !flags.verbose ? "a container" : (boxes > 1) ? "one" : "it"); if (!check_capacity(buf) && able_to_loot(cc.x, cc.y, FALSE)) { if (boxes > 1) { - /* use menu to pick a container to tip */ - int n, i; - winid win; - anything any; - menu_item *pick_list = (menu_item *) 0; - struct obj dummyobj, *otmp; - int clr = NO_COLOR; - - any = cg.zeroany; - win = create_nhwindow(NHW_MENU); - start_menu(win, MENU_BEHAVE_STANDARD); - - for (cobj = gl.level.objects[cc.x][cc.y], i = 0; cobj; - cobj = cobj->nexthere) - if (Is_container(cobj)) { - ++i; - any.a_obj = cobj; - add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, - clr, doname(cobj), MENU_ITEMFLAGS_NONE); - } - if (gi.invent) { - add_menu_str(win, ""); - any.a_obj = &dummyobj; - /* use 'i' for inventory unless there are so many - containers that it's already being used */ - i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0; - add_menu(win, &nul_glyphinfo, &any, i, 0, ATR_NONE, - clr, "tip something being carried", - MENU_ITEMFLAGS_SELECTED); - } - end_menu(win, "Tip which container?"); - n = select_menu(win, PICK_ONE, &pick_list); - destroy_nhwindow(win); - /* - * Deal with quirk of preselected item in pick-one menu: - * n == 0 => picked preselected entry, toggling it off; - * n == 1 => accepted preselected choice via SPACE or RETURN; - * n == 2 => picked something other than preselected entry; - * n == -1 => cancelled via ESC; - */ - otmp = (n <= 0) ? (struct obj *) 0 : pick_list[0].item.a_obj; - if (n > 1 && otmp == &dummyobj) - otmp = pick_list[1].item.a_obj; - if (pick_list) - free((genericptr_t) pick_list); - if (otmp && otmp != &dummyobj) { - tipcontainer(otmp); - return ECMD_TIME; - } - if (n == -1) - return ECMD_OK; + int res; + /* pick one container via menu or ... */ + if ((res = choose_tip_container_menu()) != ECMD_OK) + return res; /* else pick-from-gi.invent below */ } else { for (cobj = gl.level.objects[cc.x][cc.y]; cobj; cobj = nobj) {