Issue reported by argrath: if getoptstr() executed its loop to
find the latest phase that set a role/race/gender/alignment option
value, the first iteration of the loop would use an index that's
out of bounds.
The code in question is wrong but happens to not be used, so the
out of bounds access doesn't occur. Fix the value for the first
iteration in case the offending code eventually gets used.
Fixes#960
Underwater vision was updated only once per turn, so if the hero had
more than one move per turn it could cause some spots to be left behind
on the map. For example, after moving around underwater while very fast
for a while:
}
}}}
}}}}
} }}@}
} }}}
Not only does the radius of vision appear to "smear" temporarily, but if
the hero moves fast enough, isolated spots can be left entirely behind
(since the normal underwater vision update only clears nearby spots, not
the entire map). Both these effects are visible in the example above.
The fix in this commit is to update the frequency of underwater vision
updates to "once-per-time-taken" rather than "once-per-turn", so that it
updates with every move. I'm not sure if it needs to happen more
frequently than that (i.e. in the "once-per-input" section) but I might
be overlooking something.
Also add missing punctuation to the message for applying a lamp
underwater.
Unless you kill the monster with one hit, it'll wake up
cranky and make noise - waking up other sleeping monsters.
This was a bit tricky with all the message sequencing; I tested
all the hit/throw/fire/zap combos I could think of, and it took
a while to get things looking right.
scan-build from llvm-14 (clang) doesn't complain about bite() or
maybe_finished_meal() so this is unlikely to fix those. But this
does fix one bogus complaint it has for doeat(). Testing whether
the result from touchfood() is Null was fooling it into thinking
that that was a possibility when it's not.
Also, use plain 1 and 0 instead of TRUE and FALSE when assigning
to the victual bit-fields. The analyzer doesn't care but the type
was mismatched due to the cast to (boolean) hidden in their macro
definitions.
This code was in three different places; pet eating,
monster eating metal, and monster eating other objects.
Other than very minor changes (eg. rustproofing completely
protects pets from bad effects, rustproof items are no longer
giving apport, and monsters eating corpses are healed), it
should behave the same as before... But I haven't exhaustively
gone through every iteration.
The brace added to dokick was misplaced - it should have included
the You_hear() as well.
The puts the code back the way it was, and relocates the Soundeffect().
The Soundeffect should play whether the hero is Blind or not, and the
Soundeffect() macro already includes a Deaf guard.
Cope with get_nh_lua_variable() possibly returning Null.
Either or both of the DISABLE_WARNING_UNREACHABLE_CODE and
RESTORE_WARNING_UNREACHABLE_CODE in the vicinity looked misplaced so
I took them out. They may need to be added back in.
Insert the calls to trigger a number of potential soundeffects
into the core.
If no additional soundlib support is integrated into the
build, then the Soundeffect macro (sndprocs.h) expands to nothing:
[#define Soundeffect(seid, vol)
]
If, however, at least one additional soundlib support is integrated
into the build, then the Soundeffect macro gets defined as this
in sndprocs.h:
[#define Soundeffect(seid, vol) \
do { \
if (!Deaf && soundprocs.sound_soundeffect \
&& ((soundprocs.sndcap & SNDCAP_SOUNDEFFECTS) != 0)) \
(*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
} while(0)
]
That macro definition checks for the hero not being Deaf; it checks
to ensure that the active soundlib interface has a non-null
sound_soundeffect() function pointer; and it checks to ensure
that the active soundlib interface has declared that it supports
soundeffects by setting the SNDCAP_SOUNDEFFECTS bit in its sndcap
entry. That just means that the interface routines are prepared to
accept and deal with the calls from the core, whether or not it
actually produces the desired soundeffect.
When using mouse to move to a location next to the hero,
the test_move result was reversed, causing the click to fall
in to the travel case instead of normal movement.
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.
The Gehennom changes broke the vibrating square, allowing hero to go
down into the Sanctum via stairs without performing the invocation.
Fix this by making the hellfill lua check for invocation level, and
placing down the vibrating square trap, instead of stairs.
When playing as a Samurai, add things like "osaku" to the discoveries
list even though they don't have separate descriptions to be used
when not yet discovered. Non-magic ones are pre-discovered and
players can now use the '\' command to figure out what things like
"tanko" mean without resorting to '/?'.
"wooden harp" has been getting changed to "koto (harp)"; make that be
| koto [wooden harp] (koto)
"magic harp" has been staying as "magic harp (harp)"; add it to the
list of Japanese item names. Since it's magic it isn't pre-discovered.
Once discovered it becomes
| magic koto [magic harp] (koto)
Those two needed special case handling, none of the other items did
aside from forcing them to be discoverable when lacking descriptions.
The discoveries list now has things like
| wakizashi [short sword]
| naginata [glaive] (single-edged polearm)
| gunyoki [food ration]
if--and only if--the hero is a Samurai.
Include some assertions to convince the analyzer that some pointers
can't be Null. They're Null if 'vis_func' is non-Null but only used
when that function pointer is Null and they have values.
If there's a macro that's defined when the analyzer is running and
undefined when not--or vice versa--it could be used to control NDEBUG
and avoid the assertion code when not analyzing. That's a bit like
using fake code to pacify 'lint'; however, since the assertions should
never fail, suppressing them isn't really switching to fake code.
I reordered a couple of macros so that the set of them matches the
comment which precedes them and refers to "the last three". It is
referring to the three within the block comment rather than the macro
defintions but putting those in the same order removes any ambiguity.
The complaint is that victual.canchoke might be used without having
been initialized. I'm fairly sure that that isn't correct but get
dizzy trying to trace through the eating code.
This might improve the situation, or maybe not.
This is similar to the earlier potential fix that I didn't like,
but I think think one is better.
The analyzer claimed that 'fptr' might be Null inside the switch
case for
|struct permonst *fptr = NULL;
|if (obj->otyp == CORPSE || ...) fptr = &mons[obj->corpsenm];
|switch (obj->otyp) { case CORPSE: ... /* dereference 'fptr' */ }
even though it will always have a non-Null value for otyp==CORPSE.
Make the assignment of 'fptr' unconditional. mons[NUMMONS] is
valid and won't match any actual monster. In this case it will
only be used when initializing fptr, never when fptr gets used.
Allow setting a per-level "temperature": hot, cold, or temperate
via special level flags. Currently it only affects some messages
in Gehennom, but it could be expanded to ice melting, water freezing,
or monster generation, for example.
Invalidates saves and bones.
Add a couple of redundant tests for 'shkp = shop_keeper()' yielding
Null to pacify the static analyzer.
Make the paired calls to shkp = shop_keeper() and inhishop(shkp) look
more consistent. Barring typos, the behavior hasn't been changed.
When going down stairs while punished, if you had quivered a mirror
and the mirror was dropped because you fell down the stairs, it would
not have been unequiped.
When hallucinating, random object selection for objects was including
the new generic objects. It was already excluding 'strange object'
by using 'rn2(NUM_OBJECTS - 1) + 1' to skip objects[0]; changing that
to be 'rn2(NUM_OBJECTS - MAXOCLASSES) + MAXOCLASSES' will skip the
first 18 objects, 'strange object' plus the 17 generic objects.
(I'm trying to convince myself that there's no off-by-1 or off-by-N
error and think I've succeeded.)
Try to fix a fuzzer issue. I wasn't able to reproduce it so am not
sure whether this actually fixes it. A mimic seemed to be mimicking
object #1 (generic ILLOBJ_CLASS object which shouldn't occur) rather
than #0 (strange object). Strange object always has dknown==1 and
generic objects should always have dknown==0 but farlook of mystery
object #1 had its dknown flag set.
An earlier fix to force non-Null oc_name when formatting objects in
order to pacify the static analyzer might have been the reason that
the problem couldn't be reproduced.
This includes a few miscellaneous changes made while unsuccessfully
hunting for the problem.
The code tested u.uswallow and then accessed u.ustuck. Under normal
circumstances that works fine but it could be a problem if the two
fields got out of synch. This ought to fix the analyzer complaint
and avoid any trouble with mondata access.
The analyzer complained that the second call to Japanese_item_name()
might return Null after the first one didn't.
| if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp))
| actualnm = Japanese_item_name(otyp);
even though the code involved is self-contained and deterministic.
Then later in obj_typename() 'actualnm' gets passed to strcat() or
strcpy() where Null isn't acceptable.
Could probably fix that by caching and reusing the first return value:
| if (Role_if(PM_SAMURAI) && (jname = Japanese_item_name(otyp)) != 0)
| actualnm = jname;
but I went a different route, revising that routine to take a second
argument:
| if (Role_if(PM_SAMURAI))
| actualnm = Japanese_item_name(otyp, actualnm);
It now passes back 'actualnm' instead of Null when no substitution
takes place.
The recent introduction of generic objects without names meant that
'actualnm' could actually be Null, but generic objects only occur
for map glyphs and only when dknown is 0, so the actual-name field
shouldn't ever be get used for them. Give actualnm a fallback value
just in case.
Wishing is a place that loops over all of objects[] so have it skip
the generic objects. They're all flagged no-wish so weren't being
chosen, but explicitly skipping them makes the intention clear.
Redo the restore_waterlevel() code a bit to eliminate a static
analyzer complaint. The previous code would not have done the right
thing if 'gb.bbubbles' was already non-Null, but that should not be
possible. I didn't backtrack to make sure that it was always Null
at the time restore_waterlevel() gets called.
Also, some of the code was misformatted.
Amend the safe_wait so it still waits if you have a deadly property,
even if you have a resistance to it.
External resistances do not protect against already existing
deadly properties, for example becoming deadly ill is not cured
even if you wear a green dragon scale mail.
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.
A recent commit to alloc.c by Keni drew attention to the fact that
there are extern prototypes scattered around in various .c files.
Those can make use of ATTRNORETURN (non-gcc compilers and C23) the
same way the prototypes in extern.h can, and they were overlooked
when ATTRNORETURN was first added.