The role, race, gender, and alignment string values are 3 letters
preceded by a dash. I was looking at "name-race-role-gend-algn"
and mistakenly treated them as 4 letters preceded by a dash.
Fixing that changes PL_NSIZ_PLUS and there is one item of that size
written into save files, so the fix invalidates existing save files.
Instead of a menu listing
a - hero1
b - hero2
n - New game
q - Quit
show
a - hero1-role1-race1-gend1-algn1
b - hero2-role2-race2-gend2-algn2
n - New game
q - Quit
or
a - - hero1-role1-race1-gend1-algn1
b - X hero2-role2-race2-gend2-algn2
c - D wizard-role3-race3-gend3-algn3
n - New game
q - Quit
when any game in the list wasn't saved during normal play. (Those
are sorted by character name; the playmode is just coincidence.)
The dash for 'normal' doesn't look great but -/X/D are codes used in
entries written to paniclog. The whole playmode prefix doesn't look
particularly good but I suspect that most players relying on restore
via menu won't see it.
It should work when the character name has dashes in it but that
hasn't been properly tested.
The gender and alignment suffices reflect their value at the time of
save rather than at the start of the game. That might be considered
a bug but it was easiest.
Increments EDITLEVEL; existing save and bones files are invalidated.
The 'spot_monster' option (extra feedback for "accessibility") was
causing messages to be delivered during save, and they could end up
triggering unwanted "--More--" interruptions for tty.
I couldn't reproduce it but it was easy to see where it would happen.
This shuts such messages off in two ways. Only one should be needed
but I'm not sure which one it ought to be.
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
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.
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.
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.
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.
Some functions are passed an obj or monst chain,
and the callers typically don't check them
against 0, so mark them explicitly as NO_NONNULLS
(NO_NONNULLS expands to nothing, but it flags that
some null arg analysis has been done)
The tracks left by hero were cleared when player saved and
restored the game, or changed levels. Now the tracks are
saved in the dungeon level, so changing levels keeps the tracks
left by hero in that level.
Also increased the length of tracks from 50 to 100, and
simplify the tracking function.
Thing not done: fade out old tracks when returning to a level.
Breaks saves and bones.
Adds a new lua command
des.exclusion({ type = "teleport", region = { x1,y1, x2,y2 } });
which allows defining "exclusion zones" in the level, areas where
random teleports (or falling into the level) will never place the hero.
Does not prevent targeted teleportation into the area.
Breaks saves and bones.
When returning to play from within the tutorial, remove the level files
similar to how they're discarded for the rest of the dungeon when going
into the endgame. It turned out to be a bit messier than anticipated.
The dungeon.c bit is sufficient for #overview, which now hides regular
level 1 while in the tutorial and hides all tutorial levels once exited.
Those will still appear in end-of-game disclosure.
Reported five months ago, a save was performed while a mounted hero
was engulfed. Restore issued a warning about the engulfer being
placed on top of the steed (who shouldn't have been on the map).
The report arrived at about the same time as engulfing a riding
hero was changed to force a dismount instead of engulfing both hero
and steed so nothing further was done about it. This changes
restore to not put a steed on the map and then take it off again.
It also attempts to simplify usteed and ustuck handling during save
and restore.
Testing so far indicates that things are still working correctly.
Keep makeplural(body_part(FINGER)) crossed.
Existing save and bones files are invalidated.
A number of C compiler suites have a math.h library that includes a yn()
function name that conflicts with NetHack's yn() macro:
"The y0(), y1(), and yn() functions are Bessel functions of the second kind,
for orders 0, 1, and n, respectively. The argument x must be positive. The
argument n should be greater than or equal to zero. If n is less than zero,
there will be a negative exponent in the result."
At one point, isaac64.h included math.h, although that has since been removed.
Some libraries used in NetHack (Qt for one) do include math.h and that required
build work-arounds to avoid the conflict.
Rename the NetHack macro from yn() to y_n() and avoid the math.h conflict
altogether, eliminating the need for that particular work-around.
Keep track of how a role|race|gender|alignment option got its value
so that role:!Tourist in .nethackrc and role:!Priest in NETHACKOPTIONS
yield 'role:!Priest' rather than merging into 'role:!Priest !Tourist'.
It also doesn't write the value into new config file for #saveoptions
if that value comes from environment or command line (not applicable
since the command line arguments for role,&c don't go through options
handling). Also, the old config file value takes precedence over
the current game's value file so that 'role:random' doesn't become
'role:Healer' or such in a new config after the random value gets
picked for play.
This only tracks the role, race, gender, and alignment options but the
concept could be extended to all options. The data would need to be
saved and restored if values set interactively need to be retained in
restore sessions (doesn't apply to role,&c since those don't change
during play).
The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.
It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.
Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.
To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.
A global variable named 'amulets', would be found in ga.
ga.amulets
^ ^
A global varable named 'move', would be found in gm.
gm.moves
^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
gv.val_for_n_or_more
^ ^
A global variable named 'youmonst' would be found in gy.
gy.youmonst
^ ^
Trap doors saved their destinations as an absolute level, rather than a
relative one, so if you loaded bones from a special level their
destinations would reflect the dungeon layout from the bones player's
game. For example, die on the Oracle level, on dlvl5, with a trap door
that goes to dlvl6. Another player gets those bones on their Oracle
level, which is dlvl8... the trap door would still go to dlvl6. Pretty
amazing trap door -- something you might see in a funhouse!
Include relative rather than absolute destinations in save and bones
files, much like stairs do, to avoid this problem.
I bumped EDITLEVEL because although this won't break save files in an
obvious way, it will interpret the (absolute) destinations in existing
save and bones files as relative, leading to some crazy long falls. :)
The pull request included some changes that were neither accidental nor
unintentional, so only a subset of the changes from pull request #869
submitted by klorpa were manually applied.
behaviour -> behavior
speach -> speech
knowlege -> knowledge
incrments -> increments
stethscope -> stethoscope
staiway -> stairway
arifact -> artifact
extracing -> extracting
The uses of "iff" were left alone.
Close#869
Make sure u.uswallow is cleared when u.ustuck gets set to Null so
that they won't be out of sync with each other. Having u.uswallow
be non-zero does imply that u.ustuck is non-Null.
Running #panic while swallowed didn't produce any anomalies for me,
either before or after this change.
Add a #saveoptions extended command, to allow saving configuration
settings from within the game. This is still highly experimental,
and gives plenty of warnings before asking to overwrite the file.
Lack of option saving is one of the biggest complaints new players
have, so this should help with it. More experienced players with
highly customized config file should not use this feature, as it
completely rewrites the file, removing all comments and non-config
lines.
Stair dlevels weren't being restored with the correct values when
recovered after the game crashed, apparently because they weren't being
reset back to their 'absolute' level from a 'relative' level. I'm not
totally sure of why this affected only recovered games (maybe that's the
only time when the 'relative' stair values are used?) but this fix seems
to work.
Fixes#812
One of the drivers of this change was that screen coordinates require a
type that can hold values greater than 127. Parameters to the window
port routines require a large type in order to be able to have values
a fair bit larger than COLNO and ROWNO passed to them, particularly for
their use to the right of the map window.
This splits the uses of xchar into 3 different situations, and adjusts
their type and size:
xchar
|
-----------------------
| | |
coordxy xint16 xint8
coordxy: Actual x or y coordinates for various things (moved to 16-bits).
xint16: Same data size as coordxy, but for non-coordinate use (16-bits).
xint8: There are only a few use cases initially, where it was very
plain to see that the variable could remain as 8-bits, rather
than be bumped to 16-bits. There are probably more such cases
that could be changed after additional review.
Note: This first changed all xchar variables to coordxy. Some were
reviewed and got changed to xint16 or xint8 when it became apparent that
their usage was not for coordinates.
This increments EDITLEVEL in patchlevel.h
Reported by entrez: fix memory being accessed after having been
freed by trying to keep ball&chain data up to date when they're
processed by the save code. This fix is a little more elaborate
than this suggested one. I'm crossing my fingers on this one....
savelev() gets run to clean up memory even if the player quits before
level 1 is created, and a change made yesterday panicked if it couldn't
figure out what level the hero is on. Caught by entrez, again....
If not actually writing a level's file, don't panic if both u.uz and
g.uz_save are 0. Having one of those be non-zero is only essential
when the level being processed is the Plane of Water or Plane of Air.
The air bubbles on the Plane of Water and the clouds on the Plane of
Air were being saved and restored as part of the current level's state
(which is the 'u' struct and invent and such) rather than with the
current level itself. That was ok for normal play, but for wizard
mode's ^V allowing you to return to a previously visited endgame level
after moving to a different one it meant a new set of bubbles for
Water and new set of clouds for Air. Even that was ok since it only
applied to wizard mode, but using #wizmakemap to recreate Water or Air
while you were on it added a new set of bubbles or clouds to the
existing ones. If repeated, eventually there wouldn't be much water
or air left.
Instead of just adding a hack to #wizmakemap, change save/restore to
keep the bubbles/clouds with the level rather than with the state.
That wasn't trivial and now I know why the old odd arrangement was
chosen. Saving hides u.uz by zeroing it out for levels that the hero
isn't on and it is zero during restore so simple checks for whether a
given level is water or air won't work.
This also adds another non-file/non-debugpline() use of DEBUGFILES:
DEBUGFILES=seethru nethack -D
will make water and clouds be transparent instead of opaque. It also
makes fumaroles and other light-blocking gas clouds be transparent
which wasn't really intended, but avoiding it would be extra work that
doesn't accomplish much.
Increments EDITLEVEL for the third time this week....
Handle thrown or kicked object that's in transit for hangup save and
panic save in addition to normal end of game. Affects ball and chain
placement too, if they've been temporarily taken off the map.
MONITOR_HEAP+heaputil pointed out some unreleased memory. The livelog
stuff wasn't being freed. Not surpringly the data used for collecting
and formatting build-options that just got changed from strdup() to
dupstr() wasn't being freed. And a couple of date/version bits.
Log game events, such as entering a new dungeon level, breaking
a conduct, or killing a unique monster, in a new "Major events"
chronicle. The entries record the turn when the event happened.
The log can be viewed with #chronicle -command, and the entries
also show up in the end-of-game dump, if that is available.
This feature is on by default, but can be disabled by
defining NO_CHRONICLE compile-time option.
This also contains "live logging", writing the events as they
happen into a single livelog-file. This is mostly useful for
public servers. The livelog is off by default, and must be
compiled in with LIVELOG, and then turned on in sysconf.
Mostly this a version of livelogging from the Hardfought server,
with some changes.