Re-use the array allocated for iterating over all monsters during
monster movement much of the time. It was being allocated from
scratch for each round of monster movement, then freed after they
moved, then repeated the next round.
While hunting for a memory leak in object allocation--which I haven't
found yet--I discovered one in monster movement. iter_mons_safe()
allocates an array of (monst *) pointers for the monsters on the
current level, loops over that array to call a function for each
one, then frees the array. But if the game ends while that called
function is running, execution never returns to iter_mons_safe() so
it wasn't able to free the memory.
Since that can happen at most once per game, it wasn't a signifcant
leak. This fixes it anyway.
There was a second issue: make sure that iter_mons_safe() doesn't
call alloc(0) to make the temporary array for zero monsters when
there aren't any on the level. That might not be able to happen for
monster movement but the routine is written to be more general than
just movement. alloc(0) could confuse the MONITOR_HEAP code. In
C89/C90 I think malloc(0) is allowed to return NULL (don't recall
for sure; maybe that was just known pre-standard behavior for some
implementations). Null return would trigger a panic even without
MONITOR_HEAP. Don't know about C99 and later.
Consistent with their mythological role of punishing those who had
violated societal taboos -- oathbreakers, hosts who attacked their
guests, etc -- erinyes scale with the cumulative amount of alignment
abuse the hero has committed over the course of the game. This is
tracked separately from the alignment record, and cannot be cleared by
the hero improving her favor with her god via "good deeds" as the normal
alignment record can. Erinyes will gain abilities, levels, and attacks
as the hero's alignment abuse worsens. They will also aggravate
monsters when near the hero.
Pull request by mkuoppal: some objects which use the corpsenm field
to access the mons[] array can have a corpsenm value of NON_PM (-1)
and weren't avoiding array access in those cases.
In addition to a fixes entry for it, this makes some revisions to the
commited code, handling a few of the cases differently.
Closes#1175
corpsenm can be -1 (for EGGs and TINs) so touch_petrifies
using this as index would point to bad entry.
Fix this by making mstoning as helper function and bailing
out early if corpsenm <= LOW_PM (while keeping MEDUSA as is)
Issue reported by Umbire: an engulfing monster capable of passing
through iron bars (vortices and air elemental) could do so while
carrying the hero.
Prevent an engulfer from doing that unless the hero happens to be
polymorphed into a subset of the types of monsters that can move to
iron bar locations.
Fixes#1192
Adds a new boolean option, accessiblemsg. If on, some game messages
are prefixed with direction or location information, for example:
(west): The newt bites!
(northwest): You find a hidden door.
I added the info to the most common messages, but several are
still missing it.
Issue reported by Umbire: reviving a human corpse into a human
monster and then killing it entails murder penalty even when it is
hostile.
This is probably a non-issue. Human monsters tend to not leave
human corpses, they leave shopkeeper corpses or sergeant corpses
and so forth. Most human corpses created in normal play have
montraits attached and revive as a zombie, mummy, or vampire rather
than as a human.
This doesn't attempt to be clever, it just treats PM_HUMAN like
role monsters, not subject to 'murder'.
Closes#1180
Some functions are passed an obj or monst chain,
and the callers typically don't check them
against 0, so mark them explicitly as NO_NONNULLS
(NO_NONNULLS expands to nothing, but it flags that
some null arg analysis has been done)
Donning elven boots while riding and not already stealthy, you'd get
the message "you walk quietly" when not walking at all. Instead of
just changing the message, make riding a non-flying steed block
stealth. Riding a flying steed (or one you take aloft with an amulet
of flying) does not. It would have been quite a bit simpler to have
made riding anything block stealth, but the hard part is done.
Fixup some of the inconsistently formatted code that has been
introduced recently or been building up for a while. Done manually.
I wasn't systematic except for looking for lines ending in '&' or '|'
(which wouldn't find such things if they're followed by a comment)
so there might be lots more. I changed a bunch of C++-style //...
comments to old style C /*...*/ so that they'll match the rest of
the core's code rather than because they shouldn't be used.
Playtesting has shown that there is too much permafood in the game
at present: in the late-game the only food-related problem is how
much to carry in order to avoid burdening yourself. In the early
game, food could previously have been a problem prior to
Minetown/Sokoban (thus the recent commit to add a guaranteed ration
in the upper dungeons), but past that point, there is easily enough
food generated on the ground. Additionally, the recent commits to
make healing sources more available in the early game reduce the
amount of time that needs to be spent waiting to heal, thus
further reducing food requirements.
The main purposes of food as a mechanic are to given an incentive
to press onwards and to discourage grinding. However, if monsters
are deathdropping non-corpse permafood, then beyond the very
early game, grinding actually generates more food than it uses up,
so the nutrition mechanic doesn't do its job properly.
Playtesting (including a full ascension!) has shown that there is
still plenty of food available even without deathdrops available
(my test game had 8 spare non-deathdrop food rations upon reaching
the Castle, at which point nutrition is no longer an issue due to
the Castle food stores and the huge numbers of C- and K-rations
dropped by the soldiers). I will address the potential problems
this causes for vegetarian Monks in a future commit.
Various places checking for whether a monster was on the map based on
mstate flags were inconsistent about which ones they checked (and then
place_monster() was additionally inconsistent with all of them about
which bits were cleared when placing a monster onto the map). I think
some places were also more convoluted than is now necessary because they
date back to mstate being an alias for mspare1, which it shared with
migflags before those became two separate dedicated fields (MSTATE_MASK
also dates back to this and is no longer used, so I removed it).
I tried to go through all the MON_foo mstate bits, understand when/why
they are set, and make the various functions I noticed more consistent
(with each other, and with my understanding of how the bits work) about
how they are treated. I don't know for a fact that I understood
everything right -- some diagnostic bits that aren't used for much of
anything, like MON_OBLITERATE, had me mystified until I read the 5ee78c5
commit message -- but this patch hasn't caused any new problems (sanity
check or otherwise) with the fuzzer in my testing so far. All the same,
it could probably use review by someone who has a good sense of what the
mstate bits mean.
Change 852f8e4 by requiring a minimum impact before a buried zombie
nearby will be disturbed: light, but still excluding things like
scrolls, if it's a violent impact (dropped while levitating, thrown, or
kicked), and fairly heavy if the hero is just placing the item on the
ground normally.
Moving the call out of flooreffects meant it no longer applied to
pushing boulders around, so have moverock disturb nearby zombies. I
additionally had wake_nearby do the same thing.
Finally, I renamed check_buried_zombies (which doesn't really reflect
what it does) to disturb_buried_zombies.
Reported by a hardfought user, a ceiling_hider monster hid on the
Astral level, triggering a sanity check warning that gets repeated
each move until the hider comes out of hiding. Normally sanity_check
can only be set in wizard mode, but hardfought must force it on for
to-be-3.7.
I was able to reproduce it before this fix and unable to do so
afterward, but there is a random factor involved hence no guarantees.
I think that lack of ceiling for Astral is recent, but this could
have happened on other levels which lack a ceiling. I didn't try to
figure out whether it might happen with 3.6.x, just put the fixes
entry in the "exposed by git" (found in code not yet released, that
is) section.
If you killed a second high priest (either two on Astral or first in
the Sanctum and another on Astral) the livelog/#chronicle message
would report "killed high priest of Foo (2nd time)" even though the
first was the high priest of Bar, or even just "killed high priest
(2nd time)" if second kill happened when not adjacent.
High priests pass the 'unique monster' test (even though they aren't
actually unique--there will be four of them) so get logged for killing
such. Always report "killed high priest of Foo" and only do so if the
specific high priest[ess] monster hasn't been revived and re-killed.
Logging deaths of unique monsters normally reports the 1st, 2nd, 3rd,
5th, 10th, and various later instances. If you were to kill Moloch's
high priest and all three on Astral, the last one wouldn't be logged
because 4th instance gets skipped. This forces each one to be treated
as the 1st (provided that the mrevived flag is clear), so for logging
purposes it will now behave as if there are 4 distinct high priests.
Don't use "slither" for movement action when observing an aquatic
monster go into hiding underwater. Use "dive" instead.
Shark, pirahna, and jellyfish had been flagged M1_SLITHY but aren't
anymore. Giant eel and electric eel are still M1_SLITHY and kraken
wasn't and still isn't.
There may be some odd cases that used to use slither and it went by
unnoticed where now use of the default verb might become noticeable.
I saw this in the YANI archive, and I think it's fairly interesting.
Doppelgangers are known for commiting identity theft, but in NetHack
they function as just another shapeshifter. This commit makes them
a bit more interesting, I think.
Original YANI by aosdict and Andrio.
Pull request #1005 introduced some code that needed minor reformatting.
This goes beyond that, splitting the livelog/#chronicle handling and
the vampire unshifting code out of mondead() into separate routines.
The livelog phrasing for death of a unique monster always assumed that
the hero was directly responsible:
"killed|destroyed <unique mon|shk+details> (Nth time)."
If it dies while monsters are moving, switch to:
"<unique mon|shk+details> has been killed|destroyed (Nth time)."
It isn't phrased as if the hero is responsible if the monster dies due
to passive counter-attack against poly'd hero but that isn't blatantly
wrong and doesn't seem worth worrying about.
The livelog message includes the shopkeeper's shop type, since the
livelog for stealing also mentions the shop type.
Only the first kill per shopkeeper is logged.
Noticed when testing erodeproof Mitre of Holiness: the cloud of
stinking gas released by Nalzok when he died ending up killing my pet
and my hero got blamed for that. Don't blame--or credit--the hero for
monsters affected by the gas cloud when a dying nemesis produces such.
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".