diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 19c4c4d82..231b19406 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -HDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1152 $ $NHDT-Date: 1681293789 2023/04/12 10:03:09 $ +HDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1153 $ $NHDT-Date: 1681429662 2023/04/13 23:47:42 $ General Fixes and Modified Features ----------------------------------- @@ -1139,6 +1139,10 @@ a chameleon in giant form who gets trapped (bear trap?) while carrying boulders and changes shape could be killed when dropping them; shape-change traversal of its inventory would continue after it dropped everything, possibly resulting in a crash +if hero is engulfed and polymorphs into a monster form which is too big to be + engulfed, make engulfer expel the poly'd hero +give feedback if monster holding onto the hero has to let go when hero polys + into a form which can't be held Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/mon.c b/src/mon.c index e1dba116d..dccda6267 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mon.c $NHDT-Date: 1681293789 2023/04/12 10:03:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.494 $ */ +/* NetHack 3.7 mon.c $NHDT-Date: 1681429657 2023/04/13 23:47:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.495 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1158,9 +1158,9 @@ m_consume_obj(struct monst *mtmp, struct obj *otmp) int poly, grow, heal, eyes, mstone, vis = canseemon(mtmp); int corpsenm = (otmp->otyp == CORPSE ? otmp->corpsenm : NON_PM); - deadmimic = (otmp->otyp == CORPSE && (otmp->corpsenm == PM_SMALL_MIMIC - || otmp->corpsenm == PM_LARGE_MIMIC - || otmp->corpsenm == PM_GIANT_MIMIC)); + deadmimic = (otmp->otyp == CORPSE && (corpsenm == PM_SMALL_MIMIC + || corpsenm == PM_LARGE_MIMIC + || corpsenm == PM_GIANT_MIMIC)); slimer = (otmp->otyp == GLOB_OF_GREEN_SLIME); poly = polyfodder(otmp); grow = mlevelgain(otmp); @@ -4782,8 +4782,8 @@ newcham( if (u.uswallow) { if (!attacktype(mdat, AT_ENGL)) { /* Does mdat care? */ - if (!noncorporeal(mdat) && !amorphous(mdat) - && !is_whirly(mdat) && (mdat != &mons[PM_YELLOW_LIGHT])) { + if (!noncorporeal(mdat) && !is_whirly(mdat) + && !(amorphous(mdat) || mdat->mlet == S_LIGHT)) { char msgtrail[BUFSZ]; if (is_vampshifter(mtmp)) { @@ -4794,7 +4794,6 @@ newcham( } else { msgtrail[0] = '\0'; } - /* Do this even if msg is FALSE */ You("%s %s%s!", (amorphous(olddata) || is_whirly(olddata)) diff --git a/src/polyself.c b/src/polyself.c index a93cf6a15..583f18e68 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 polyself.c $NHDT-Date: 1647912064 2022/03/22 01:21:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.178 $ */ +/* NetHack 3.7 polyself.c $NHDT-Date: 1681429658 2023/04/13 23:47:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.197 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -171,7 +171,7 @@ DISABLE_WARNING_FORMAT_NONLITERAL static void polyman(const char *fmt, const char *arg) { - boolean sticky = (sticks(gy.youmonst.data) && u.ustuck && !u.uswallow), + boolean sticking = (sticks(gy.youmonst.data) && u.ustuck && !u.uswallow), was_mimicking = (U_AP_TYPE != M_AP_NOTHING); boolean was_blind = !!Blind; @@ -188,7 +188,7 @@ polyman(const char *fmt, const char *arg) skinback(FALSE); u.uundetected = 0; - if (sticky) + if (sticking) uunstick(); find_ac(); if (was_mimicking) { @@ -680,9 +680,9 @@ polyself(int psflags) int polymon(int mntmp) { - char buf[BUFSZ]; - boolean sticky = sticks(gy.youmonst.data) && u.ustuck && !u.uswallow, - was_blind = !!Blind, dochange = FALSE; + char buf[BUFSZ], ustuckNam[BUFSZ]; + boolean sticking = sticks(gy.youmonst.data) && u.ustuck && !u.uswallow, + was_blind = !!Blind, dochange = FALSE, was_expelled = FALSE; int mlvl, newMaxStr; if (gm.mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ @@ -738,6 +738,8 @@ polymon(int mntmp) dochange = TRUE; } + Strcpy(ustuckNam, u.ustuck ? Some_Monnam(u.ustuck) : ""); + Strcpy(buf, (u.umonnum != mntmp) ? "" : "new "); if (dochange) { flags.female = !flags.female; @@ -830,6 +832,7 @@ polymon(int mntmp) skinback(FALSE); break_armor(); drop_weapon(1); + find_ac(); /* (repeated below) */ (void) hideunder(&gy.youmonst); if (u.utrap && u.utraptype == TT_PIT) { @@ -841,13 +844,55 @@ polymon(int mntmp) } newsym(u.ux, u.uy); /* Change symbol */ - /* [note: this 'sticky' handling is only sufficient for changing from + /* you now know what an egg of your type looks like; [moved from + below in case expels() -> spoteffects() drops hero onto any eggs] */ + if (lays_eggs(gy.youmonst.data)) { + learn_egg_type(u.umonnum); + /* make queen bees recognize killer bee eggs */ + learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); + } + + if (u.uswallow) { + uchar usiz; + + /* if new form can't be swallowed, make engulfer expel hero */ + if (unsolid(gy.youmonst.data) + /* subset of engulf_target() */ + || (usiz = gy.youmonst.data->msize) >= MZ_HUGE + || (u.ustuck->data->msize < usiz && !is_whirly(u.ustuck->data))) { + boolean expels_mesg = TRUE; + + if (unsolid(gy.youmonst.data)) { + if (canspotmon(u.ustuck)) /* [see below for explanation] */ + Strcpy(ustuckNam, Monnam(u.ustuck)); + pline("%s can no longer contain you.", ustuckNam); + expels_mesg = FALSE; + } + expels(u.ustuck, u.ustuck->data, expels_mesg); + was_expelled = TRUE; + /* FIXME? if expels() triggered rehumanize then we should + return early */ + } + + /* [note: this 'sticking' handling is only sufficient for changing from grabber to engulfer or vice versa because engulfing by poly'd hero always ends immediately so won't be in effect during a polymorph] */ - if (!sticky && !u.uswallow && u.ustuck && sticks(gy.youmonst.data)) + } else if (u.ustuck && !sticking /* && !u.uswallow */ + /* being held; if now capable of holding, make holder + release so that hero doesn't automagically start holding + it; or, release if no longer capable of being held */ + && (sticks(gy.youmonst.data) || unsolid(gy.youmonst.data))) { + /* u.ustuck name was saved above in case we're changing from can-see + to can't-see; but might have changed from can't-see to can-see so + override here if hero knows who u.ustuck is */ + if (canspotmon(u.ustuck)) + Strcpy(ustuckNam, Monnam(u.ustuck)); set_ustuck((struct monst *) 0); - else if (sticky && !sticks(gy.youmonst.data)) + pline("%s loses its grip on you.", ustuckNam); + } else if (sticking && !sticks(gy.youmonst.data)) { + /* was holding onto u.ustuck but no longer capable of that */ uunstick(); + } if (u.usteed) { if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { @@ -861,6 +906,70 @@ polymon(int mntmp) dismount_steed(DISMOUNT_POLY); } + find_ac(); + if (((!Levitation && !u.ustuck && !Flying && is_pool_or_lava(u.ux, u.uy)) + || (Underwater && !Swimming)) + /* if expelled above, expels() already called spoteffects() */ + && !was_expelled) { + spoteffects(TRUE); + /* FIXME? if spoteffects() triggered rehumanize then we should + return early */ + } + if (Passes_walls && u.utrap + && (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL)) { + if (u.utraptype == TT_INFLOOR) { + pline_The("rock seems to no longer trap you."); + } else { + pline_The("buried ball is no longer bound to you."); + buried_ball_to_freedom(); + } + reset_utrap(TRUE); + } else if (likes_lava(gy.youmonst.data) && u.utrap + && u.utraptype == TT_LAVA) { + pline_The("%s now feels soothing.", hliquid("lava")); + reset_utrap(TRUE); + } + if (amorphous(gy.youmonst.data) || is_whirly(gy.youmonst.data) + || unsolid(gy.youmonst.data)) { + if (Punished) { + You("slip out of the iron chain."); + unpunish(); + } else if (u.utrap && u.utraptype == TT_BURIEDBALL) { + You("slip free of the buried ball and chain."); + buried_ball_to_freedom(); + } + } + if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) + && (amorphous(gy.youmonst.data) || is_whirly(gy.youmonst.data) + || unsolid(gy.youmonst.data) + || (gy.youmonst.data->msize <= MZ_SMALL + && u.utraptype == TT_BEARTRAP))) { + You("are no longer stuck in the %s.", + u.utraptype == TT_WEB ? "web" : "bear trap"); + /* probably should burn webs too if PM_FIRE_ELEMENTAL */ + reset_utrap(TRUE); + } + if (webmaker(gy.youmonst.data) && u.utrap && u.utraptype == TT_WEB) { + You("orient yourself on the web."); + reset_utrap(TRUE); + } + check_strangling(TRUE); /* maybe start strangling */ + + gc.context.botl = 1; + gv.vision_full_recalc = 1; + see_monsters(); + (void) encumber_msg(); + + retouch_equipment(2); + /* this might trigger a recursive call to polymon() [stone golem + wielding cockatrice corpse and hit by stone-to-flesh, becomes + flesh golem above, now gets transformed back into stone golem; + fortunately neither form uses #monster] */ + if (!uarmg) + selftouch(no_longer_petrify_resistant); + + /* the explanation of '#monster' used to be shown sooner, but there are + possible fatalities above and it isn't useful unless hero survives */ if (Verbose(2, polymon)) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; @@ -900,67 +1009,6 @@ polymon(int mntmp) pline(use_thec, "sit", eggs_in_water(uptr) ? "spawn in the water" : "lay an egg"); } - - /* you now know what an egg of your type looks like */ - if (lays_eggs(gy.youmonst.data)) { - learn_egg_type(u.umonnum); - /* make queen bees recognize killer bee eggs */ - learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); - } - find_ac(); - if ((!Levitation && !u.ustuck && !Flying && is_pool_or_lava(u.ux, u.uy)) - || (Underwater && !Swimming)) - spoteffects(TRUE); - if (Passes_walls && u.utrap - && (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL)) { - if (u.utraptype == TT_INFLOOR) { - pline_The("rock seems to no longer trap you."); - } else { - pline_The("buried ball is no longer bound to you."); - buried_ball_to_freedom(); - } - reset_utrap(TRUE); - } else if (likes_lava(gy.youmonst.data) && u.utrap - && u.utraptype == TT_LAVA) { - pline_The("%s now feels soothing.", hliquid("lava")); - reset_utrap(TRUE); - } - if (amorphous(gy.youmonst.data) || is_whirly(gy.youmonst.data) - || unsolid(gy.youmonst.data)) { - if (Punished) { - You("slip out of the iron chain."); - unpunish(); - } else if (u.utrap && u.utraptype == TT_BURIEDBALL) { - You("slip free of the buried ball and chain."); - buried_ball_to_freedom(); - } - } - if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) - && (amorphous(gy.youmonst.data) || is_whirly(gy.youmonst.data) - || unsolid(gy.youmonst.data) || (gy.youmonst.data->msize <= MZ_SMALL - && u.utraptype == TT_BEARTRAP))) { - You("are no longer stuck in the %s.", - u.utraptype == TT_WEB ? "web" : "bear trap"); - /* probably should burn webs too if PM_FIRE_ELEMENTAL */ - reset_utrap(TRUE); - } - if (webmaker(gy.youmonst.data) && u.utrap && u.utraptype == TT_WEB) { - You("orient yourself on the web."); - reset_utrap(TRUE); - } - check_strangling(TRUE); /* maybe start strangling */ - - gc.context.botl = 1; - gv.vision_full_recalc = 1; - see_monsters(); - (void) encumber_msg(); - - retouch_equipment(2); - /* this might trigger a recursive call to polymon() [stone golem - wielding cockatrice corpse and hit by stone-to-flesh, becomes - flesh golem above, now gets transformed back into stone golem] */ - if (!uarmg) - selftouch(no_longer_petrify_resistant); return 1; }