Remove a stale comment and update one or two others.
Remove several trailing spaces.
Change the data type of a couple of variables from schar to int and a
couple others from int to coordxy.
Redo a nested 'if' sequence to un-nest; results in a bloated diff due
to reducing indentation for a big chunk of code.
Change monster movement to use u_on_newpos() when swallowed hero's
location moves along with engulfer so that a clipped map will be kept
up to date.
Fuzzer encountered "m_detach: monster already detached?"
A monster hit a black pudding that split. The clone was
created on top of a rolling boulder trap, which triggered,
the boulder hit the original black pudding, and killed it.
The dead pudding then retaliated (as the code didn't check
if it was dead) and a passive attack of the other monster
tried to kill the already dead pudding.
I think one of these checks would be enough, but adding the
DEADMONSTER check just in case.
Issue reported by vultur-cadens: tame monsters capable of using items
would pick up cursed ones and even wear cursed armor.
The report cites commit 6c9700ab25 but
I don't see any reason why it would be the cause. However, I was able
to reproduce the misbehavior and this commit seems to fix it.
Fixes#1072
Reported by Umbire: if a statue of a hider-under was activated by
a statue trap, it would hide underneath its own statue. Also, the
hero saw a snake hide under unseen submerged kelp.
Both of those things were exposed by new "you see <monster> hide"
message rather than caused by it. It also led to the [re-]discovery
that an existing monster hiding under a statue that was a not-yet-
triggered trap prevented the trap from producing a monster.
This redoes yesterday's can't-hide-under-statue change: hiders can
hide under statues again, but they can't hide under anything at trap
locations. [Pits containing one or more objects are an exception,
although it seems silly that a hero is prevented from falling into
one by the presence of a tiny creepy-crawly hiding under a ring or
dart in there.] So, hider-underers won't be able to interfere with
statue traps by being present at the trap location. [Trappers and
lurkers-above probably need a similar restriction; I didn't look.
They avoid trap spots rather than get lured to such by objects.]
It also prevents newly created hider-underers from becoming hidden
as part of the their creation (except when that creation is part
of level creation) whether their creation uses up an object (statue
activation, egg hatching) or there are simply other items present.
That will prevent statue of a hider producing a monster that hides
under the activated statue (which was happening due to the sequence
create monster, transfer any statue contents to monster inventory,
destroy statue).
The can't-hide-under-statues code has been repurposed to prevent
hiding under gold pieces unless there are at least 10 (arbitrary
threshold) of those or they're in a pile with some other object(s).
Sea monsters hide in water regardless of the presence of objects.
Prevent other swimmers from hiding under objects at water locations.
Such creatures don't have gills and shouldn't be able to stay
submerged in hiding for an arbitrary length of time. [No exception
is made for non-breathers. The overlap between swimmers and hider-
underers is limited to small snakes, even though it is feasible for
a creature wearing an amulet of magical breathing to polymorph into
one. Heros don't spend enough time underwater to worry about snakes
hiding under kelp or thrown junk.]
Lastly, alter the "suddenly, you notice a <monster>" message if
monster-vs-monster activity causes one you've just seen going into
hiding comes back out again without any intervening messages. [I'm
not sure whether something similar is needed for the "Wait. There's
something there" message in the you-vs-monster case.]
Fixes#1062
Unlike ground clutter, statues are typically in pretty tight contact
with the ground; statue traps are sometimes proclaimed as "monsters
posing as statues".
This was caused by the mind flayer mind blasting polymorphed hero,
causing them to revert back to human form, and dropping into a pool,
doing an automatic teleport to save them from drowning.
After that the mind flayer tried to hit them in melee, but the hero
was far away.
Recalculate the nearby and inrage variables after mind blast.
Extracted from a larger pending commit. While trying to make sure
that bhitpos and notonhead are up to date when attacks are processed,
I noticed that covetous monster handling was buggy. For dist2(),
a value of 1 means adjacent in an orthogonal direction, so testing
for less than 2 unintentionally excluded diagonal adjacency.
Engraving in an empty doorway and then using locking magic to create
a door there resulted in an impossible warning: "engraving sanity:
illegal surface (23)" if the 'sanity_check' option was On (wizard
mode only). Engraving in an open doorway and then simply closing
the existing door produced the same effect.
Accept engravings at closed doors. Presumably hero will be using
Passes_walls to attempt that so treat closed doors same as open ones.
Update the engraving sanity check to deal with that.
Bonus fix: engraving sanity checking stopped after the first problem
instead of checking every engraving. Have it continue instead.
Not fixed: vault wall repair and temporary corridor removal does
not delete engravings and can trigger the illegal surface warning if
player engraves before the repairs. I didn't test shop wall repair
but it doesn't have any engr references so probably has the same bug.
... if the boulder is in a position they want to move to.
Shopkeepers, priests, and the quest leader can break one boulder
and then need to take several turns before being able to break
another. Riders can break a boulder every turn.
Previously when monster was interested to pick up an item,
the code went through the whole object chain, so going through
all the items on the level. This caused problems with some games,
for example where the player created thousands of meatballs
in separate stacks.
Changed the code so it now looks at the map locations inside
the search radius, and the stacks in those map locations,
skipping locations as early as possible.
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.
Clean up some of the code for monster deciding what objects
to pick up, removing duplicate code. There should be no real
difference in behaviour, other than monsters now can pick up
one stack of items at a time; previously monster could pick up
gold, then a practical item, followed by a magical item all
in a single turn, although this very rarely mattered.
Not extensively tested.
Code originally from NetHack4.
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.
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
^ ^
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.
Instead of using index() macro defined to strchr, use C99 strchr.
Instead of using rindex() macro defined to strrchr, use C99 strrchr.
If you want to try building on a platform that doesn't offer those
two functions, these are available:
define NOT_C99 /* to make some non-C99 code available */
define NEED_INDEX /* to define a macro for index() */
define NEED_RINDX /* to define a macro for rindex() */
Issue reported by vultur-cadens: Elbereth used to be effective in
inhibiting monster movement when an object was present on the same
spot, but since 3.6.0 it isn't. It only functions that way when the
hero--or hero's displaced image--is present these days. So special
levels that have been using engraved Elbereth to try to protect
objects from monsters haven't been providing any useful protection.
This makes Elbereth that's engraved during level creation work like
it used to in 3.4.3 and earlier: when there's at least one object
on the engraving's spot, monsters who are affected by Elbereth will
be affected. [I'm fairly sure that that behavior started out
unintentionally, as a side-effect of an optimization to only check
for scroll of scare monster when there was at least one item present
which is a necessary condition for such a scroll.]
Old-style Elbereth includes Elbereth chosen as a random engraving
during level creation in addition to engravings specified in special
level definitions. Engravings by the player don't have the required
attribute and player-engraved Elbereth behaves in the 3.6 way.
This ought to be replaced by something more general. Perhaps a new
engraving type not usable by the player?
Fixes#900
A monster which has grabbed you could move away without becoming unstuck
if it hit the "move and shoot" or "helpless" conditions in the dochug
MMOVE_MOVED case (since those lead to early return or break), leaving
the hero stuck to a monster which is no longer adjacent. Put the
'grabber moved away -> become unstuck' stuff at the top of the block so
that it will always be evaluated if a grabber has moved.
I would have liked to move the whole "grabber checks" block up, but I
think it'd change behavior to have the u.uswallow attack come before the
early return for a helpless monster, so I split it up instead.
When a monster did something trying to get out of a boulder fort,
it usually meant teleporting or going down stairs or a hole.
The code didn't check for the action return value, and resulted
in a migrating monster being able to throw a potion at hero.
If a monster cannot move, for example because it's being
blocked off by boulders or walls, it will try to escape by some
method - such as a wand or scroll of teleportation.
The mind blast code was previously a part of dochug().
This commit pulls that code into its own function, and also
happens to eliminate a goto and label with no change in functionality.
This commit removes the gotos from set_apparxy, making it easier to read.
It also cuts out at 1-2 variable assignments on certain calls,
so technically it is an efficiency win as well.
Reported by copperwater: if an engulfer swallowed a mounted hero,
odd things could happen if the hero dismounted. The steed would be
silently expelled and float-down flooreffects were attempted.
It turns out that if the engulfer is classified as an animal (so
purple worm, lurker above, trapper), the hero got "plucked from
<steed>'s saddle" and was forcibly dismounted prior to completing
the engulf operation, but non-animals (vortices, air elemental,
ocher jelly, Juiblex) swallowed the hero+steed intact. The most
straightforward fix to dismounting-while-engulfed issues is to change
engulfing to always pluck the hero from the saddle even when the
engulfer isn't an animal.
If there's no room on the level to place the former steed, it gets
killed off. I looked at changing that to put the steed into limbo,
waiting to migrate back to the current level if hero leaves and
subsequently returns, but that breaks movemon()'s assumption that
when monsters are in the process of moving, only the currently moving
one can be taken off the fmon list to be placed on migrating_mons.
[The recently added monster knockback code violates that assumption
too when knocking the victim into a level changer trap. It needs to
be fixed in one fashion or another.]
Make monsters with magic and gaze attacks avoid hero,
just like spitters and breathers already did.
Some small code cleanup related to the ranged attacks.
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.
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
Switch to using a macro invocation Verbos(n, s) in place of the
flags.verbose checks.
Provide the mechanics for individual suppression of any of the
existing messages that were considered verbose.
Mechanics only - this code update does not provide any means of
setting the suppression bits.
iflags.verbose = 0
is still a master suppression of all the verbose messages.
iflags.verbose = 1
turns on the verbose messages only for those whose suppression
bit is 0 (not set).
Reverse the sense of dochugw()'s new 'X' argument. Use True for the
usual case and False for the special case rather than the other way
around.
Call the special case variant when a monster teleports so that hero
stops occupation if the monster jumps to a position where it becomes
a threat.
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.