polyself u.ustuck fixes

More towards not being able to swallow or hold an non-solid creature.
When engulfed, expel hero if the new form is unsolid or too big.
Give a message if hero is being held (rather than engulfed) and has
to be released.

Adding a call to expels() required some code reordering because it
calls spoteffects().

Give the hint about using '#monster' at the very end of polymon().
This commit is contained in:
PatR
2023-04-13 16:47:42 -07:00
parent 25bf9d2a49
commit ced75cb88e
3 changed files with 129 additions and 78 deletions

View File

@@ -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

View File

@@ -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))

View File

@@ -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;
}