fix prayer infinite loop
Reported internally, if a prayer resulted in 'fix all troubles' and one of those was TROUBLE_STUCK_IN_WALL but safe_teleds() couldn't find any place to relocate the hero to, nothing was done and STUCK_IN_WALL would be found again as the next trouble to fix. Since safe_teleds() eventually resorts to trying every single spot on the map, there was no other result possible than failing to find an available spot again, nothing would be done, and next trouble would be STUCK_IN_WALL, ad naseum. I started out with a fix that looked for secret corridors to expose and doors to open, to make more space available, then try to move a monster off the level, then try digging out rock and/or walls and smashing boulders. None of those guarantee success and I got bogged down by the digging case. This was going to be a last resort if all of those still failed to make somewhere to move the hero, but for now, at least, I'm skipping all that other stuff and going directly to the last resort: give the hero Passes_walls ability for a short time, and let him or her find own way out of trouble. The next trouble to fix won't be STUCK_IN_WALL because Passes_walls makes that a non-issue. I'm not thrilled with the new messages involved but want to get this behind me.
This commit is contained in:
@@ -517,6 +517,8 @@ whatis lookup for 'more info?' would behave strangely for plural names, either
|
||||
you should not hear a whistle if you are deaf
|
||||
change the deity's "congratulations" message upon ascension to something which
|
||||
sounds a bit more archaic to fit better with the other messages
|
||||
prayer boon of 'fix all troubles' could get stuck in an infinite loop for
|
||||
TROUBLE_STUCK_IN_WALL if there was no spot to teleport into available
|
||||
|
||||
|
||||
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
|
||||
|
||||
@@ -1917,6 +1917,7 @@ E const char *NDECL(bottlename);
|
||||
/* ### pray.c ### */
|
||||
|
||||
E boolean FDECL(critically_low_hp, (BOOLEAN_P));
|
||||
E boolean NDECL(stuck_in_wall);
|
||||
#ifdef USE_TRAMPOLI
|
||||
E int NDECL(prayer_done);
|
||||
#endif
|
||||
|
||||
57
src/pray.c
57
src/pray.c
@@ -140,6 +140,31 @@ boolean only_if_injured; /* determines whether maxhp <= 5 matters */
|
||||
return (boolean) (curhp <= 5 || curhp * divisor <= maxhp);
|
||||
}
|
||||
|
||||
/* return True if surrounded by impassible rock, regardless of the state
|
||||
of your own location (for example, inside a doorless closet) */
|
||||
boolean
|
||||
stuck_in_wall()
|
||||
{
|
||||
int i, j, x, y, count = 0;
|
||||
|
||||
if (Passes_walls)
|
||||
return FALSE;
|
||||
for (i = -1; i <= 1; i++) {
|
||||
x = u.ux + i;
|
||||
for (j = -1; j <= 1; j++) {
|
||||
if (!i && !j)
|
||||
continue;
|
||||
y = u.uy + j;
|
||||
if (!isok(x, y)
|
||||
|| (IS_ROCK(levl[x][y].typ)
|
||||
&& (levl[x][y].typ != SDOOR || levl[x][y].typ != SCORR))
|
||||
|| (blocked_boulder(i, j) && !throws_rocks(youmonst.data)))
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return (count == 8) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 if nothing particular seems wrong, positive numbers for
|
||||
* serious trouble, and negative numbers for comparative annoyances.
|
||||
@@ -158,7 +183,7 @@ STATIC_OVL int
|
||||
in_trouble()
|
||||
{
|
||||
struct obj *otmp;
|
||||
int i, j, count = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* major troubles
|
||||
@@ -183,19 +208,8 @@ in_trouble()
|
||||
return TROUBLE_LYCANTHROPE;
|
||||
if (near_capacity() >= EXT_ENCUMBER && AMAX(A_STR) - ABASE(A_STR) > 3)
|
||||
return TROUBLE_COLLAPSING;
|
||||
|
||||
for (i = -1; i <= 1; i++)
|
||||
for (j = -1; j <= 1; j++) {
|
||||
if (!i && !j)
|
||||
continue;
|
||||
if (!isok(u.ux + i, u.uy + j)
|
||||
|| IS_ROCK(levl[u.ux + i][u.uy + j].typ)
|
||||
|| (blocked_boulder(i, j) && !throws_rocks(youmonst.data)))
|
||||
count++;
|
||||
}
|
||||
if (count == 8 && !Passes_walls)
|
||||
if (stuck_in_wall())
|
||||
return TROUBLE_STUCK_IN_WALL;
|
||||
|
||||
if (Cursed_obj(uarmf, LEVITATION_BOOTS)
|
||||
|| stuck_ring(uleft, RIN_LEVITATION)
|
||||
|| stuck_ring(uright, RIN_LEVITATION))
|
||||
@@ -396,9 +410,22 @@ int trouble;
|
||||
}
|
||||
break;
|
||||
case TROUBLE_STUCK_IN_WALL:
|
||||
Your("surroundings change.");
|
||||
/* no control, but works on no-teleport levels */
|
||||
(void) safe_teleds(FALSE);
|
||||
if (safe_teleds(FALSE)) {
|
||||
Your("surroundings change.");
|
||||
} else {
|
||||
/* safe_teleds() couldn't find a safe place; perhaps the
|
||||
level is completely full. As a last resort, confer
|
||||
intrinsic wall/rock-phazing. Hero might get stuck
|
||||
again fairly soon....
|
||||
Without something like this, fix_all_troubles can get
|
||||
stuck in an infinite loop trying to fix STUCK_IN_WALL
|
||||
and repeatedly failing. */
|
||||
set_itimeout(&HPasses_walls, (long) d(4, 4));
|
||||
/* how else could you move between packed rocks or among
|
||||
lattice forming "solid" rock? */
|
||||
You_feel("much slimmer.");
|
||||
}
|
||||
break;
|
||||
case TROUBLE_CURSED_LEVITATION:
|
||||
if (Cursed_obj(uarmf, LEVITATION_BOOTS)) {
|
||||
|
||||
@@ -275,6 +275,7 @@ levitation_dialogue()
|
||||
|
||||
if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) {
|
||||
const char *s = levi_texts[SIZE(levi_texts) - i];
|
||||
|
||||
if (index(s, '%')) {
|
||||
boolean danger = (is_pool_or_lava(u.ux, u.uy)
|
||||
&& !Is_waterlevel(&u.uz));
|
||||
@@ -336,6 +337,30 @@ burn_away_slime()
|
||||
}
|
||||
}
|
||||
|
||||
/* Intrinsic Passes_walls is temporary when your god is trying to fix
|
||||
all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
|
||||
it can't find anywhere to place you. If that happens you get a small
|
||||
value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
|
||||
Message given is "you feel much slimmer" as a joke hint that you can
|
||||
move between things which are closely packed--like the substance of
|
||||
solid rock! */
|
||||
static NEARDATA const char *const phaze_texts[] = {
|
||||
"You start to feel bloated.",
|
||||
"You are feeling rather flabby.",
|
||||
};
|
||||
|
||||
STATIC_OVL void
|
||||
phaze_dialogue()
|
||||
{
|
||||
long i = ((HPasses_walls & TIMEOUT) / 2L);
|
||||
|
||||
if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
|
||||
return;
|
||||
|
||||
if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
|
||||
pline1(phaze_texts[SIZE(phaze_texts) - i]);
|
||||
}
|
||||
|
||||
void
|
||||
nh_timeout()
|
||||
{
|
||||
@@ -373,8 +398,10 @@ nh_timeout()
|
||||
vomiting_dialogue();
|
||||
if (Strangled)
|
||||
choke_dialogue();
|
||||
if (Levitation)
|
||||
if (HLevitation & TIMEOUT)
|
||||
levitation_dialogue();
|
||||
if (HPasses_walls & TIMEOUT)
|
||||
phaze_dialogue();
|
||||
if (u.mtimedone && !--u.mtimedone) {
|
||||
if (Unchanging)
|
||||
u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
|
||||
@@ -526,6 +553,15 @@ nh_timeout()
|
||||
case LEVITATION:
|
||||
(void) float_down(I_SPECIAL | TIMEOUT, 0L);
|
||||
break;
|
||||
case PASSES_WALLS:
|
||||
if (!Passes_walls) {
|
||||
if (stuck_in_wall())
|
||||
You_feel("hemmed in again.");
|
||||
else
|
||||
pline("You're back to your %s self again.",
|
||||
!Upolyd ? "normal" : "unusual");
|
||||
}
|
||||
break;
|
||||
case STRANGLED:
|
||||
killer.format = KILLED_BY;
|
||||
Strcpy(killer.name,
|
||||
|
||||
Reference in New Issue
Block a user