Reported by entrez: applying a bullwhip towards a medium or small
peaceful monster used to be an attack but that stopped working when
'safepet' was extended to peacefuls in order for the hero to be able
to swap places which those. Also, side-effects were different when
hero applied the whip from within a pit compared to when not in one.
This allows the hero trapped in a pit to try to snag furniture or a
boulder even when a small or medium is present, and escaping that
pit if successful. (It still snags big monsters in preference to
furniture/boulder at their location.) When no such non-monster
target is available, it attacks the monster if hostile or peaceful
but not when tame. When revealing a previously unseen monster it
prevents snagging that monster's wielded weapon because hero couldn't
possibly target the weapon in that situation.
This makes other changes, mostly dealing with finding and exposing
concealed monsters, which may introduce some new bugs.
Since I was already in the right place, implement snagging an item
off the floor while flying. It isn't necessary since a flyer can
pick things up off the floor directly, but there isn't any pressing
reason to disallow it. Supersedes the commit in pull request #632
by RojjaCebolla.
Closes#632
3.6.1 changed a bunch of messages in shk.c to give the actual shk
name even when a the shopkeeper couldn't be seen, to avoid things
like "You owe It <N zorkmids> for <item>." But there are various
messages issued outside of shk.c which were overlooked. Fix those.
Closes#642
Simplify a glob handling bit in a recent shrink_glob change used when
catching for lost time upon returning to a level.
Revise a clumsily worded fixes entry.
Fix a comment typo in makedefs that's been there for a bunch of years
now. It's been within the diff context for several recent patches
and I still hadn't noticed it until just now.
Populating some of the types of special rooms can pick monsters that
sometimes come in groups, and getting a group could have some members
spill out of the room (or inhibit other random choices by filling some
spots that haven't been populated yet, preventing subsequent monster
creation there).
The misbehavior isn't new so it seems surprising that no one has ever
previously reported this.
Closes#640
of Sky
Add a page citation for Monstrous Regiment passage 1 and add four new
passages, bringing its total to 12.
Add two new passages to A Hat Full of Sky, bringing its total to 13.
Solve the uneven distribution situation that has been present for
picking random rumors for a long time and for random engravings,
epitaphs, and hallucinatory monster names since 3.6.0. This relies
on the previous partial solution where short lines have been padded
to a longer length. When that length is N and random seek lands in
a long line of length L, retry if the position is in the first L-N
characters. Put differently, it if takes more than N characters to
reach the next newline, reject that random seek and try again. This
effectively makes long lines behave as if they had the same length
of N as the short lines have been padded to and when all lines are
the same length, all entries have the same chance to be chosen.
While testing 'the("Capitalized Hallucinatory Monster")' I noticed that
some hallucinatory monsters showed up more often than others. When
the random engravings, epitaphs, and bogus monsters were converted from
hard-coded arrays to data files accessed by random seek (3.6.0), they
became subject to the same distribution irregularites that rumors suffer
from. The chance that an entry will be chosen depends upon the chance
that a random seek will hit somewhere in the line which precedes it, so
entries that follow long lines are more likely to be chosen and entries
that follow short lines are less likely. We improved that for rumors
by having makedefs pad the shortest lines. Distribution still isn't
uniform but is much better than it was (and could be further improved
with a longer padding length at the cost of making data files bigger so
possibly slower to access; both overall size and access speed mattered
back when floppy discs were supported but are probably irrelevant now).
Start doing the same thing for the newer files: pad the shortest lines
to increase the chance that seek will find them. The tradeoff is that
the data files become bigger. Rumors, engravings, and epitaphs lines
are all at least 60 characters now; bogus monsters are at least 20.
These are the data file sizes I see (in bytes: old, new; padding for
rumors was already in use so its size hasn't changed):
bogusmon 4449 7211
engrave 1326 2894
epitaph 14159 24075
rumors 49173 49173
The only place that padding is noticeable in-game is #wizrumorcheck.
A shop-owned glob picked up by the hero was added to shop's bill
and if that shrank to nothing it moved from the unpaid portion to
used-up portion as intended. But once there it retained obj->owt
of 0 and if 'sanity_check' was enabled, that triggered a warning
every move until finally paid for. Both the 'Ix' list of used-up
items and itemized shop billing revealed a weight of 0 aum if
'wizweight' was enabled.
Keep track of the weight a glob had when it becomes unpaid, then
reset from 0 to that amount if it becomes used-up. This overloads
the obj->oextra->omid field which is an unsigned int previously
only used for corpses. Now for globs it is pre-bill obj->owt which
is also unsigned int. I didn't add new oextra access functions for
it; it is only used in two places and existing omid ones suffice.
Reported by entrez: when fruit name is given the name of an artifact
that doesn't use "the" at the start of its name, messages about the
artifact could be altered. Example was fruit=Excalibur causing usual
|You are blased by Excalibur's power!
to unintentionally change to
|You are blased by the Excalibur's power!
because of a false match during special handling for named fruit in
function the().
This fixes that, and also changes basic inventory formatting. Former
|f - an Excalibur
will now be
|f - Excalibur
for a fruit that has been assigned that name. When sort pack in On,
as it is by default, that will be listed under Comestibles rather than
under Weapons so really shouldn't fool anyone. And
|f - 2 Excaliburs
also breaks the illusion.
This formatting change only affects named fruits. User assigned names
for object types or for individual objects behave the same as before.
Noticed while testing revised "the" handling and trying to trigger
"you can't polymorph into [the] Oracle", if the character was human
it would turn into a new man or woman instead of having the unique
form be rejected.
Function the() wasn't supposed to be used for monsters because many
of the ones with capitalized names confuse it, but over time multiple
instances of the(mon_nam()) have crept into the code. Instead of
ripping those out, modify the() to handle that situation better.
Pull request #636 by entrez dealt with this with one extra line of
code, but could end up scanning all the names in mons[] repeatedly
if the("Capitalized string") gets called a lot. This uses a similar
one line fix but calls a whole new routine that scans through mons[]
once collecting all the relevant special case names. As a bonus,
it does the same for hallucinatory monster names which name_to_mon()
couldn't handle.
Fixes#626
Fixes entry for pull request by entrez. If poly'd hero is wearing
an amulet of magical breathing, avoid gradually losing hit points
while out of water when in aquatic form. You won't be able to put
on an amulet of magical breathing if already in aquatic form, but
you could have one carry over from being worn in some other form.
Implemented for monsters too but won't have any effect during play
for them because they never use that particular type of amulet.
Closes#635
Reported by Vivit-R, the chance of freeing a monster from being
trapped in a web was very small and failure resulted in creation of
a new web at the hero's spot, eventually making it impossible to
attempt to #untrap the monster (if hero escaped the new web and moved
to another spot adjacent to trapped monster, eventually surrounding
it with webs). [That's actually misleading. Escaping the new web
but staying at the same spot lets the player try again; repeat as
needed.... But chance of failure still seemed way too high.]
This reduces the chance of failure from 29/30 to 6/7 and makes the
chance of spreading the web after failure be 1/3 instead of 100%. It
also supplies missing feedback about the monster still being trapped
if the attempt to make a new web fails.
Closes#608
If the hero left a level that had globs on the floor or in floor
containers or being carried by monsters and stayed away for a
while, returning to the level only shrunk them by one unit of
weight. Account for all the time away. The complexity of this
has steadily grown; I hope its peak has been reached.
I had wizweight On when testing glob changes and noticed
|Slasher drops a gold piece (0 aum).
Coins are supposed to weigh 1/100 of a unit, and the calculation
rounds rather than simply truncates any fraction, but that still
yielded 0 for quantities of 1..49. Force any non-zero stack of
gold to weigh at least 1 unit.
Also, add a check for attempting to weigh a quantity 0 or less
(of anything, not only for gold) just in case.
Globs never rotted away but did become tainted after a relatively
short while, which seemed like a contradiction. Change them to never
be tainted but shrink by 1 unit of weight approximately every 25
turns. An ordinary glob (one that hasn't combined with any others)
starts out weighing 20 units, so it takes about 500 turns to vanish.
That's roughly twice as long as a corpse takes to rot away.
Shrinking globs give feedback when in hero's invent or in a container
in hero's inventory, but rarely (when going from an exact multiple
of 20 weight units; that is, from integral number of N globs to
N-1 + 19/20, or if weight reduction triggers an encumbrance change).
When a glob goes away completely, there is feedback for those two
circumstances and also for seeing the glob vanish from the floor.
I haven't touched how much nutrition eating a glob confers. I have
changed formatting of glob names to use "small", "medium", "large",
"very large" instead of "small", [no adjective], "large", &c. You
still need to have at least five globs coalesced together for the
adjective to become "medium", same amount as before.
I don't think EDITLEVEL needs to be modified but have incremented it
anyway to play things safe.
Add a page citation to passage #1 of Night Watch, and add five new
passages, briging the total to 12.
Add four new passages to The Wee Free Men, bringing the total to 13.
Reported by Vivit-R with comments by several others. The prize item
in one of the closets off the Sokoban treasure zoo is sometimes
missing, most likely picked up by an elf who won't be dissuaded by
the presence of engraved Elbereth or a scroll of scare monster.
This fix prevents monsters from targetting the mines' and sokoban's
prizes for pickup (or for eating). Once the hero picks either of the
prizes up, they stop being prizes and will be ordinary monster fodder
if dropped/stolen/stashed.
One of the comments by copperwater suggested this approach as a
possible way to fix things. I had already implemented it from scratch
before noticing that. It handles the usual monster behavior toward
items, but there could easily be some unusual cases still susceptible
to taking the prize before the hero gets to it. Those are the breaks.
Fixes#603
like the leg hackery, if the baalz level gets flipped during creation
the fixup that modifies the locations in front of the eyes to allow
digging needs to deal with that too.
If the baalz level got transposed during creation, the fixup for
a decorative portion of the map didn't work properly. Monsters
eligible to be created at pool locations could end up trapped in
a couple of inaccessible locations.
[To be fair, the baalz hackery predates level flipping....]
Closes#598
Reported by eakaye. Selection of equipment when creating a soldier
or watchperson can pick a polearm, but random selection among those
had a chance to choose dwarvish mattock which doesn't use polearms
skill and isn't appropriate for a human soldier or watchperson.
Not mentioned, but lance was in the same boat.
Change the selection to only pick something which uses polearms
skill, then make that moot by moving lance and dwarvish mattock out
of the midst of the polearms so that they're no longer candidates
for special case rejection.
A couple of other things which might have had a similar issue were
already ok. Giving a polearm when creating a troll selects between
a few choices rather than among all the polearms. And wishing for
"polearm" only considers items which use polearms skill.
While changing objects.h to reorder the two non-polearms, I removed
a bunch of tabs that were present in the scroll definitions.
EDITLEVEL is incremented due to objects[] reordering, so existing
save and bones files will be invalidated.
Fixes#623
Explicitly un-create a randomly generated artifact if it gets
rejected (too big to include as a treasure drop with a small corpse)
so that it remains eligible for creation later. And when generating
random contents for a new container, explicitly avoid artifacts
(which were already implicitly avoided).
Closes#599
A vampire in bat form was seen via infravision or possibly telepathy,
then when it changed into fog cloud form the feedback was
|You now detect it where the vampire bat was.
The message substitutes "detect" for "see" when the new form can't
be seen and the monster name formatting yields "it" for that case.
Give a vanish message instead since that is effectively what happens.
The pull request by argrath changes weight_cap() to never return a
value less than 1 because try_lift() divides by that return value
and a 0 would trigger a crash. The code involved is used when
attempting to pull a monster out of a pit via #untrap.
I'm fairly sure that weight_cap() can never produce a value that's
less than 1 already, but have put in a variation of the PR's fix.
I've also implemented a different fix that removes the division
from try_lift(). The original code seems to have gone out of its
way to avoid calculating inv_weight() twice, but doing the latter
(for the once in a hundred games where it might happen) greatly
simplifies things by removing details of carrying capacity.
Fixes#621
Reported by G7Nation; attacking walls and such with a polearm just
gave lackluster "you miss; nobody's there" feedback.
Make applying a polearm at some non-monster locations give feedback
similar to using 'F'orcefight with melee weapons. Was
|You miss; there is no one there to hit.
now
|You uselessly attack the closed door.
Also, extend the supported locations to include dungeon furniture.
Was
|You attack thin air. ('F')
now
|You harmlessly attack the throne. ('F')
|You uselessly attack the throne. ('a')
This doesn't address #613: attempting to hit non-visible locations
with an applied polearm.
Closes#614
Reported by entrez, wielding something fragile (potion of acid
perhaps), and using F to smash it against iron bars called breaktest()
directly, then a second time indirectly through hero_breaks() via
hit_bars(). There is a random chance to resist breaking (99% for
artifacts, 1% for other items) so breaktest() might say that something
will break on the first call and that it will not break on the second
call, or vice versa. That could remove uwep from inventory then leave
it in limbo without destroying it, or destroy uwep without removing it
from inventory first triggering impossible "obfree: deleting worn obj".
Engraving with a weapon which has known enchantment or with a magic
marker which has known charge count that decremented the amount did
so without updating the persistent inventory display. Report was
for curses but applied to every interface that can show perm_invent.
This includes some reformatting (mostly
if {
}
else {
}
to
if {
} else {
}
multiple times; also add some new braces after 'if' or 'else' where
one half already had those and the other didn't). And removal of
some unnecessary 'register' designators.
Plus fix up one sanity check which complained if number of charges
being used was more than a marker had, but then let the engraving
continue and decrement the count by that large amount. If that
impossible situation ever occurred, it would result in a marker
with negative charges.
Noticed when testing the "wall_angle: unknown" fix, if there is a
boulder rather than a door in the breach in a vault's walls at the
spot where the guard arrives, the guard would walk onto it, tell the
hero to drop any gold and follow, then move back. The boulder would
remain in the hero's way and couldn't be pushed because the guard was
in the boulder's way. Have the guard smash any such boulder(s) into
rocks when arriving (with no explanation for how that is accomplished,
just a message about seeing or hearing boulder(s) shatter). Later
when repairing the walls, delete any rocks or boulders at all vault
wall locations (even when no gap-to-wall repair is needed).
Reported directly to devteam by entrez via email:
>
> I noticed some potential issues with (melting) ice:
>
> * Digging down into ice, or setting a land mine on the ice and
> triggering it, doesn't remove the melt_ice timeout, so it can result
> in a sequence like dig down -> pit fills with water -> freeze water
> -> freezing water tries to set melt_ice timeout -> duplicate timeout
> impossible. Or if you don't freeze the water again, melt_ice will
> run on a non-ice surface, which might at least produce strange
> messages.
>
> * Setting a land mine on ice: melting ice doesn't do anything with
> the trap, so there is still a land mine which you can trigger by
> flying over the water (the land mine's trigger is also still
> described as being 'in a pile of soil', despite being underwater at
> this point). Similar thing happens with bear traps.
>
> * Not really related to _melting_ ice, but an exploding land mine
> doesn't reset the typ from ICE to FLOOR (like normal digging does),
> so it will result in a square with a pit that is also an ice square,
> where the ice can melt under the pit and produce a combination
> pit/moat. If you then freeze the moat, the pit reappears on top of
> the ice.
https://github.com/NetHack/NetHack/pull/573 by entrez
Pull request comment states:
"Moving into a position containing a warning symbol with m-<direction> to
'safely' move would still attack as though the 'm' prefix was not
specified. Ensure warning symbols are counted as 'detected' monsters
for this purpose, to avoid falling through to do_attack()."
Closes#573
https://github.com/NetHack/NetHack/pull/592 comment states:
"In commit db68395, most of the instances of xdir and ydir here were
changed to u.dx and u.dy, but not all of them. The remaining ones are
out-of-bounds on xdir and ydir, because i is always set to 12 from an
earlier loop and is no longer involved in handling user input. They
should be u.dx and u.dy like the rest."
triggering an impossible warning about "wall_angle: unknown" due
to the known conflict between door state and wall info which both
overlay the flags field for map locations.
Reported and diagnosed by vultur-cadens: if a shop's wall was dug
open, followed by use of locking magic to plug the gap with a door,
and then unlocking that door, the D_CLOSED door flag was left as
invalid wall_info when shop damage was repaired. Map re-display
complained. Leaving the door locked or opening it after unlocking
did not result in any complaint because the values for those door
states do not conflict with wall angle values.
The problem was reproducible and is now fixed by adding an extra
field to the shop damage structure. A similar change has been
made to the vault guard's 'fake corridor' structure but I have no
test case for that so don't know whether it makes any difference.
At least it doesn't seem to have broken anything.
Existing save and bones files are invalidated by the fixes.
Fixes#606
Revise the m<dir>-toward-boulder handling to let a hero who would be
able to squeese into the boulder's spot if it was blocked from being
pushed to do the squeeze without any pushing.
Unlike the previous changes, this might have an impact on play. It
allows squeezing under then stepping past an unblocked boulder that's
in a corridor in order to be able to push it back the other direction
where maybe there's more room to maneuver it out of the way.
Allow a hero polymorphed into a giant to move to a boulder's spot
via m<dir> no-pickup move, instead of having to push it until the
way is blocked by something and then having push failure move hero
to the spot.
Also change m<dir> when not a giant to no longer push the boulder.
No time will elapse when not moving unless hero who didn't know
that there was a boulder there learns that one is. Since no actual
push attempt gets performed, player doesn't learn whether there is
anything beyond the boulder that inhibits it from being pushed.
Reported directly to devteam, player observed that objects on the
floor had their bless/curse state change when reading a blessed
scroll of remove curse while confused. Message feedback mentioned
a silver saber being dropped. I didn't attempt to view the ttyrec
playbacks; what I'm sure happened was that the saber was secondary
weapon for dual wielding and had been uncursed; the confused remove
curse effect cursed it, which in turn caused it to be dropped. The
saber's 'next object' pointer became the [previous] top of the pile
at that spot and further object traversal intended to process the
rest of hero's inventory ended up processing floor objects there
instead.
This bug has been present for over 20 years (since 3.3.0 came out
in late 1999, when dual wielding was introduced and cursing of the
secondary weapon forced it to be dropped since making it become
welded was deemed to be too complicated) and never been reported.
Most likely players keep secondary weapons blessed so the scroll
effect doesn't touch them and simple object traversal sticks with
inventory. Or items at the spot have unknown BUC state so having
them be affected wouldn't be particularly noticeable.
Reported directly to devteam: monster vs monster location swapping
didn't handle single-segment long worms properly. Multi-segment
worms are disallowed but a worm with no visible segments (which
actually has 1 segment at the head's location) are allowed and the
segment wasn't being moved with the core monster and could trigger
warnings if sanity checking is enabled. The next time that the
worm moved, it got itself back in synch.
I couldn't reproduce the warning but mdisplacem() clearly assumed
that a long worm reporting 0 segments didn't have any so wasn't
attempting to handle the hidden one.
for helm of opposite alignment.
Discovered and described by vultur-cadens.
The #adjust command can be used to split an object stack and if the
shop price of the two halves are different, the new stack will have
its obj->o_id modified to make the prices the same. That could be
used to tip off the player as to what the low bits of the next o_id
will be. Since no time passes, no intervening activity such as
random creation of a new monster can take place, so the player could
wish for something that depends on o_id with some degree of control.
Matters mainly for helms of opposite alignment intended to be used
by neutral characters since the player isn't supposed to be able to
control that. (Other items like T-shirt slogan text and candy bar
wrapper text had a similar issue but controlling those wouldn't have
had any tangible difference on play.)
The issue writeup suggested allowing the player to specify a helm's
alignment during a wish. That would defeat the purpose of having
o_id affect the helm's behavior in an arbitrary but repeatable way
so is rejected.
I implemented this fix before seeing a followup comment that suggests
using a more sophisticated decision than 'obj->o_id % N' for the
arbitrary effect. This just increments context.ident for the next
obj->o_id or mon->m_id by 1 or 2 instead of always by 1 and should
be adequate. It also has the side-effect that two consecutive wishes
for helm of opposite alignment won't necessary give one for each of
the two possible 'polarities', even with no intervening activity by
monsters, reinforcing the lack of player control.
Minor bonus fix: it moves the incrementing check for wrap-to-0 into
a single place instead of replicating that half a dozen times. Ones
that should have been there for shop billing and for objects loaded
from bones files were missing.
Fixes#596