Lock context wasn't being cleared if it was for a container and that
container got destroyed. Case discovered was forcelock() ->
breakchestlock() -> delobj() (sometimes the container is destroyed
rather than just breaking its lock) followed by #wizmakemap (replace
current level) and maybe_reset_pick() trying to check whether
xlock.box was being carried. But being interrupted, destroying the
container or dropping it down a hole to ship it to another level, then
attempting to resume picking the lock would also find a stale pointer.
new domove_core() assessment results
potentially smudge engravings
Proceed to wipe engraving after domove_core() now, but only under
all of the following conditions:
- you can reach the floor
- preceding domove_core() move attempt was marked as
having succeeded in domove_core()
- there is actually an engraving there to impact at
your original spot, or your new spot, or both
The check I added to make sure that a monster was at the hero's
coordinates before deciding to move one or the other would have been
confused by a long worm's tail. Check that they're at that spot but
not by comparing monst.<mx,my> coordinates with <ux,uy>.
Also, don't have wiz_makemap() assume that each level of the Wizard's
Tower has the same boundary coordinates. Keep track of whether hero
is inside that tower before discarding the old level.
Both u_on_rndspot() and losedogs() might result in having a monster
and the hero be at the same location. Have wiz_makemap() use the
same fixup for that as goto_level().
The need for resetting lock picking when swapping in a new level made
me wonder whether other things should be reset too, and there were a
bunch: digging, travel destination, polearm target, being in water,
being swallowed or held, hiding. Hero placement was ignoring arrival
region. Also, it turned out to be pretty easy to fix the FIXME about
steed.
Fixes#172
Casting teleport-away via ^T used different requirements for energy,
strength, and hunger than casting it via 'Z'. The strength and hunger
requirements were more stringent, the energy one more lenient. When
it rejected a cast attempt due to any of those, it used up the move,
but 'Z' didn't.
When testing my fix, I wanted an easier way than a debugger to control
how ^T interacts with wizard mode, so finally got around to a first
cut at being able to invoke it via wizard mode but not override those
energy/strength/hunger requirements. It uses the 'm' prefix to ask
for a menu. 'm^T' gives four options about how to teleport. (There
are other permutations which aren't handled.)
Also noticed while testing: ^T wouldn't attempt to cast teleport-away
if you didn't know the corresponding spellbook. 'Z' will attempt that
because it is possible to forget a book and still know its spell.
From Jessie's old static analysis report. 'prezero' was used in 3.4.3
when processing a count for 'multi', but count handling is now done in
a separate routine and 'prezero' in parse() never changes value, so
get rid of it.
'sz' is the size of the buffer; 'if (count < sz) buf[count++] = c;'
can fill the entire buffer, leaving count==sz, so buf[count] = '\0';
would be out of bounds.
Formatting was way off. Indentation these days should be multiples
of 4 spaces, never tabs.
When a hero dies due to turning into green slime, actually polymorph
him into a green slime monster before killing him off. That way he'll
show as a green 'P' on the map instead of white '@' during final
disclosure. Also, armor that gets destroyed by polymorphing into that
form will be absent from resulting bones file.
When deciding whether to discard interrupted lock/unlock context while
changing levels, maybe_reset_pick() checks whether xlock.box is being
carried. But it was doing so after the old level had been saved and
memory for non-carried container there had been freed.
That led to a couple of other issues. context.travelcc was using -1
for 'no cached value', but the fields of travelcc have type 'xchar' and
shouldn't be given negative values. 0 should be fine for 'no cache'.
Failed partial restore which occurred after old game's context had been
loaded would begin a new game with old game's stale context. Restoring
goes out of its way to avoid that for 'flags' but didn't for 'context'.
Change the command list to always include #shell and #suspend so that
a user's preferred key bindings can span platforms without worrying
about whether those exist or not. They're still effectively no-ops
when compiled out.
'#?' suppresses them from the list of displayed commands. Interface-
specific extended command handling may want to check new extcmd.flag
value CMD_NOT_AVAILABLE to do the same, but failing to do so shouldn't
pose a problem. They behave sanely if executed when not supported.
My sysconf allows shell escape, and the fuzzer seems fond of that.
Suppress '!' and also '^Z', although I didn't notice it execute the
latter. Without this hack, the sequence '!', sub-shell exit, '&'
causes nethack to be killed via SIGTTOU while fiddling with terminal
settings for introff().