fix #K3436 - crash during restore

triggered by Grayswandir's hallucination resistance.  If the game
is saved while hero is hallucinating but having that be suppressed
by wielding Grayswandir, is riding, and the steed is on an object,
then during restore the hero's location will be updated because
of the presence of the object but the attempt to display the hero
there is made before u.usteed has been restored and fails.
This commit is contained in:
PatR
2021-09-05 15:44:00 -07:00
parent e813cf5b05
commit 9f230c3cd4
4 changed files with 44 additions and 8 deletions

View File

@@ -599,6 +599,12 @@ don't include time spent suspended in background (^Z) or in shell escape (!)
if a monster is starting to turn into green slime, eat the corpse, tin, or
egg of any creature that might polymorph into a fiery monster to cure
the slime, not just of one of a chameleon
yet another fix for display problems during restore: if game is saved while
hero is hallucinating but that's suppressed because of wielding
Grayswandir, hero is riding, and the steed is on or over an object,
restore will try to update hero's spot when making sure objects aren't
being obfuscated by hallucination, but when displaying the hero there
instead it would access steed pointer before that has been set up
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository

View File

@@ -349,6 +349,7 @@ extern void map_invisible(xchar, xchar);
extern boolean unmap_invisible(int, int);
extern void unmap_object(int, int);
extern void map_location(int, int, int);
extern boolean suppress_map_output(void);
extern void feel_newsym(xchar, xchar);
extern void feel_location(xchar, xchar);
extern void newsym(int, int);

View File

@@ -57,6 +57,9 @@ do_statusline1(void)
register char *nb;
register int i, j;
if (suppress_map_output())
return strcpy(newbot1, "");
Strcpy(newbot1, g.plname);
if ('a' <= newbot1[0] && newbot1[0] <= 'z')
newbot1[0] += 'A' - 'a';
@@ -112,6 +115,9 @@ do_statusline2(void)
int hp, hpmax, cap;
long money;
if (suppress_map_output())
return strcpy(newbot2, "");
/*
* Various min(x,9999)'s are to avoid having excessive values
* violate the field width assumptions in botl.h and should not
@@ -241,9 +247,10 @@ do_statusline2(void)
void
bot(void)
{
/* dosave() flags completion by setting u.uhp to -1 */
/* dosave() flags completion by setting u.uhp to -1; supprss_map_output()
covers program_state.restoring and is used for status as well as map */
if (u.uhp != -1 && g.youmonst.data && iflags.status_updates
&& !g.program_state.saving && !g.program_state.restoring) {
&& !g.program_state.saving && !suppress_map_output()) {
if (VIA_WINDOWPORT()) {
bot_via_windowport();
} else {
@@ -256,11 +263,18 @@ bot(void)
g.context.botl = g.context.botlx = iflags.time_botl = FALSE;
}
/* special purpose status update: move counter ('time' status) only */
void
timebot(void)
{
/* we're called when iflags.time_botl is set and general g.context.botl
is clear; iflags.time_botl gets set whenever g.moves changes value
so there's no benefit in tracking previous value to decide whether
to skip update; suppress_map_output() handles program_state.restoring
and program_state.done_hup (tty hangup => no further output at all)
and we use it for maybe skipping status as well as for the map */
if (flags.time && iflags.status_updates
&& !g.program_state.saving && !g.program_state.restoring) {
&& !g.program_state.saving && !suppress_map_output()) {
if (VIA_WINDOWPORT()) {
stat_update_time();
} else {

View File

@@ -529,6 +529,20 @@ warning_of(struct monst *mon)
return wl;
}
/* map or status window might not be ready for output during level creation
or game restoration (something like u.usteed which affects display of
the hero and also a status condition might not be set up yet) */
boolean
suppress_map_output(void)
{
if (g.in_mklev || g.program_state.restoring)
return TRUE;
#ifdef HANGUPHANDLING
if (g.program_state.done_hup)
return TRUE;
#endif
return FALSE;
}
/*
* feel_newsym()
@@ -562,6 +576,10 @@ feel_location(xchar x, xchar y)
struct obj *boulder;
register struct monst *mon;
/* replicate safeguards used by newsym(); might not be required here */
if (suppress_map_output())
return;
if (!isok(x, y))
return;
lev = &(levl[x][y]);
@@ -721,12 +739,9 @@ newsym(register int x, register int y)
boolean worm_tail;
register struct rm *lev = &(levl[x][y]);
if (g.in_mklev)
/* don't try to produce map output when level is in a state of flux */
if (suppress_map_output())
return;
#ifdef HANGUPHANDLING
if (g.program_state.done_hup)
return;
#endif
/* only permit updating the hero when swallowed */
if (u.uswallow) {