Rewrite much of the paragraph about the run-time config file.
Remove mention of '-p @' since it doesn't actually work.
Expand 'nethack -s' a bit.
Revise --showpaths.
Shuffle --scores, --version, --showpaths, and --usage into the same
order as usage feedback lists them, primarily scores first and usage
last.
Take unpaid shop items off the bill if they're on the floor and
wall repair moves them from the shop boundary to all the way inside
the shop.
I don't think it's possible for items to be moved out of the shop
except for the very special case of moving into an adjacent shop
which shares the wall, so clearing no_charge for an item that is no
longer inside a shop is academic.
If hero zaps self with a wand and the result is fatal, report the
death as "zapped himself with <a wand of sometype>" rather than just
"zapped himself with a wand".
Throwing while levitating or getting hit for knockback effect could
move hero carrying unpaid items out of a shop. If that happened,
sanity_check complained that unpaid items weren't in a tended shop.
Check for entering and leaving special rooms during recoil same as
gets done for ordinary movement. Leaving a shop via recoil or
knockback while owing a bill now gets treated as robbery immediately
rather than waiting until hero voluntarily moves to another spot
after recoil has finished.
I don't know whether we'll ever run the code through clang-format
again, but in case we do, end-of-line comments which span lines
should begin continuation lines with '*', otherwise they get turned
into block comments beginning on the next line.
|code; /* start
| end */
gets changed to
|code;
|/* start end */
but
|code; /* start
| * end */
stays as-is.
Reconcile boulder pushing with no_charge sanity checking. The hack.c
part comes from entrez.
Pushing a for-sale boulder from inside the shop to the shop's boundary
("free spot", doorway, or gap in wall) adds it to the shop bill even
though it's still on the floor. Leaving the shop without paying for
it is a robbery. Also, pushing an unpaid boulder that's on the shop
boundary to any spot that's all the way outside the shop is robbery.
More unpaid/no_charge sanity checking. If a shop contained any
no_charge objects and was robbed, they would be left no_charge and
trigger sanity check warnings (no_charge in "untended shop") once
the shopkeeper got past any Kops in the way and exited the shop.
Earlier testing didn't wait around long enough for that exit to
happen.
Clear no_charge as soon as the robbery is detected.
Redo the way coordinate pairs are lined up for /m /O &c.
Original
| <8,9> $ gold pieces
| <10,10> * rocks
| <9,12> % newt corpse
Previous
| <8, 9> $ gold pieces
| <10,10> * rocks
| <9,12> % newt corpse
Now
| <8,9> $ gold pieces
| <10,10> * rocks
| <9,12> % newt corpse
Override right justification instead of inserting a space. It looks
better for the situation where all y values are 1 digit.
An object in a shop that was marked no_charge and got removed from
the shop by means other than the hero picking it up (test case
teleported it out while hero was inside shop) was left with the
no_charge bit set. It's supposed to only be set for objects inside
shops so was triggering the recently added no_charge sanity checks.
Changing stolen_value() to have it pass the reset_nocharge arg to
billable() solves this but could have unanticipated results with
other stealing from shops.
When /m or /M or /o or /O shows monsters or objects with locations
displayed as map coordinates, make those line up by their commas.
Old
| <8,9> $ gold pieces
| <10,10> * rocks
| <9,12> % newt corpse
New
| <8, 9> $ gold pieces
| <10,10> * rocks
| <9,12> % newt corpse
(The data is gathered by row so implicitly sorted by y.)
If someone is crazy enough to set ROWNO to three digits, values
will only line up by the comma when all values have row less than
100 or all are 100+. Setting COLNO to three digits isn't an issue
unless the total witdh of "<" + xxx + "," + yy ">" is more than 8
(which would push object class letter and object description one or
more extra columns to the right, messing up overall alignment but
still showing accurate data).
If you kill an engulfer and get dropped onto a level teleporter or
magic portal, wait until end of turn to perform the level change.
The code to finish off killing the engulfer was left with a stale
pointer for the monster when level change happens immediately.
The level change was being forced to be immediate so that something
noticable happened before being asked for what to name a teleport
scroll read while cursed or confused, but such scrolls become
discovered these days. So when no prompting for what to call the
scroll takes place, there's no need to change levels instantly.
This issue was just fixed but this commit is simpler. The previous
fix is left in place in case some other level change path is--or
becomes--possible.
When running #wizkill, if hero was swallowed and you killed the
engulfer and that dropped hero onto a level teleporter, the targetting
loop for selecting the next monster to kill kept going after changing
to another level. Terminate #wizkill if killing something sends you
to a different level.
Not fixed, and an old bug, or variation of one: the cursor got
positioned at the coordinates of your spot on the prior level even
though the part of the new level where you actually arrived was
displayed.
The hack.c and trap.c bits are just reformatting.
When a monster could first knock you back and then grab you,
the game would emit impossible, because the knockback moved you
but the distance variables used for the grab attack were not
updated.
Update the range variables within the loop iterating through
the monster attacks.
Used up items moved to the billobjs list still have obj->unpaid set.
That should probably be cleared since it has no meaning there, but
this hasn't done that.
For those keeping score: unpaid checking has triggered three false
positives (so far) and found one bug.
If you were on a level teleporter, the spoteffects() call after
the hero gets expelled could end up going to a new level and
freeing all the monst chains from the level you were originally
engulfed on.
#0 0xba0507 in free
#1 0x87feda in dealloc_monst src/mon.c:2369
#2 0x880a02 in dmonsfree src/mon.c:2194
#3 0x9a7aa2 in savelev_core src/save.c:507
#4 0x9a7a21 in savelev src/save.c:466
#5 0x71eb9d in goto_level src/do.c:1483
#6 0x71833f in deferred_goto src/do.c:1903
#7 0xa2533f in level_tele src/teleport.c:1117
#8 0xa2567b in level_tele_trap src/teleport.c:1198
#9 0xa5c007 in trapeffect_level_telep src/trap.c:1861
#10 0xa5f856 in trapeffect_selector src/trap.c:2497
#11 0xa47497 in dotrap src/trap.c:2586
#12 0x7d669b in spoteffects src/hack.c:2859
#13 0x89d495 in xkilled src/mon.c:3187
The latter parts of xkilled() after the spoteffects() call would
then attempt to dereference the free'd monst pointer.
Save a copy of the monst struct prior to spoteffects() if you were
expelled, then point at the reference copy afterwards.
Resolves#938
Autodescribe was not updating during browse_map() when the cursor was
moved over a gold glyph that was actually a trap, causing the trap to
be described as the previous square that the cursor was on (probably
"unexplored area") instead of as gold pieces. This was especially
noticeable when using OPTIONS=whatis_coord:m, because the coordinate
was not updating when moving the cursor over the trap.
Split some lines that began with one sentence and then continued with
another so that each sentence has its own line as per 'roff guidelines.
Change the continuation lines in the files and environment sections
to begin with <backslash><space><tab> instead of just <tab>, again to
meet the guidelines (don't begin lines with whitespace). This had a
side-effect of suppressing some space insertion for justifying right
margin of right-hand column on some of the lines. That hadn't looked
very good anyway.
Add new file 'usagehlp' to the files section.
Also add previously unmentioned Guidebook[.txt], but it's hard to
explain why it probably won't be present....
Update the bones file entry.
'cmdhelp' isn't used anymore. Should it be moved to outdated/dat and
the Makefile install steps be updated to stop bothering with it?
Pull request from entrez: memory freed when changing levels could be
accessed if the level change happened when hero caused an engulfer to
expel him onto a level teleporter. Wouldn't happen when monsters are
moving because hero's level change will be deferred. Wouldn't happen
for trap doors and holes, but could happen for magic portal if hero
got swallowed while on one after coming through from other side.
Fixes#937
An engulfing monster can expel you onto a level teleporter or other
level-changing trap, in which case it may (under highly specific
circumstances[1]) no longer have been in memory by the time mtmp->mx/my
were accessed to see whether the "Brrooaa" message should be printed.
It also doesn't make much sense to print that message by the time you've
already fallen through a portal, trapdoor, etc, onto another level, so I
think moving it before the spoteffects() call kills two birds with one
stone.
[1] The highly specific circumstances: you must die due to illness or
some other timeout (or generally die on your own turn rather than the
monsters' turn, since this ensures the level change isn't deferred until
the end of the turn), while engulfed above a level teleporter [or maybe
another similar trap -- I tested with a level teleporter], and be
lifesaved, while positioned such that the engulfer can't follow you
through the levelport after expulsion (e.g. surrounded by other
monsters). It may happen under some other conditions too, but even if
so it's pretty rare and was tough to reproduce.
Pull request #936 took away the destruction of potions of acid ("acid
and water don't mix") if they survived water_damage(). Restore that
by forcing them to not survive. Exception: if they're greased and
pass the 50:50 chance of retaining the grease, they aren't destroyed.
Pull request from entrez: if a greased item loses its grease after
being affected by water, say so.
Also, the post-water code could access freed memory for an item that
had been destroyed by the water (potion of acid).
Fixes#936
A potion of acid could be destroyed and freed by dipping into a
fountain, then dereferenced after the fact -- both when checking its
type immediately after the water_damage() call (as was noticed by
hackemslashem and amateurhour on IRC), and also in the later switch/case
a few lines further down in dipfountain().
I basically reversed the original 'er != ER_DESTROYED' test here: as it
was before this, I think the only thing that could hit it was a greased
potion of acid, which would survive the initial dip due to the grease.
Such a potion would be silently deleted. Potions of acid which were
actually destroyed by water_damage, on the other hand, could be allowed
to continue down to the switch/case of further effects (and associated
dereferences). I think this makes more sense in reverse, with potions
that were protected by grease actually being protected and producing
normal dip effects, and potions of acid which exploded causing an early
return with no further effects. This effectively prevents the various
use-after-free scenarios that were possible, too.