fix #H2645 - invulnerability during prayer is vulernable to stinking cloud

From a bug report, stinking cloud
harms hero even when u.uninvulnerable is set during successful prayer.
This makes the cloud harmless during prayer as he suggested.

     It also makes being inside a stinking cloud become a major trouble
that prayer can fix.  (With magical breathing such a cloud is harmless and
with poison resistance it is just a nuisance; it won't be considered to be
trouble in such cases.)  The fix is to clear away the cloud, or to teleport
the hero if he's inside multiple overlapping clouds or in one that is
marked as permanent (which I think isn't currently possible).
This commit is contained in:
nethack.rankin
2012-05-07 01:44:38 +00:00
parent b1dbd463c5
commit 0add521787
4 changed files with 74 additions and 8 deletions

View File

@@ -838,6 +838,7 @@ declining to attack a peaceful monster via movement used up nutrition even
though no action took place
declining to attack a peaceful monster via kicking woke nearby monsters and
scuffed engraving at hero's location even though no action took place
make hero be immune from stinking cloud damage during successful prayer
Platform- and/or Interface-Specific Fixes
@@ -1043,6 +1044,8 @@ repeatedly setting the fruit option will check to see if fruits have been
created, so the user can't easily overflow the maximum this way
bones files now include extra data to identify dead hero and reason for death
dipping multiple potions in another potion may only dip part of their stack
make being inside a stinking cloud (when not immune or resistant) become a
major trouble which is fixable by prayer
Platform- and/or Interface-Specific New Features

View File

@@ -1932,6 +1932,8 @@ E void FDECL(show_region, (NhRegion*, XCHAR_P, XCHAR_P));
E void FDECL(save_regions, (int,int));
E void FDECL(rest_regions, (int,BOOLEAN_P));
E NhRegion* FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int));
E boolean NDECL(region_danger);
E void NDECL(region_safety);
/* ### restore.c ### */

View File

@@ -69,12 +69,13 @@ static int p_type; /* (-1)-3: (-1)=really naughty, 3=really good */
* order to have the values be meaningful.
*/
#define TROUBLE_STONED 13
#define TROUBLE_SLIMED 12
#define TROUBLE_STRANGLED 11
#define TROUBLE_LAVA 10
#define TROUBLE_SICK 9
#define TROUBLE_STARVING 8
#define TROUBLE_STONED 14
#define TROUBLE_SLIMED 13
#define TROUBLE_STRANGLED 12
#define TROUBLE_LAVA 11
#define TROUBLE_SICK 10
#define TROUBLE_STARVING 9
#define TROUBLE_REGION 8 /* stinking cloud */
#define TROUBLE_HIT 7
#define TROUBLE_LYCANTHROPE 6
#define TROUBLE_COLLAPSING 5
@@ -168,6 +169,7 @@ in_trouble()
if(u.utrap && u.utraptype == TT_LAVA) return(TROUBLE_LAVA);
if(Sick) return(TROUBLE_SICK);
if(u.uhs >= WEAK) return(TROUBLE_STARVING);
if (region_danger()) return TROUBLE_REGION;
if (critically_low_hp(FALSE)) return TROUBLE_HIT;
if(u.ulycn >= LOW_PM) return(TROUBLE_LYCANTHROPE);
if(near_capacity() >= EXT_ENCUMBER && AMAX(A_STR)-ABASE(A_STR) > 3)
@@ -200,7 +202,7 @@ in_trouble()
/*
* minor troubles
*/
if(Punished || (u.utrap && u.utraptype == TT_BURIEDBALL))
if (Punished || (u.utrap && u.utraptype == TT_BURIEDBALL))
return(TROUBLE_PUNISHED);
if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) ||
Cursed_obj(uarmf, FUMBLE_BOOTS))
@@ -336,6 +338,10 @@ register int trouble;
You_feel("better.");
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
break;
case TROUBLE_REGION:
/* stinking cloud, with hero vulnerable to HP loss */
region_safety();
break;
case TROUBLE_HIT:
/* "fix all troubles" will keep trying if hero has
5 or less hit points, so make sure they're always

View File

@@ -918,7 +918,7 @@ genericptr_t p2;
reg = (NhRegion *) p1;
dam = reg->arg.a_int;
if (p2 == (genericptr_t)0) { /* This means *YOU* Bozo! */
if (nonliving(youmonst.data) || Breathless)
if (u.uinvulnerable || nonliving(youmonst.data) || Breathless)
return FALSE;
if (!Blind) {
Your("%s sting.", makeplural(body_part(EYE)));
@@ -1000,4 +1000,59 @@ int damage;
return cloud;
}
/* for checking troubles during prayer; is hero at risk? */
boolean
region_danger()
{
int i, f_indx, n = 0;
for (i = 0; i < n_regions; i++) {
/* only care about regions that hero is in */
if (!hero_inside(regions[i])) continue;
f_indx = regions[i]->inside_f;
/* the only type of region we understand is gas_cloud */
if (f_indx == INSIDE_GAS_CLOUD) {
/* completely harmless if you don't need to breathe */
if (nonliving(youmonst.data) || Breathless) continue;
/* minor inconvenience if you're posion resistant;
not harmful enough to be a prayer-level trouble */
if (Poison_resistance) continue;
++n;
}
}
return n ? TRUE : FALSE;
}
/* for fixing trouble at end of prayer;
danger detected at start of prayer might have expired by now */
void
region_safety()
{
NhRegion *r = 0;
int i, f_indx, n = 0;
for (i = 0; i < n_regions; i++) {
/* only care about regions that hero is in */
if (!hero_inside(regions[i])) continue;
f_indx = regions[i]->inside_f;
/* the only type of region we understand is gas_cloud */
if (f_indx == INSIDE_GAS_CLOUD) {
if (!n++ && regions[i]->ttl >= 0) r = regions[i];
}
}
if (n > 1 || (n == 1 && !r)) {
/* multiple overlapping cloud regions or non-expiring one */
safe_teleds(FALSE);
} else if (r) {
remove_region(r);
pline_The("gas cloud enveloping you dissipates.");
} else {
/* cloud dissipated on its own, so nothing needs to be done */
pline_The("gas cloud has dissipated.");
}
/* maybe cure blindness too */
if ((Blinded && TIMEOUT) == 1L) make_blinded(0L, TRUE);
}
/*region.c*/