- fix stack imbalances
- call panic() instead of nhl_error() if L==0 to prevent immediate crash
- drop unused argument prep in get_nh_lua_variables
- change nhl_pcall_handle to clean up stack after calling impossible()
- don't force full garbage collection runs
- don't collect garbage to do memory usage checking
- remove unnecessary stack resets
Having an item that allowed being in/on water/lava be stolen could
result in the hero teleporting. If the thief wasn't visible from
hero's new location, the message given was "It stole <whatever>."
Save the thief's name/description before removing the item and
potentially dropping hero into trouble and triggering teleport, then
use that in the eventual message.
Three months ago to prevent an "object lost" panic situation when
stealing an item that let hero survive water (several candidates)
would result in drowning, remove_worn_item() was changed to flag the
item being removed as in_use and emergency_disrobe() was changed to
avoid dropping in_use items while drowning. That seemed to work ok.
But for lava instead of water, in_use is a flag to destroy the item
(set in advance, before issuing messages that can give the player a
chance to trigger a hangup save). So instead of keeping the item
around for theft to finish, it was deallocating it. steal() would
format the freed object and then access some of its fields, leading
to havoc.
This adds a hack to allow one item already flagged as in_use to be
treated differently by lava_effects() from the ones it flags for
destruction. This also seems to work ok, but we may need to start
putting freed items on a deferred deallocation list similar to how
dead monsters are kept around for the rest of the current move.
The fix/hack has revealed two more bugs that this doesn't address.
An item being stolen is removed without any message, then if that
removal doesn't kill the hero a theft message is given. The message
sequencing is wrong. Flying hero who loses amulet of flying just
gets affected by lava; player is only told why after life saving.
The other issue is that life-saving from lava can teleport the hero
to where the thief can no longer be seen, yielding "It steals <item>"
even though "It" was visible when the theft started.
For tty, if ^C interrupt occurred while the terminal was displaying
VT line drawing characters, it wouldn't finish updating the map and
switch back to regular characters, so the "Really quit?" prompt was
illegible.
Rather than muck about with the signal handler, just add a fixup to
tty_putstr() since prompting ultimately uses putstr(WIN_MESSAGE).
Reproducing the situation isn't straightforward; I didn't even try.
Lembas wafers give more than normal nutrition for elves and less than
normal for orcs. Cram rations give more that nomral for dwarves. The
way that was implemented affected the weight of those items, at least
after they were partly eaten. Polymorphing to or from any of the
affected races resulted in inconsistent partly eaten food.
Change how the nutritional bonus or penalty is applied so that there
isn't any affect on item weight.
I haven't incremented EDITLEVEL, so any wafers/rations with incorrect
weight in existing save files will continue to have that wrong weight.
I suppose that it matters more for bones files but even they should be
ok living with this instead of being forced to be thrown away.
merge_choice() doesn't need the address of its list argument, just to
return Null if that list is Null. Could have been solved by having
its callers check for Null invent and skip the call if necessary but
this is simpler.
Finishes reverting commit 378648bd9c.
This reverts commit 378648bd9c.
The problem was triggered by marking the 'objlist' argument in
merge_choice() prototype with __attribute__((nonnull)) when it
shouldn't have been, then a followup which relied on that. The
'objlist' argument might be Null. Instead of passing its address to
force it to be non-Null, remove the attribute.
Add distinct potential steps into Makefile.top for putting
sysconf into place, instead of appending the steps for doing so
to the generic POSTINSTALL.
SYSCONFINSTALL is used for 'make install' and unconditionally
copies sys/unix/sysconf to the install directory.
SYSCONFENSURE is used for 'make update' and only copies
sys/unix/sysconf to the installation directory if it doesn't
already exist.
The initial trigger for revisiting this was because of new reports
that cp from (GNU coreutils) 9.4 is now issuing a warning during
NetHack builds. The warning pertains to deprecated use of the '-n'
switch with cp, which is used to only copy the file if the target
does not exist.
After this update, the shell is used to make that determination,
and if the file doesn't exist, cp is now invoked on Linux without
the '-n' switch.
For the macOS hints file, macOS.370, cp wasn't being used for sysconf
anyway, a utility script was being invoked and this doesn't change
that. macOS.370 was updated to remain in sync with linux.370 and
Makefile.top regarding the use of SYSCONFINSTALL and SYSCONFENSURE.
Reported directly to dev-team: vapor cloud dissipation didn't always
update vision properly.
Region removal affecting visibility needs to make two passes, the
first unblocking all no longer blocked spots, then the second deciding
whether spots are visible.
Attempting to do that in one pass was doing
| unblock <x1,y1>
| if cansee <x1,y1> whatever
| unblock <x2,y2>
| if cansee <x2,y2> whatever
and the cansee <x1,y1> test wasn't accurate if <x2,y2> blocked it and
hadn't been unblocked yet.
Testing with steam didn't seem to trigger the problem but with poison
vapor trail from green dragon breath did. The order of evaporation
mattered too; sometimes the single pass unblocking plus vision-testing
worked ok by coincidence.
Eliminate the 'goto' for human corpse added a day or two ago.
If a dead gnome is generated with a candle, light it if/when the spot
is dark. (Testing never managed to verify that this works as intended.)
mkcorpstat() never returns Null.
AFAICT, we only used the first char of the "command_line" string.
Just turn it into int to hold the key the main input loop parse() got.
Shouldn't have any functional difference.
Re-use the array allocated for iterating over all monsters during
monster movement much of the time. It was being allocated from
scratch for each round of monster movement, then freed after they
moved, then repeated the next round.
Update some potential weight issues. Eggs won't hatch when in
containers so they weren't affected but add some bulletproofing.
Corpse revival from inside containers was already ok too, so
effectively there's no change except for making container_weight() be
global instead of local to mkobj.c.
When a low-level trap is created with a dead pseudo-adventurer,
usually make a player monster when the human case gets picked.
They have default level and no inventory. They should probably be
given montraits that force low level but this doesn't do that.
The recent acurr() changes introduced a bug that caused Str less
than 25 to be limited to 18/07. 25 was treated correctly as a
special case but 18/01 through 18/100 and 19 through 24 were not.
The cap of 25 imposed on the other characteristics is the same as
encoded Str 18/07.
Restore its ability to reject a string longer than will fit within
size_t that was lost by moving away from strnlen(). Determine the
length inline rather than using strlen().
Move it from hacklib.c to alloc.c so that utility programs have easy
access, and remove the copy of it from dlb_main.c.
Fix a logic bug in str_start_is(). If a string was considered to
be too long, it exited the loop when n was 0 but also performed
post-decrement. So after the loop, n would be -1 and the 'if (n==0)'
test would fail. panic() would occur if the initial string matched
and happened to be LARGEST_INT-1 characters long.
doengrave was the largest function by far, so split it up into smaller
ones. Use a structure to hold the dozens of variables needed all over it.
Should have no difference in behaviour, but I haven't tested everything.
Previously reported via github pull request #1188 as an out of bounds
access to u.uhpinc[], followed by issue #1189 when it was closed, the
backtrace accompanying new assertion failure provided more information
that led to figuring out the problem.
Only mattered for the debug fuzzer; wouldn't happen in regular play.
When the hero dies during fuzzing, the fuzzer sometimes restores lost
levels via blessed potion of restore ability. If that happened to a
hero who died by being life-drained while at level 1 then losexp()'s
assumption that life-saved hero was still level 1 got violated. If
levels had been lost all the way down from a peak of 30, restoration
to u.ulevel==30 resulted in invalid array indexing into u.uhpinc[],
then failure of 'assert(u.ulevel >= 0 && u.ulevel < MAXULEV)' which
was added to avoid that.
Pull request #1188 and issue #1189 are already closed, but they hadn't
actually been solved yet.
Fixes#1188Fixes#1189
There were few places where the object weight was not updated:
- container when the contents were broken by impact
- starting to eat but getting stopped by rotten food
- using lua, container when putting an object inside it
- when a single egg of a larger stack hatched
Juiblex could expel the hero over water, they'd get relocated to
a safe location, but Juiblex was still thinking they were at
the location it expelled them.