From b150594d68476940266d115897b9b124fd861d8a Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 21 Mar 2022 18:21:07 -0700 Subject: [PATCH] hide-under webmakers... Offer the chance to explicitly hide via #monster when poly'd into a hides-under creature. hides_under() doesn't pass the is_hider() test so wasn't being allowed before. If poly'd hero's monster form is both a webmaker and can hide-under, have #monster prompt the player for which is intended. When poly'd hero successfully spins a web, say so. If poly'd hero deliberately tries to hide under a cockatrice corpse, turn to stone. --- src/cmd.c | 35 +++++++++++++--------- src/polyself.c | 78 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 35 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 32ac3e1c6..170019f6c 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 cmd.c $NHDT-Date: 1646136938 2022/03/01 12:15:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.528 $ */ +/* NetHack 3.7 cmd.c $NHDT-Date: 1647912063 2022/03/22 01:21:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.533 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -770,21 +770,30 @@ RESTORE_WARNING_FORMAT_NONLITERAL int domonability(void) { - if (can_breathe(g.youmonst.data)) + struct permonst *uptr = g.youmonst.data; + boolean might_hide = (is_hider(uptr) || hides_under(uptr)); + char c = '\0'; + + if (might_hide && webmaker(uptr)) { + c = yn_function("Hide [h] or spin a web [s]?", "hsq", 'q'); + if (c == 'q' || c == '\033') + return ECMD_OK; + } + if (can_breathe(uptr)) return dobreathe(); - else if (attacktype(g.youmonst.data, AT_SPIT)) + else if (attacktype(uptr, AT_SPIT)) return dospit(); - else if (g.youmonst.data->mlet == S_NYMPH) + else if (uptr->mlet == S_NYMPH) return doremove(); - else if (attacktype(g.youmonst.data, AT_GAZE)) + else if (attacktype(uptr, AT_GAZE)) return dogaze(); - else if (is_were(g.youmonst.data)) + else if (is_were(uptr)) return dosummon(); - else if (webmaker(g.youmonst.data)) - return dospinweb(); - else if (is_hider(g.youmonst.data)) + else if (c ? c == 'h' : might_hide) return dohide(); - else if (is_mind_flayer(g.youmonst.data)) + else if (c ? c == 's' : webmaker(uptr)) + return dospinweb(); + else if (is_mind_flayer(uptr)) return domindblast(); else if (u.umonnum == PM_GREMLIN) { if (IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { @@ -792,16 +801,16 @@ domonability(void) dryup(u.ux, u.uy, TRUE); } else There("is no fountain here."); - } else if (is_unicorn(g.youmonst.data)) { + } else if (is_unicorn(uptr)) { use_unicorn_horn((struct obj **) 0); return ECMD_TIME; - } else if (g.youmonst.data->msound == MS_SHRIEK) { + } else if (uptr->msound == MS_SHRIEK) { You("shriek."); if (u.uburied) pline("Unfortunately sound does not carry well through rock."); else aggravate(); - } else if (is_vampire(g.youmonst.data) || is_vampshifter(&g.youmonst)) { + } else if (is_vampire(uptr) || is_vampshifter(&g.youmonst)) { return dopoly(); } else if (Upolyd) { pline("Any special ability you may have is purely reflexive."); diff --git a/src/polyself.c b/src/polyself.c index 222613843..df670f674 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 polyself.c $NHDT-Date: 1626312523 2021/07/15 01:28:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.162 $ */ +/* NetHack 3.7 polyself.c $NHDT-Date: 1647912064 2022/03/22 01:21:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.178 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -847,38 +847,41 @@ polymon(int mntmp) if (flags.verbose) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; + struct permonst *uptr = g.youmonst.data; + boolean might_hide = (is_hider(uptr) || hides_under(uptr)); - if (can_breathe(g.youmonst.data)) + if (can_breathe(uptr)) pline(use_thec, monsterc, "use your breath weapon"); - if (attacktype(g.youmonst.data, AT_SPIT)) + if (attacktype(uptr, AT_SPIT)) pline(use_thec, monsterc, "spit venom"); - if (g.youmonst.data->mlet == S_NYMPH) + if (uptr->mlet == S_NYMPH) pline(use_thec, monsterc, "remove an iron ball"); - if (attacktype(g.youmonst.data, AT_GAZE)) + if (attacktype(uptr, AT_GAZE)) pline(use_thec, monsterc, "gaze at monsters"); - if (is_hider(g.youmonst.data)) + if (might_hide && webmaker(uptr)) + pline(use_thec, monsterc, "hide or to spin a web"); + else if (might_hide) pline(use_thec, monsterc, "hide"); - if (is_were(g.youmonst.data)) - pline(use_thec, monsterc, "summon help"); - if (webmaker(g.youmonst.data)) + else if (webmaker(uptr)) pline(use_thec, monsterc, "spin a web"); + if (is_were(uptr)) + pline(use_thec, monsterc, "summon help"); if (u.umonnum == PM_GREMLIN) pline(use_thec, monsterc, "multiply in a fountain"); - if (is_unicorn(g.youmonst.data)) + if (is_unicorn(uptr)) pline(use_thec, monsterc, "use your horn"); - if (is_mind_flayer(g.youmonst.data)) + if (is_mind_flayer(uptr)) pline(use_thec, monsterc, "emit a mental blast"); - if (g.youmonst.data->msound == MS_SHRIEK) /* worthless, actually */ + if (uptr->msound == MS_SHRIEK) /* worthless, actually */ pline(use_thec, monsterc, "shriek"); - if (is_vampire(g.youmonst.data) || is_vampshifter(&g.youmonst)) + if (is_vampire(uptr) || is_vampshifter(&g.youmonst)) pline(use_thec, monsterc, "change shape"); - if (lays_eggs(g.youmonst.data) && flags.female - && !(g.youmonst.data == &mons[PM_GIANT_EEL] - || g.youmonst.data == &mons[PM_ELECTRIC_EEL])) + if (lays_eggs(uptr) && flags.female + && !(uptr == &mons[PM_GIANT_EEL] + || uptr == &mons[PM_ELECTRIC_EEL])) pline(use_thec, "sit", - eggs_in_water(g.youmonst.data) ? "spawn in the water" - : "lay an egg"); + eggs_in_water(uptr) ? "spawn in the water" : "lay an egg"); } /* you now know what an egg of your type looks like */ @@ -1406,6 +1409,7 @@ dospinweb(void) } ttmp = maketrap(u.ux, u.uy, WEB); if (ttmp) { + You("spin a web."); ttmp->madeby_u = 1; feeltrap(ttmp); if (*in_rooms(u.ux, u.uy, SHOPBASE)) @@ -1604,10 +1608,40 @@ dohide(void) u.uundetected = 0; return ECMD_OK; } - if (hides_under(g.youmonst.data) && !g.level.objects[u.ux][u.uy]) { - There("is nothing to hide under here."); - u.uundetected = 0; - return ECMD_OK; + if (hides_under(g.youmonst.data)) { + long ct = 0L; + struct obj *otmp, *otop = g.level.objects[u.ux][u.uy]; + + if (!otop) { + There("is nothing to hide under here."); + u.uundetected = 0; + return ECMD_OK; + } + for (otmp = otop; + otmp && otmp->otyp == CORPSE + && touch_petrifies(&mons[otmp->corpsenm]); + otmp = otmp->nexthere) + ct += otmp->quan; + /* otmp will be Null iff the entire pile consists of 'trice corpses */ + if (!otmp && !Stone_resistance) { + char kbuf[BUFSZ]; + const char *corpse_name = cxname(otop); + + /* for the plural case, we'll say "cockatrice corpses" or + "chickatrice corpses" depending on the top of the pile + even if both types are present */ + if (ct == 1) + corpse_name = an(corpse_name); + /* no need to check poly_when_stoned(); no hide-underers can + turn into stone golems instead of becoming petrified */ + pline("Hiding under %s%s is a fatal mistake...", + corpse_name, plur(ct)); + Sprintf(kbuf, "hiding under %s%s", corpse_name, plur(ct)); + instapetrify(kbuf); + /* only reach here if life-saved */ + u.uundetected = 0; + return ECMD_TIME; + } } /* Planes of Air and Water */ if (on_ceiling && !has_ceiling(&u.uz)) {