Commit Graph

587 Commits

Author SHA1 Message Date
Michael Meyer
a3e8d8eacb Clean up trapeffect code a little bit
Some minor cleanup of artifacts from the splitting up of trap effects
into the various trapeffect_foo functions: consolidate redundant
variables in trapeffect_pit (tt vs ttype), and simplify the definition
of 'inescapable' traps a couple functions (since the functions are now
specialized to a particular trap, it's unnecessary to check ttype
there in determining whether it's an inescapable Sokoban pit or hole).
2024-01-22 17:02:59 -08:00
PatR
13ff565a67 github issue #1201 - Forcefighting webs
Issue reported by Umbire:  suggestion to always destroy adjacent webs
via 'F'<dir> if wielding Sting or Fire Brand.

Sting already did that; this adds Fire Brand.

This also augments the #untrap command when wielding either of those,
or any other blade.  And rephrases successful untrap message
"You remove {the or your} {bear trap or webbing} from Fido." to
"You extract Fido from {the or your} {bear trap or web}." since the
trap remains intact.

Forcefight and #untrap against webs ought to be reconciled to remove
[some of] their differences and/or share code.  But not by me...

Closes #1201
2024-01-21 11:58:44 -08:00
Pasi Kallinen
57747535af Add m_next2u, analogous to m_next2m and next2u 2024-01-19 21:53:25 +02:00
nhmall
25a8c258e6 replace x >= LOW_PM with ismnum(x) shorthand macro 2024-01-11 14:01:10 -05:00
Mika Kuoppala
0ca1a1ca8e src/trap: Fix isclearpath out of bound access on levl array
Do isok check apriori to accessing the levl array to filter
out dx/dy that have grown too large.

This fixes:
trap.c:3455:19: runtime error: index 80 out of bounds for type 'rm [80][21]'
2024-01-09 01:18:17 +02:00
nhmall
4e19221e55 variable 'display' causes shadow variable warnings in X11 build
display.botl      -> disp.botl
display.botlx     -> disp.botlx
display.time_botl -> disp.time_botl
2024-01-05 05:58:51 -05:00
nhmall
22e52ee905 bundle the display-related hints, that tell bot() and others
that an update is required, into a struct. Remove it from
context since there is no reason to save those.
2024-01-04 23:16:27 -05:00
Pasi Kallinen
dc8d9d6cd0 Accessibility: Add location info to messages
Adds a new boolean option, accessiblemsg.  If on, some game messages
are prefixed with direction or location information, for example:

   (west): The newt bites!
   (northwest): You find a hidden door.

I added the info to the most common messages, but several are
still missing it.
2024-01-02 18:59:25 +02:00
nhmall
0927726900 static analyzer bit for trap.c
src/trap.c(5794): warning: Dereferencing NULL pointer 'which'.
2023-12-27 11:13:22 -05:00
nhmall
e9e05db113 add a pair of shorthand macros to validate an index into an array
Two variations:

IndexOk(idx, array)       validate that idx is a valid index into the array

IndexOkT(idx, array)      validate that idx is a valid index into the
                          array, excluding the final Terminator element
2023-12-23 13:46:54 -05:00
PatR
0713b91beb recalc_mapseen() followup
Update several places where lazy lastseentyp[] might be an issue.

I think it isn't updated in a timely fashion when newsym() shows
a spot covered by an object or trap, but didn't manage to find any
cases where that caused a problem.  This is more in the nature of
a precaution.
2023-12-20 03:17:29 -08:00
nhmall
70dcab833d remove obj guard from stone_missile(obj) macro
Checking the callers:
toss_up() would have segfaulted prior to use of stone_missile() if obj were NULL.
thitu() now has a guard prior to use of stone_missile()
ohitmon() would have crashed from earlier dereference otmp->dknown if it were NULL,
   otmp arg is declared nonnull
thitm() now has a guard prior to use of stone_missile().
hmon_hitmon_do_hit() null obj takes a different code path than the code path
    using stone_missile(); comment asserting that added
2023-12-16 07:58:44 -05:00
PatR
9d3710163e fix #K4063 - "back on ground" given at odd time
Moving over at item that's resting on ice gives a message about there
being ice present and then about the item, whether mention_decor is On
or Off.  With it On, you'll get a message about being back on solid
ground as soon as you leave the ice.  With it Off you wouldn't get
that at all if not levitating; that's the basic no-mention_decor
behavior for ice.  However, if you were levitating, you would get a
delayed "back on solid ground" message when moving over some other
object, which might occur quite a bit later.  Autopickup handling is
calling describe_decor() when the hero is levitating and some of that
wasn't appropriate for no-mention_decor.

This issue has been present since I first implemented mention_decor,
not introduced by recent back_on_ground() changes.
2023-12-13 13:15:18 -08:00
PatR
a7db78f7d6 fix #K4060 - "you walk quietly" while riding
Donning elven boots while riding and not already stealthy, you'd get
the message "you walk quietly" when not walking at all.  Instead of
just changing the message, make riding a non-flying steed block
stealth.  Riding a flying steed (or one you take aloft with an amulet
of flying) does not.  It would have been quite a bit simpler to have
made riding anything block stealth, but the hard part is done.
2023-12-10 22:09:26 -08:00
Pasi Kallinen
5dc94f3d83 Macro for picking random entry from array 2023-12-05 10:06:27 +02:00
Alex Smith
7ca9951996 Reduce code duplication in extrinsics-protect-items code
The same checks were being repeated for every damage type; this
sends them through two centralised functions (one for checking
whether an extrinsic blocks a specific instance of item destruction
and one for the enlightenment message), so that new mechanisms of
item destruction prevention will need to change only one point in
the code.
2023-12-05 04:34:24 +00:00
PatR
ed6b78e227 fix #K4054 - spellbook weight bug
Report was that converting a novel into a blank spellbook via water
damage resulted in a spellbook of blank paper that increased weight
when put into a bag of holding.

Spellbooks weigh 50 units but novels were defined with a weight of 0;
when one was created, a non-zero weight of 1 got assigned.  Blanking
it didn't update the weight; that stayed at 1.  Putting it into a
container reset the weight to match the new type: spellbook of blank
paper, so its weight increased.

Do that when blanking rather than wait until a container might fix it
up.  If it is already in a [possibly nested] container, update that
container's weight too along with any outer ones.

This also changes the base weight of novel from 0 to 10, so it still
gets magically heavier when turned into a spellbook of blank paper.
(The alternative seems to be to destroy it instead.)

The Book of the Dead weighed only 20 units which seemed odd to be so
much less than a spellbook.  This changes that to 50 to match those.
2023-12-03 18:03:16 -08:00
nhmall
d064ac2cda more cast style consistency 2023-11-13 20:31:02 -05:00
PatR
4512ae5bbe warning fix
Adding U suffixe to ELF_WT lead indirectly to comparing signed rn2()
with macro specifying an unsigned magic constant.
2023-11-10 10:33:50 -08:00
Michael Meyer
a1b1f3b250 Try to unify "back on solid ground" messaging
Put everything through a single function that can handle all the
complicated parts of using the correct proposition for different terrain
types, and will not just call things "solid ground" indiscriminately.
This got complicated but I'm not sure if it's possible to do it much
simpler while still using the distinct names for each type of terrain
(unless you are OK with the sentences sounding sort of wonky).
2023-11-07 16:13:55 -08:00
Michael Meyer
ccf997b28b Cache and restore gb.bhitpos in water_damage_chain
If throwing an item while levitating sent the hero hurtling into a wall
of water, the item would land in the water due to water_damage_chain's
use of bhitpos.  Restore the previous value when it is finished to avoid
interfering with the use of bhitpos further up the call stack.
2023-11-03 11:04:35 -07:00
PatR
fa0f3751a3 fix #K4026 - "object lost" panic during theft
"object lost" panic occurred when hero's worn amulet of magical
breathing was stolen.  This prevents drown() -> emergency_disrobe()
from dropping an item while in the midst of it being stolen, avoiding
the possibility of it no longer being in inventory when the theft
completes.  There may be variations other than drowning that lead to
unwear -> drop-or-destroy that are still vulnerable, and this fix can
potentially cause items to vanish from hangup save files.

It also has a side-effect of not being able to drop levitation boots
to lighten encumbrance enough to crawl out of water if the drowning
occurs while they are being taken off, not just when being stolen,
even though they should be easily droppable in such circumstance.  The
hero will just need to drop other things instead.
2023-11-01 01:54:32 -07:00
nhmall
6cbefc7c2d Revert "granular verbose message suppression mechanics"
This reverts commit be76727265.
2023-10-29 20:39:07 -04:00
Pasi Kallinen
ff4f81af1b Make rolling boulders hit walls and trees
While testing something else, I noticed rolling boulders
just ignored walls and trees; in normal play this isn't
a problem - but should probably make boulders handle other
terrain too.  Lava and water is already handled correctly.
2023-10-21 18:42:43 +03:00
Michael Meyer
fa1f1134c8 Disambiguate b_trapped null bodypart value
b_trapped was treating 0 as a null value for its bodypart parameter, but
0 is actually the value of ARM, so b_trapped(..., ARM) would be treated
as intending no A_CON abuse.  Add NO_PART = -1 to the bodypart_types
enum, and use that instead of 0 as the "no body part" value in
b_trapped, so that ARM can be passed to it without any ambiguity.

aosdict identified this issue in xNetHack and handled it differently; he
added NO_PART with a value of 0, incremented the existing bodypart_types
values, and padded the body part arrays so the actual body parts would
start at index 1.  I think using NO_PART = -1 is simpler, but that's an
alternative approach that can be used instead -- it is advantageous in
that it automatically fixes any other places where 0 is assumed to be a
non-body-part value that I may have overlooked.
2023-09-27 10:40:27 +03:00
PatR
1a64ee1c28 github PR #259 - paranoid_confirmation:trap
Fairly old pull request from copperwater:  add new paranoid_confirm
setting 'trap'.

The old commit suffered from bit rot and merging needed too much
fixing up despite there not being many bands of change in the commit's
diffs.  I ultimately redid it from scratch, although the two biggest
chunks of code started with copy+paste of the pull request's commit.

It operates like paranoid:pray.  Setting paranoid:trap adds a new
"Really step into <trap>?" y/n prompt when attempting to move
into/onto a known trap, even if an object covers it on the map.
Setting both 'paranoid:Confirm trap' turns that into a yes/no prompt.
(Adding 'Confirm' affects other paranoid confirmations; in addition
to requiring yes<return> rather than just y to accept, it also forces
no<return> to reject.)

However, moving into a known trap that is considered to be harmless
behaves as if no trap was present.  Some of the trap classification
might be out of date; several types of traps have undergone changes
since implementation of the original pull request, notably anti-magic
field.  When the hero is hallucinating, all known traps are considered
harmful since the map no longer reliably describes them.

Preceding a movement command with the 'm' prefix also behaves as if
no trap was present, bypassing confirmation for that move, similar to
how paranoid:swim currently behaves.  Being stunned or confused also
behaves as if no trap was present, taking priority over hallucination.

This updates the documentation.

Supersedes #259
Closes #259
2023-09-08 15:55:31 -07:00
Michael Meyer
8fa53d6ac5 Adjust seenres when observed attack succeeds
If a monster sees an elemental attack succeed from some other creature
or environmental danger, it will be willing to try those attacks again.
2023-08-29 12:05:48 +03:00
PatR
1b79f00a39 more PR #1077 - #sit on floor trap while Flying
Sitting on a squeaky board wasn't triggering it even after the
handler for that type of trap allowed VIASITTING to override Flying.
The check_in_air() test for floor traps didn't have the same override,
so the squeaky board handler didn't get called.

This fixes that, which led to inconsistency with some other trap
types, and additional fixes for pits and bear traps.  There might be
others that still behave oddly.  For example, if flying over a hole,
using #sit yields
 |You land.  There's a gaping hole under you!  You don't fall in.
I think that's a message phrasing issue rather than a falling trap
issue; if you want to go down, use '>' instead of #sit.  On the other
hand, you do now fall into pit traps for #sit while flying over them.
2023-07-09 14:51:30 -07:00
Ardub23
6406c9d055 Sit to trigger squeaky board even if flying
If the hero deliberately sits on the floor while flying over a squeaky
board, then either they're trying to squeak it on purpose or they haven't
noticed it. Either way, sitting should trigger it.
2023-07-09 09:28:09 -06:00
Michael Meyer
ab37888b36 Restore altar destruction from magical digging
Especially powerful magic is meant to be able to destroy altars
(breaking a wand of digging or using a drum of earthquake), but it was
being blocked by a check added to maketrap() in a7f6460 designed to
prevent wizard-mode trap wishing from overwriting stairs.  The check was
refined in 6a3d82c to add an exception for digging up graves, but
continued to prevent the destruction of other types of
previously-destructible terrain.

Since this block was a side effect of an attempt to add some guard rails
to wizmode terrain wishes, and the code to explicitly permit the
destruction of other furniture with especially powerful magic is still
present, it doesn't seem like it was actually intended.  Open up terrain
destruction by digging magic a bit more by excluding only
non-destructible terrain, not all furniture other than graves, from
being overwritten by pits and holes.

Also, use AM_SANCTUM to more precisely identify non-destructible high
altars in dig_check() rather than checking whether the hero is on the
Astral or Sanctum levels.
2023-07-07 10:41:18 -07:00
PatR
2d6d151b28 PR #1009 - higher statue trap difficulty
Pull request from NulCGT:  make statues created for statue traps be
5 to 10 points higher in difficulty than the default would be.

5 to 10 points of difficulty higher is already used for figurines.
The pull request chose the same amount but I've reduced it to 3 to 6.
Partly so that they won't be the same, partly so that they won't be
too hard when activated, and partly so that the creature won't be
quite as obvious a give away that the statue is a trap.

Closes #1009
2023-07-02 15:27:58 -07:00
Kestrel Gregorich-Trevor
2dd0af630e Adjust statue traps to be biased toward more difficult monsters. 2023-07-02 15:16:57 -07:00
PatR
8fd8d1defa Mitre of Holiness
If the priest quest artifact Mitre of Holiness (a helm of brilliance,
so crystal helmet) is acquired via the quest (rather than by wishing)
make it start out tempered (aka crackproof|erodeproof).
2023-06-17 13:27:40 -07:00
PatR
1bd966f826 fix issue #1061 - dipping container into water
Issue reported by loggersviii:  dipping a container into an uncursed
potion of water mentions water getting into the container.  That
happens even when that type of potion hasn't been discovered yet.

Make POT_WATER become discovered if this occurs.  Doesn't apply when
hallucinating where a random liquid is mentioned instead of water.

Fixes #1061
2023-06-15 02:29:51 -07:00
PatR
e9c58c2fe4 breaking crystal armor
Instead of a 5% chance for crystal plate mail or crystal helmet to
break each time it's subjected to breakage, switch to a 10% chance
but the damage is treated as erosion rather than break/don't-break.
'crystal foo' will need to go through four stages of damage before
breaking:  cracked crystal foo, very cracked crystal foo, thoroughly
cracked crystal foo, then gone.  Crackproof handling is included,
described as tempered crystal foo.

It mostly still applies to throwing and kicking the item.  Having
some hits trigger damage might be worthwhile but isn't implemented.

Object creation within lua code probably needs to be updated, and
when the Mitre of Holiness is created in the priest/priestess quest
it should start out as tempered (erodeproof).  Perhaps it ought to
be erodeproof regardless of where/how it's created.
2023-06-14 15:54:04 -07:00
PatR
450f060132 github issue #1060 - crystal helmet
Issue reported by vultur-cadens:  changing helm of brilliance to
crystal made it stop being classified as "hard helmet" so it gave
less protection against things falling onto the hero's head.

Change the is_metallic() tests used on helmets to new hard_helmet().
Unlike when thrown, crystal helmets don't break when objects fall
on them.

Fixes #1060
2023-06-14 06:13:11 -07:00
PatR
59677e7440 rewrite safe_teleds()
The teleport to safety routine would try to find a viable spot 400
times, the first 200 rejecting trap locations and the last 200
accepting such.  While testing various escape from lava variations
recently, I noticed that I could fail to reach safety even when there
was an open spot immediately adjacent to me.  I added a BandAid(tm)
to make another 400 tries if the first attempt failed, but that was
clumsy and still didn't guarantee picking a viable spot.

This adds a new routine, collect_coords(), which will gather a list
of coordinates for the entire map.  safe_teleds() goes through them
one by one until either finding a spot or exhausting the possibilies,
without randomly trying and retrying the same spot multiple times and
without missing other potential spots, also without just scanning the
map from left to right and top to bottom or similar.

Various other things which retry over and over, and especially the
ones which make a bunch of random attempts and then fallback to trying
every spot on the map, could be switched over to this, at least for
the falling back phase.  Right now collect_coords() is local to
teleport.c but that could be easily changed.

The try-at-random method is much quicker when there are lots of
available spots but the gather-shuffled-candidates method is
guaranteed to succeed if success is possible.  The way safe_teleds()
is presently using it collects the list with all locations within
2 steps first, then those within 3 to 4, then 5 to 6, and so on out,
randomized within each block of ranges.  So the destination will be
within one step of being as close to the starting spot as possible
but not always immediately adjacent when that happens to be available.
2023-05-15 01:42:13 -07:00
PatR
2646688e2d back_on_ground()
Replace a couple of hardcoded "back on solid ground" messages with
something more versatile.

Also, make life-saving handling for failed rescue from drowning
similar to that of failed rescue immolation by lava.  If there are
any cases where more than two tries is needed, they elude me.  The
new code doesn't confer temporary water walking if emergency teleport
fails; perhaps it should.
2023-05-15 01:08:04 -07:00
PatR
dd7d7f2eae fuzzer vs lava, take III
Change dying in lava to attempt life-saving at most twice.  The first
time might be via amulet or via declining to die.  The second time
can only be via declining to die after failing to teleport to safety
the first time, but could happen in explore mode as well as in wizard
mode, either interactive or fuzzer.

If the hero dies twice without ending the game, confer temporary fire
resistance and water walking so that other actions can be attempted.
After 5 turns without getting away from the lava or doing something
to acquire those capabilities, the hero will be subject to falling in
again.

Then the whole cycle might repeat, even many times, but the fuzzer
will eventually choose ^V or #wizmakemap and escape.  Players in
explore mode will either figure out a way to get out of it or
eventually have to give up but can try as many times as they like,
not that much different than being cornered by a deadly monster.
2023-05-08 15:21:03 -07:00
PatR
210387c176 break fuzzer out of life-save loop, take II
When being burned up by lava, die 20 times before giving up the
attempt at life-saving (was unlimited).  Giving up leads to the hero
standing on lava rather than dying.  Normally moveloop() dunks the
hero again on next turn but fuzzer life-saving now has a chance to
confer temporary fire resistance.  So hero might have an opportunity
to level teleport or use ranged attacks that free up spots so have
somewhere available to teleport to safety if/when dunked again.

The recent code to give up on trying to resurrect the dying hero
after 15 deaths on the same move is extended to 20.  They apply to
each of the 20 lava resurrect attempts but still doesn't guarantee
that the hero will eventually get free before done() gives up.
2023-05-08 01:35:21 -07:00
PatR
6de996971b fix #K3915 - "deleting worn obj" warning
Knocking a monster into lava triggering impossible warnig "deleting
worn object" for a wooden shield.  The monster had to be wearning
flammable armor and be fire resistant to survive instead dying and
dropping inventory, and it couldn't be a creature that can survive at
lava locations like a salamander and the armor needed to already be
thoroughly burnt.

It wasn't hard to figure out what needed to be fixed, but it was very
hard to reproduce the situation in order to verify that fix.  The
report was for monster vs monster knockback but I jousted with a lance
instead.  I still don't understand why burning up a worn wooden shield
triggered the warning but burning up a worn orcish cloak did not.
2023-05-06 00:08:35 -07:00
PatR
e28d15f491 endgame portal fix
A recent change to prevent creating webs at water locations also
deliberately prevented them at air locations but had the unintended
side-effect of preventing creation of magic portals on the Planes
or Air and Water.  Those two levels always place the portal in air.
Explicitly allow air if the trap being created is a magic portal.
2023-05-05 17:42:57 -07:00
PatR
d2f4edc209 'm #genocided' bit
Overlooked part of customizing the #genocided sort menu.

A bit of unrelated trap.c formatting included.
2023-05-03 05:20:13 -07:00
PatR
b3580289be fix github issue #1017 - webs in/on water
Reported by copperwater, it was possible for a web to be created
at a water or lava location.  It would not be displayed even after
being discovered; showing the terrain superseded showing the trap.
But it functioned normally and could trap the hero.  Webs pull the
victim to the floor so hero would drown or burn up on next move
even if the spot had been reached while floating or flying.

A monster spider couldn't survive at a water or lava location, but
a poly'd hero could.  Creating a web via #monster or wizard mode
wish could result in it affecting some unsuspecting player via bones.

Disallow creation of webs at water, lava, and air or cloud spots.
(They're already disallowed at furniture spots.)

Fixes #1017
2023-05-01 01:54:35 -07:00
nhmall
826ce951e7 get rid of NetHack macro conflict with curses routine delay_output() 2023-04-21 08:25:53 -04:00
copperwater
dad1c3f8b7 Fix: breathless monsters always generate in water in special levels
... unless explicitly specified to generate at a specific point or
within a specific area. But if they are permitted to generate anywhere
on the level, and it contains water, they always end up in the water. I
noticed this when trying to explicitly specify ghouls to generate
anywhere on a level with a minimal amount of water.

This was due to the definition of "amphibious" being conflated with
"breathless", such that all breathless monsters counted as amphibious.
There are plenty of breathless monsters in the game that decidedly don't
normally inhabit water, such as undead, but they would pass the
amphibious() check in pm_to_humidity and thus the game decides that they
must generate in wet terrain if there is any available.

This fix takes the approach of changing amphibious() so that it no
longer checks the M1_BREATHLESS flag and only considers M1_AMPHIBIOUS,
then updating the places where amphibious() and Amphibious are used
accordingly. I also added a new macro cant_drown() which wraps up
swimming, amphibiousness, and breathlessness because these three things
are frequently checked together in the context of whether something
should drown.

Places where amphibious() or Amphibious did NOT have an extra
breathless() or Breathless check added on, and thus where behavior has
been changed:
- The pm_to_humidity function (to fix the bug).
- Player vs water in goodpos; it didn't seem like being polymorphed into
  a breathless non-amphibious monster should make it fair game to
  randomly teleport into water even though it's technically safe.
- Awarding extra experience when killing an eel. (So the hero will get
  the extra experience if they are polymorphed into a breathless
  non-amphibious monster and don't have magical breathing. Very much an
  edge case.)
2023-04-16 09:57:41 +03:00
PatR
bbd76562b0 redo fix for issue #1003 - energy drain
The fix in commit 14d003c4ba prevented
current energy from ending up 1 point above maximum energy but it
didn't preserve the intent of splitting the drain with up to half
coming out of maximum and the remainder out of current.  This restores
that intent but now only does so when maximum is more than the full
drain amount rather than when it is more than the up-to-half portion,
becoming less harsh when hero's max energy is very low.  If current
is also very low then max energy will be reduced anyway, but by less.

Some unrelated formatting of invent.c has gotten mixed in.

Revises #1003
2023-04-08 16:40:21 -07:00
PatR
14d003c4ba fix github issue #1003 - anti-magic field energy
Issue reported by vultur-cadens:  when trap effect of an anti-magic
field reduced maximum energy, the result might end up with current
energy being one point higher than new maximum.

Fixes #1003
2023-04-07 23:34:19 -07:00
PatR
dad67436e6 fix #K3895 - 'o' at own spot during pass-walls
If standing at the location of a closed door while having Passes_walls
ability, attemping to open that door with 'o' reported "you don't find
anything here to loot".

Using 'o' to loot for direction ./>/< is intentional but it ignored
the possibility of there also being a closed door present.  When the
latter applies, only switch from open to loot for direction '>' so
that '.' (and '<') will open the door.  Doesn't matter for creatures
that can ooze under a closed door--trying to use 'o' gets rejected for
them because they lack hands.

Also allow hero in Passes_walls form to use 'c' when at open door spot.
(For creatures that ooze under doors, 'c' is rejected just like 'o'.)

Unrelated:  fix a typo in a recently added comment.
2023-03-29 13:48:42 -07:00
PatR
0532eae7d2 feedback when escaping lava
Fix the duplicate feedback given when landing on one or more items
after teleporting out of lava.

This also avoids "you find yourself back on solid water" if you are
able to survive at a water location and safe_teleds() puts you on one.
2023-03-27 17:08:18 -07:00