When not carrying any contained gold, or the only contained gold is
inside container(s) whose contents aren't known, ^X writes one line
about the hero's "wallet". When known contained gold is present, it
writes two lines for gold, first one about wallet with the second
one about contained gold being a continuation of the first. Move
the conjunction that combines them from the start of the second line
to the end of the first.
So change
|Your wallet contains M zorkmids,
|and you have N more contained in your pack.
to
|Your wallet contains M zorkmids, and
|you have N more contained in your pack.
and
|Your wallet is empty,
|but you have N zorkmids contained in your pack.
to
|Your wallet is empty, but
|you have N zorkmids contained in your pack.
It evens out the line lengths a little bit and starting the second
line with uncapitalized "you" seems slightly less jarring than with
"and" or "but".
Reported by entrez: using ^A instead of #retravel after interrupted
travel can pick wrong location if cursor was previously positioned
with movement commands rather than feature targeting because it
won't be starting from the original spot. Also, ^A after ';' will
just redescribe whatever was examined previously instead of having
the player pick a new spot.
This suppresses cursor positioning from the do-again queue so that
repeating travel or quick-look or other command that needs player
to choose a position will repeat the command but then need to have
a position chosen. For interrupted #travel, the cursor will already
be placed on the previous destination so that's relatively painless,
but also allows a different destination to be chosen.
It adds iflags.remember_getpos that callers of getpos() could set to
be able to restore the old behavior but none do so far.
Fixes#905
Issue reported by vultur-cadens: Elbereth used to be effective in
inhibiting monster movement when an object was present on the same
spot, but since 3.6.0 it isn't. It only functions that way when the
hero--or hero's displaced image--is present these days. So special
levels that have been using engraved Elbereth to try to protect
objects from monsters haven't been providing any useful protection.
This makes Elbereth that's engraved during level creation work like
it used to in 3.4.3 and earlier: when there's at least one object
on the engraving's spot, monsters who are affected by Elbereth will
be affected. [I'm fairly sure that that behavior started out
unintentionally, as a side-effect of an optimization to only check
for scroll of scare monster when there was at least one item present
which is a necessary condition for such a scroll.]
Old-style Elbereth includes Elbereth chosen as a random engraving
during level creation in addition to engravings specified in special
level definitions. Engravings by the player don't have the required
attribute and player-engraved Elbereth behaves in the 3.6 way.
This ought to be replaced by something more general. Perhaps a new
engraving type not usable by the player?
Fixes#900
Fix most of the things pointed out by #wizmondiff.
Weakening of placeholder 'elf' is due to recent removal of M2_STRONG
for it as part of the "orc strongmonst" changes.
I assume that the discrepancies for multiple quest leaders came about
as part of the change that allows killing the leader as an alternate
way to gain access to the lower levels of the quest, but didn't check.
I don't know what's up with 'piranha' but just changed it to match
generated value.
'{freezing,flaming,shocking} sphere' still show up as discrepancies
with hardcoded (mons[].difficulty) value higher than generated value.
They got harder when their explosion was beefed up, so the formula to
calculate difficulty ought to be updated to account for that.
Shorten the name of the recently added debug command that validates
monster difficulty values. 'wizcheckmdifficulty' was 19 characters
long, the next longest is 14 ('wiztelekinesis'). The extra width
messed up the Qt interface's extended command selection dialog when
wizard mode commands are included. It sizes the button for every
command to fit the longest name; the increase in size from 14 to 19
made the button grid become too big for the screen.
Add monsters' base difficulty level to the #wizmondiff output.
Add #wizmondiff and #wizdispmacros to 'wizhelp'.
Force windowtype to be the first option written to new RC file since
its value can affect how other options are processed. (Only saved if
comes from existing RC file, not command line.) doset() lists a few
compound options before the rest too. Combine the two sets of want-
to-be-first and move the handling for that to optlist.h where the only
cost is that the options are no longer in alphabetical order.
I hadn't ever used #saveoptions before and when I checked to see
whether the autounlock:none changes were being handled properly, I
discovered that options set via 'm O' weren't being handled at all.
This includes some miscellaneous reformatting of things noticed
while tracking down the problem.
Because the existing error was the default case in a switch/case
statement only reachable if the option matched one of the expected ones
in the list, it wasn't actually reachable: something totally out of
left-field wouldn't match one of the expected options so never hit the
switch, and something that did match one of the expected options would
by definition have a first character handled by one of the cases in the
switch/case.
Do it a slightly different way that should successfully raise an
unexpected value error for 'OPTIONS=autounlock:foobar'. I didn't remove
the default case entirely, because it could still catch an error if
some new value is added to unlocktypes[] without a corresponding case
being added to the switch statement.
The autounlock handler included an explicit 'none' option, a choice that
gave it a different UX from similar existing compound option handlers
(e.g. paranoid_confirm or pickup_types), which set 'none' simply by
deselecting all options. It didn't make the menu any easier to use (at
least in my experience), since in order to go from some combination of
options to 'none', you'd have to deselect everything anyway (which on
its own was enough to set 'none', so there was no reason to explicitly
select it after doing so).
Make the autounlock handler work like other compound option handlers,
such that deselecting all options is the way to set 'none', and there is
no explicit 'none' option included in the list.
The line got a lot longer than most other #attributes lines when the
hero had gold both in open inventory and in stashed containers, so break
it up into two lines (using the same approach as the pantheon info in
the first section). Maybe this isn't necessary but it does make it
stand out less.
The #showgold command now mentions (known) gold socked away in
containers in your inventory as of 706b1a9. Since the gold info in the
attributes display and dumplog matches the output of #showgold
otherwise, update it to do the same thing. Also refactored doprgold a
bit to be a little more compact, as opposed to enumerating all the
different combinations of gold/no gold in open inventory/containers.
This eliminated some string constants that were broken up into multiple
constants/lines (like "line 1 " "line 2"), which NetHack code style
seems to prefer to avoid.
Add a stack of 2 tins of spinach near the leader on the monk quest
start level and another stack of 2 blessed tins of spinach at a
random spot on the monk quest locate level, to compensate for the
inability to gain strength from giant corpses if they adhere to
vegan or vegetarian conduct. paxed supplied the 'tinplace' magic.
4 tins of spinach aren't nearly enough to get to 18/100, but by
uncursing the first pair, if necessary, and waiting until strength
is at least 18, they can be eaten to add 4..40 (average 22) points
of exceptional strength. (Players choosing either of those conducts
for other roles or foodless for any role are on their own as far as
boosting Str goes, same as before.)
The special level loader needed to be modified to handle tins of
spinach. It now accepts "spinach" as a fake monster type for an
object of type "tin". Also added support for empty tins since it
involved the same code, and use of fake monster type "empty" with
object type "egg" to be able to create generic (unhatchable) eggs.
(Wishing for "egg" produces those by default but it also accepts
explicit "empty egg" by coincidence.)
Handle alternate values for hero poly'd into a 'strongmonst' form
more thoroughly by propagating max values other than 18/100 to the
attribute manipulation routines.
ATTRMAX(A_STR), which used to be a relatively simple expression, now
contains a function call.
Along the way, change the races[] terminator's value for 'mnum' from
0 (giant ant) to NON_PM.
When strength loss is so big as to cause HP damage, but reduce
strength if the damage causes hero to revert to normal form. There's
no point in adjusting strength before rehumanization and not fair to
do so afterward.
Also, validate strength and its intended adjustment before doing
anything else. (Just paranoia; there's no reason to suspect that any
bad data ever gets passed in.)
Try again to make losestr() do what's intended. If it would take
strength below 3, it takes away HP and max HP instead. If hero is
poly'd, those come from the hero-as-monst values. If hero was
poly'd but isn't any more, hero-as-monst died and rehumanized as
previous self; leave max HP alone. If hero wasn't poly'd, take
HP and max HP from their usual values, but don't take max HP below
the threshold of minimum max HP (experience level times 1). The old
check for max HP going below minimum can't happen anymore, unless
hero was below that threshold already (which shouldn't happen; if it
does somehow, don't punish hero further).
If this still isn't right, I'll throw up my hands and my lunch.
Refine pull request #802 by entrez. Applying damage within a loop
could potentially damage the hero multiple times, maybe using up
an amulet of life saving and then killing hero anyway, or causing
rehumanization and taking further HP from normal form, or both,
causing rehumanization and then using up amulet of life saving.
Accumulate the damage in the loop and then apply it as a unit.
Issue reported by vultur-cadens: Elbereth used to be effective in
inhibiting monster movement when an object was present on the same
spot, but since 3.6.0 it isn't. It only functions that way when the
hero--or hero's displaced image--is present these days. So special
levels that have been using engraved Elbereth to try to protect
objects from monsters haven't been providing any useful protection.
This makes Elbereth that's engraved during level creation work like
it used to in 3.4.3 and earlier: when there's at least one object
on the engraving's spot, monsters who are affected by Elbereth will
be affected. [I'm fairly sure that that behavior started out
unintentionally, as a side-effect of an optimization to only check
for scroll of scare monster when there was at least one item present
which is a necessary condition for such a scroll.]
Old-style Elbereth includes Elbereth chosen as a random engraving
during level creation in addition to engravings specified in special
level definitions. Engravings by the player don't have the required
attribute and player-engraved Elbereth behaves in the 3.6 way.
This ought to be replaced by something more general. Perhaps a new
engraving type not usable by the player?
Fixes#900
Fix most of the things pointed out by #wizmondiff.
Weakening of placeholder 'elf' is due to recent removal of M2_STRONG
for it as part of the "orc strongmonst" changes.
I assume that the discrepancies for multiple quest leaders came about
as part of the change that allows killing the leader as an alternate
way to gain access to the lower levels of the quest, but didn't check.
I don't know what's up with 'piranha' but just changed it to match
generated value.
'{freezing,flaming,shocking} sphere' still show up as discrepancies
with hardcoded (mons[].difficulty) value higher than generated value.
They got harder when their explosion was beefed up, so the formula to
calculate difficulty ought to be updated to account for that.
Shorten the name of the recently added debug command that validates
monster difficulty values. 'wizcheckmdifficulty' was 19 characters
long, the next longest is 14 ('wiztelekinesis'). The extra width
messed up the Qt interface's extended command selection dialog when
wizard mode commands are included. It sizes the button for every
command to fit the longest name; the increase in size from 14 to 19
made the button grid become too big for the screen.
Add monsters' base difficulty level to the #wizmondiff output.
Add #wizmondiff and #wizdispmacros to 'wizhelp'.
Force windowtype to be the first option written to new RC file since
its value can affect how other options are processed. (Only saved if
comes from existing RC file, not command line.) doset() lists a few
compound options before the rest too. Combine the two sets of want-
to-be-first and move the handling for that to optlist.h where the only
cost is that the options are no longer in alphabetical order.
I hadn't ever used #saveoptions before and when I checked to see
whether the autounlock:none changes were being handled properly, I
discovered that options set via 'm O' weren't being handled at all.
This includes some miscellaneous reformatting of things noticed
while tracking down the problem.
Pull request from entrez: simply the 'O' submenu for autounlock by
removing choice 'none'. Fix error reporting for bad autounlock value
from run-time config file or NETHACKOPTIONS.
Fixes#897
Because the existing error was the default case in a switch/case
statement only reachable if the option matched one of the expected ones
in the list, it wasn't actually reachable: something totally out of
left-field wouldn't match one of the expected options so never hit the
switch, and something that did match one of the expected options would
by definition have a first character handled by one of the cases in the
switch/case.
Do it a slightly different way that should successfully raise an
unexpected value error for 'OPTIONS=autounlock:foobar'. I didn't remove
the default case entirely, because it could still catch an error if
some new value is added to unlocktypes[] without a corresponding case
being added to the switch statement.
The autounlock handler included an explicit 'none' option, a choice that
gave it a different UX from similar existing compound option handlers
(e.g. paranoid_confirm or pickup_types), which set 'none' simply by
deselecting all options. It didn't make the menu any easier to use (at
least in my experience), since in order to go from some combination of
options to 'none', you'd have to deselect everything anyway (which on
its own was enough to set 'none', so there was no reason to explicitly
select it after doing so).
Make the autounlock handler work like other compound option handlers,
such that deselecting all options is the way to set 'none', and there is
no explicit 'none' option included in the list.
The line got a lot longer than most other #attributes lines when the
hero had gold both in open inventory and in stashed containers, so break
it up into two lines (using the same approach as the pantheon info in
the first section). Maybe this isn't necessary but it does make it
stand out less.
The #showgold command now mentions (known) gold socked away in
containers in your inventory as of 706b1a9. Since the gold info in the
attributes display and dumplog matches the output of #showgold
otherwise, update it to do the same thing. Also refactored doprgold a
bit to be a little more compact, as opposed to enumerating all the
different combinations of gold/no gold in open inventory/containers.
This eliminated some string constants that were broken up into multiple
constants/lines (like "line 1 " "line 2"), which NetHack code style
seems to prefer to avoid.
Add a stack of 2 tins of spinach near the leader on the monk quest
start level and another stack of 2 blessed tins of spinach at a
random spot on the monk quest locate level, to compensate for the
inability to gain strength from giant corpses if they adhere to
vegan or vegetarian conduct. paxed supplied the 'tinplace' magic.
4 tins of spinach aren't nearly enough to get to 18/100, but by
uncursing the first pair, if necessary, and waiting until strength
is at least 18, they can be eaten to add 4..40 (average 22) points
of exceptional strength. (Players choosing either of those conducts
for other roles or foodless for any role are on their own as far as
boosting Str goes, same as before.)
The special level loader needed to be modified to handle tins of
spinach. It now accepts "spinach" as a fake monster type for an
object of type "tin". Also added support for empty tins since it
involved the same code, and use of fake monster type "empty" with
object type "egg" to be able to create generic (unhatchable) eggs.
(Wishing for "egg" produces those by default but it also accepts
explicit "empty egg" by coincidence.)
Handle alternate values for hero poly'd into a 'strongmonst' form
more thoroughly by propagating max values other than 18/100 to the
attribute manipulation routines.
ATTRMAX(A_STR), which used to be a relatively simple expression, now
contains a function call.
Along the way, change the races[] terminator's value for 'mnum' from
0 (giant ant) to NON_PM.
When strength loss is so big as to cause HP damage, but reduce
strength if the damage causes hero to revert to normal form. There's
no point in adjusting strength before rehumanization and not fair to
do so afterward.
Also, validate strength and its intended adjustment before doing
anything else. (Just paranoia; there's no reason to suspect that any
bad data ever gets passed in.)
Try again to make losestr() do what's intended. If it would take
strength below 3, it takes away HP and max HP instead. If hero is
poly'd, those come from the hero-as-monst values. If hero was
poly'd but isn't any more, hero-as-monst died and rehumanized as
previous self; leave max HP alone. If hero wasn't poly'd, take
HP and max HP from their usual values, but don't take max HP below
the threshold of minimum max HP (experience level times 1). The old
check for max HP going below minimum can't happen anymore, unless
hero was below that threshold already (which shouldn't happen; if it
does somehow, don't punish hero further).
If this still isn't right, I'll throw up my hands and my lunch.
Refine pull request #802 by entrez. Applying damage within a loop
could potentially damage the hero multiple times, maybe using up
an amulet of life saving and then killing hero anyway, or causing
rehumanization and taking further HP from normal form, or both,
causing rehumanization and then using up amulet of life saving.
Accumulate the damage in the loop and then apply it as a unit.