Try to exercise ^A more when running the fuzzer. Also ^P, although
that is tty-centric.
I couldn't notice any difference in behavior so this doesn't seem to
be very useful.
If there is at least one genocided or extinct type of monster, final
disclosure asks if you want to see the list. It was using "ynaq"
for the choice of answer, where 'a' is used to prompt for sort order
rather than "all". Change it to only include the 'a' choice if there
are more than 1 of either category or 1 each of both categories (since
they're listed interspersed with each other, sorting is relevant for
the one-of-each situation).
It seems surpristing that no one has noticed this since the code that
is responsible has been present for six months. Inventory list at
end of game included bogus "? - (list likely candidates)".
Iterating over a large set of locations in a selection caused a memory leak.
Lua couldn't do garbage collection in the middle of the iterator function,
so it eventually ran out of space, and just quietly dropped stuff.
A comment in rm.h claimed that secret doors can't be trapped so I
used door flag D_TRAPPED to handle secret doors that should be shown
as trees instead of walls. But the comment was inaccurate and secret
doors can be trapped.
Such trapped secret doors in ordinary rooms ended up being shown as
trees too. Switch from using D_ARBOREAL in levl[][].doormask to new
levl[][].arboreal_sdoor which overloads levl[][].candig.
Also, wizard mode wishing for secret doors needed updating to allow
creating trapped ones (at wall or door locations).
This ought to update EDITLEVEL but I think existing save files can
live with secret door display issues. Untrapped secret doors in
garden-fill rooms will end up becoming trapped.
Replaces the fix for github issue #1309
Commit 050846ada9 checked for
re_alloc(NULL,n) and returned alloc(n) for that case. After testing
MONITOR_HEAP and heaputil, the original code worked as intended.
I'm not sure what was going wrong yesterday.
Switch back to the previous code. I could have used 'git revert'
but haven't.
I hope this is temporary. nhrealloc() intends to deal with
realloc(NULL, size) but something isn't working correctly. The
code in alloc.c looks right so the problem might be in heaputil.
However, the code there looks ok too.
Not sure why my earlier attempt was unsuccessful. This one isn't as
comprehensive but is simpler and better yet, works as intended.
When saving a level or exiting the program, objects can be deleted
directly rather than having to pass though the objs_deleted list.
If the yn_function() delivers its impossible about returning a result
that isn't considered to be viable, put the prompt into paniclog.
The updated comment contains my guess about what it going wrong, and
I'm fairly sure it is correct. But I don't know how to fix it unless
we change ^A to just repeat the last command without attempting to
also repeat whatever followed.
At the moment, users will occasionally get strange outcome from ^A.
'heaputil' is producing a lot of complaints. This fixes one of them,
about freeing memory that was never allocated. In this case, it's
when removing an overview annotation for a level. The annotation
is using dupstr_n() and not being recorded due to dupstr_n() being
placed after MONITOR_HEAP undefines the macro that overrides alloc().
There's only one use of dupstr_n(), and its length checking isn't
needed there, so just switch to dupstr() and comment out the
implementation of dupstr_n(). I left the prototype in extern.h;
that's harmless.
If dupstr_n() needs to be resurrected, a second MONITOR_HEAP-aware
version should be implemented, with corresponding macro to choose
which one to use.
Warning about missing parantheses when mixing '+' and '?:'. It didn't
cause 'make' to quit but resulted in incorrect score-in-progress values
eing generated.
Provide a way to bypass a debugger when initiating fuzzing.
nethack -D --debug:fuzzer # run fuzzer in wizard mode
nethack --debug:fuzzer # run it in normal mode
nethack [-D] -@ --debug:fuzzer # skip role/race/&c selection
This is the first of several savefile-related changes to
follow later. This one is groundwork for those later changes.
Remove internal compression schemes (RLECOMP and ZEROCOMP)
and discard the savefile_info struct that was primarily used to
convey which internal compression schemes had been in use.
Relocate some struct definitions into appropriate header files
for use by code to come in later changes.
Remove the two struct size-related fields from version_info and
from the nmakedefs_s. Instead, include a series of bytes near the
beginning of the savefile, representing the size of each
struct or base data type that impacts the historical savefile
content. Those are referred to as the "critical bytes".
(Related note: the "you" struct required two bytes, low and high,
due to its size).
Compare those critical bytes in a savefile against the NetHack
build that is reading the savefile. This allows mismatch detection
early in the savefile-reading process, and a clean exit, rather than
proceeding to read nonsensical values from the file. Include some
feedback on what the first mismatch was when encountering
one.
For arrays stored in the savefile, use loop-logic in the core
to write/read the array elements one at a time, rather than in
a single blob. This will be required for changes to follow later.
(impacts artiexist[], artidisco[], svd.dungeons[], svl.level_info[],
svl.level.locations[][], msrooms[] field of mapseen, svb.bases[],
svb.disco[] objects[], svm.mvitals[], svs.spl_book[], svd.doors[],
go.oracle_loc[], utrack[], wgrowtime[])
This also adds data model to the long version information.
This invalidates existing save and bones files due to the changes in
the information at the start of the file.
When I reworked amnesia to not forget levels or objects, I removed
the forgetting from the mind flayer attacks. I intended to add
something to replace it, but forgot ...
Issue reported by elunna: when a room gets converted into a theme
room with fill type Garden, its walls are changed to trees but any
secret doors in those walls are still displayed as regular walls.
This adds a new D_ARBOREAL flag for secret doors, used to force them
to be displayed as a tree instead of a wall.
Fixes#1309
Grimtooth is now permanently poisoned, protects the wielder from
poison, and can be invoked to throw poison.
Permapoison code comes from xNetHack by copperwater <aosdict@gmail.com>.
A common pain point I encounter when working on themed rooms is making
specific rooms generate. The only ways to do this were mass commenting
out the rooms not being tested, or hacking in different room frequency
values (even more annoying when testing a fill, not a room, or testing
pure-function rooms/fills that have no frequency).
This change solves that problem by allowing a wizard-mode user to define
THEMERM or THEMERMFILL environment variables to make specific rooms or
fills generate.
The first part of this change is converting all themed rooms and fills
that were plain functions into tables, and converting their comment
names into actual names in those tables. The names are not intended to
be shown during gameplay, but instead serve as values that THEMERM or
THEMERMFILL can be matched to to generate those rooms. It's no longer
possible to have a function themeroom; this will raise an impossible.
As far as I'm concerned, this is a good change because it allows some
code simplification of themerooms_generate and makes it easier to add
difficulty or eligibility parameters to rooms.
The second part of this change is adding a new nh.debug_themerm function
to make the environment variable values accessible to themerms.lua. I
looked for an existing way to do this but didn't see one (nh.variable
is the closest but appears to be for variables that get saved).
The final part is inserting behavior into the actual themeroom
generation code that changes how they generate when either a room or a
fill is set. I don't think it's safe to generate every single room with
the requested type or fill - that might lead to cases where the stairs
or a magic portal cannot generate. So it creates ordinary rooms half of
the time, which still results in plenty of themed rooms on levels.
Another thing to note is that any themed room using filler_region will
still only pick a fill 30% of the time. If one specifies both a fill and
a room that uses filler_region, many of those rooms will appear without
a themed fill.
Added the silver mace to be the base weapon type of Demonbane. It is appropriate that an artifact weapon designed to slay Demons would be made of (or plated with) silver. This helps to offset the damage reduction when Demonbane was changed from a longsword to a mace and makes it more specialized against silver-haters.
Set the probability to 2, equal to that of a silver spear.
Increased the weight of the silver mace by 120% -- equal to the weight increase from a normal spear to a silver spear. (Assuming the weapon is silver plated rather than made entirely out of silver.)
Increased the base cost to 60, a similar increase as spear to silver spear, to be an even number between silver spear and silver saber.
Monsters will prefer silver maces over regular maces.
Otherwise, identical in function to a normal mace.
If user has changed the stone glyph to something other than a space
(or uses a tileset), Sokoban levels showed the unreachable stone outside
the map area. Prevent marking those areas as seen, so the stone
glyphs aren't shown.
Author: PatR <rankin@nethack.org>
Date: Mon Apr 7 13:58:28 2025 -0700
fix issue #1404 - re-tamed feral pet starves
Issue reported by k21971: changes in 'struct edog' initialization
resulted in re-taming of a feral former pet producing a tame monst
that immediately dies of starvation.
I didn't look at the earlier behavior, just forced hunger to be
initialized separately from other edog fields.
Fixes#1404
Fix up a few comments in the monster throwing code. And change a
couple 'if (!Blind)' checks to use 'if (canseemon(magr))' instead
of that the player won't be told about a returning aklys hitting an
invisible monster ("it") on the arm.
Issue reported by k21971: a gnome throwing a wielded aklys at the
hero was killed when failing to catch its return. Bookkeeping for
dead monsters got messed up, then a crash occurred.
This fixes things. Instead of a comment stating that the thrower
might be dead, kill it off.