Allow the player to precede q/#quaff or M-d/#dip with the 'm' prefix
to skip asking about fountains, sinks, or pools if one of those
happens to be present, similar to how using it for e/#eat skips food
on the floor and goes straight to inventory.
If you use it and don't have any potions, you'll get "you don't have
anything to drink" or "you don't have anything to dip into", same as
when there is no suitable dungeon feature present combined with no
potions. However, if an applicable dungeon feature is present and
you don't use the prefix but answer 'no' to drink from fountain,&c
and you don't have any potions, "else" will be inserted into the
message: "you don't have anything else to drink".
A big part of the diff is just a change in indentation level for
code that is now inside 'if (!iflags.menu_requested) {' ... '}'.
rhack() normally calls parse(), parse() sets context.move to True
assuming that the player's next action will take game time, then
when it returns, rhack() sets context.move back to False if the
assumption turned out to be incorrect. But when performing actions
after picking something in inventory, rhack() doesn't call parse()
so context.move is left at False.
This was hidden by making the inventory command take game time if
the player picked an item and set up an action to be done with it
even though the action hadn't taken place yet. So time was being
accounted for but if the hero didn't get consecutive moves then
monsters got their turn between the shouldn't-take-time inventory
command and the ought-to-behave-like-normal-command queued action.
My initial attempt to fix this (before figuring out how context.move
works) by stopping inventory from taking time didn't work because
queued item-actions stopped taking time too, or rather the fact that
they took no time became exposed. This second attempt doesn't have
that problem and I think it is correct.
Issue reported by Meklon2007: picking a container from inventory
didn't offer #tip as a possible use of the item.
Implemented in commit 7b351bc20d
but I forgot to close the issue, so this adds a fixes entry for
it in order to do that.
Closes#727
Noticed when adding a 'tip container' choice to item-actions for
context sensitive inventory (update pending). Putting items into a
container with menustyle traditional and then takiing them out with
the #tip command while 'sanity_check' is On would produce warnings
once they were on the floor.
askchain() uses object bypassing to be able to cope with multi-drop
potentially changing invent, and it tried to reset that when done.
But it did so with the original object list (invent in this case)
and that doesn't reset individual objects that have been moved to
any other list. The between-turn resetting of bypass bits wasn't
doing so for container contents. The sanity check wasn't--still
isn't--checking those either, so it wasn't noticeable while items
were still inside the container. But taking them out with #tip
doesn't touch any bypass bits, so between-turn reset isn't triggered
and the items that came out of the container with bypass set
continued to have it set while on floor. sanity_check complained.
Change clear_bypasses() to handle container contents, and change
askchain() to call it instead of just clearing bypasses for whatever
is left of its input chain. (The latter probably isn't necessary
now that the between-turn cleanup deals with contents.)
While testing the new mouse action menus, it was quite annoying
to try and hit some shorter entries. Make all the selectable entries
the same maximum length, and with text left justified.
Stop attempting to catch up for lost time for shop damage repair
when getlev() loads a previousl visited level. Normal shopkeeper
behavior will take care of that.
Also, fixes the display related aspects of shop damage repair
interacting with ball and chain. They don't happen when its done
while the map is being shown.
Reported by entrez, restoring a saved game runs the shop wall/floor
damage repair routine. It was taking place before attached ball
and chain were fully restored so the repair routine treated them as
ordinary objects if they happened to be in a wall gap that gets
fixed on the same turn as restore takes place. They could end up
being moved to a spot that's too far from the hero and then trigger
an impossible "b&c distance".
This restores ball and chain before shop damage repair takes place
so the repair routine deals with them sanely and the impossible won't
occur any more. However, the repair still happens before the current
level's map has been displayed and that looks pretty strange during
the shopkeeper's message. Also, if the hero and the ball start on
opposite sides of the gap, after the gap is repaired the ball will
still be shown as a remembered object at its old spot even though it
ends up being located at the hero's feet.
Closes#726
but more work is needed...
Issue #722 posted by copperwater and commented on by Entrez: both
shk_your() and the() inserted "the" in front of a unique monster's
corpse, yielding "the Lord Surtur's corpse glows iridescently" and
"the Lord Surtur's corpse drops to the floor."
Teach both of those routines to skip "the" when used for monsters
with personal names. It now omits "the" for "Medusa's corpse" but
still gives "the Oracle's corpse".
shk_your() operates on an object and can deal explicitly with corpses
of named monsters. the() operates on text and has to guess whether
it is being used in a similar situation. Right now the guess is just
"is there an apostrophe present?" and might need further refinement.
Fixes#722
Allow selecting an item from inventory and show a menu of actions
applicable for that particular item. Some of the entries might
be slightly spoilerish (eg. it'll reveal that you can read T-shirts),
but the improved usability for new players is more than worth it.
Generally known as "item actions", this was first implemented
in AceHack by Alex Smith.
Pull request from entrez makes object detection of statues that are
actually mimics show the statue's monster type instead of always
depicting tengus.
Fixes#725
detecting monsters when none are present
Give some feedback for monster detection if drinking from a fountain
fails to find any monsters. Potion or spell gives "strange feeling"
feedback in that situation but fountain didn't report anything.
Fixes#724
Implement the suggestion by entrez to avoid "while helpless" in the
reason for the second death if hero gets killed, life-saved, and
killed again at the same time. Life saving sets 'multi' to -1 which
prevents the hero from moving again until next turn and is intended
to make the sequencing of "you survived that attempt on your life"
work if you're being interrupted during some multi-turn activity.
It used to behave differently when the first death occurred while
engaged in some voluntary multi-turn activity. I've removed that
because I couldn't figure out why; it might need to be put back.
menuitem_invert_test() is intended for invert-all/invert-page/
select-all/select-page but was being called for group accelerators.
In the #wizidentify menu, the 'all' choice specifies ^I as a group
accelerator but that stopped working on tty when it recently became
flagged as skip-invert.
Use 'fuzzymatch(,," -",)' when checking whether the name specified
in a player's wish text matches an artifact name so that extra or
omitted spaces and dashes are ignored. Wishing for "firebrand" will
yield "Fire Brand" and "demon bane" will yield "Demonbane".
monster and Elbereth unless there's no other choice.
Suggested by NetSysFire, don't create new monsters on top of scrolls
of scare monster. Not mentioned in the suggestion: unless they are
a type of monster that isn't affected by such scrolls. This extends
it to teleport destination too.
Avoid placing a monster on a scroll of scare monster or on engraved
Elbereth if there are other locations available. Only performed for
callers of goodpos() who explicitly request it, which at the moment
are makemon(), rloc(), and enexto().
Also, propagate 'mmflags_nht' to a bunch of places that were left
using long or unsigned for makemon() and goodpos() flags. I didn't
attempt to be systematic about that though.
Implements #717
while wielding a cockatrice corpse without gloves
Reported by vultur-cadens: if safely wielding a cockatrice corpse
without gloves due to temporary stoning resistance or wearing yellow
dragon scales/mail, having the resistance be lost to timeout or to
taking off the dragon armor should have turned the hero to stone but
didn't.
Extend the handling for taking off gloves to cover these other two
cases too. The feedback for these deaths is usually too verbose to
fit on the tombstone but does show up in logfile.
Fixes#715
Implement the suggestion by NetSysFire that a levitating of flying
hero won't treat pits and holes as off limits when testing potential
destinations during teleport.
Closes#716
Using #name and picking an item on the floor to be assigned a type
name allowed any of the four types of globs to be named. After
that, wishing for those by the assigned name bypassed the code that
forced the quantity to stay at 1. Asking for "3 foo" could then
produce "3 small globs of gray ooze" which fails obj_sanity() and
issues an impossible warning (which the fuzzer escalates to panic).
The "getobj refactor" patch changed the return value of call_ok().
When it gets used to check whether an object on the floor could have
a type name assigned (rather than as a getobj() callback), the test
that should have rejected the naming attempt accepted it instead.
Update the wishing code to handle globs differently: you can still
specify the relative size via small, medium, large, or very large,
but now you can specify a count either instead or in addition. A
count of more than 1 is used to multiply the created glob's weight,
although it's less likely to be honored as-is when the size is bigger
than small. Quantity is always forced to 1, at a different place in
readobjnam() than previously.
The change in the long-standing default for 'autopickup' warrants
mention in the Guidebook. Also, the X11 interface can switch to
alternate tiles but doesn't use the 'tile_file' option to do so.
In Guidebook.mn, the list of options pads ones shorter than 8
characters with trailing spaces, necessitating quotes. A few longer
ones had such quotes and even trailing spaces. Take those away.
From a report by a beta tester 8 years ago: kicking a chest gave
"THUD! The chest explodes!" but the chest remained intact. The
explosion was destroying all floor items at the hero's spot rather
than at the chest's spot. Fixing that results in the chest being
destroyed because it's one of the items at its own spot.
While fixing that I noticed that delobj() was only protecting the
Amulet and the invocation items from destruction, not Rider corpses.
You could destroy one or more of those by getting a trapped chest's
explosion while using a key at its spot rather than by kicking it
from adjacent. (Getting the exploding chest result is not easy,
particuarly with positive luck. I eventually resorted to forcing
it with a debugger.)
There's been occasional reports (perhaps once or twice a year)
of travel getting stuck moving repeatedly between two locations
next to each other, but it has never been reproduced before.
This special level lua code fragment is a minimal test case
which triggers it:
--- special level lua fragment, indented
des.map([[
--##---
###----
#-+----
####--L
]]);
des.door("open", 2,2)
--- end of special level lua fragment
The open door is required.
Magic map the level. Start from somewhere NW of the door, and try
to travel to the lava pool. Hero will get stuck oscillating between NW
of the door and two steps west of the door.
Here are the maps of the travel[][] array values from findtravelpath()
in those two steps in the above map:
------------- -------------
| . . 2 3 | | . . 1 2 |
| 1 1 2 . | | 1 @ 1 . |
| @ . . . | | 1 . 2 . |
| 1 1 2 . | | 2 . 3 4 |
------------- -------------
There are two possible closest locations to the lava pool,
the one marked with "3" on the left map, and "4" on the right map.
Based on that alone, both would be valid places to path to.
But, in the left case, hero could not see the bottom location, so
the code won't even consider pathing to it, so it will start moving
towards the "3".
When hero moves to the second position, in the right map, now the "4"
could be seen. Now there are two possible closest locations we could
choose from. The code that scans the possible locations goes from top-left
to bottom-right, first going down (y-axis). So, the code sees the
"2" on the right. distmin() to there is 2. Good, we pick that location
to path to. Next, going down, the code considers the "4" ... which is
also equally close to the lava pool. and distmin does not consider terrain,
so ignores the door, so it has the same distmin value of "2", so the
code picks this location.
But: this was just a guess, because there's no known valid path to the
lava pool. The code loops back up to rebuild the travel[][] array
with a new starting location as the "4" from the right map, pathing
back to hero.
This is that travel array map:
-------------
| . . . . |
| 4 @ 3 . |
| 3 . 2 . |
| 3 2 1 x |
-------------
The way travelstepx and travelstepy arrays are built means that the first
location that considers the hero's location is the "3" SW of hero, so
hero will move there next. Repeat from beginning. If there was no door,
the travelsteps would reach hero's location first from SE.
(I left the travel[][] array rebuild and travelstepx/travelstrepy build
off from the other movement position, as it's not relevant)
The fix: When considering which of the two possible closest places to the
lava pool to path to, use the one with the lowest value in the travel array.
That value is the real number of moves it takes for the hero to walk there,
so the code will consistently path to the upper location, as it is "2",
instead of considering the "4" below it.
Also some minor code reorg, so it considers couldsee first instead of
later in two separate places.
It turns out that there were a bunch more monsters with the corpse-
conveys-stoning-resistance flag than just green mold. Instead of
stripping it off, give them (including green mold) a chance to confer
timed resistance against stoning and also against acid.
All of these can convey either of those two resistances. Like other
intrinsics obtained via eating, at most one can be obtained from any
given corpse.
green mold, acid blob, spotted jelly, ochre jelly, black naga,
yellow dragon, Chromatic Dragon
These can confer temporary stoning resistance but not acid resistance:
lizard, chickatrice, cockatrice, gargoyle, winged gargoyle,
xorn, Medusa
There aren't any that confer just acid resistance without a chance for
stoning resistance.
The effect lasts for 3d6 turns, or is extended by 3d6 more if randomly
chosen and applied when already in effect.
Having temporary acid resistance time out during another meal when
eating a corpse that ends up conferring acid resistance seems strange.
The protection against acid is granted at the start of the meal and
continues to the end (in regards to eating, not external attacks) even
when the intrinisic is lost in between. I'm not sure whether that
needs some form of fixing, and if so, what that fixing should be.
A reddit posting points out that the green mold monster definition
has the flag for conveying stoning resistance but it doesn't work.
There seem to be 3 choices:
1) implement being able to gain that resistance;
2) take the flag away;
3) mark green molds no-corpse so that the issue becomes moot.
The poster was hoping for (1) but I've gone with (2). Green molds
are too common and not at all dangerous; being able to gain stoning
resistance--even with a tiny chance--could potentially be a major
change in play balance.
I polymorphed into something wimpy and became overloaded or even
overtaxed so I dropped everything. The status line still showed
overloaded or overtaxed until my next move. That didn't happen in
3.6.x or 3.4.3 but I didn't pursue trying to figure out what caused
this misbehavior.
I wanted to add an encumber_msg() call to freeinv() but that would
cause message sequencing issues. Instead, add a call to it in a
few places where items are leaving hero's inventory, particularly
for the chain of calls for dropping stuff. I've left it off in a
bunch of other potential places.
Also add a few missing (void) casts where the return value of
existing encumber_msg() calls is being ignored.
Make selection rndcoord return a table with x and y keys.
Allow (most) coordinate parameters accept such a table.
Fix selection and des lua tests broken by the above changes and
an earlier change, because selections tried to set terrain
at column 0, and it now causes a complaint.
Fix the bug reported by entrez where you could end up hiding under
nothing if while poly'd into a hides-under creature and hiding under
something edible you ate whatever you were hiding under. Same thing
could happen if it was a corpse on an altar and you offered it rather
than consumed it.
While in there, fix monsters hiding under cockatrice corpses. They
won't do that unless there are multiple objects in the pile, but
there was no check for the possible case of all additional objects
also being other cockatrice corpses.
Life-saving has been setting u.uhpmax to max(2 * u.ulevel, 10)
and if it took place during level drain that could make u.uhpmax
increase instead of decrease, confusing healing which gets applied
to a monster who has drained the hero with Stormbringer or the
Staff of Aesculapius. Change the setting to be max(u.ulevel, 10)
(removing the times two part) and also have level drain force it
to be set back to previous value if/when it gets increased.
Max HP loss due to strength trying to drop below 3 or to fire trap
or to being hit by Death now uses a mininum max HP of u.ulevel
rather than 1. They don't have the alternate minimum of 10; I'm
uneasy that there are still two different minimum values.
I changed adjattrib() to set the flag to request a status update
before it gave its optional message rather than after so that the
new characteristic value would be visible during the message. That
resulted in not updating status when eating royal jelly changed HP
or max HP after boosting strength. But the same missing update
would have occurred--or rather, failed to occur--without the change
in sequencing if the strength boost causes a change in encumbrance.
Pull request from entrez: the log message "hit with a wielded weapon
for first time" for breaking the "never hit with a wielded weapon"
conduct wss being given when hitting with wielded non-weapons. Since
the conduct remained unbroken in that situation, the 'first hit'
message would be re-logged for subsequent non-weapon hits. This bug
was not present in initial livelog implementation; it was introduced
by the change to log first-hit before first-kill when those occurred
on the same attack. Verify that the wielded object is actually a
weapon or weapon-tool when deciding whether to log first-hit event.
Closes#708
github issue #697 from copperwater points out that using a menu for
pickup and attempting to give a count to pickup a subset of gold was
ignoring the count and picking up all gold. That was an unintended
side-effect of making '$' be a group accelerator for gold in addition
to being the 'letter' for a stack of gold (so that it can be chosen
even when not displayed on the current page, the way other groups
behave).
Picking groups via their accelerator ignored any pending count (in
tty; curses seems to apply the count). Change tty to apply a pending
count to all menu entries that get toggled on via group accelerator.
It's intended to address the gold bug but might also be used to
select one from every potion stack via '1!', for example. (Seems to
be of very limited functionality, but that was more straightforward
than singling out gold's group to behave differently.)
While in there, change how tty uses menuitem_invert_test(): call it
for set-page/set-all/unset-page/unset-all in addition to existing
invert-page/invert-all. unset-page/unset-all won't actually be
affected unless 'menuinvertmode' option is set to 2.
Closes#697
Expose map-location specific timers to lua scripts. For example:
nh.start_timer_at(x,y, "melt-ice", 10);
Currently only available timer type is "melt-ice".
Eucalyptus leaves are famously inedible except by certain animals such
as koalas. I consider it very strange that a single leaf in NetHack
gives you six meatballs' worth of calories.
I considered making it 0 nutrition, but am not sure if a 0-nutrition
comestible would end up violating some assumption that all food is at
least 1 nutrition.
Selection difference is something I have found myself wanting a lot when
working on levels, and have had to defer to a clunkier xor-then-and
approach. This commit implements the TODO-ed addition and subtraction
operators on two sets.
I don't see how the addition operator would be any different from
logical or, so it just calls l_selection_or rather than implement a new
function.
Allow defining rolling boulder launching location in special level
lua scripts:
des.trap({ type="rolling boulder", coord={7, 5}, launchfrom={-2, -2} });
launchfrom is relative to the trap coord.
If any artifacts are discovered and menustyle traditional is in use,
the player can type `a to get the artifact subset of discovered items.
Likewise with `u to for unique items (the invocation tools and the
real Amulet). For normal object classes, `<class> works for every
class, even when there aren't any discoveries for it (where you get
told "you haven't discovered any yet" if you pick such). But `a
and `u were only allowed if at least one thing in the corresponding
category had been discovered. Change to allow it even when none have
been. The feedback of "you haven't discovered any {unique items,
artifacts} yet" was already in place.
Doesn't apply for picking the class via menu. Menus don't have any
concept of "allowed as a response even though not listed as a choice".
get lawful artifacts
Reported by vultur-cadens, Angels can be given Sunsword or Demonbane
for starting equipment even when they aren't lawful so won't attempt
to use those.
This should fix it but it's a pain to test.
Closes#691