diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 66be2e7f8..891d81762 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.49 $ $NHDT-Date: 1578190894 2020/01/05 02:21:34 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.50 $ $NHDT-Date: 1578216006 2020/01/05 09:20:06 $ General Fixes and Modified Features ----------------------------------- @@ -28,6 +28,9 @@ monster wielding Stormbringer or healer's Staff against another monster would heal the hero instead of the wielding monster when draining life change twoweapon feedback from "not a weapon" to "not a suitable weapon" don't allow twoweapon combat if either weapon is a bow, crossbow, or sling +drum of earthquake feedback reported various things (fountains, thrones, &c) + falling into a chasm but they remained intact because trap creation + had been changed to not clobber such things (so couldn't make pits) Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/music.c b/src/music.c index 055c407d6..2a6123d10 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 music.c $NHDT-Date: 1573063606 2019/11/06 18:06:46 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.60 $ */ +/* NetHack 3.6 music.c $NHDT-Date: 1578216006 2020/01/05 09:20:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -224,16 +224,20 @@ static void do_earthquake(force) int force; { + static const char into_a_chasm[] = " into a chasm"; register int x, y; struct monst *mtmp; struct obj *otmp; struct trap *chasm, *trap_at_u = t_at(u.ux, u.uy); - int start_x, start_y, end_x, end_y; + int start_x, start_y, end_x, end_y, amsk; + aligntyp algn; schar filltype; unsigned tu_pit = 0; if (trap_at_u) tu_pit = is_pit(trap_at_u->ttyp); + if (force > 13) /* sanity precaution; maximum used is actually 10 */ + force = 13; start_x = u.ux - (force * 2); start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); @@ -246,180 +250,185 @@ int force; for (y = start_y; y <= end_y; y++) { if ((mtmp = m_at(x, y)) != 0) { wakeup(mtmp, TRUE); /* peaceful monster will become hostile */ - if (mtmp->mundetected && is_hider(mtmp->data)) { + if (mtmp->mundetected) { mtmp->mundetected = 0; - if (cansee(x, y)) - pline("%s is shaken loose from the ceiling!", - Amonnam(mtmp)); - else - You_hear("a thumping sound."); - if (x == u.ux && y == u.uy) - You("easily dodge the falling %s.", mon_nam(mtmp)); newsym(x, y); - } - } - if (!rn2(14 - force)) - switch (levl[x][y].typ) { - case FOUNTAIN: /* Make the fountain disappear */ - if (cansee(x, y)) - pline_The("fountain falls into a chasm."); - goto do_pit; - case SINK: - if (cansee(x, y)) - pline_The("kitchen sink falls into a chasm."); - goto do_pit; - case ALTAR: - if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) - break; - - if (cansee(x, y)) - pline_The("altar falls into a chasm."); - goto do_pit; - case GRAVE: - if (cansee(x, y)) - pline_The("headstone topples into a chasm."); - goto do_pit; - case THRONE: - if (cansee(x, y)) - pline_The("throne falls into a chasm."); - /*FALLTHRU*/ - case ROOM: - case CORR: /* Try to make a pit */ - do_pit: - chasm = maketrap(x, y, PIT); - if (!chasm) - break; /* no pit if portal at that location */ - chasm->tseen = 1; - - /* TODO: - * This ought to be split into a separate routine to - * reduce indentation and the consequent line-wraps. - */ - - levl[x][y].doormask = 0; - /* - * Let liquid flow into the newly created chasm. - * Adjust corresponding code in apply.c for - * exploding 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 */ - liquid_flow(x, y, filltype, chasm, (char *) 0); - } - - mtmp = m_at(x, y); - - if ((otmp = sobj_at(BOULDER, x, y)) != 0) { + if (ceiling_hider(mtmp->data)) { if (cansee(x, y)) - pline("KADOOM! The boulder falls into a chasm%s!", - (x == u.ux && y == u.uy) ? " below you" - : ""); - if (mtmp) - mtmp->mtrapped = 0; - obj_extract_self(otmp); - (void) flooreffects(otmp, x, y, ""); - break; + pline("%s is shaken loose from the ceiling!", + Amonnam(mtmp)); + else if (!is_flyer(mtmp->data)) + You_hear("a thump."); } + } + if (M_AP_TYPE(mtmp) != M_AP_NOTHING + && M_AP_TYPE(mtmp) != M_AP_MONSTER) + seemimic(mtmp); + } + if (rn2(14 - force)) + continue; - /* We have to check whether monsters or player - falls in a chasm... */ - if (mtmp) { - if (!is_flyer(mtmp->data) - && !is_clinger(mtmp->data)) { - boolean m_already_trapped = mtmp->mtrapped; + switch (levl[x][y].typ) { + case FOUNTAIN: /* make the fountain disappear */ + if (cansee(x, y)) + pline_The("fountain falls%s.", into_a_chasm); + goto do_pit; + case SINK: + if (cansee(x, y)) + pline_The("kitchen sink falls%s.", into_a_chasm); + goto do_pit; + case ALTAR: + if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) + break; + /* no need to check for high altar here; we've just + excluded those */ + amsk = altarmask_at(x, y); + algn = Amask2align(amsk & AM_MASK); + if (cansee(x, y)) + pline_The("%s altar falls%s.", + align_str(algn), into_a_chasm); + goto do_pit; + case GRAVE: + if (cansee(x, y)) + pline_The("headstone topples%s.", into_a_chasm); + goto do_pit; + case THRONE: + if (cansee(x, y)) + pline_The("throne falls%s.", into_a_chasm); + /*FALLTHRU*/ + case ROOM: + case CORR: /* Try to make a pit */ + do_pit: + /* maketrap() won't replace furniture with a trap, + so remove the furniture first */ + if (levl[x][y].typ != CORR) { + if (levl[x][y].typ != DOOR) + levl[x][y].typ = ROOM; + levl[x][y].flags = 0; /* clear doormask (D_NODOOR) or + * altarmask or looted throne */ + levl[x][y].horizontal = 0; /* clear blessed fountain, + * disturbed grave */ + } + chasm = maketrap(x, y, PIT); + if (!chasm) + break; /* no pit if portal at that location */ + chasm->tseen = 1; - mtmp->mtrapped = 1; - if (!m_already_trapped) { /* suppress messages */ - if (cansee(x, y)) - pline("%s falls into a chasm!", - Monnam(mtmp)); - else if (humanoid(mtmp->data)) - You_hear("a scream!"); - } - /* Falling is okay for falling down - within a pit from jostling too */ - mselftouch(mtmp, "Falling, ", TRUE); - if (!DEADMONSTER(mtmp)) { - mtmp->mhp -= rnd(m_already_trapped ? 4 : 6); - if (DEADMONSTER(mtmp)) { - if (!cansee(x, y)) { - pline("It is destroyed!"); - } else { - You("destroy %s!", - mtmp->mtame - ? x_monnam(mtmp, ARTICLE_THE, - "poor", - has_mname(mtmp) - ? SUPPRESS_SADDLE - : 0, - FALSE) - : mon_nam(mtmp)); - } - xkilled(mtmp, XKILL_NOMSG); + /* Let liquid flow into the newly created chasm. + Adjust corresponding code in apply.c for exploding + 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 */ + liquid_flow(x, y, filltype, chasm, (char *) 0); + } + + mtmp = m_at(x, y); /* (redundant?) */ + if ((otmp = sobj_at(BOULDER, x, y)) != 0) { + if (cansee(x, y)) + pline("KADOOM! The boulder falls into a chasm%s!", + (x == u.ux && y == u.uy) ? " below you" : ""); + if (mtmp) + mtmp->mtrapped = 0; + obj_extract_self(otmp); + (void) flooreffects(otmp, x, y, ""); + break; /* from switch, not loop */ + } + + /* We have to check whether monsters or player + falls in a chasm... */ + if (mtmp) { + if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) { + boolean m_already_trapped = mtmp->mtrapped; + + mtmp->mtrapped = 1; + if (!m_already_trapped) { /* suppress messages */ + if (cansee(x, y)) + pline("%s falls into a chasm!", Monnam(mtmp)); + else if (humanoid(mtmp->data)) + You_hear("a scream!"); + } + /* Falling is okay for falling down + within a pit from jostling too */ + mselftouch(mtmp, "Falling, ", TRUE); + if (!DEADMONSTER(mtmp)) { + mtmp->mhp -= rnd(m_already_trapped ? 4 : 6); + if (DEADMONSTER(mtmp)) { + if (!cansee(x, y)) { + pline("It is destroyed!"); + } else { + You("destroy %s!", + mtmp->mtame + ? x_monnam(mtmp, ARTICLE_THE, "poor", + has_mname(mtmp) + ? SUPPRESS_SADDLE : 0, + FALSE) + : mon_nam(mtmp)); } + xkilled(mtmp, XKILL_NOMSG); } } - } else if (x == u.ux && y == u.uy) { - if (u.utrap && u.utraptype == TT_BURIEDBALL) { - /* Note: the chain should break if a pit gets - created at the buried ball's location, which - is not necessarily here. But if we don't do - things this way, entering the new pit below - will override current trap anyway, but too - late to get Lev and Fly handling. */ - Your("chain breaks!"); - reset_utrap(TRUE); + } + } else if (x == u.ux && y == u.uy) { + if (u.utrap && u.utraptype == TT_BURIEDBALL) { + /* Note: the chain should break if a pit gets + created at the buried ball's location, which + is not necessarily here. But if we don't do + things this way, entering the new pit below + will override current trap anyway, but too + late to get Lev and Fly handling. */ + Your("chain breaks!"); + reset_utrap(TRUE); + } + if (Levitation || Flying || is_clinger(g.youmonst.data)) { + if (!tu_pit) { /* no pit here previously */ + pline("A chasm opens up under you!"); + You("don't fall in!"); } - if (Levitation || Flying - || is_clinger(g.youmonst.data)) { - if (!tu_pit) { /* no pit here previously */ - pline("A chasm opens up under you!"); - You("don't fall in!"); - } - } else if (!tu_pit || !u.utrap - || (u.utrap && u.utraptype != TT_PIT)) { - /* no pit here previously, or you were - not in it even if there was */ - You("fall into a chasm!"); - set_utrap(rn1(6, 2), TT_PIT); - losehp(Maybe_Half_Phys(rnd(6)), - "fell into a chasm", NO_KILLER_PREFIX); - selftouch("Falling, you"); - } else if (u.utrap && u.utraptype == TT_PIT) { - boolean keepfooting = + } else if (!tu_pit || !u.utrap || u.utraptype != TT_PIT) { + /* no pit here previously, or you were + not in it even if there was */ + You("fall into a chasm!"); + set_utrap(rn1(6, 2), TT_PIT); + losehp(Maybe_Half_Phys(rnd(6)), + "fell into a chasm", NO_KILLER_PREFIX); + selftouch("Falling, you"); + } else if (u.utrap && u.utraptype == TT_PIT) { + boolean keepfooting = ((Fumbling && !rn2(5)) || (!rnl(Role_if(PM_ARCHEOLOGIST) ? 3 : 9)) || ((ACURR(A_DEX) > 7) && rn2(5))); - You("are jostled around violently!"); - set_utrap(rn1(6, 2), TT_PIT); - losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)), - "hurt in a chasm", NO_KILLER_PREFIX); - if (keepfooting) - exercise(A_DEX, TRUE); - else - selftouch( - (Upolyd && (slithy(g.youmonst.data) - || nolimbs(g.youmonst.data))) - ? "Shaken, you" - : "Falling down, you"); - } - } else - newsym(x, y); - break; - case DOOR: /* Make the door collapse */ - if (levl[x][y].doormask == D_NODOOR) - goto do_pit; - if (cansee(x, y)) - pline_The("door collapses."); - if (*in_rooms(x, y, SHOPBASE)) - add_damage(x, y, 0L); - levl[x][y].doormask = D_NODOOR; - unblock_point(x, y); + You("are jostled around violently!"); + set_utrap(rn1(6, 2), TT_PIT); + losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)), + "hurt in a chasm", NO_KILLER_PREFIX); + if (keepfooting) + exercise(A_DEX, TRUE); + else + selftouch((Upolyd && (slithy(g.youmonst.data) + || nolimbs(g.youmonst.data))) + ? "Shaken, you" + : "Falling down, you"); + } + } else { newsym(x, y); - break; } + break; + case DOOR: /* make the door collapse */ + if (levl[x][y].doormask == D_NODOOR) + goto do_pit; + /* TODO: if door is trapped, the trap should explode; + forcing D_NODOOR just makes trap silently go away */ + if (cansee(x, y)) + pline_The("door collapses."); + if (*in_rooms(x, y, SHOPBASE)) + add_damage(x, y, 0L); + levl[x][y].doormask = D_NODOOR; + unblock_point(x, y); + newsym(x, y); + break; + } } }