When asking for an inventory subset for one of the meta-classes that
can generate output which spans object classes (so B,U,C,X, and P),
insert a title at the start of the resulting inventory list. (Iu and
Ix produce alternate output that already includes a title.)
Also, stop handling '$' differently for menustyles traditional and
combination from full and partial. 'I$' was running the '$' command
for the first two styles but just showing the inventory entry for
gold for the last two. Change to the latter for all styles.
My fixes to the travel stuck oscillation did not fix all of them,
and I've even seen a 3-step loop - which my fixes cannot detect.
I guess there could be arbitrary-sized loops too.
To definitely fix this, keep track of all the map locations travel
has moved the hero through, and if it tries to go on a location already
used, stop travel and give the unsure -message.
Lay groundwork for generating a log event when finding an artifact
on the floor or carried by a monster. This part should not produce
any change in behavior.
Move g.artidisco[] and g.artiexist[] out of the instance_globals
struct back to local within artifact.c. They are both initialized
at the start of a game (and only used in that file) so don't need
to be part of any bulk reinitialization if restart-instead-of-exit
ever gets implemented.
Convert artiexist[] from an array of booleans to an array of structs
containing a pair of bitfields. artiexist[].exists is a direct
replacement for the boolean; artiexist[].found is new but not put to
any significant use yet. If will be used to suppress the future
found-an-artifact event for cases where a more specific event (like
crowning or divine gift as #offer reward) is already produced.
Remove g.via_naming altogether and add an extra argument to oname()
calls to replace it.
Add an extra argument to artifact_exists() calls.
Add a type to force g.{command_count,last_command_count,multi} to have the
same type (because cmd.c: g.multi = g.command_count;) and some resulting
cleanup.
I've implemented 'nethack -nethackrc=filename' as an alternative to
'NETHACKOPTIONS='@filename' nethack' but at the moment it doesn't
work because the command line parsing comes after the run-time config
file has already been processed. But this part should work, or maybe
have problems spotted and fixed if it doesn't. The RC file part of
initoptions_finish() has been rewritten so that it won't need extra
replication of
| set_error_handling()
| process_file()
| reset_error_handling()
| if (NETHACKOPTIONS) {
| set_error_handling()
| process_options()
| reset_error_handling()
| }
I've tried to test all the combinations mentioned in the comment but
am not sure that I covered everything, particulary for repeating
earlier tests after making incremental changes.
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.
Trying to use #reqmenu/#rush/#run/#fight prefixes by their extended
command names didn't work because rhack()'s post-processing was stuck
dealing with the entry for the '#' key after using doextcmd() to run
any command. Use a static variable (actually a global one since I put
it into struct g) to notify rhack() of the command that ultimately got
executed.
... you will also get a message when a seen stinking cloud
or the one surrounding the hero dissipates.
Original feature comes from Fourk, but this version (with some
minor changes) comes from xnethack by copperwater <aosdict@gmail.com>
Changes most of the special keys used in the main input loop
into extended commands:
- movement keys are now bound to extended commands, eg.
#movewest and so on.
- m-prefix is now #reqmenu extended command, still bound to
the 'm' key.
- run, rush, and fight are now extended commands, still bound
to the same keys as previously.
- nopickup and runnopickup keys are removed.
Nopickup was using 'm' key, the same as the m-prefix, so
allow #reqmenu to modify movement commands to disable pickup.
- multiple prefix commands are allowed. This lets user to
use #reqmenu, followed by #run, followed by movement to simulate
runnopickup behaviour. (If necessary, adding runnopickup back
as an extended command would be easy)
'moves' is actually turns and there hasn't been any straightforward
way to track actual hero moves. Add hero_seq for that. It isn't a
counter but is distinct each time the hero makes a move. I wanted
it for curses ^P support but so far use it for checking stethoscope
usage and for shopkeeper behavior when items in a shop are broken by
the hero.
Increment EDITLEVEL due to change in save file contents.
Give a better message than "Unknown config statement" if SOUNDDIR or
SOUND directives are found in the configuration file being loaded by
an executable built without support for USER_SOUNDS. And just give
it for the first occurrence since when present there will likely be
multiple SOUND instances.
It doesn't attempt to deal with the case where the current interface
does not support sound but USER_SOUNDS is enabled because another
interface in the same executable does.
I thought there were more places that checked for "it" and substituted
"someone" or "something". Perhaps there are and I'm just not finding
them now. Anyway, this extends x_monnam() and adds some_mon_nam() and
Some_Monnam() to do that during monster name formatting instead of
having various bits of code try fix it up after the fact. The fixups
could be fooled by monsters given the name "it" or "It"; x_monnam()
won't be.
Get rid of the last reference to 'g.restoring' (which managed to
unintentionally survive the change to 'g.program_state.restoring').
Also have suppress_map_output() check 'g.program_state.saving' and
switch the couple of checks against that flag to use the function.
Eliminate a couple of compile warnings produced when DEF_PAGER is
defined: unixmain.c: g.catmore=DEF_PAGER; wintty.c: fd=open(...).
Override its use when DLB is also defined since an external pager
could access 'license' but not 'history', 'opthelp', &c when those
are in the dlb container file.
In the commented out value for DEF_PAGER, show a viable value for
the default configuration these days.
The walls for the mines, gehennom, knox, and sokoban had been
changed at the "tile"-level, with no awareness of the core game,
or non-tile interfaces.
- Expand the glyphs to include a set of walls for the main level
as well as each of those mentioned above.
Altars had been adjusted at the map_glyphinfo() level to substitute
some color variations on-the-fly for unaligned, chaotic, neutral,
lawful altars, and shrines. The tile interface had no awareness of
the feature.
- Expand the glyphs to include each of the altar variations that
had been implemented in the display code for tty-only. This required
the addition of four placeholder tiles in other.txt. Someone with
artistic skill will hopefully alter the additional tiles to better
reflect their intended purpose.
Explosions had unique tiles in the tile window port, and the display
code for tty tinkered with the colors, but the game had very little
awareness of the different types of explosions.
- Expand the glyphs to include each of the explosion types: dark,
noxious, muddy, wet, magical, fiery and frosty.
Pile-markers to represent a pile had been introduced at the
display-level, without little to no awareness by the core game.
- Expand the glyphs to include piletops, including objects,
bodys, and statues.
Recently male and female variations of tiles and monsters had been
had been introduced, but the mechanics had been mostly done at the
display-level through a marker flag. The window port interface then
had to increment the tile mapped to the glyph to get the female version
of the tile.
- Expand the glyphs to include the male and female versions of the
monsters, and their corresponding pet versions, ridden, detected
versions and statues of them.
Direct references to GLYPH_BODY_OFF and GLYPH_STATUE_OFF
in object_from_map() in pager.c were getting incomplete results.
- Add macros glyph_to_body_corpsenm(glyph) and
glyph_to_statue_corpsenm(glyph) macros for obtaining the corpsenm
value after passing the glyph_is_body() or glyph_is_statue() test.
Other relevant notes:
- The tile ordering in the win/share/*.txt tile files has been altered,
other.txt in particular.
- tilemap.c has had a lot of alterations to accommodate the expanded
glyphs. Output that is useful for troubleshooting will end up in
tilemappings.lst if OBTAIN_TILEMAP is defined during build.
It lists all of the glyphs and which tile it gets mapped to, and also
lists each tile and some of the references to it by various glyphs.
- An array glyphmap[MAXGLYPH] is now used. It has an entry for each
glyph, ordered by glyph, and once reset_glyphs(glyph) has been run, it
contains the mapped symindex, default color, glyphflags, and tile
index.
If USE_TILES is defined during build, the tile.c produced from the
tilemap utility populates the tileidx field of each array element with
a glyph-to-tile mapping for the glyph. Later on, when reset_glyphmap()
is run, the other fields of each element will get populated.
- The glyph-to-tile mapping is an added field available to a window
port via the glyphinfo struct passed in the documented interface. The
old glyph2tile[] array is gone. The various active window ports that
had been using glyph2tile[] have been updated to use the new interface
mechanism. Disclaimer: There may be some bug fixing or tidying
required in the window port code.
- reset_glyphmap() is called after config file options parsing
has finished, because some config file settings can impact the results
produced by reset_glyphmap().
- Everything that passes the glyph_is_cmap(glyph) test must
return a valid cmap value from glyph_to_cmap(glyph).
- An 'extern glyph_info glyphmap[MAX_GLYPH];' is inserted into the
top of only the files which need awareness of it, not inserted into
display.h. Presently, the only files that actually need to directly
reference the glyphmap[] array are display.c, o_init.c (for shuffling
the tiles), and the generated tile.c (if USE_TILES is defined).
- Added an MG_MALE glyphflag to complement the MG_FEMALE glyphflag.
- Provide an array for wall colorizations. reset_glyphmap() will draw
the colors from this array: int array wallcolors[sokoban_walls + 1];
The indices of the wallcolors array are main_walls (0), mines_walls
(1), gehennom_walls (2), knox_walls (3), and sokoban_walls (4).
In future, a config file option for adjusting the wall colors and/or
an 'O' option menu to do the same could be added. Right now, the
initializaton of the wallcolors[] array entries in display.c leaves the
walls at CLR_GRAY, matching the defsym color.
- Most of the display-level kludges for some of the on-the-fly
interface features have been removed from map_glyphinfo() as they
aren't needed any longer. These glyph expansions adhere more closely to
the original glyph mechanics of the game.
- Because the glyphs are re-ordered and expanded, an update to
editlevel will be required upon merge of these changes.
When using a menu to drop or put in items into a container,
allow putting in the item (or items) you picked up previously,
by selecting the 'P' entry from the item class menu
Inspired by the itemcat patch by Stanislav Traykov.
Invalidates saves and bones.
It's redundant with g.moves, so there is no more need for it.
Way, way back, it looks like g.moves and g.monstermoves can and did
desync, where g.moves would track the amount of moves the player had
gotten (and would therefore increase faster if the player were hasted)
and g.monstermoves would track the amount of monster move cycles, aka
turns. But this has not been the case for a long time, and they both
increment together in the same location in allmain.c. There are no
longer any cases where they will not be the same value.
This is a save-breaking change because it changes struct
instance_globals, but I have not updated the editlevel in this commit.
When discussing the recent commit that removed makedefs -o from the
build process, nhmall pointed out that a sanity check ensuring all
objects within one class add up to 1000 probability had been removed as
well. This requirement was a perennial thorn in the side for anyone
doing anything that touches object probabilities, because allocating
probability to something meant deciding what to take it away from,
without a good way to evenly distribute that across all the other
members of the object class.
I had gotten around this in xNetHack by removing the sanity check and
making mkobj() total up the probability within an object class and then
using that instead of 1000. This commit takes a similar approach, but
instead of inefficiently recalculating the sum every time mkobj() is
called, it instead computes it at the start of the game or when
restoring the save file and stores it in a global variable.
This fixes a slight bias problem with rings - they are all supposed to
be of equal probability, but there are 28 of them and 1000 is not evenly
divisible by that, so the old formula made the later rings slightly more
likely. Now instead of a 35/1000 or 36/1000 chance, they are all
uniformly 1/28. (Internally they have a oc_prob of 1 now, not 0).
Gems are also weird, because their oc_prob values change every level.
This ought to have still worked without a change, because the arcane
formula for assigning the probabilities would still end up with them
adding to 1000. But I added in code to reset the total gem probability
anyway; this may help make the formula less arcane in the future.
There is still a sanity check against object classes having a nonzero
number of objects but zero total probability, in which case an
impossible will be thrown and every member of the class will be given
equal probability. I also downgraded the "probtype error" panic in
mkobj() to an impossible because it has a reasonable failure case -
return the first item in that class.
This evolves and hopefully eases the game-build requirements by
removing game-compile dependencies on any header files generated
by the makedefs utility, including:
date.h dependency and its inclusion is removed and comparable functionality
is produced at runtime via new file src/date.c.
pm.h dependency and its inclusion is removed and comparable functionality is
produced by moving the monster definitions from monst.c into new header
file called monsters.h and altering them slightly. The former pm.h header
file #define PM_ values are now replaced with appropriate emitted enum
entries during the compiler preprocessing.
onames.h dependency and its inclusion is removed and comparable functionality
is produced by moving the object definitions from objects.c into new header
file called objects.h and altering them slightly. The former onames.h header
file #define values are now replaced with appropriate emitted enum entries
during the compiler preprocessing.
artilist.h has been slightly altered, and the former onames.h artifact-related
header file #define ART_ values are now replaced with appropriate emitted enum
entries during the compiler preprocessing.
makedefs can still produce date.h (makedefs -v), pm.h (makedefs -p), and
onames.h (makedefs -o) for reference purposes. They won't be used during
the compiler.
The other uses for makedefs remain. They are used to prepare external
file content that the game utilizes, not prerequisite code for the
compile:
makedefs -d (database)
makedefs -r (rumors)
makedefs -h (oracles)
makedefs -s (epitaphs, engravings, bogusmons)
date.c
Pull the code for date/time stamping from mdlib.c into date.c.
Set date.o to be dependent on source files, header files, and .o files
so that date.o is rebuilt from date.c when any of those changes, thus
ensuring an accurate date/time stamp. It also includes git sha
functionality formerly done by makedefs writing #define directives
into include/date.h. For unix it passes the git info on
the compile line for date.c (via sys/unix/hints/linux.2020, macOS.2020)
nethack --dumpenums (optional, but on by default)
Allow developer to obtain some internal enum values from NetHack
without having to resort to an external utility such as
makedefs.
Uncomment #define NODUMPENUMS in config.h to disable this.
The updates to sys/windows/Makefile.gcc have not been tested yet.
Put the flag that parse() uses to tell readchar() that the next
keystroke is a command into the program_state structure instead of
having it be a static variable in cmd.c. Conceivably an interface
could make use of it, and even if none do, it is program state....
More #558
Retravel travels to the previously selected destination.
Also changes the travel-via-mouse to execute the extended command
instead of faking a special key.
Put the rush and run movement keys into g.Cmd instead of bit twiddling
the normal walk keys in multiple places to get the run and rush keys.
Allow meta keys in getpos. Use the normal running keys to fast-move
in getpos, instead of explicit HJKL - I polled couple places online,
and number_pad users did not use the HJKL keys in getpos.
Make meta keys work even after a prefix key.
Allows the fire-command to autowield a launcher; it will now
do either swapweapon or wield an appropriate launcher, if you
have ammo quivered.
This assistance can be turned off with the fireassist boolean option.
Adds a rudimentary command queue, which allows the code to add keys
or extended commands into the queue, and they're executed as if
the user did them. Time passes normally when doing the queue,
and the queue will get cleared if hero is interrupted.
Adds possible callbacks for "start_new_game", "restore_old_game",
"moveloop_turn", and "game_exit" which when defined, will be called
from core code at the appropriate time.
Adds lua hooks for dump_fmtstr (only if DUMPLOG), dnum_name, u.moves,
u.uhave_amulet, and u.depth.
If the killer and the paralyzer are the same monster, truncate
that to "Killed by a foo, while paralyzed". When not the same,
spell out the paralyzer's monster type instead of using generic
"monster". "Killed by a fox, while paralyzed by a ghoul", or
"Killed by a ghoul, while paralyzed by a ghoul" *if* they were
two different ghouls.
'final_fpos' shouldn't have been moved to the 'g' struct. Even if
a game went all the way through topten and was restarted as a new
game that also went all the way through topten, 'final_fpos' would
get a new value rather than being messed up by a stale old one.
Change Trollsbane versus troll corpse revival: instead of revival
failing if Trollsbane is wielded at time of revival attempt, mark
the corpse no-revive if killed by Trollsbane (whether by the hero
or a monster).
If a no-revive corpse is within view when time to revive occurs,
give "the troll corpse twitches feebly" even when the hero isn't
responsible. That used to only apply if the hero zapped the
corpse with undead turning, which would have become inoperative
because now being zapped by undead turning clears the no-revive
flag and revives as normal. In other words, undead turning magic
overrides killed-by-Trollsbane or non-ice troll having been in an
ice box.
further adjustments to the window port interface to pass a pointer
to a glyph_info struct which describes not just the glyph number
itself, but also the ttychar, the color, the glyphflags, and the
symset index.
This affects two existing window port calls that get passed glyphs
and does the parameter consistently for both of them using the
glyph_info struct pointer:
print_glyph()
add_menu().
The recently added glyphmod parameter is now unnecessary and has been
removed.
ensure that monster female name variation ends up as a female during ^G
arbitrate when there is a conflict between gender term (male or female) and
a gender-tied monster name (cavewoman) during ^G; gender term wins
add MALE, FEMALE, and gender-neutral names for individual monster species
to the mons array. The gender-neutral name (NEUTRAL) is mandatory, the
MALE and FEMALE versions are not.
replace code uses of the mname field of permonst with one of the three
potentially-available gender-specific names.
consolidate some separate mons entries that differed only by species into a
single mons entry (caveman, cavewoman and priest,priestess etc.)
consolidate several "* lord" and "* queen/* king" monst entries into
their single species, and allow both genders on some where it makes some
sense (there is probably more work and cleanup to come out of this at some
point, and the chosen gender-neutral name variations are not cast in stone
if someone has better suggestions).
related function or macro additions:
pmname(pm, gender) to get the gender variation of the permonst name. It
guards against monsters that haven't got anything except NEUTRAL naming
and falls back to the NEUTRAL version if FEMALE and MALE versions are
missing.
Ugender to obtain the current hero gender.
Mgender(mtmp) to obtain the gender of a monster
While the code can safely refer directly to pmnames[NEUTRAL] safely in the
code because it always exists, the other two (pmnames[MALE] and
pmnames[FEMALE] may not exist so use:
pmname(ptr, gidx)
where -ptr is a permonst *
-gidx is an index into the pmnames array field of the
permonst struct
pmname() checks for a valid index and checks for null-pointers for
pmnames[MALE] and pmnames[FEMALE], and will fall back to pmnames[NEUTRAL] if
the pointer requested if the requested variation is unavailable, or if the
gidx is out-of-range.
Allow code to specify makemon flags to request female or male (via MM_MALE
and MM_FEMALE flags respectively)to makedefs, since the species alone doesn't
distinguish male/female anymore. Specifying MM_MALE or MM_FEMALE won't
override the pm M2_MALE and M2_FEMALE flags on a mons[] entry.
male and female tiles have been added to win/share/monsters.txt.
The majority are duplicated placeholders except for those that were
separate mons entries before. Perhaps someone will contribute artwork in the
future to make the male and female variations visually distinguishable.
tilemapping via has the MALE tile indexes in the glyph2tile[]
array produced at build time. If a window port has information that the
FEMALE tile is required, it just has to increment the index returned
from the glyph2tile[] array by 1.
statues already preserved gender of the monster through STATUE_FEMALE
and STATUE_MALE, so ensure that pmnames takes that into consideration.
I expect some refinement will be required after broad play-testing puts it to
the test.
consolidate caveman,cavewoman and priest,priestess monst.c entries etc
This commit will require a bump of editlevel in patchlevel.h because it alters
the index numbers of the monsters due to the consolidation of some. Those
index numbers are saved in some other structures, even though the mons[] array
itself is not part of the savefile.
Window Port Interface Change
Also add a parameter to print_glyph to convey additional information beyond
the glyph to the window ports. Every single window port was calling back to
mapglyph for the information anyway, so just included it in the interface and
produce the information right in the display core.
The mapglyph() function uses will be eliminated, although there are still some
in the code yet to be dealt with.
win32, tty, x11, Qt, msdos window ports have all had adjustments done to
utilize the new parameter instead of calling mapglyph, but some of those
window ports have not been thoroughly tested since the changes.
Interface change additional info:
print_glyph(window, x, y, glyph, bkglyph, *glyphmod)
-- Print the glyph at (x,y) on the given window. Glyphs are
integers at the interface, mapped to whatever the window-
port wants (symbol, font, color, attributes, ...there's
a 1-1 map between glyphs and distinct things on the map).
-- bkglyph is a background glyph for potential use by some
graphical or tiled environments to allow the depiction
to fall against a background consistent with the grid
around x,y. If bkglyph is NO_GLYPH, then the parameter
should be ignored (do nothing with it).
-- glyphmod provides extended information about the glyph
that window ports can use to enhance the display in
various ways.
unsigned int glyphmod[NUM_GLYPHMOD]
where:
glyphmod[GM_TTYCHAR] is the text characters associated
with the original NetHack display.
glyphmod[GM_FLAGS] are the special flags that denote
additional information that window
ports can use.
glyphmod[GM_COLOR] is the text character
color associated with the original
NetHack display.
Support for including the glyphmod info in the display glyph buffer
alongside the glyph itself was added and is the default operation.
That can be turned off by defining UNBUFFERED_GLYPHMOD at compile time.
With UNBUFFERED_GLYPHMOD operation, a call will be placed to map_glyphmod()
immediately prior to every print_glyph() call.
number_pad==1 adds
'5' => 'G'
M-5 => 'g'
'0' => 'i'
number_pad==2 swaps 5 and M-5 and adds M-0
'5' => 'g'
M-5 => 'G'
'0' => 'i'
M-0 => 'I'
M-5 and M-0 were missing from the bound key handling; they still
used hardcoded digits even though the actions for plain 5 and
plain 0 can be bound to other keys these days. This implements
the M-5 variation as NHKF_RUSH2. Changing numpad from 1 to 2
or vice versa will swap the NHKF_RUN2 and NHKF_RUSH2 actions
regardless of what keys they're assigned to. I haven't done
anything for unimplemented NHKF_DOINV2 though (and am not
planning to in case someone else wants to jump in...).
This also fixes the description of the 'I' command. The extended
command name for that still misleadingly refers to "type" rather
than "class" though.
I started activating new program_state.saving and discovered that
saving of ball and chain could access freed memory. The change
for the former and fix for the latter are mixed together here (but
easily distinguishable).
The saving flag inhibits status updating and perm_invent updating,
also map updating that goes through flush_screen(). That should
fix the exception triggered after an impossible warning was issued
during a save operation. impossible() goes through pline() which
tries to bring the screen up to date before issuing a message.
During save, data for that update can be in an inconsistent state.
The code to save ball and/or chain when not on floor or in invent
(I think swallowed is the only expected case) was examining the
memory pointed to by uball and uchain even if saving the level had
just freed floor objects and saving invent had just freed carried
objects. So for the usual cases, stale pointer values for uball
and uchain would be present and checking their obj->where field
was not reliable.
Move the core's global restoring flag (not the same as main()'s
local resuming flag) to a more logical place. Add a saving flag
in the process, but it isn't being set or cleared anywhere yet.
(Once in use it will probably fix the exception during save that
was just reported, but before that it would be useful to figure
out what specifically caused the event.)
The program_state struct really ought to be standalone rather
than part of struct g but I haven't made that change.
Removing an unused variable for wishing and some reformatting
that whent along with it got mixed in. Removes some trailing
whitespace in sfstruct.c too.
Only lightly tested...
If we ever want huge maps with COLNO or ROWNO larger than signed char,
this will at least allow the game to compile and start when typedef'ing
xchar to int. Trying to use huge maps exposes more bugs.
Use a linked list to store stair and ladder information, instead
of having fixed up/down stairs/ladders and a single "special" (branch)
stair.
Breaks saves and bones.
Adds information to migrating objects and monsters for the dungeon
and level where they are migrating from.
When a zombie (or lich) kills a monster in melee without a weapon,
the monster can rise few turns later as a zombie.
The only creatures that can be zombified are ones that actually have
a zombie counterpart monster. A zombie cannot turn a jackal into
a zombie, for instance. But it could turn a shopkeeper into a human
zombie, or a dwarf king into a dwarf zombie.
Zombies will fight with monsters that can be turned into zombies.
Originally this was a SliceHack feature, but this is based on xNetHack
version of it, with some modifications.
Since teleporation gives a "you matrialize" message even when
arriving close by, the old behavior of not learning a scroll of
teleportation when you land quite close to your original spot
no longer made sense. Always [almost] discover teleport scroll
when reading it.
Also adds one-shot teleport control when reading a blessed scroll
of teleportation. I changed that to be prevented when hero is
stunned, same as with full-fledged teleport control.
I reworded or reformatted several of the comments. And removed
the EDITLEVEL increment in patchlevel.h; save and bones file
contents are not affected.
I've also added an unrelated comment about reading mechanics to
doread().
Closes#386