Commit Graph

4556 Commits

Author SHA1 Message Date
PatR
feac8c8f68 'm' prefix for drinking and dipping
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) {' ... '}'.
2022-04-13 03:14:39 -07:00
PatR
60c504dd40 context-sensitive inventory - action sequencing
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.
2022-04-12 14:56:38 -07:00
PatR
8992c0f8b1 implement github issue #727 - item-action '#tip'
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
2022-04-11 02:27:03 -07:00
PatR
fbbcd7c9cb object bypass bit sanity for container contents
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.)
2022-04-11 02:16:22 -07:00
Pasi Kallinen
24d3c96c1d X11: set menu entries to same length
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.
2022-04-10 16:09:43 +03:00
PatR
593c3532fc more shop damage repair
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.
2022-04-09 15:55:21 -07:00
PatR
dadbea1d8c preliminary fix for github issue #726 - restdamage
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...
2022-04-09 12:02:30 -07:00
PatR
d52e6732a8 fix github issue #722 - unique monster's corpse
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
2022-04-09 10:15:34 -07:00
Pasi Kallinen
e53a4c0abd Context sensitive item usage from inventory
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.
2022-04-09 15:28:23 +03:00
PatR
bd7ed0d343 pull request #725 - detecting mimic as statues
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
2022-04-08 10:23:54 -07:00
PatR
12185138d2 fixes entry for pull request #724 - fountain \
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
2022-04-08 10:14:44 -07:00
PatR
835a4e78f5 pull request #720 - specifying monster gender \
in lua code was ignored

I'm taking this one on faith....

Fixes #720
2022-04-08 10:03:42 -07:00
PatR
b7d9bed8c5 X11 build fix
The X11 interface wouldn't build if STATUS_HILITES was disabled.
Failure was due to post-3.6.x changes.
2022-04-06 11:18:51 -07:00
PatR
1b4ad3c30d fixes entry typo 2022-04-06 00:41:22 -07:00
PatR
47cef18a9b life-saved, while helpless
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.
2022-04-04 10:20:28 -07:00
Pasi Kallinen
16d813b44a Give a message when stinking cloud is created on top of hero 2022-04-03 20:43:04 +03:00
Pasi Kallinen
92c21b588b Ask to kick a locked door open, if hero has no unlocking tool 2022-04-03 13:58:50 +03:00
Pasi Kallinen
38a6cee1ab Don't pacify unique monsters when untrapping them from web 2022-04-02 19:38:50 +03:00
PatR
fd355d6f6c tty logic error using menuitem_invert_test()
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.
2022-04-02 01:00:09 -07:00
PatR
eea362249c wishing for artifacts
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".
2022-04-02 00:28:48 -07:00
PatR
f0c7394968 git issue #717 - avoid putting monsters on scare \
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
2022-04-01 05:09:58 -07:00
Pasi Kallinen
f45e79e1a0 Fix medusa levels
My recent commit broke medusa-3 and medusa-4, so fix those.

Make des.stair and des.ladder also accept hash-coordinate:
  des.stair("up", {8, 10});
2022-04-01 08:53:15 +03:00
PatR
a230034af7 github issue #715 - losing stoning resistance \
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
2022-03-31 04:48:26 -07:00
PatR
8fbb6dc93b github issue #716 - teleporting onto pits
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
2022-03-30 14:41:53 -07:00
PatR
b0067493c9 fix #K3564 - obj sanity failure: N globs for N>1
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.
2022-03-30 14:11:29 -07:00
PatR
2a8727c459 couple of Guidebook bits: autopickup, tile_file
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.
2022-03-29 11:24:45 -07:00
PatR
73d2f9d420 fixes3-7-0 typo
Remove an extraneous space from a recent fixes entry.
2022-03-29 10:47:35 -07:00
PatR
6a2ff5743a items destroyed by exploding chest
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.)
2022-03-27 17:55:52 -07:00
Pasi Kallinen
1d78d3c3f2 Fix travel getting stuck oscillating between two locations
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.
2022-03-26 23:58:30 +02:00
PatR
071d79dce2 stoning resistance revisited
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.
2022-03-26 11:23:06 -07:00
PatR
167dec0d56 eating green mold corpses
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.
2022-03-24 15:49:27 -07:00
Pasi Kallinen
60bf399f91 Don't stop travel when going past a closed door 2022-03-24 19:33:37 +02:00
PatR
3f4b5ea557 fixes entry for pull request #710
Pull request from entrez:  body parts for spiders and cockatrices.

Closes #710
2022-03-22 14:31:53 -07:00
PatR
385a9a7fde encumbrance checks
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.
2022-03-22 10:48:23 -07:00
Pasi Kallinen
6eadff01b8 Lua: selection get and rndcoord changes 2022-03-22 10:45:20 +02:00
Pasi Kallinen
27898340b9 Lua: coordinate tweaking
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.
2022-03-22 09:16:19 +02:00
PatR
88a61f1c40 eating food while hiding under it
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.
2022-03-21 18:11:26 -07:00
PatR
d53c1a7a67 max HP manipulation
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.
2022-03-21 12:32:07 -07:00
PatR
8a9578e94c pull request #708 - logging of first hit
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
2022-03-19 18:10:12 -07:00
PatR
df58dc30b9 tty: count for group accelerators
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
2022-03-16 17:03:52 -07:00
Pasi Kallinen
811299edaf Lua: allow calling impossible 2022-03-16 16:58:42 +02:00
Pasi Kallinen
38924002e0 Lua: ice theme room and melting ice
Allow the ice theme room to occasionally have melting ice.
Add nh.abscoord() to convert room-relative to map-absolute coords.
2022-03-15 22:05:36 +02:00
Pasi Kallinen
bdc81ab389 Lua: allow obj chain iteration 2022-03-15 18:24:49 +02:00
Pasi Kallinen
e33dd11e99 Document the lua object class 2022-03-15 14:17:46 +02:00
Pasi Kallinen
957c0fbee0 Lua: location-specific timers
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".
2022-03-15 13:46:56 +02:00
copperwater
1483778e96 Reduce eucalyptus leaf nutrition to 1
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.
2022-03-15 07:41:53 +02:00
copperwater
b4a460f81b Implement selection addition and difference
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.
2022-03-14 18:42:28 +02:00
Pasi Kallinen
4be6fb0df9 Rolling boulder launch coordinates
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.
2022-03-12 18:34:44 +02:00
PatR
d4cec7d947 discovered objects within class for a and u
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".
2022-03-10 14:57:15 -08:00
PatR
0effaf529a fix github issue #691 - non-lawful Angels \
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
2022-03-07 15:12:12 -08:00