The bug was that you could easily displace peaceful sleeping monsters.
The source of this was that there was no check for sleeping in the
attack() function that checks for immobilization.
As well as adding the sleeping check, this logic is modified so that it
makes more sense: if a monster is immobilized at all (sleeping, frozen,
or mcanmove = 0) it always "doesn't seem to move!" You can't randomly
displace it anyway 1/6 of the time.
Sessile monsters who are otherwise not immobilized don't move 5/6 of the
time, but can be displaced with the other 1/6.
When polymorphed into a nymph and melee hit steals items from the
target, the same-gender charm message vs opposite-gender seduce
message is being chosen by hero's base gender rather than nymphs
always being female. The seduce message used dynamic pronouns for
the target monster but the charm message used hardcoded She and her
for female nymph attacking female target. I'm not sure why hero's
base gender is used so left that alone; this changes charm message
to use dynamic pronouns that correctly match the target monster.
Handling botl updates for 'time' was inconsistent. Set the flag to
do that when moves is incremented (where the update is suppressed if
running) or when running stops short.
losehp() would cancel running/traveling if called when in normal form
but not if called when polymorphed, so theoretically you could take
damage and keep on running. I don't have a test case to verify that.
Setting or clearing u.ustuck now requires that context.botl be set,
so make a new routine to take care of both instead of manipulating
that pointer directly.
Fixes#240
Monster versus monster (melee and throwing) didn't handle shades
(need silver or blessed weapon to take damage) or silver feedback
(extra info when silver-haters are hit).
I did a lot of test, revise, re-test but didn't always re-test
everything that had previously been tested, so bugs that I thought
were quashed might have crept in.
Now if a missile weapon "passes harmlessly through the shade" it
will continue on and maybe hit something else. (Regular misses
still stop at the missed target.)
A couple of minor ball&chain changes accidentally got included.
Fixes#218
Hallucinating hero has 75% to be unaffected by a gaze counterattack
that paralyzes. Check for that before checking free action (100%
chance to be unaffected). The only change is that player might get
different feedback when both forms of protection against the gaze.
I moved some stuff around after testing the changes in
58583cacf8 before committing it. It
accidentally ended up with 'gold' always being Null at the first
place it gets used (to vary the feedback when stealing everything
except gold).
Nymphs won't steal gold from the hero (so that their steal-item damage
isn't a superset of lerprechaun's steal-gold damage; straightforward
back when gold wasn't kept in inventory), but hero poly'd into a nymph
would steal gold from monsters.
When cloning a monster, clear the clone trapped and hiding states.
When splitting a monster (eg. a black pudding), the clone could
be placed on a trap, so do mintrap.
When removing a monster from the map, clear the trapped state.
Preserve temporary fake object's previous dknown value by storing it
as a flag value within the m_ap_type field of the posing monster, and
recalling it when it is needed.
This is intended to help eliminate observable differences in price display
between real objects and mimics posing as objects.
98% of this is just switching the code to utilize macro M_AP_TYPE(mon)
everywhere to ensure that the flag bits are stripped off when needed.
Noticed while trying to find the reason for the wildmiss impossible(),
you could be teleported and then drop dead at the destination. A QM's
AD_TLPT hit also does 1d4 physical damage which gets applied after the
teleport. Getting "You die." seemed pretty strange, particularly after
picking the destination with telport control. This makes sure that the
damage will never be fatal when teleport is attempted.
Cleaver's ability to hit up to three adjacent targets could kill a
long worm and then try to cut it in two. When this was first reported
I was unable to reproduce it, but this time I've managed to do so.
But not reliably, so it's hard to claim that it's now fixed. However,
the new report's explanation of why it happens and suggested fix was a
big help. I had been trying to hit three tail segments, but you need
to attack a segment next to the head, then have Cleaver hit and kill
the head first (50:50 chance depending upon whether current swing is
clockwise or counter). Worm cutting would be looking at the location
of the targetted segment but there won't be any monster there when the
head dies. (Cleaver's attack itself already copes the situation where
its 2nd and/or 3rd potential targets aren't there any more by the time
it's ready to try to hit them.)
This is based on the multiple-RNGs code fron NetHack4, but using
only the parts relevant to the display RNG (and with substantial
changes, both because of post-3.4.3 changes, and because Nethack4's
display code is based on Slash'EM's rather than NetHack's).
I did much of this quite some time ago, as prequisite for a different
bug report about monsters vs shades, then set it aside. It ended up
being more complicated than I anticipated.
When deciding whether various non-weapon attacks might hit a shade,
hmonas() was not checking for blessed or silver armor that should have
been applicable. It did check boots when kicking, but not gloves or
rings (when no gloves) when touching, or outermost of cloak/suit/shirt
when hugging, or helmet when head-butting. (The last one is actually
moot because nothing with a head-butt attack is able to wear a helm.)
The problem was more general than just whether attacks might hit and
hurt shades. Various undead and/or demons are also affected by blessed
and/or silver attack but weren't for non-weapon attacks by poly'd hero.
At least two unrelated bugs are fixed: a rope golem's AT_HUGS attack
gives feedback about choking but was fully effective against monsters
which fail the can_be_strangled() test. And it was possible to hug a
long worm's tail, rendering the entire worm immobile.
The report also suggested that all artifacts be able to hit shades for
full effect, but by the time shades are encountered everyone has an
artifact so that would nullify a shade's most interesting ability.
TODO: monster against hero and monster against other monster need to
have similar changes.
Extracted from a larger patch: the only way to get silver damage
bonus from attacking with a shield of reflection (polished silver
shield) is to throw it or to wield it. Give different feedback when
hitting something while wielding a shield (or an iron ball; it seemed
appropriate despite having nothing to due with wanting to dish out
silver damage).
Regular two-weapon requires that both weapons actually be weapons or
at least weapon-tools. Simulation of that while polymorphed allowed
any one-handed object as the primary weapon.
This fixes the weapon related aspects of #H7980: having an alternate
weapon be used in cases where it shouldn't when polymorphed into a
monster form with multiple weapon attacks. The most egregious was
using an off-hand artifact, but it would also use off-hand two-handed
weapon, off-hand silver weapon when in silver-hating form, or any
reasonable off-hand weapon when wearing a shield. That last is iffy
whether or not to allow, since you'll still get the extra attacks
whether it switches to secondary weapon or stays with the primary.
I've made it re-use the primary since two-weapon mode doesn't allow
a shield. The other oddity was being able to use the secondary
weapon on the second swing even if the first swing was weaponless.
I went with ingoring the secondary weapon if there's no primary one
or if the primary is two-handed.
Report included "cursed secondary doesn't weld" but that has nothing
to do with polymorph attacking. I've changed that to drop the weapon
if you attack with it when it's cursed, similar to what happens when
secondary weapon becomes cursed while two-weaponing.
It also included "marilith's attacks beyond the second don't use any
weapon and can hit cockatrices without touching them". A marilith has
two weapon attacks and then four claw attacks. Claw attacks only use
the weapon if it hasn't been used yet, so marilith hits with primary,
secondary (or primary a second time if no secondary), claw, claw,
claw, claw and that's the intended behavior. It is able to hit
cockatrices if wielding anything at all, same as a monster with just
a single attack. Since it is impossible to wield six weapons or three
pairs of gloves, that has to be intended behavior too. Playability
trumps realism even if it is silly to hit without a 3rd through 6th
weapon and be safe from touching the target due to the 1st weapon or
one pair of gloves. [Situation is different from having no control
over unsafely biting something after making a safe weapon or claw
attack; perhaps a better solution would be to refrain from using the
four claw attacks when attacking something that is fatal to touch.]
Reported 14 months ago, a monster reading a scroll of earth which
dropped a boulder that killed another monster in an adjacent pit
was giving credit/blame to the hero and could also trigger a panic.
If the monster was killed, the pit would be filled and deleted via
m_detach and then when flooreffects tried to delete the same trap,
it accessed freed memory and deltrap could panic.
When SEDUCE is disabled, instead of swapping attacks in mons[] once,
do it on the fly in getmattk() whenever needed. That allows mons[]
to become readonly, although this doesn't declare it 'const' because
doing so will require a zillion 'struct permonst *' updates to match.
This seemed trickier than it should be, but that turned out to be
because the old behavior was broken. Setting SEDUCE=0 in sysconf or
user's own configuration file resulted in all succubus and incubus
attacks being described as monster smiles engagingly or seductively
rather than hitting (while dishing out physical damage). I didn't
try rebuilding 3.4.3 to see whether this was already broken before
being migrated to SYSCF.
Dropping an existing fragile item while levitating will usually
break it. Getting a new wished-for fragile item and dropping it
because of fumbling or overfull inventory never would.
Some callers of hold_another_object() held on to its return value,
others discarded that. That return value was unsafe if the item
was dropped and fell down a hole (or broke [after this change]).
Return Null if we can't be sure of the value, and make sure all
callers are prepared to deal with Null.