Commit Graph

642 Commits

Author SHA1 Message Date
Alex Smith
82edcca402 Improve messages for oilskin sack protection versus water
The existing messages made sense for brief dips into water, but
didn't make sense when using an oilskin sack for an extended
period underwater (and also assumed that the player was able to
see the sack). This commit changes the message to make sense
(and to be less spamy) if the hero enters water and remains there,
and prevents oilskin sacks self-IDing if the hero is blind and
thus can't see the water.
2025-11-07 18:21:21 +00:00
nhmall
a943c4c10b replace some weight-related magic numbers
adds a header file include/nhconst.h  (I'm open to a better name)
2025-03-19 13:29:58 -04:00
nhmall
57825b170d pull request #1397 by copperwater
Closes #1397
2025-03-14 10:00:35 -04:00
PatR
90717ca633 more chest->tknown handling
Disarming a chest trap was setting obj->tknown = 0 even though the
hero just discovered that it isn't trapped.

Triggering a chest trap behaved similarly.  Since there are no
repeating chest traps, hero should know that the chest whose trap
just went off is no longer trapped.

chest_trap() didn't document its return value but was clearly meant
to return True if the chest was destroyed.  It didn't handle that
correctly when the chest was being carried.  However, none of the
callers actually use the return value.  [This fix tracks whether the
chest gets deleted; a better fix would be to destroy an exploding
chest even when it is being carried.]
2025-03-13 13:54:56 -07:00
copperwater
49b43f760f Fix: a number of unblock_points shouldn't unblock unconditionally
Initially diagnosed in an xnethack fuzzer crash - unblock_point
shouldn't be called when a closed door becomes non-closed, because it's
possible that there's a gas cloud on the space which means it still
blocks vision. These always need to be recalc_block_point. A number of
them were fixed, but when I went through all the xnethack ones, I found
some that were unchanged from upstream NetHack. I reproduced the sanity
check impossibles usually by breathing gas at a door as an iron golem
and then opening or destroying the door to trigger the unblock_point
call.

The use of recalc_block_point in wizterrainwish was not triggering this
bug, but the previous code there basically duplicated
recalc_block_point.
2025-03-08 07:53:57 -05:00
nhmall
785f78c39b avoid "You fall down a deep shaft!" if flying down
Fixes #1371
2025-02-03 00:53:06 -05:00
Pasi Kallinen
991a1dbe43 Fix exploding landmine and boulders next to lava
Same issue as with breaking a wand of digging in commit 7ce0751a
2025-01-20 19:26:12 +02:00
PatR
34dc5d7acf static analyzer changes for trap.c
Picked arbitrarily; there weren't any unresolved analyzer complaints
for trap.c.  I wonder why the onefile analysis isn't complaining here.

'in_sight' may have been relevant before the trapeffect_xyz() code
was split apart, but it isn't useful for trapeffect_hole() despite
the comment about it.

release_holding_trap() is fairly convoluted and the complaints being
addressed here were relevant.
2025-01-17 21:26:32 -08:00
SHIRAKATA Kentaro
9b7bcf67ba change the type of xytod()'s return value to int
xytod()'s return value is an index, so its type should be int, not coordxy.
2025-01-12 14:37:13 +09:00
Pasi Kallinen
c956e3e215 Fix vision when applying a wand of digging 2025-01-08 13:59:50 +02:00
Pasi Kallinen
2ebe8915f6 Prevent melting ice destroying necessary traps
A magic portal ended up on a melting ice.
2025-01-04 16:05:07 +02:00
Pasi Kallinen
d11747899e Fix boulder-over-pit sanity after landmine blows up 2024-12-28 20:30:11 +02:00
Pasi Kallinen
87694e1a95 Hero remembers trapped boxes
After finding a trap on a chest or a large box, remember it
as trapped: "You see here a trapped large box."
Randomly generated chests and boxes can be obviously trapped.
Allow defining obviously trapped containers via lua.

Invalidates saves and bones.
2024-12-19 13:11:25 +02:00
Pasi Kallinen
fd23463941 Sparkle shield effect and accessibility
When sparkle is turned off, there are some places where
a monster resisting the effect did not give any message.

This fixes some of those.
2024-12-14 14:34:22 +02:00
PatR
b2b9b685c5 fix issue #1305 - failed #untrap from doorway
Issue reported by loggersviii:  attempting #untrap from an adjacent
doorway can move the hero diagonally out of the doorway.

A followup comment by elunna pointed out that a monster's attack that
results in knockback can produce similar result.

Fixes #1305
2024-12-13 22:48:32 -08:00
nhmall
0792e5fe9e expand implicit fallthrough detection to non-gcc compilers
gcc has recognized various "magic comments" for white-listing
occurrences of implicit fallthrough in switch statements for
a long time:

    The range and shape of "falls through" comments accepted are
    contingent upon the level of the warning. (The default level is =3.)

    -Wimplicit-fallthrough=0 disables the warning altogether.
    -Wimplicit-fallthrough=1 treats any kind of comment as a "falls through" comment.
    -Wimplicit-fallthrough=2 essentially accepts any comment that contains something
     that matches (case insensitively) "falls?[ \t-]*thr(ough|u)" regular expression.
    -Wimplicit-fallthrough=3 case sensitively matches a wide range of regular
     expressions, listed in the GCC manual. E.g., all of these are accepted:
        /* Falls through. */
        /* fall-thru */
        /* Else falls through. */
        /* FALLTHRU */
        /* ... falls through ... */
       etc.
    -Wimplicit-fallthrough=4 also, case sensitively matches a range of regular
     expressions but is much more strict than level =3.
    -Wimplicit-fallthrough=5 doesn't recognize any comments.

Plenty of other compilers did not recognize the gcc comment convention,
and up until now the compiler warning for detecting unintended
fallthrough had to be suppressed on other compilers. That's because the code
in NetHack has been relying on the gcc approach, and only the gcc approach.

The C23 standard introduces an attribute [[fallthrough]] for the
functionality, when implicit fallthrough warnings have been enabled.

Several popular compilers already support that, or a very similar attribute
style approach, today, even ahead of their C23 support:

       C compiler                       whitelist approach
       ---------------------------   -------------------------------------
       C23 conforming compilers         [[fallthrough]]

       clang versions supporting
       standards prior to
       C23                              __attribute__((__fallthrough__))

       Microsoft Visual Studio
       since VS 2022 17.4.
       The warning C5262 controls
       whether the implict
       fallthrough is detected and
       warned about with
       /std:clatest.                    [[fallthrough]]

This adds support to NetHack for the attribute approach by inserting a
macro FALLTHROUGH to the existing cases that require white-listing, so
other compilers can analyze things too.

The definition of the FALLTHROUGH macro is controlled in include/tradstdc.h.

The gcc comment approach has also been left in place at this time.
2024-11-30 14:16:27 -05:00
PatR
9c0e47785a digging in ice
If the spot in front of a closed drawbridge was ICE, digging there
had issues....
2024-11-27 08:41:55 -08:00
nhmall
1dbba0f63b rename IS_ROCK() macro to IS_OBSTRUCTED()
It has included trees since they were added, so give it a
more fitting name.
2024-11-09 11:12:42 -05:00
nhmall
e863583c56 iterating gi.invent (github issue #1315)
GitHub issue #1315 points out that it is possible for
a downstream function to change an object's nobj field
to point to a completely different chain.

The cited example by @vultur-cadens was:

     for (obj = gi.invent; obj; obj = obj->nobj)
         if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) {
             curse(obj);
             ++buc_changed;
         }

    curse() drops the weapon with drop_uswapwep(),
        which calls dropx(),
            which calls dropy(),
                which calls dropz(),
                    which calls place_object().

place_object alters the nobj pointer, to point to the floor chain:
    otmp->nobj = fobj;
    fobj = otmp;

The result was that the next loop iteration was then using floor
objects from the floor chain.

This alters several for-loops to use a more consistent approach,
particularly when the obj is being handed off to a function,
where a downstream function might, or might not, alter the nobj
field.

References:

https://github.com/NetHack/NetHack/issues/1315
https://www.reddit.com/r/nethack/comments/1gkc9ub/even_if_you_drop_an_item_before_drinking_from_the/
2024-11-06 16:59:51 -05:00
PatR
e9a25a0a1c sanity_check: current hero health better than max
Changes to setuhpmax() a couple of days ago to deal with sanity_check
for "current hero health as monster better than maximum" ended up
triggering sanity_check about "current hero health better than maximum"
when gaining experience level(s) while polymorphed.
2024-09-26 23:00:42 -07:00
PatR
0dad60e485 fix github issue #1291 - water walking vs lava
Issue reported by ars3niy:  non-fireproof water walking boots are
supposed to be destroyed if worn on lava, but a post-3.6 change
made that only happen if the hero died and left bones.

The boots remained intact if hero was fire resistant or survived
6d6 damage.  Staying intact should only happen if they're fireproof.

This seems to work but each time lava_effects() gets modified it
becomes more fragile.  Having deleted objects stick around doesn't
help with this problem, which is to keep an item which is being
stolen--and whose loss causes the hero to drop into lava--from
being burned up before being transferred to the thief's inventory.

Fixes #1291
2024-09-26 08:10:26 -07:00
PatR
993c3b303f some reformatting (4 of 4) 2024-09-05 16:49:42 -07:00
nhmall
6c0ae092c6 distinguish global variables that get written to savefile
The g? structs had a mix of variables that were written to
the savefile, and those that were not.

For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.

This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.

Details:

    gb.bases            -> svb.bases
    gb.bbubbles         -> svb.bbubbles
    gb.branches         -> svb.branches
    gc.context          -> svc.context
    gd.disco            -> svd.disco
    gd.dndest           -> svd.dndest
    gd.doors            -> svd.doors
    gd.doors_alloc      -> svd.doors_alloc
    gd.dungeon_topology -> svd.dungeon_topology
    gd.dungeons         -> svd.dungeons
    ge.exclusion_zones  -> sve.exclusion_zones
    gh.hackpid          -> svh.hackpid
    gi.inv_pos          -> svi.inv_pos
    gk.killer           -> svk.killer
    gl.lastseentyp      -> svl.lastseentyp
    gl.level            -> svl.level
    gl.level_info       -> svl.level_info
    gm.mapseenchn       -> svm.mapseenchn
    gm.moves            -> svm.moves
    gm.mvitals          -> svm.mvitals
    gn.n_dgns           -> svn.n_dgns
    gn.n_regions        -> svn.n_regions
    gn.nroom            -> svn.nroom
    go.oracle_cnt       -> svo.oracle_cnt
    gp.pl_character     -> svp.pl_character
    gp.pl_fruit         -> svp.pl_fruit
    gp.plname           -> svp.plname
    gp.program_state    -> svp.program_state
    gq.quest_status     -> svq.quest_status
    gr.rooms            -> svr.rooms
    gs.sp_levchn        -> svs.sp_levchn
    gs.spl_book         -> svs.spl_book
    gt.timer_id         -> svt.timer_id
    gt.tune             -> svt.tune
    gu.updest           -> svu.updest
    gx.xmax             -> svx.xmax
    gx.xmin             -> svx.xmin
    gy.ymax             -> svy.ymax
    gy.ymin             -> svy.ymin

Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
          gf.ftrap, gl.light_base, gt.timer_base
2024-07-13 14:57:50 -04:00
PatR
a33f1edd24 YMonnam(monst)
Replace several upstart(y_monnam(mon)) with new YMonnam(mon) to
produce "Your little dog" and such.

Also change one or two Monnam(mon) to YMonnam(mon) and one pline(...)
to pline_mon(mon, ...).
2024-07-04 14:27:28 -07:00
Pasi Kallinen
89ea47f702 Monsters can track hero through fixed teleport traps
Also make fixed teleport traps always trigger when entered.
2024-06-15 18:44:30 +03:00
Pasi Kallinen
951401e52a Allow fixed-destination teleport traps
Add a theme room with multiple visible teleportation traps
which will always teleport to specific locations in the same level.

Teleport trap change from xNetHack by copperwater <aosdict@gmail.com>.
2024-06-14 19:50:20 +03:00
Pasi Kallinen
a72b95e4bc Accessibility: more message locations
Add a new pline_mon() which sets the message location
to the monster location.

Add locations to several trap messages.
2024-06-13 19:04:33 +03:00
PatR
6718a8af1f fire_damage() vs containers
Containers can't become fireproofed so the line of code in
fire_damage() which tested for that led to confusion.

Also, add missing handling for statues as containers.
2024-06-08 15:22:08 -07:00
Pasi Kallinen
2ba42cf78c Fix accessing freed landmine trap
Landmine blew up, scatter exploded a potion of oil, which melted
the ice on which the landmine was, resulting in the landmine trap
being deleted.  The code then tried to access it to make a pit.
2024-05-31 10:28:44 +03:00
Pasi Kallinen
5b94745658 Fix only flying monsters able to evade some traps 2024-05-30 17:51:56 +03:00
PatR
5641e2560f fix issue #1248 - drowning on Plane of Water
Issue reported by Umbire:  if hero dies by drowning on the Plane
of Water, cause of death was reported as "drowning in a limitless
water".

Reported for livelogging but applied to tombstone and logfile too.
Omit the article "a" in this situation.

For 3.6.7, it would have started as "drowning in a water" and been
updated on the fly to be "drowning in deep water".  3.7 changed
terrain type WATER to be "wall of water", where "a" is expected,
and also added "limitless water" for Plane of Water, but it was
neglecting to include a similar fixup for the latter.  The "deep
water" fixup is still present but doesn't get triggered anymore.

Fixes #1248
2024-05-29 14:24:10 -07:00
Pasi Kallinen
61e54c2a87 Fix monster hp being above max hp
If the monster took damage from a fire trap, got killed, and then
lifesaved, the trap effect then reduced the map hp below the hp.
2024-05-28 20:58:03 +03:00
Pasi Kallinen
2ebbd13f79 Fix boulder over a hole or a pit dug by a monster
When a monster digs down and creates a pit or a hole,
drop the boulder at the location into it.
2024-05-28 19:10:36 +03:00
Pasi Kallinen
ed5c7114ab Untrapping containers or doors gives some experience 2024-05-08 20:10:32 +03:00
Pasi Kallinen
b76a96bf40 Add missing break
A rolling boulder hitting a wall or a tree could keep going,
possibly going out of map bounds
2024-04-22 14:46:18 +03:00
Pasi Kallinen
00d0700e75 Pit fiends can easily climb out of pits 2024-04-12 11:13:24 +03:00
Pasi Kallinen
defb5d5f80 Pets considered any noise made by hero as whistling
In 3.6.2 parts of the wakeup code were merged together, and this
caused pets consider any noise made by the hero - such as hitting
iron bars or digging - as whistling for them to come to the hero.

Change it to only consider actual whistling and ringing a bell.
2024-04-03 12:46:15 +03:00
PatR
e4ffda7386 blanking novels
Simplify converting novels into blank spellbooks via water damage.
Since that can occur, update cancellation to do it too.
2024-03-28 23:44:34 -07:00
Pasi Kallinen
f131942dd2 Another tamedog message
Give a different message when a peaceful creature was tamed.
Allow suppressing this and the previous message, when the caller
handles messaging.
2024-03-24 10:48:29 +02:00
nhkeni
54c3dd35ac Merge branch 'keni-staticfn' into NetHack-3.7 2024-03-16 09:38:21 -04:00
nhkeni
9c0ed8ae63 NOSTATICFN for src/* 2024-03-14 17:41:51 -04:00
PatR
68312f7feb magic trap uncursing vs scroll of remove curse
Reported directly to devteam:  if a magic trap gave its uncurse
effect, scroll of remove curse could become discovered.

Turns out that it would happen if hero was wielding a stack of
unholy water potions.  It didn't matter whether they were known
as water or known to be cursed or whether hero was carrying any
scrolls of remove curse.
2024-03-13 12:39:50 -07:00
nhmall
6d22361fca separate function for acid potion damage pr#1195
Also includes a couple of trailing whitespace removals.
2024-03-09 09:25:43 -05:00
nhmall
2bda94e982 Merge branch 'pot-acid-damage' of https://github.com/argrath/NetHack into NetHack-3.7 2024-03-09 09:23:20 -05:00
RainRat
a3658f85ac fix typos 2024-02-28 20:15:56 -08:00
PatR
9f7fffc823 rolling boulder trap fix
The recent "trap.c reformatting" commit included a non-formatting
change switching from gb.bhitpos.x,.y to local x,y in the rolling
boudler trap routine.  The part of that routine used when a rolling
boulder hits another boulder and transfers its remaining momentum
to that other one got switched to wrong x,y and the first boulder
basically kept going, possibly hitting itself at each new position.
2024-02-22 11:00:18 -08:00
Erik Lunna
eb22a81088 Refactor, unify, and nerf item destruction
Note: Original change is from xNetHack by copperwater <aosdict@gmail.com>,
      but this commit comes from HACKEM-MUCHE by Erik Lunna, with
      some minor code formatting.

From xNetHack commit a0a6103bea:

'The original goal: nerf item destruction using a method I initially
 proposed for SpliceHack, in which the number of items subject to
 damage from any single source is limited by the amount of damage the
 effect caused. The intent was to be more fair all around and prevent
 aggravating situations where, for instance, a chest shock trap zaps
 you for 4 damage and immediately ten of your rings and wands blow up.

 Problem 1: no easy way to limit the items destroyed without biasing
 heavily towards the start of the invent chain. The old code was able
 to get away without bias by just indiscriminately destroying
 everything eligible with a 1/3 chance. Here, I had to introduce
 reservoir sampling in a somewhat more complex form than I've applied
 it elsewhere, since there are a pool of potential items.

 Problem 2: destroy_item no longer worked remotely like destroy_mitem,
 which still destroyed 1/3 of items indiscriminately. Commence the
 process of squishing them into one function that handles both the
 player and monsters. (Which required making a lot of adjustments to
 destroy_one_item, now named maybe_destroy_item, on nits such as
 messaging and when to negate damage. An annoying consequence of the
 merge is that in the player case, their HP is deducted and they can
 be killed directly, but for monsters they need to add up the
 destruction damage and return it.)

 Unifying destroy_item and destroy_mitem has some advantages: in
 addition to the obvious code duplication removal, it ensures monsters
 now take the same damage as players for destruction (previously they
 took a piddly 1 damage per destroyed item). Now when you hit
 something with Mjollnir and their coveted wand of death breaks apart
 and explodes, you at least get the satisfaction of knowing they took
 the standard amount of damage from it.  Monsters also now get
 symmetry with players in having extrinsic elemental resistance
 protect them from item destruction, and damage negation from item
 destruction if they were appropriately resistant.

 Problem 3: a lot of callers didn't preserve the "amount of incoming
 damage" that this refactor relies on. E.g. if the defender resisted
 that element, the local dmg variable would be set to 0. So I had to
 do some wrangling with callers to save that original damage
 value. The rule of thumb is: all *incoming* damage counts. So that
 includes the player's spellcasting bonus if applicable, but not
 things like half damage, negation due to resistance, or extra damage
 due to being vulnerable to cold/fire.

 Then I figured, while I'm here let's get rid of all those silly cases
 where destroy_items is called multiple times for various different
 object classes, and cut the object class parameter out of it. This
 has a few minor effects:

 - Places where different object classes previously rolled
   independently for destruction to happen at all now roll
   once. (Which, by my calculation, generally means less incidences of
   destruction - a fire attack now won't have three separate chances
   to hit your scrolls, potions, and spellbooks. On the flip side, a
   lucky roll will no longer save an entire object class in your
   inventory.)

 - Callers can no longer specify different probabilities for
   destroying different object classes. The only place this was really
   used was to call destroy_item with a slightly lower probability on
   SPBOOK_CLASS.  With the nerf in this commit, less of them ought to
   be destroyed anyway.

 - A very edge case of where explosion-vs-monster damage was totted up
   differently for golems, which could result in differences of a hit
   point here or there.

 - All object classes being processed in one go means that less items
   are destroyed than would be if they were still processed
   independently.  This is not really visible compared to the old
   baseline of just destroying 33% of everything, but would be a
   marked difference versus a copy of the game that still called
   destroy_items separately for different object classes. To
   compensate, I adjusted my planned damage-to-destruction-limit
   scaling factor down from 8 to 5.

 Not done: merging in ignite_items(), though that would probably be
 really easy now.'

Notes from porting from xNetHack:

- It might be necessary to reexamine at all the conditional checks for
calling destroy_items. Because item destruction is much more
restrained and uses the actual damage from an effect, we might now
need to check 'if (!rn2(3))' and similar in all the places item
destruction occurs.
2024-02-20 22:03:54 +02:00
nhmall
688ac6ffbe remove register from variable declarations 2024-02-19 16:30:07 -05:00
PatR
c84dc79610 trap.c reformatting
Monstly changing '<type>* <var>' to '<type> *<var>'.  Wrap or shorten
a few wide lines.

One of the rolling boulder routines accessed gb.bhitpos.x,y many times;
change that to use local x,y instead.
2024-02-19 11:11:23 -08:00
PatR
d688309012 openholdingtrap() message sequencing
If a trap is blocking levitation or flight and you use wand of opening
or spell of knock to get out, you'd get things like
|You start to float in the air!
|You are released from the bear trap.

Give the release message before the actual untrapping.
2024-02-18 11:18:48 -08:00