character_race() was going out of bounds when scanning the races[]
array, relying on a field value that the fencepost entry didn't set.
This incorporates the previous fix for UNDEFINED_RACE but also changes
character_race() to not care about that anymore.
For '*' and for persistent inventory with perminv_mode==inuse, show
the items in a specific order and within four labelled groups rather
than within their object classes:
|Accessories
| amulet
| right ring
| left ring
| blindfold
|Wielded/Readied Weapons
| primary weapon
| alternate or secondary weapon
| quiver/ammo pouch
|Armor
| suit
| cloak
| shield
| helmet
| gloves
| boots
| shirt
|Miscellaneous
| lit candles and/or lamps
| attached leashes
The accessories come first due to the default 'packorder' position
for amulets; weapons before armor likewise. If you wield a potion or
quiver some gold, those non-')' items will appear in the weapons
section since the ordering is based on slot rather than object class.
I used ^G to create a monster and specified "invisible owlbear". I
then got "An owlbear appears next to you." Except it didn't; it was
invisible and I lacked see-invisible. I imagine that newsym() was
called for the new-yet-invisible monster, but that remained buffered
and was gone overridden by the time pending map update got flushed
at some point after the monster was made invisible.
Add a new makemon() flag to turn a newly created monster invisible
during its creation, before "monster appears" message is delivered.
Since that message will now be suppressed in this situation, use the
cursor-flash hack that indicates where the new, unseen monster got
placed. Creating "1000 invisible <mon>" is something you probably
won't do twice.
Everything else in c_commmon_strings had this qualifier, but
c_vision_clears was just const char *. There doesn't seem to be any
reason for that so change it to be consistent with the others.
Rest of 'not PR #1102'. Resizing the terminal while getpos was in
operation recalculated the map from scratch instead of redrawing what
the core considers to already be shown. And it was always operating
while an asynchronous signal was excuting which could potentially
clobber whatever was running at the time the signal arrived.
This uses same redrawing as the prior '^R during getpos()' fix. It
also only performs the resize while tty_nhgetch() is waiting for
input. If that is the situation at the time that the signal arrives
then it will resize immediately (while in the asynchronous signal
handler); if not, it will set a flag and tty_nhgetch() will do the
resize the next time it gets called.
This builds with TTY_PERM_INVENT enabled and doesn't seem to be any
worse than before, but there are bugs with that. The only way I could
get perminv to appear was to save and restore, then perm_invent was
honored for both RC file and mO command. And once I managed to get it
to display, moving an item from a lower case slot to slot 'A', made
that item vanish; nothing appeared in the invent's right hand panel.
Both of those misbehaviors already happen prior to this commit. I
also saw an abort+panictrace if I resized while at the "Dump core?"
prompt when running the pre-commit code and didn't see that with the
post-commit code (although the prompt wasn't shown so I couldn't tell
that it was waiting for an answer). The abort probably sounds scarier
than it warrants; I suspect that the pre-commit code just treated the
resize as answering 'y' for some reason, possibly a stale value in the
variable it uses.
b_trapped was treating 0 as a null value for its bodypart parameter, but
0 is actually the value of ARM, so b_trapped(..., ARM) would be treated
as intending no A_CON abuse. Add NO_PART = -1 to the bodypart_types
enum, and use that instead of 0 as the "no body part" value in
b_trapped, so that ARM can be passed to it without any ambiguity.
aosdict identified this issue in xNetHack and handled it differently; he
added NO_PART with a value of 0, incremented the existing bodypart_types
values, and padded the body part arrays so the actual body parts would
start at index 1. I think using NO_PART = -1 is simpler, but that's an
alternative approach that can be used instead -- it is advantageous in
that it automatically fixes any other places where 0 is assumed to be a
non-body-part value that I may have overlooked.
If there were outdated savefiles encountered during
startup, each individual one was getting a wait_synch
that required a <return> even though a message window
wasn't being used at that point.
Allow suppression of the individual per-file wait_synch()
calls on Windows, so that a single one can be done once
the selectsave processing is overwith.
This was a little messy because an indicator had to flow
down through validate(), uptodate(), etc.
There shouldn't be any change in how things behave on
any non-Windows platforms.
When calling panic() or impossible(), create the option
of opening a browser window with most of the fields
already populated. Code for MacOS and linux is included;
other ports are affected by argument change to early_init
which are done but not tested.
To enable, define CRASHREPORT in config.h and set
CRASHREPORTURL in sysconf to (for the moment at least)
http[s]://www.nethack.org/common/contactcr.html
Adds --grep-defined option to makedefs for Makefiles.
Adds "bid" (binary identifier), an MD4 of the main nethack
binary. This is ONLY for helping (in the future) contact.html
to set the "NetHack from" field automatically for our own
binaries. This can be faked, but the user can lie so nothing
lost. There's nothing magic about MD4; other ports can use
anything that prodcues a long apparently random string we can
match against.
- new option --bidshow for us to get the MD4 of a
released binary so I can add it to the website.
Only available in wizard mode and not in nethack.6.
- typo macos -> macosx in hints file
No support for packaging builds as I'm not sure what that
would look like.
Adds a javascript helper for MacOS.
Adds a lua helper for linux (and builds and installs
nhlua).
The sortloot classification routine had some inappropriate casts to
'coordxy' for things had nothing to do with map coordinates. I was
going to change the relevant fields to 'short' but that seems iffy
for 'indx' so I changed them all to 'int'.
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.
While running the tutorial, the Save command is disabled. When the
tutorial was extended to two levels, stashing and restoring the
hero's equipment stopped working as intended if player entered the
second level. The attempted fix for that broke re-enabling Save
even if the player left the tutorial without entering its second
level.
This seems to fix things, but I'm flailing around with barely a clue
here. A couple of simpler attempts didn't work and I haven't figured
out why, so this is a bit more complex than what I wanted.
Reorganizing nhl_callback() isn't part of the fix, just avoids use
of some redundant code.
Instead of a 5% chance for crystal plate mail or crystal helmet to
break each time it's subjected to breakage, switch to a 10% chance
but the damage is treated as erosion rather than break/don't-break.
'crystal foo' will need to go through four stages of damage before
breaking: cracked crystal foo, very cracked crystal foo, thoroughly
cracked crystal foo, then gone. Crackproof handling is included,
described as tempered crystal foo.
It mostly still applies to throwing and kicking the item. Having
some hits trigger damage might be worthwhile but isn't implemented.
Object creation within lua code probably needs to be updated, and
when the Mitre of Holiness is created in the priest/priestess quest
it should start out as tempered (erodeproof). Perhaps it ought to
be erodeproof regardless of where/how it's created.
Reported by Noisytoot: going from level tut-1 to tut-2 returned the
hero's starting equipment too soon, and exiting the tutorial from
tut-2 let the hero keep any equipment acquired within the tutorial.
Entering and leaving the tutorial was being handled by lua code in
the level description of tut-1 and adding a second level messed that
up. I didn't see any way of handing that with level-specific lua
code so I made it become the core's responsibility. gotolevel()
knows when the hero is moving from one dungeon branch to another so
it can recognize entry to or exit from the tutorial easily.
While fixing this, prevent #invoke of the Eye of the Aethiopica from
offering the tutorial as a candidate destination (was feasible if it
had been entered at start of game).
Not fixed: levels visited in the tutorial become part of #overview.
Show location as "Tutorial:1" instead of "Dlvl:1" on status lines.
Only tested with tty; some interfaces handle location themselves and
may need their own fixup for this.
Fixes#1046
The safe_teleds() change that restored picking random destination
attempts prior to making an exhaustive search contained a typo tjat
accidentally only accepted invalid positions instead of valid ones.
So unless it randomly picked 40 good spots, erroneously rejecting
all of them and then falling back to the try-everywhere situation
(which has its own testing without any typo), it would yield strange
results by placing the hero in walls or solid rock via choosing the
first inappropriate spot it tried.
Not part of that bug but related, sort of: for rloc(), use
rloc_pos_ok() instead of goodpos() during the exhaustive search as
well as during the random tries, but hang on to the first (after
randomization) position that passes goodpos() for a last resort.
The collect_coords() flag for 'skip-inaccessible' intended to be a
quick way to filter out walls and solid rock was using !ACCESSIBLE()
which also rejects water and lava locations. So such spots wouldn't
be picked by either safe_teleds() or rloc() when they were finding
a spot for aquatic or lava-tolerant forms. Instead of duplicating
a bunch of code to decide whether the hero's current form or the
teleporting monster should avoid !ACCESSIBLE() for a reason other
than having Passes_walls, make collect_coords(CC_SKIP_INACCS) use
!ZAP_POS() which rejects walls and rock but allows pools.
Make recently added collect_coords() global even though it is still
only being used in teleport.c.
Add CC_SKIP_INACCS flag to only collect accessible locations so that
there's no need for a custom filter callback or of collecting spots
that will always be rejected when put to use. Caller needs to check
Passes_walls/passes_walls() to decide whether that is suitable.
Merge some of the old safe_teleds() with the new, making it try
randomly 40 times before collecting coordinates for an exhaustive
selection. Prior to the recent change which added collect_coords()
it was trying 400 times and giving up if that didn't find a good spot.
Start using collect_coords() for rloc() as well as for safe_teleds().
Only try to pick a spot randomly 50 times now instead of 1000. If
those all fail, it does an exhaustive search of a randomized list of
candidates instead of old left-to-right, top-to-bottom map traversal.
Has not had nearly as much testing as safe_teleds() underwent.
rloc() was explicilty ignoring map column 1 for some reason. Unlike
reserved column 0, column 1 is part of every level and should be
considered for monster teleport destination even though most levels
don't utilize it.
to program_state.input_state
Rename program_state.getting_a_command and give it an int value
instead of treating it as boolean. Start using to it for Qt to
suppress commands initiated from the drop down menus in the title bar
if nethack isn't expecting to get a command from the user. Those menu
choices inject extended command text into the input stream and should
be avoided when entering text or waiting for a menu to be dismissed.
These menus would be better if they grayed out unavailable choices
when pulled down instead of accepting any choice and then treating
that no good. I'm not going to try to figure out to do that with Qt.
And this workaround for the menus doesn't have any affect on the
toolbar buttons below the title bar. Those execute core commands
directly and when I tried to use jacket routines instead, the tool bar
stopped showing up so I've given up.
This won't fix the reported problem of getting stuck in a loop.
- Move secondary preprocessor defines down further in config.h
so that they can be overridden via [platform]conf.h which is
included from global.h, specifically:
LIVELOGFILE when LIVELOG is defined
DUMPLOG_FILE when DUMPLOG is defined
- Minimize platform-specific, or compiler-specific code in hack.h and decl.h.
- reorganize src/decl.c to align with include/decl.h.
- a new header file cstd.h added, containing calls to C99
standard header files.
- hack.h, decl.h, and decl.c have been cleaned up and had code
moved so that things line up as follows:
hack.h defines values that are available to all
NetHack source files, contains enums for use in all
NetHack source files, and contains a number of
struct definitions for use in all NetHack source files.
It does not contain variable declarations or variable
definitions.
decl.h contains the extern declarations for variables that
are defined in decl.c. These variables are global and
available to all NetHack source files. The location of
the variables within decl.h was random, so give it some
order for now.
decl.c contains the definition of the variables declared in
decl.h, and initializes them where appropriate. The
variable definitions are laid out in much the
same order as their declarations in decl.h.
- wintty.h: There were some varying terminal-related prototypes in
system.h, and that was the only thing left that demanded that
system.h be included. Those have been replaced by an #include
<term.h> in include/wintty.h to get the more current (and hopefully
more correct) prototypes, rather than hardcoding them in NetHack
sources.
For edge-case platform compatiblity, there is no #include <term.h>
if the build defines NO_TERMCAP_HEADERS. In that case one set of
hardcoded prototypes is still used in include/wintty.h.
The added #include "term.h" is also bypassed for NO_TERMS builds (builds
that don't link to terminfo/termcap at all, but still present a tty
interface using platform or window-port specific functions to fulfill
the same role as that of terminfo/termcap).
- some scattered, unnecessary #include "integer.h" were removed from
various files, since that's always included in current NetHack-3.7
sources, either directly from config.h or indirectly from #include
"hack.h".
- system.h references removed.
- new cstd.h added; the #include "system.h" references in Makefiles
and project files (Xcode, visual studio), were replaced
with #include "cstd.h" references. A "make depends" is probably
warranted.
Also:
- Use of <term.h>, which defines clear_screen() as a macro, conflicts
with an actual function with that name in win/tty/termcap.c. The most
straight-forward course of action was to rename the NetHack function,
and change the references to it, from clear_screen() to
term_clear_screen(), so that was done.
Reverse part of commit 4021a63bcf
"wand/spell/breath killer reason" so that wand of magic missile
zapped by a monster isn't ambiguous about who is responsible.
I happened to notice when looking at a ttyrec that farlooking
with automatic description would blink the cursor on hero for
one frame, and then back on the farlooked map location.
Extend "killed by the touch of death inflicted by <monster>" to buzz().
"Killed by a bolt of cold" becomes "killed by a bolt of cold zapped by
<monster>" or "killed by a blast of cold" becomes "killed by a blast
of cold exhaled by <monster>" and so forth.
More work than expected; the zap code isn't passed enough context.
BZ_M_WAND() was producing the wrong value for wands zapped by monsters.
Adds a more general way to handle gameplay tips, and adds
a boolean option "tips", which can be used to disable all
tips. Adds a helpful longer message when the game goes
into the "farlook" mode.
Also adds a lua binding to easily show multi-line text
in a menu window.
Breaks save compat.
sound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol,
int32_t moreinfo);
-- NetHack will call this function when it wants to pass text of
spoken language by a character or creature within the game.
-- text is a transcript of what has been spoken.
-- gender indicates MALE or FEMALE sounding voice.
-- tone indicates the tone of the voice.
-- vol is the volume (1% - 100%) for the sound.
-- moreinfo is used to provide additional information to the soundlib.
-- there may be some accessibility uses for this function.
It may be useful for accessibility purposes too.
A preliminary implementation has been attempted for macsound to test
the interface on macOS. No tinkering of the voices has been done.
Use of the test implementation requires the following at build time with make.
WANT_SPEECH=1
That needs to be included on the make command line to enable the test code,
otherwise just the interface update is compiled in.
I don't know for certain when AVSpeechSynthesizer went into macOS, but older versions
likely don't support it, and would just leave off the WANT_SPEECH=1.
If built with WANT_SPEECH=1, the 'voices' NetHack option needs to be enabled.
It was a bit strange, when I first started up the test, to hear Asidonhopo,
the shopkeeper, talking to me as I entered his shop and interacted with him.
Groundwork for a more versatile interface for using
sound libraries. A lot of sound libraries work across
multiple platforms.
The current NetHack sound stuff is quite limited.
Binaries can have a variety of window ports linked into
them, and it makes sense to have something similar for
sound.
This tries to set things up in a more soundlib-centric way,
rather than inserting things in a platform-centric way.
It establishes a new top-level directory sound (akin to win
for the window interface routines, or "window-port") where
sound-related additions and sndprocs and support files can be
added and used across platforms.
The default interface is nosound and the 'nosound' interface
is in src/sounds.c
The interface for 'windsound', which contains the same minimal
USER_SOUNDS support using built-in routines that has been in the
windows port for a long time is added to
sound/windsound/windsound.c.
For now, the sound interface support for 'qtsound' has been added
to the existing Qt files win/Qt/qt_bind.h and win/Qt/qt_bind.cpp,
and a note has been placed in sound/qtsound/README.md to avoid
confusion.
New header file added: include/sndprocs.h.
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.
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
^ ^
If paranoid_confirm settings include praying, don't put the answer
to "are you sure you want to pray?" into the do-again buffer where ^A
would use it to ignore confirmation if prayer is repeated. And for
wizard mode, when confirmation is 'y' then the answer to "force the
gods to be pleased?" has to be suppressed from the do-again buffer too
or it would be used by subsequent ^A to answer "are you sure?".
This is basically a band-aid just for #pray. There are probably other
confirmations that should be suppressed from do-again instead of being
reusable. The rest of the paranoid_confirm ones should be ok because
they require "yes" and that doesn't end up in the do-again buffer, but
there are bound to be other confirmations that shouldn't automatically
be re-used during repetition.
When dist2() got changed to use coordxy parameters, a macro that uses
it in its definition was overlooked and it had (int) casts in it.
That caused a warning about possible data loss when the int
then got converted to coordxy for the dist2() call.
Give online2() coordxy parameters instead of int, like its bretheren.
Avoid a couple of implicit conversion warnings where ints were being assigned
to smaller uchar or ints being assigned to smaller short.
A couple of signed vs unsigned warnings on some rumor processing.
Avoid some signed vs unsigned warnings in mdlib/makedefs where a signed int
param eventually got used in an external call that took size_t.
Eliminate all of it by just having the outer NetHack routine also take
a size_t.
Lastly, insert some default C99 alternative time-related code
in mdlib/makedefs since asctime() and ctime() are being flagged as
deprecated in the upcoming C23 standard and will now start to trigger
warnings for anyone using a C23-compliant compiler.
Short for distu(mtmp->mx, mtmp->my) (i.e. the distance between the hero
and the specified monster), which is a very common use of distu(). The
idea is that this would be a convenient shorthand for it; I actually
thought it (or something very similar) existed already, but couldn't
find it when I tried to use it earlier. Based on the number of uses of
fully-spelled-out 'distu(mtmp->mx, mtmp->my)' replaced in this commit
I'm guessing I just imagined it.
I was trying to reproduce the reported "no monster to remove" warning
from remove_monster() when a mounted hero was knocked off jabberwocky
steed but so far haven't been able to.
While trying, I came across a more minor bug. The hero got knocked
off a flying steed and got feedback of "you fly off" rather than
"you fall off". Flying capability came from the steed and dismount
feedback is aware of that but calls u_locomotion() which isn't. This
commit fixes that.
This adds some groundwork (DISMOUNT_KNOCKED) for better dismount
control. With a map fragment of
|....
|.Du.
|....
I got knocked off my steed by the attacking dragon and ended up with
|..@.
|.Du.
|....
It would be better to prefer spot 1, then the 2s, then 3s, then 4s
(not sure about farther spots if none of those are available)
|.432
|.D@1
|.432
when forced to dismount by knockback. This does _not_ implement that.
This is an alternate way to deal with pull request #876, where
splitting a stack that has a name assigned updated perm_invent when
cloning the name and ran into trouble with shop billing when trying
to format for persistent inventory display.
The PR#876 fix has been left in place but wouldn't have been needed
if this had gone in first.