Spotted by Janet: in the ``using #monster to breath[e] at self''
patch I accidentally reversed the Half_spell_damage adjustment (to breath
only from non-breath attacks only, not by doubling instead of halving
damage :-). Changing it to include zaps by the hero is intentional.
When testing the monster-breath-at-self patch I noticed that trying
to cure green slime by having hero breathe at self didn't work. The code
was calling buzz() with arguments that produced an attack directed against
the hero's location, but there was a chance for it to miss outright and
when it didn't, reflection would block it. This makes breathing at
yourself with `#monster' comparable to zapping a wand or casting a spell
at yourself: it always hits.
Extend defense against being turned into slime to monsters who can
breathe fire. Other attack types which dish out fire damage didn't seem
suitable for this.
Move some of the singular<->plural transformations from code to data.
Also fixes one more missed singularization: lurkers above. A big chunk
of this is just a bit of minor reorganization: moving otense() & vtense()
next to makeplural(), and moving the wishable subranges array from between
makeplural & makesingular to in front of the wishing code.
I was going to redo makeplural to use the same style as makesingular
(switch from ``len >= N && !strcmpi(buf, spot-(N-1))'', with spot pointing
at final character, over to ``BSTRCMPI(bp, p-N)'' which tests p-N against
bp as the bounds check and has p pointing to the string's terinating '\0')
but have decided not to tackle that.
Extend makeplural/makesingular case-insensitivity to vtense() and to
wizard mode wishing for dungeon features. And the previous set of fixes
missed one: makesingular("zombies") was producing "zomby". Plus a bit of
groundwork for a likely second overhaul of makeplural/makesingular.
I stumbled across a copy of an old newsgroup bug report which
complained that wishing for "Gauntlets of Power" didn't work. I thought
that this was something which had already been fixed, but when I tried it
out, I discovered that you still couldn't wish for that. It was failing
because case-sensitive makesinglar() didn't recognize that "Gauntlets"
needs special handling. After the unwanted transformation, the case-
insensitive object matching would fail to find "gauntlet of power".
Removing case-sensitivity for special cases like "boots" and "gloves"
would have fixed that, but this patch goes further and removes case-
sensitivity entirely for both makesingular and makeplural. Words which
get their endings modified work when the input is upper or mixed case.
Any modified letters retain the case of the original, so the reason for
case-sensitivity--user specified fruits that aren't lower case--is covered.
Some makeplural fixes: the plural for dingo is dingoes (dictionary
says "-es", not "-s") and for roshi is roshi (just guessing here; most of
the Japanese names use same spelling for singular and plural, but we were
producing roshis). Several words which makesingular leaves in plural form
(boots, gloves, &c) are now recognized by makeplural (avoiding gloveses).
It also fixes a bunch of incorrect singularizations of plural monster
names: foxes, *wolves, lynxes, fungi/humunculi/succubi, mumakil, wumpuses,
baluchitheria, Aleaxes, *elves, erinyes, djinn, priestesses, & valkyries.
Some non-monsters that makeplural handles correctly were also not being
singularized right: feet, hooves, lice/mice, algae, children, nemeses.
For an explosion caused by the player while the hero is engulfed,
skip adjacent monsters. Also, don't give "you hear a blast" when an
unseen explosion is caused by a scroll of fire (explosion is always unseen
when hero is engulfed, regardless of explosion's cause). [Offhand I'm
not sure whether something other than the player can trigger an explosion
while the hero is engulfed.] Lastly, round up instead of down when a
monster takes half damage, so that non-zero can't be reduced to zero.
Like their use of lizard corpses to defeat being turned into stone,
let monsters use wands of fire, fire horns, and scrolls of fire to try to
defeat being turned into slime. If the scroll is read while confused, it
won't succeed. Otherwise, monsters who don't resist fire will take some
damage in the process and might end up killing themselves (although with
the testing I've gone I've yet to see that happen--I guess that means
that handling for dying-in-the-process hasn't been adequately tested...).
So far, they don't know how to jump onto adjacent fire traps, nor
will fire breathing monsters breath at themselves. I don't know whether
I'll get around to tackling either of those.
New macro slimeproof() to decide whether something is susceptible
to turning into green slime. Most of this is just making use of existing
cached permonst values in damageum() and mdamagem() and shouldn't affect
anything. I wanted to avoid mixing that in with the actual slime changes
which are coming.
Something that pops up in the newsgroup periodically, with <Someone>
inevitably pointing out the bit of code that the user needs to tweak,
about control of feedback when hero is walking across floor objects.
Implement new option ``pile_limit'' which allows user to set the point
at which the game switches from listing the objects to giving "there are
several/many objects here". Default is 5, same as previous hard-coded
value (1 object gets listed via pline, 2..4 are listed in a corner popup,
5 or more objects yields a pline message instead). Setting pile_limit
to 0 means no limit, so objects will always be listed regardless of pile
size. Setting it to 1 effectively forces no listing since any non-empty
pile size is always at least that big, so can produce "there is an object
here" even though that's no briefer than a pline() to show one object.
From a bug report: moving while blind
and gloveless onto spot containing a cockatrice corpse is fatal if there
are fewer than 5 items there, but harmless when you get the "there are
several/many objects here" result for 5 or more. I thought that this was
something which had already been changed, but it wasn't. Run a touch
check on the whole pile of objects even when no object-by-object feedback
is being given.
Trunk only because it's using the trunk version of corpse_xname().
Noticed while testing a patch for touching cockatrice corpses;
corpse_xname(,, CXN_ARTICLE) would produce "a cockatrice corpses" when the
object stack quantity was greater than 1. (This applies to the post-3.4.3
expansion of corpse_xname() in the trunk code, so no fixes entry.)
While updating discard_minvent I noticed that m_useupall is using
the wrong routine to get rid of a monster's weapon. It probably doesn't
matter since I don't think monsters can use up items they're wielding or
wield items they could use up.
Genociding * to clear a level in wizard mode, or paying off a
shopkeeper to dismiss kops in any mode, could trigger the recently added
warning about deleting worn items in obfree(). mongone -> discard_minvent
wasn't bothering to unwear/unwield monster gear before deletion.
From a bug report, mimics
which were exposed at the time the hero leaves a level remain unhidden
upon return no matter how long the hero is away. It was actually expected
behavior since the old level is stuck in stasis and hiders only hide when
it's their turn to move, but it was noticeably odd. This makes unhidden
hiders attempt to hide when hero returns to a previous level or enters a
bones level. I reorganized the monster handling in getlev() because the
relevant part was taking place before floor objects got restored, so
hidesunder() monsters had nothing to hide under at the time.
From a bug report: rogue's backstab bonus
(extra damage when foe is fleeing) doesn't apply when dual-wielding but
does apply to thrown weapons--unless both conditions apply. Having it
apply to throwing is too powerful. Elbereth makes it trivial to get
monsters to flee and a rogue with expert dagger skill can throw up to 4
of those at a time, so a level 30 rogue could get rnd(30) bonus 4 times
in a single attack. This makes the backstab bonus only applicable to
melee and polearm attacks.
There was a suggestion in the newsgroup that if you use the 'f'
command when your quiver is empty, that whatever missile you supply to the
"what do you want to throw?" prompt be automatically put into the quiver.
This implements that, and separates most of the common code from dothrow()
and dofire() into a separate routine. A post-3.4.3 change to dothrow() to
require hands for throwing wasn't propagated to dofire(). With the common
routine, they're much less likely to get out of sync like that.
This is going into the branch as well as the trunk because the hands
checking mismatch was added there too.
Suggested by <Someone>: in the special level compiler, support
"random" in addition to "open" and "closed" for a drawbridge's inital
state. Drawbridge shares code with door, so the necessary parsing was
already present. This just treats random as valid for drawbridge instead
of explicitly rejecting it, and makes the special level loader process it.
He also suggested that the two drawbridges on the bottom level of
the Valk's quest be changed from open to random, but this patch doesn't
go that far. I think it's a good idea, but since the player can't use a
musicial instrument on those bridges, this has more impact on game play
than it might at first seem. I don't really want to see Valkyries be
required to use magic for occasions where both bridges start out closed.
A couple of things noticed when looking at the death-by-brainlessness
code. The 3.4.3 code ran a loop while life-saving was keeping the hero
alive, which would work if someone added other sources of life-saving than
the amulet but not if they added some form which didn't get used up when
it kicked in. Post-3.4.3, the dev code eliminated the loop but was no
longer guarding against additional forms of life-saving. This attempts to
clear the relevant field once any form of life-saving takes effect (for
brainlessness). It's not perfect since someone could change `Lifesaved'
to look at something other than the hero's properties, but at least it
still avoids the risk of getting stuck in a loop if someone makes a really
bad customization.
Also, make life-saving use min(2*level,10) instead of flat 10 for
amulet or 8*level for explore/wizard survival when it saves someone whose
max HP have been clobbered somehow. Other places assume that 1 HP per
level is the lowest the hero will have; saved-life gives a modest bit more.
Lastly, some post-3.4.3 code to make ghosts/shades immune to brain
sucking was using mon_nam() to start a sentence; Monnam() is needed there.
Reported--more or less--by <email deleted>:
chargeable rings don't show up as likely candidates in the "what do you
want to charge?" prompt. They're supposed to be there once the type has
been discovered but it was using the wrong field so basing that on whether
the player had assigned a name to the type instead. (Picking a chargeable
ring's letter even though it wasn't listed did work correctly though.)
Noticed while looking at something else: zapping a wand of opening
or spell of knock downwards while riding causes your steed's saddle to
fall off, which in turn causes the hero to fall and take some damage.
If that damage was fatal, the saddle would be left worn in bones data.
This reorganizes mdrop_obj() to defer until last the part that ultimately
makes the hero fall off, and changes bhitm() to call that instead of
handling saddle removal inline, also gives new saddle-off feedback there.
The patch made a month ago to handle remaining at a lava or pool
location without moving had a problem with being in pools of water. It
was yielding "But you don't drown. You touch bottom." if you had magical
breathing and took actions other than moves. I think it's fixed now.
[New bug, or rather newly noticed old bug: slowly sinking while being
stuck in lava doesn't notice if you lose fire resistance and ought to be
burned up immediately. Also, fully sinking into lava doesn't appear to
burn up equipment--unless it's done in the bones handling--the way that
falling directly in without fire resistance does.]
Reported in Dec'04 by <email deleted>, the
monster spell "summon nasties" could mistakenly give a message of "a
monster appears" instead of "monsters appear" when more that one monster
gets summoned. Some of the candidate monsters for nasty() can produce a
group from makemon(), as can ones for msummon() which nasty() sometimes
calls in Gehennom. Compare the number of monsters before and after the
creation attempt(s) instead of assuming makemon() creates one at a time.
I don't know whether other routines face the same mis-count issue,
but I suspect there may be several.
Reported in Dec'04 by <email deleted>,
salamanders are capable of using items and of eating green slime corpses
without being transformed into slime, but would not pick up nor eat such
corpses to recover from being turned into stone. Now they will. Also,
monsters who are able to open tins (mainly via carrying a dagger or knife)
will pick up tins of lizard and of acidic monsters in order to use those
to be cured from stoning. The latter is already covered by this new
feature entry in fixes35.0 which previously applied only to nymphs:
"some monsters can eat tins in addition to corpses to cure some ailments".
Reported in Dec'04 by <email deleted>, an
unpoly'd hero or a hero poly'd into monster form which lacks a kick
attack both get bonus from rings of increase damage when kicking, but
a hero poly'd into monster form which has a kick attack did not.
My last fix from the Dec'04 report sent by <email deleted>. Many of its remaining observations/complaints are
about things which aren't bugs. This implements the suggestion that
doppelgangers should take on humanoid form, although it doesn't take away
the 1/7 chance for pick_nasty() and it can still fall back to arbitrary
shapes when it doesn't pick a humanoid within 5 tries. This also allows
doppelgangers to take on the shape of the various quest guardian monsters
[mostly the quest leaders' attendants, although there is at least one
extra foe (ninja)]. It excludes the quest guardian for the player's own
role, and I don't think there are any cases where it can yield unexpected
quest guardian behavior.
This also allows specifying monster class (via description or letter)
when #monpolycontrol asks for type of monster to give to a polymorphing/
shapechanging monster.
One of the complaints included in the Dec'04 report from <email deleted> was that spell of charm monster doesn't give
any feedback. This makes that spell, and scroll of taming, always give a
message. And the scroll will become discovered if a visible or sensed
monster gets converted from hostile or peaceful to tame, or from hostile
to peaceful.
Scroll of taming/spell of charm monster didn't hit steed when hero
is mounted; now it does. I don't know whether that matters though. You
can saddle a non-tame monster, but you can't ride one even in wizard mode.
However, I'm not sure whether a tame steed you're already riding can
become untame, let alone if it can do so without throwing you. If latter
is possible then re-taming while still mounted has now become feasible.
Another item from the Dec'04 report sent in by <email deleted>. When prompted for a type of monster to polymorph
into, giving a monster class description like "dog or other canine" (or
single letter like 'd'), triggered "I've never heard of such monsters".
Instead of adjusting the message, this chooses a member from the class.
I put this into the fixes file as a new feature.
Move the code for determining monster class from user's input string
out of do_class_genocide() and into new routine name_to_monclass(). I'm
planning to use it when name_to_mon fails to match anything for controlled
polymorph (not ready for prime time yet).
Also, avoid getting stuck in a loop if hangup occurs while prompting
player for class of monster to genocide. ESC, whether deliberate or fake
input after hangup, will now be the same as specifying "none", throwing
away the genocide opportunity.
<email deleted> reported a long list
of inconsistencies and suggestions. This attempts to address the ones
about werecritters and vampires.
> Polymorphed player does not get werecreature changes. (intentional?)
> Player in were form does not turn into werehuman form, ever. (Previous
> bugged behavior was that player turned into a plain human)
> Player afflicted with a were cannot polymorph into werecreature or
> werehuman form.
The first guess is right; being polymorphed blocks lycanthropy state
changes. The second is not a bug either; hero is either a <werecritter>
when in beast form or a <role> when in human form, never human werecritter
monster. The last one feels more like a bug though; it happened because
all lycanthrope monster entries are marked NOPOLY. This patch extends
an earlier post-3.4.3 change to allow player with polymorph control to
explicitly specify werecritter when in role form or human werecritter when
in beast form to toggle shape. It also allows closely related monsters
to toggle from role to beast (ie, "giant rat" yields wererat).
> Vampire or Werecreature changing form may change sex.
Now the three semi-controlled changes--becoming a dragon due to armor,
toggling were form, and vampire into various critters--are prevented from
having the 10% chance of sex change kick in. For monsters, lycanthropy
didn't apply (sex never toggles) and vampire shifting is now covered but
turning into a dragon due to scales/mail remains susceptible to sex change.
Also, post-3.4.3 code made polymorphing into a vampire enable the
#monster command but neglected to tell the player.
Reported in August by <email deleted>, the code that handles
slower rotting for corpses on top of or buried under ice is misusing its
ROT_ICE_ADJUSTMENT factor such that a value other than the current 2 would
produce incorrect results. Instead of multiplying by 1/N it needs to use
(N-1)/N, which happens to be the same when N is 2. In a second message he
asked about why putting a corpse on ice starts out by subtracting from its
age to make it older, and it took me a while to decide that that is correct
behavior.
No effect on game play since ROT_ICE_ADJUSTMENT remains set to 2.
Zapping cold at an ice location which has a melt timer would set
new timeout to a random value which could actually cause that ice to melt
sooner. Make sure the new value is always at least as big as the old one.
Also, MAX_ICE_TIMEOUT wasn't actually the maximum ice timeout; now it
is--if the generated value is higher, omit the timer so that that ice is
permanent. No fixes35.0 entries necessary; this is post-3.4.3 code.
Reported two months ago by <email deleted>,
having a water elemental become trapped in a bear trap seems pretty
strange. Fixed by marking water elementals as M1_UNSOLID (like air and
fire elementals), which has a side-effect of making them immune to webs
as well. Tweaked some unused digging code which checks unsolid(), added
unsolid() to the types allowed to bar through iron bars, and brought the
check for whether a monster is willing to enter a bear trap location up
to date. That code also needed an update to reflect the change made to
anti-magic traps last year. Lastly, there was another report which
suggested that being hit by a bear trap should dish out some damage
(along with a suggestion that wand of opening should work to escape such
traps, which has already been done). This makes bear trap do 2d4 damage
(on entry, not when trying to pull out after becoming stuck).
Prevent monster with barge-through capability--currently only the
astral Riders--from swapping places with another monster which has that
same capability. Otherwise, if the target one moves after the barger,
it might just repeat the maneuver, undoing the first swap. If there's
no room to move anywhere else--maybe they've barged through a crowd into
a narrow spot--they could get stuck swapping and re-swapping every turn.
I've also allowed swapping with baby long worms and with adult ones
which lack a tail. When testing that, something strange happened and
the displacer was drawn on the map as a long worm tail. mdisplacem()'s
place_worm_seg() must have been responsible, but I don't understand how
the bit of code involved could kick in for a worm without tail segments.
I've reorganized mdisplacem() to avoid this occurrence, I hope....
Also, barge-through swapping with a mimic exposes it as a mimic;
swapping with an eating pet causes the meal to end. No fixes entries;
this is post-3.4.3 code.
Back in <email deleted> complained
that randomly generated giants in Sokoban would drop boulders when killed,
interfering with the puzzle solution. He suggested that giants either
be disallowed or be generated without inventory in that dungeon branch.
This doesn't go that far; it just rejects giants on the first pass during
random monster selection, making them much less likely to appear there
but still allowing them if giant is chosen two times in a row. (Existing
boulders aren't an issue here; giants can't pick them up in Sokoban.)
Back port the trunk fix that prevents stone-to-flesh on self when
wielding a figurine from leaving stale worn object pointer and eventually
triggering a panic or crash. Branch only except for fixes34.4 update.
Back in <email deleted> in #U1216
suggested that statues of stone golems which are hit by stone-to-flesh
spell should leave flesh golem corpses instead of meatballs. But they
should actually have revived as flesh golems. Stone-to-flesh revival of
golem statues and golem figurines didn't work as intended because golems
other than flesh or leather were considered to be vegan/vegatarian, which
caused them to produce meat rather than living monsters. Also, S-to-F of
a leather golem statue worked as intended and created a flesh golem, but
S-to-F of a leather golem firugine created a leather golem out of stone
object. This fixes it so that any type of golem statue or golem figurine
revives as a flesh golem.
Two other bugs noticed and fixed: (1) S-to-F cast on self while a
figurine of a non-veggy monster was "worn" in one of the three weapon
slots triggered an "extract_nobj: object lost" panic similar to several
similar cases which were recently fixed (that was 3.4.3; for development
code, it gave "obfree: deleting worn obj" warning instead). (2) S-to-F
activating a shop-owned figurine didn't charge for it.
Back in Nov'04, <Someone> pointed out that even with only 5%
chance for dropping a horn upon the death of a unicorn which has been
revived from corpse, it's still possible to produce a nearly unlimited
number of them for polypile fodder. This bumps the chance for a horn up
to 50%, but flags the horn as coming from a revived corpse and makes such
horns be treated by polymoprh as if they're non-magic (which practically
guarantees that they'll poly into mundane tools instead of magic ones).
From a bug report, walk_path() was
favoring orthogonal steps at beginning of the path and diagonal ones at
end, when intermixing diagonal and orthoganal produced a more accurate
representation of the real path. Only mattered for long distance jumps
3x2 or 3x1 steps away; hurtling always moves in a straight line and short
(2x1 knight) jumps aren't affected by the patch supplied with the report.