During a synchronous save operation initiated by the player (or
other trigger for dosave0()), the u.usteed_mid and u.ustuck_mid
values get set by savemonch(), and the monst pointers that
u.ustuck and u.usteed point to are no longer valid, but not
cleared.
The checkpoint operation, which also needs to ensure that
u.ustuck_mid and u.usteed_mid are set, must set them during
the checkpoint, which is okay because the u.usteed and
u.ustuck pointers _are_ valid during a checkpoint operation.
So, we need to distinguish between a save game sequence,
and a checkpoint sequence when writing out the u struct.
When corpses haven't stacked, and there is no player-discernable
reason why, provide some additional information in some cases,
but only when it is required.
Gender variance is the supported case in this commit.
Related to GitHub issue #1607.
This commit doesn't change the underlying mechanics to allow
the corpses to stack, but it does help the player understand
why that's the case in this instance.
In file included from ../include/hack.h:34,
from sp_lev.c:14:
In function ‘create_monster’,
inlined from ‘lspo_monster’ at sp_lev.c:3386:5:
../include/rm.h:528:32: warning: array subscript -1 is below array bounds of ‘struct monst *[80][21]’ [-Warray-bounds=]
528 | if (!svl.level.monsters[x][y]) \
| ~~~~~~~~~~~~~~~~~~^~~
sp_lev.c:2045:25: note: in expansion of macro ‘remove_monster’
2045 | remove_monster(x, y);
| ^~~~~~~~~~~~~~
../include/rm.h: In function ‘lspo_monster’:
../include/rm.h:476:19: note: while referencing ‘monsters’
476 | struct monst *monsters[COLNO][ROWNO];
| ^~~~~~~~
In function ‘create_monster’,
inlined from ‘lspo_monster’ at sp_lev.c:3386:5:
../include/rm.h:530:27: warning: array subscript -1 is below array bounds of ‘struct monst *[80][21]’ [-Warray-bounds=]
530 | svl.level.monsters[x][y] = (struct monst *) 0; \
| ~~~~~~~~~~~~~~~~~~^~~
sp_lev.c:2045:25: note: in expansion of macro ‘remove_monster’
2045 | remove_monster(x, y);
| ^~~~~~~~~~~~~~
../include/rm.h: In function ‘lspo_monster’:
../include/rm.h:476:19: note: while referencing ‘monsters’
476 | struct monst *monsters[COLNO][ROWNO];
| ^~~~~~~~
see_monsters() was producing spurious vault guard at 0,0
messages
Reproduce issue by:
1. Entering vault via teleport.
2. Wait for guard to enter.
3. Drop gold (if necessary) and follow guard.
4. Right after the guard disappears, but before
the corridor does, the following can lead to
the messages:
a) control-R to refresh the display.
or
b) save the game and restore.
In both cases, see_monsters() will get called and lead
to the spurious messages for the vault guard that is
parked.
Also, add a macro PARKEDMONSTER(mon) instead of checking the
the isgd bit and the value of mon->mx being zero in multiple
places
Also, adds MON_PARKED bit to mstate.
Currently the PARKEDMONSTER(mon) macro mentioned above,
does not use the new bit.
u.ustuck and u.usteed are handled differently in 5.0.0 than
in previous releases, and an unexpected halt to NetHack could
result in an inability to use recover to get the game back.
If the hero was engulfed, u.uswallow, could get saved to the
checkpoint file with a value of 1 without a corresponding
u.ustuck_mid value representing the m_id of the engulfing monster.
Recover had no information to use to restore the u.ustuck pointer
when loading the monsters on the level.
With u.uswallow set to 1, the game would proceed to enter if-blocks
based on that, and then crash/fault when it attempted to dereference
u.ustuck, during the recover attempt.
This updates the values of u.ustuck_mid immediately before saving
struct you during a checkpoint, so that the resulting file had
u.uswallow and u.ustuck_mid values that were in concert.
It does the same for u.usteed and u.usteed_mid.
This also now adds a save_currentstate() checkpoint call when
the swallowed/unswallowed status changes, that is whenever set_ustuck()
is called.
track which locations had updates that could be seen in tmp_at()
to aid in cleanup.
ensure that nothing is shown for places that the hero can't see
(internal buglist entry 3161).
adjust several aklys messages to better reflect the tethering
aspect.
A very small number of boolean options had drifted, such that
their initval setting did not match its opt_in or opt_out value.
Correct that, by ensuring opt_in or opt_out reflects what was
actually happening.
The only option whose initial value is changing as a result
of this is timed_delay. It was listed as an opt_out option, but
was not being initialized as such. Now it is. This makes the
Mac X11 throwing animations work correctly with the earlier
timed_delay option adjustments for X11. There was nothing
displaying on Mac X11 after those earlier changes, unless
the timed_delay option was turned on.
Going forward, for boolean options, setting opt_in or opt_out
is all that is required, as that was the original intention
of those fields. It will take precedence if they fall out of
sync again.
This is better placement for making the original
engraving vanish when told that it vanishes;
helps to ensure that it isn't showing for any
next steps.
also, a warning bit
During a restore from a savefiles is not the only
time that levels are processed by getlev() in NetHack.
They are read back in as the hero moves up and down
between levels and dungeons.
The previous fix checked for program_state.beyond_savefile_load,
but once set, that remains static through level changes.
It would be better to check the status of the level
being read, because those operations do placements as well.
Add the following:
struct levelstatus level_status;
level_status.making - in the midst of makelevel processing
level_status.loading - in the midst of loading a level via getlev()
level_status.ready - the level is fully ready
(all 3 of the above status settings are mutually exclusive)
level_status.shkready - the level processing is far enough
along to allow shop keeper tests and actions
This also relocates the find_lev_obj() call in getlev() down several
lines, so that it falls after any set_residency() calls, so that it
has a better chance of carrying out what it was intending to do with
the shop_keeper() checks made by its subfunctions.