Add macros to convert AD_foo, WAN_foo, and SPE_foo to relative values
for passing to BZ_U_foo and BZ_M_foo macros.
Change some return values in monster spellcasting function from
magic numbers to MM_MISS or MM_HIT.
Make buzzmu consider hero resistances - previously the
monster with innate zapping ray (Angels and Asmodeus) would
just keep doing that attack, but they will now just curse if
it saw the hero resist the attack.
When a monster at least two sizes larger hits another one,
there's a chance the smaller defender will be knocked back.
This applies also to hero, attacking when polymorphed to
a large monster, or defending from a large monster.
Most of the monsters that can knock back are giants and dragons.
Idea and some of the code from EvilHack.
viz_array[][] is indexed by coordinates but the data it contains has
nothing to do with them so it shouldn't have been changed to coordxy.
'char' was sufficient; 'uchar' would have been better; this invents
'seenV' instead. This led to a cascade of required changes. The
result is warning free and seems to be working but my fingers are
crosssed....
back into play with bad data
I don't have a test case to verify the fix, and I'm not absolutely
certain that the cause has been correctly diagnosed, but I think the
problem was caused by a guard being sent into limbo because the map
was too full to place it, then while it was on the migrating monsters
list waiting for a chance to come back the fuzzer executed #wizmakemap.
If the hero left the level and subsequently returned, the guard would
arrive back but monst->mextra->egd contained data for the previous
incarnation of the level that's invalid for wizmakemap's replacement.
Treat any shopkeeper, temple priest, or vault guard who is not on his
'home' level like the Wizard has been treated since 3.6.0. When
leaving the level they're on, put them on the migrating monsters list
scheduled to return to present position instead of stashing them in
the level's data file. That way they can be accessed from any dungeon
level, so wizmakemap can pull ones for the level it's replacing off
the migrating monsters list when removing the old level's monsters,
handling both migration-pending and already-arrived-on-another-level.
Bonus fix: put monsters who are on the migrating_mons list solely in
order to be accessible from other levels back first when returning to
the level they're on so that pets and the hero can't hijack their spot
when those arrive. The Wizard has been vulnerable to that.
Not fixed: #wizfliplevel command needs to flip parts of shk->mextra->
eshk and priest->mextra->epri for shk or priest on migrating_mons.
Vault guards don't contain anything flippable when migrating, but do
have coordinates that need fixing up while they're maintaining a
temporary corridor to/from the vault.
Change the inner workings of the experimental TTY_PERM_INVENT.
Switch to delivering the content to tty for the experimental perm_invent
via the existing window port interface (start_menu(), add_menu(), end_menu).
This also adds a new window port interface call ctrl_nhwindow() for
delivering information to the window port, and/or obtaining specific
information from the window port. The information and requests can
be extended as required. To be documented later once the changes settle
down.
Due to the intrusive nature of these changes and the possibility of
some bugs in the new code, I'm going to leave TTY_PERM_INVENT commented
out in the repository for a day or two. Anyone wishing to test it out
can do so by uncommenting TTY_PERM_INVENT in config.h.
Change the regex_error_desc() interface. Have the caller pass in
a pointer to a buffer of at least BUFSZ characters and have
regex_error_desc() populate that. No need for static buffers or
extra dynamic alloction.
Also, change it to never return Null. None of its callers were
checking for that and could have passed Null to config_error_add()
or raw_print(). printf("%s", NULL) produces "null" on OSX but other
systems would probably crash if a Null result ever actually occurred.
The error explanation returned by cppregex included a trailing period.
config_error_add() adds one, so the message ended up with two. Have
regex_error_desc() check for final period and strip it off if found.
(My test case used a menucolor pattern of "[" which triggers an error
about mismatched brackets.)
Reformat cppregex.cpp; treat 'extern "C" {' as if it isn't introducing
a nested block. Fix the '#include <hack.h>' that 'make depend' was
ignoring.
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
This starts the tty perm_invent just in time later in the
startup rather than initializing it with the other
game windows.
This also splits the duties:
The core will inquire from the window port about how many
inventory slots it can fill.
The core will handle figuring out the inventory text and
inventory letters, and will do the traversing of internal
data structures like obj chains, and passing customization
options on to the window port.
The window port will look after placing each inventory slot's
text at an appropriate location on the screen.
This, in theory, makes the core-portion available for
window ports other than tty to use, though none currently do.
The decision of what goes in an inventory slot is all left up
to the core with the update_invent_slot interface.
Documentation updates will come later, not at this time.
Refine the code added by pull request #763 to check the quest nemesis
death message for reference to noxious fumes rather than having the
three relevant roles be hardcoded.
I forced a test compile to -std=c++20 mostly to see what we would
be up against. There was only a small number of things and they
are corrected in this commit.
c++20 has some issues with comparisons and bit twiddling between
different enums.
The vendor-supplied Qt5 header files triggered some of those issues as
well, so the qt_pre.h and qt_post.h NetHack header files were adjusted
to make those new warnings go away. I have not tested Qt6 under the
new compiler and c++ version yet.
Because there are multiple pragmas in qt_pre.h now, the conditional
ifdef structure in there was modified a little to make maintenance
simpler and have a single pragma push at the top. The pragma pop
comes after the Qt vendor-supplied header files, and is done
in qt_post.h.
The display.h macro cmap_to_glyph() was used in
a Qt c++ file and triggered a series of warnings because of that.
Rather than write c++20-friendly versions of those macros, the
simple fix is to provide a function on the C side of things
to front the cmap_to_glyph() macro, so fn_cmap_to_glyph()
was added.
Also thrown into this commit, PatR picked up on the fact that for
yesterday's new warning in qt_menu.cpp, the compiler had correctly
picked up on the fact that the format range of the variable 'cash'
had been correctly upper-capped at 999999999L in the warning message
because of an assignment prior. He suggested that perhaps by also adding
if (cash < 0)
cash = 0;
the warning might be eliminated altogether.
After a test, that was proven to be correct, so yesterday's
more-kludgy change is reverted and replaced with that variable
variable restriction ahead of the snprintf().
When a game is restored while hero is Gehennom, give the "It is hot
here. You smell smoke..." message after the welcome back message.
For both entering Gehennom and restoring there, switch from "smell" to
"sense" in the second part of that message if poly'd into a form that
doesn't have sense of smell.
Some unrelated stuff that got caught up in this diff:
1) move welcome()'s call to l_nhcore_call() to the start of the routine
instead of placing that after a potential early return;
2) remove a redundant glyphmap flags reset line; the routine being
called starts by setting its flags field to 0 for level change so
caller doesn't need to do that;
3) look_here() is just a formatting bit.
I recently captured preprocessor output for a file and the amount of
code being expanded--and subsequently compiled--for canspotmon() was
quite an eye opener. This converts most of the macros it uses into
function calls. The resulting executable generated for OSX (built
for x86_64 and containing four interfaces) is about 5.5% smaller! and
there wasn't any difference in speed that I could notice.
The knowninvisible() macro has been in error for as far back as the
git logs go (which include those for the second cvs repository, so
over 20 years now).
Reported directly to devteam by entrez, the rloc() monst vanishes/
appears nearby/&c message was being given before "satisified, <shk>
suddenly disappears" making the latter redundant. As discussed, the
fix isn't as simple as suppressing one message or the other because
both are given conditionally.
This seems to solve it but has only been lightly tested.
A new feature, enabled by default to maximize testing, but one which can
be disabled by commenting it out in config.h
With this, some additional information is added to the glyphmap entries
in a new optional substructure called u with these fields:
ucolor RGB color for use with truecolor terminals/platforms.
A ucolor value of zero means "not set." The actual
rgb value of 0 has the 0x1000000 bit set.
u256coloridx 256 color index value for use with 256 color
terminals, the closest color match to ucolor.
utf8str Custom representation via utf-8 string (can be null).
There is a new symset included in the symbols file, called enhanced1.
Some initial code has been added to parse individual
OPTIONS=glyph:glyphid/R-G-B entries in the config file.
The glyphid can, in theory, either be an individual glyph (G_* glyphid)
for a single glyph, or it can be an existing symbol S_ value
(monster, object, or cmap symbol) to store the custom representation for
all the glyphs that match that symbol.
Examples:
OPTIONS=glyph:G_fountain/U+03A8/0-150-255
(Your platform/terminal font needs to be able to include/display the
character, of course.)
The NetHack core code does parsing and storing the customized
entries, and adding them to the glyphmap data structure.
Any window port can utilize the additional information in the glyphinfo
that is passed to them, once code is added to do so.
Also, consolidate some symbol-related code into symbols.c, and remove it from
files.c and options.c
Fix the problem reported by entrez of a zombie corpse reviving and
crawling out of the ground while the hero was busy doing something
(searching, digging, &c) and having the hero fail to react and just
keep doing whatever the thing was because the zombie was already
inside the range where a monster changes from no-threat to threat.
Done in the monster creation routine so any new monster (including
one revived from a corpse) that is visible,&c will cause the hero's
action to be interrupted. Teleport arrival probably needs this too.
Only interrupts an occupation, not other voluntary multi-turn
actitivy such as running or traveling. That would be trivial to
change ['if (g.occupation...' to 'if ((g.occupation || multi > 0)...']
but I'm not sure whether it ought to be extended to that.
Implement 'untrap' as an 'autounlock' action. Quite a bit more work
than anticipated. The new documentation is rather clumsy; too many
if-this and if-not-that clauses have intruded.
I'll be astonished if all the return values are correct....
[A couple of places were checking for (rx != 0 && ry != 0) to decide
whether they were performating an autounlock action at <rx,ry> but
that erroneously excludes the top line of the map if the current
level extends that far. Just check rx for zero/non-zero.]
This is enough to prevent abuse by denying access to functions and
denial of service (RAM and instruction step limits), but not enough
to allow restricted use of things that require finer control (e.g.
filesystem access).
If something goes wrong, the whole thing can be turned off, for
now, in config.h (see NHL_SANDBOX).
None of the current functionality requires changes to build systems;
some of the possible future functionality may require some #defines
- TBD. There is lots of dead code (#ifdef notyet) for bits of that
additional functionality; we can rip it out if we don't want those
additions or we can complete (parts of) it depending on our needs.
All current uses of Lua are connected to sandboxes and guarded with
nhl_pcall (sandbox and lua_pcall wrapper); options and limits can
be set at the callsites in the passed nhl_sandbox_info. Some of
the error handling may be wrong - panic() vs. impossible() vs
silence.
Memory and instruction step limits should be tuned prior to release;
there's no point tuning them now.
When not wielding anything, ^X reports "you are empty handed" if
wearing gloves or "you are bare handed" if no gloves. The ')',
'w-', and 'A)' commands were using "empty handed" unconditionally.
Make them be consisitent with ^X.
After this, body part HANDED is no longer used anywhere except in
body_part().
Reported directly to devteam: when a Rider revived, its corpse
didn't get used up.
The change to have delobj() never destroy Rider corpses, like it
won't destroy the Amulet or invocation items, didn't take into
account that they should be destroyed when Riders revive from them.
Add delobj_core() to be able to do that without changing existing
delobj() usage.
I'm surprised hardfought players haven't been all over this one.
Add some basic functions to iterate through the monster list,
ignoring dead monsters. Mainly just to allow splitting up code
into discrete functions.
Not quite happy with the get_iter_mons_xy - should probably have
a pointer to iterator data struct, which gets passed through instead,
but this works for now.
There's no 'w-' or 'Q-' for alternate weapon, but context-sensitive
inventory is starting from the object rather than the command so can
finesse that. 'A' does allow alternate weapon to be directly unset
(aka reset to bare/gloved hands) but is not friendly to being passed
queued input.
This adds an extra internal command which only handles unset uswapwep,
even though that is something which is awfully specialized to get it's
own command. Users don't see this command so that shouldn't matter.
The fire command could claim that time passed when it hadn't (fill
quiver with ammo, which takes no time, then queue commands to switch
to matching launcher, which should also take no time while queueing,
only during subsequent execution).
If quiver is empty or has ammo in it, give wielded thrown-and-return
weapon (aklys) priority over filling quiver or switching to ammo's
launcher. Don't do that if quiver has non-ammo in it, otherwise
players running Valks who wield Mjollnir with super strength but
want to throw quivered daggers would complain.
When player is being asked what to fill the quiver with, use the
\#quiver command to do that. Using it honors a count to split a
stack, handles switching uwep or uswapwep to uquiver, and gives
feedback. This is actually a fairly substantial change.
For 'fireassist', when switching to a launcher that isn't already
uswapwep pick one known to be blessed or uncursed over one having
unknown BUC status. But use the latter as last resort.
More context-sensitive inventory support. While examining inventory,
if you pick an item other than gold and it has a quantity of more
than 1, "I - Adjust inventory by splitting this stack" will be one
of the menu choices.
Breaking doorganize() into two parts was much easier than expected,
but the new internal command added to be an alternate for the first
part had more niggling details than anticipated.
Message history only shows the first digit with "Split off how many?"
if the player enters more than that.
Fix '#repeat' for tty; both it and ^A can repeat an extended command.
Fix both for curses; they can repeat an extended command instead of
just repeating the initial '#' to start getting an extended command.
X11 (tested), Qt (tested), and probably Windows GUI (not tested)
behave the same as before: ^A (or #repeat) after an extended command
just repeats the # to run the dialog to get an extended command.
I hope this introduces fewer bugs than it fixes but I don't think I'd
bet on that....
Instead of hardcoding the lava terrain change in core, if the stairs
are created in a fixed location, force the terrain to room floor first.
Move the surrounding lava changing to room floor to the Val-goal lua
file.
Normally dipping gets the thing to dip first and what to dip it
into second and the item-action handling knows that. I'm not sure
why that wasn't working as intended and I couldn't figure out how
to make it do that, so went another way: this adds an internal
extended command that executes an alternate dip routine which gets
the potion to dip into first and the thing to dip into it second.
The #dip command should allow an 'm' prefix to skip fountains and
pools, similar to how eating accepts it to skip food on the floor.
But this doesn't implement that.
Picking a corpse while looking at inventory issued a menu that had
entry for eating that and if on an altar another one for offering
that. Picking the eat or offer choice worked as long as there
weren't any other corpses on the ground or altar. If there were
others, they'd be skipped but you'd get prompted for which item in
inventory to eat or offer instead of operating on the one that was
used to initiate the action.
Stop attempting to catch up for lost time for shop damage repair
when getlev() loads a previousl visited level. Normal shopkeeper
behavior will take care of that.
Also, fixes the display related aspects of shop damage repair
interacting with ball and chain. They don't happen when its done
while the map is being shown.
Use 'fuzzymatch(,," -",)' when checking whether the name specified
in a player's wish text matches an artifact name so that extra or
omitted spaces and dashes are ignored. Wishing for "firebrand" will
yield "Fire Brand" and "demon bane" will yield "Demonbane".
sengr_at() is used as a boolean, declared as int, and returns FALSE
if there is no engraving present. Change the declaration to boolean.
Also, using fuzzymatch() without any list of ignorable characters
just to get case-insensitve matching didn't make sense so switch to
strcmpi().
monster and Elbereth unless there's no other choice.
Suggested by NetSysFire, don't create new monsters on top of scrolls
of scare monster. Not mentioned in the suggestion: unless they are
a type of monster that isn't affected by such scrolls. This extends
it to teleport destination too.
Avoid placing a monster on a scroll of scare monster or on engraved
Elbereth if there are other locations available. Only performed for
callers of goodpos() who explicitly request it, which at the moment
are makemon(), rloc(), and enexto().
Also, propagate 'mmflags_nht' to a bunch of places that were left
using long or unsigned for makemon() and goodpos() flags. I didn't
attempt to be systematic about that though.
Implements #717
while wielding a cockatrice corpse without gloves
Reported by vultur-cadens: if safely wielding a cockatrice corpse
without gloves due to temporary stoning resistance or wearing yellow
dragon scales/mail, having the resistance be lost to timeout or to
taking off the dragon armor should have turned the hero to stone but
didn't.
Extend the handling for taking off gloves to cover these other two
cases too. The feedback for these deaths is usually too verbose to
fit on the tombstone but does show up in logfile.
Fixes#715
For timed acid resistance and timed stoning resistance, report
"You {are,were} temporarily {acid,petrification} resistant."
For items being protected by worn equipment, add "by your {armor,&c}"
similar to the existing feeback about you being protected "because
<some-reason>". Wizard mode only.
When eating a meal that is affected by acid resistance or stoning
resistance and protected by temporary resistance, increase the timeout
so that the resistance doesn't expire until after the meal finishes.
That avoids getting the "you no longer feel safe from {acid,stoning}"
during the meal and not being affected by the dangerous food despite
that message. Useful because the protection is checked at the start
of the meal and not rechecked during; extending the duration hides
the latter.