This is the second of a series of changes related to save/restore.
No EDITLEVEL bump has been included, because although the code
is changed extensively by this, the content of the savefiles have
not been changed.
Push the use of the structlevel bwrite() and mread() function use
out of the core and into sfstruct.c. This is groundwork for upcoming
changes.
In the core, replace the bwrite() and mread() calls with the
use of type-specific savefile output (Sfo) and savefile
input (Sfi) macros. The macros are defined in a new header file
savefile.h, which also contains the prototypes for the sfo_* and
sfi_* functions that the macros ultimately expand to. The functions
themselves are in src/sfbase.c.
On C99, each Sfo or Sfi macro expansion refers directly to the
corresponding type-specific sfo_* or sfi_* function.
If C23 or later is is use, the majority (all but 3 types) of the
macros refer to a single _Generic output routine sfo(nhfp, dt, tag),
and a single _Generic input routine sfi(nhfp, dt, tag), which handles
the dispatch of the type-specific underlying functions. This was
somewhat experimental, but turned out to be practical because the
compiler would gripe if the type for a variable was not included in
the _Generic when passed as an argument, so it could be fixed.
This alters the savefile verication process by having a common set
return values for the related functions such as uptodate(),
check_version(), etc. The new return values return more information
about savefile incompatibilities, beyond failure/sucess. The
additional information will be useful for an upcoming addition.
The expanded return values are:
SF_UPTODATE (0) everything matched and looks good
SF_OUTDATED (1) savefile is outdated
SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch
SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86
SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86
SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64
SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64
SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64
SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64
SF_DM_MISMATCH (9) some other mismatch
The callers in the core have been adjusted to deal with the expanded
return values.
Other miscellaneous inclusions:
- go.oracle_loc -> svo.oracle_loc.
- add a bit (1UL << 30) to called SFCTOOL_BIT as groundwork
for changes to follow.
If water walking boots haven't been discovered yet and underwater
hero rises to the surface when putting a pair on, discover them.
(Sinking while removing such on water already discovers them.)
This helps avoid a potential chicken-and-egg scenario
with the system configuration file (sysconf).
If sysconf wasn't accessible at the expected location, it
caused an immediate exit, without relaying any helpful
information. That happened even when using:
'nethack --showpaths'
That's particularly unhelpful, because the --showpaths
output might have been useful towards understanding where
NetHack was looking for such things.
That left you without an easy recourse to identify where
the game is looking for the sysconf file. That might be
especially troublesome if you didn't build the game
yourself.
Take care of most of include/*.h. I punted on extern.h.
For both src/*.c and include/*.h, I used mismatched checks of
width > 79 to decide which files to look at and then width > 78
to decide which lines to maybe revise, so I didn't look at a bunch
of the files.
I don't plan to go back and do it right. Shortening lines that are
80 or wider to less than 80 is the significant part. Otherwise
emacs puts a backslash in column 80 and the rest of the line of text
on the next line of the screen, making things harder to read.
The g? structs had a mix of variables that were written to
the savefile, and those that were not.
For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.
This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.
Details:
gb.bases -> svb.bases
gb.bbubbles -> svb.bbubbles
gb.branches -> svb.branches
gc.context -> svc.context
gd.disco -> svd.disco
gd.dndest -> svd.dndest
gd.doors -> svd.doors
gd.doors_alloc -> svd.doors_alloc
gd.dungeon_topology -> svd.dungeon_topology
gd.dungeons -> svd.dungeons
ge.exclusion_zones -> sve.exclusion_zones
gh.hackpid -> svh.hackpid
gi.inv_pos -> svi.inv_pos
gk.killer -> svk.killer
gl.lastseentyp -> svl.lastseentyp
gl.level -> svl.level
gl.level_info -> svl.level_info
gm.mapseenchn -> svm.mapseenchn
gm.moves -> svm.moves
gm.mvitals -> svm.mvitals
gn.n_dgns -> svn.n_dgns
gn.n_regions -> svn.n_regions
gn.nroom -> svn.nroom
go.oracle_cnt -> svo.oracle_cnt
gp.pl_character -> svp.pl_character
gp.pl_fruit -> svp.pl_fruit
gp.plname -> svp.plname
gp.program_state -> svp.program_state
gq.quest_status -> svq.quest_status
gr.rooms -> svr.rooms
gs.sp_levchn -> svs.sp_levchn
gs.spl_book -> svs.spl_book
gt.timer_id -> svt.timer_id
gt.tune -> svt.tune
gu.updest -> svu.updest
gx.xmax -> svx.xmax
gx.xmin -> svx.xmin
gy.ymax -> svy.ymax
gy.ymin -> svy.ymin
Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
gf.ftrap, gl.light_base, gt.timer_base
This should prevent the unexplained situation in doclassdisco(the
back-tick command) from triggering a crash, but doesn't solve the
underlying problem. And the new impossible() will be escalated to
panic() by the fuzzer, so will still cause it to die.
Still no idea why the class input letter 'c' ended up with value
'I', leading to 'oclass' being MAXOCLASSES and going out of array
bounds during during doclassdisco()'s final loop.
When using #loot to put items into a shop-owned container on a shop's
floor, you are asked "Sell it? [ynaq] (n)" for each item, but the 'a'
and 'q' choices only worked as y or n for the current item. By the
next one, the preferred answer had been reset to default and ynaq was
asked again.
Set a flag in use_container() to have in_container() set the sell vs
don't sell state for the first item but not for any others. Reset
the state at the end of use_container() instead of after each item in
in_container().
This bug was present in 3.6.x, also in 3.4.3, and probably earlier.
Make object deletion work similarly to monster deletion:
it's marked for deletion (by setting the where-field to OBJ_DELETED
and moved to specific deleted-objects chain), but they're actually
freed at the beginning of turn.
This may need some more tweaking, especially in places that iterate
over object chains, but fuzzing did not find any obvious problems.
Fix a case of accessing freed memory: a monster breathed at hero,
destroying some items. The code stored the next item in the chain
(a cloak), but a ring of levitation was destroyed, causing hero to
plop down into lava, destroying the cloak. The item destruction
code then tried to access the destroyed cloak object.
Make the code check the object where-field - which will be different
if the object was marked for deletion. Also removed an extra loop
going through the whole object chain looking for the items to
destroy.
It was too early to call the windowport change_color() routine
while processing the config file. The windowport was not yet
fully operational.
Now the palette option processing will just place the rgb
value into the appropriate ga.altpalette[CLR_MAX] entry.
init_sound_disp_gamewindows(void) [allmain.c] calls
change_palette() [coloratt.c] and it will call the windowport
change_color() function for each ga.altpalette[] entry that
has been set.
Notes:
The rgb values stored in ga.altpalette[] have the NH_ALTPALETTE bit set
so that the rgb value of 0 can be stored and be distinguishable from
a "not set" entry.
The NH_ALTPALETTE bit is cleared from the rgb value in change_palette()
prior to calling the windowport change_color() function.
The syntax for palette is colorname/r-g-b.
For example: palette:black/12-12-12
colorname must be one of the NH_BASIC_COLOR names or a suitable
alias for one of those 16 entries.
Some of the windowport CHANGE_COLOR functions had the wrong parameters,
perhaps due to bitrot. Those have been corrected to match the prototype.
move the custom color data into its own field in the glyphmap
and disassociate it from the unicode/utf8 stuff.
move the glyphcache stuff during options processing and parsing
into new file glyphs.c and out of utf8map.c, and make it
general, and not part of ENHANCED_SYMBOLS.
Do the groundwork for allowing glyph color customizations to
work when any symset is loaded and not restrict it only to
the enhanced1 H_UTF8 symsets.
The customizations in effect are still affiliated with a particular
symset.
Also closes#1224, but the PR itself references a data structure
made obsolete by this commit. The curses comment from the PR was
added into the code.
The PR also made several suggestions, but only the first
one has been included in this commit (and no longer based on
the handler), that being:
"allow defining colors if other symbol handling modes are used
(possibly limited to the standard 16 colors)."
FredrIQ also wrote the following suggestions in PR#1224:
Something I was also contemplating, unrelated to implementation of this
support in curses, would be the ability for the following:
allow defining colors if other symbol handling modes are used (possibly limited to the standard 16 colors)
allow defining attributes (for example: glyph:G_pet_female_kitten:U+0066/red/underline)
allow specifying glyphs as wildcards for defining global color/attribute changes
Something I also want to see are keywords for "don't change the current defined data". If this
were to be added, you could for example do this:
OPTIONS=glyph:G_*_fox:U+0064/blue
OPTIONS=glyph:G_statue_*:basechar/gray/underline
for "make all foxes use a blue color, make all statues gray with underline" without needing
to specify the relevant character for every statue. This ("basechar", "basefg", etc)
should perhaps also be added for MENUCOLORS and statushilites, so that you can, for
example, underline all items being worn without needing to specify a bunch of
near-duplicate rules for combining BUC colors + underline worn items
as per #1064
The new change to reset discoveries and monster-stats when exiting
the tutorial used dynamic data which wouldn't be freed if player
used #quit and declined to resume the regular game.
It turns out that such a leak was already present for start-of-game
inventory that gets stashed away during the tutorial.
In both cases, it could happen at most once per game so wasn't a big
deal as far as memory leaks go.
DUMPLOG requests the DUMPLOG feature as it does now
DUMPLOG_CORE requests the internal buffering only (used for CRASHREPORT)
This allows CRASHREPORT to access recent messages without performing
any file I/O.
add CRASHREPORT for Windows
add ^P info to report (via DUMPLOG)
new options: crash_email, crash_name, crash_urlmax
new game command: #bugreport
new config option: CRASHREPORT_EXEC_NOSTDERR
new command line option: --bidshow
deleted helper scripts:
NetHackCrashReport.Javascript
nhcrashreport.lua
misc:
update CRASHREPORTURL (will need to be updated before release)
update bitrot in winchain
winchain for Windows
add missing synch_wait for NetHackW --showpaths
add PANICTRACE (and CRASHREPORT) in mdlib.c:build_opts
missing:
packaging (Windows needs the pdb file)
no testing with MSVC command line build
port status:
linux: working, but glibc's backtrace doesn't show static functions
Windows VS: working. pdb file is large - looking into options
MacOS: working
msdos: not supported
VMS: not supported
MSVC: planned, but not attempted
MSYS2: working, but libbacktrace not showing symbols (yet?)
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.
While hunting for a memory leak in object allocation--which I haven't
found yet--I discovered one in monster movement. iter_mons_safe()
allocates an array of (monst *) pointers for the monsters on the
current level, loops over that array to call a function for each
one, then frees the array. But if the game ends while that called
function is running, execution never returns to iter_mons_safe() so
it wasn't able to free the memory.
Since that can happen at most once per game, it wasn't a signifcant
leak. This fixes it anyway.
There was a second issue: make sure that iter_mons_safe() doesn't
call alloc(0) to make the temporary array for zero monsters when
there aren't any on the level. That might not be able to happen for
monster movement but the routine is written to be more general than
just movement. alloc(0) could confuse the MONITOR_HEAP code. In
C89/C90 I think malloc(0) is allowed to return NULL (don't recall
for sure; maybe that was just known pre-standard behavior for some
implementations). Null return would trigger a panic even without
MONITOR_HEAP. Don't know about C99 and later.
Try harder to prevent buffer overflow when formatting objects.
I don't have any test cases where overflow has been happening so
don't really know whether this works reliably. And it doesn't try
to check prefix construction by doname(). [Yet?]
- add nhl_pcall_handle() to wrap all nhl_pcall calls that didn't check
return value and either panic() or impossible()
- add --loglua (unix only) to dump Lua memory and steps info to livelog
- remove old logging
- set memory and step limits on all Lua VMs
Pull request from entrez: in the class filtering menu for multi-drop
and for loot in-or-out of a container, make choosing 'A' without any
other filter choices (such as all, specific class(es), cursed, unpaid,
just-picked-up, &c) become a no-op.
I started with the pull request and then undid much of it. It would
have been simpler to start from scratch. If you don't have option
paranoid_confirmation:AutoAll set, when choosing 'A' for all-without-
prompting as the only selection, operate as the PR has made things
work: effectively, 'A' by itself is ignored and the operation ends
with nothing happening.
However, if you do have paranoid_confirm:A set, then continue treating
'A' by itself as if 'A'+'a': everything. Since paranoid confirmation
is specified, that will be followed by a confirmation prompt.
This also adds a context-sensitive hint to the menu about how the 'A'
entry works, shown every time when 'cmdassist' is On or just once (per
session) when that is Off.
The documentation probably needs some updating.
Closes#1143
selection_getbounds() has a check and early return.
Initialization will ensure a known state if that early return
were ever taken.
This is an alternative approach to pr #1163.
When picking up multiple items (or looting multiple items) in one
operation, only show encumbrance for the first item that causes that
to change instead of complaining about non-zero encumbrance on every
item. The very first item is treated as if it caused a change, so
you get "you have a little trouble lifting <obj>" even if you were
already burdened, same as before.
Only lightly tested.
Sync with decl.c. dbridge.c never had anything to do with these
variables. They were part of decl.c before they got collected into
struct g, then split among struct ga to gz. (This only fixes up
the comment in gl; there may be more, possibly quite a few more.)
These might be better classified as /*dungeon.c*/ although they
weren't defined there.
<color>
off: map, menu items, menu headings, menu prompt/title all, everything should have color suppressed.
<curses guicolor>
on: map, menu items, menu headings, menu prompt/title can all feature color, as can
menu borders, menu-selector letters.
off: map, menu headings, menu prompt and menu items (menucolors on) can still feature color,
but all other non-map features such as menu borders, menu-selector
letters will not have color.
<menucolors>
on: menu items can have colors if they match one of the regex in config
file; menu headings, menu prompt can also be in color (based on menu_headings option).
off: menu items won't have colors, but menu headings, menu prompt still
will feature colors (based on menu_headings option); those are not impacted by turning
off menucolors.
cg.zeroobj was originally added (under its previous unprefixed name)
for providing a one-line way to zero out the fields of a struct obj.
struct obj tempobj;
tempobj = cg.zeroobj;
initfn(struct obj *otmp)
{
if (otmp)
*otmp = cg.zeroobj;
}
More recently, the address of cg.zeroobj began to be used as a return
flag to indicate some things, but the 'const struct obj zeroobj' wasn't
an ideal fit for the purpose and required a number of casts, including
casting away const.
Provide a better fitting variable (gi.invalid_obj) and eliminate a
number of casts.