Commit Graph

327 Commits

Author SHA1 Message Date
PatR
1fd3bb661f fix issue #1378 - brain eaten after flayer's death
Issue reported by Umbire:  if a mind flayer got turned to stone by
hitting a hero who is polymorphed into a cockatrice and the first
tentacle drain missed but a subsequent one hit, any remaining ones
would keep being applied even though the mind flayer was dead.

This works but doesn't feel right to me.  A more substantial change
to mhitm_ad_drin() didn't work as expected so I've settled for this.

Fixes #1378
2025-02-25 09:54:14 -08:00
nhmall
a68bc3b3fb fix tamed pet issue #1379
fixes #1379
2025-02-12 23:26:03 -05:00
Pasi Kallinen
369f1ff959 Accessibility: more message locations pt 3 2024-12-14 15:36:05 +02: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
nhmall
9a42d70901 ranged attack in repertoire might not be used
Commit 22884522, ported (from Sporkhack, Evilhack), added the ability
for monsters to maintain awareness of player resistances that they
observed.

Since they will refrain from using a ranged attack that they deem
futile, take the specific monster's seen_resistance field into consideration
when choosing code paths based on the availability of ranged attacks.

Resolves #1307
2024-11-03 09:03:04 -05:00
SHIRAKATA Kentaro
d2b7c2f5c5 split "assess_dmg" on passiveum() into a separate function 2024-10-15 03:21:08 +09:00
nhmall
bf1af7c471 Merge branch 'NetHack-3.7' of https://github.com/klorpa/NetHack into NetHack-3.7 2024-09-14 09:17:48 -04:00
PatR
045d60848b hero health manipulation
I've been investigating issue #1252 (while the fuzzer was running,
sanity_check complained that hero's current health was greater
than maximum health) off and on for three months and haven't found
the cause.

I've checked all the places that lower maximum HP that I've managed
to find, but not spent much time looking for places that raise
current HP.

These changes might provide some more information.  They don't rely
on sanity_check being enabled.

Issue #1252 is still open.
2024-09-06 13:35:00 -07:00
PatR
cc1066b1ff some reformatting (3 of 4) 2024-09-05 15:55:24 -07:00
klorpa
02c4147893 Typos 2024-08-31 15:28:42 -05:00
PatR
d963c6dd6f github issue #1263 - lich attacks
Issue reported by loggersviii:  monsters killed by liches can
produce corpses which auto-revive as zombies, but liches aren't
able to harm zombies and get stuck in an endless slap fight when
those revive.

Liches have a touch attack for cold damage and they have a spell
casting attack.  They don't use their spell attack in monster vs
monster combat, so cold resistant foes don't receive any damage.
Prevent them from becoming harmless by changing the cold damage to
physical damage if the target resists cold.

Fixes #1263
2024-07-24 11:01:23 -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
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
d02028fe66 more issue #1253 - shape change vs Eleberth
I happened to restore a save file left over from testing yesterday's
attempt to fix github issue #1253 and had a werejackal change from
human to beast while next to my hero on "Elbereth", then attack me.

This should be sufficient to prevent that.  I'm not sure why the
previous fix attempt seemed to be adequate when testing it.  The new
fix relies on the previous one.
2024-06-05 22:58:44 -07:00
nhkeni
9c0ed8ae63 NOSTATICFN for src/* 2024-03-14 17:41:51 -04:00
RainRat
a3658f85ac fix typos 2024-02-28 20:15:56 -08:00
Pasi Kallinen
dd37c5326a Accessibility: showdamage option
Add a new boolean option showdamage, if on, outputs a message
like "[HP -2, 14 left]" - several variants have something similar,
but I chose the message based on how eSpeak said it, while keeping
it short.
2024-02-24 17:38:46 +02: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
Pasi Kallinen
57747535af Add m_next2u, analogous to m_next2m and next2u 2024-01-19 21:53:25 +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
49a5d043c0 consistent use of TRUE vs 1 with botl and botlx 2024-01-04 23:48:38 -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
6cbefc7c2d Revert "granular verbose message suppression mechanics"
This reverts commit be76727265.
2023-10-29 20:39:07 -04:00
PatR
86811ab266 wildmiss() sanity checking
Suggested by entrez:  have wildmiss() complain about the unexpected
"none of the above" before possibly returning early.
2023-09-28 18:47:06 -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
7f635ad25b fix github issue #1082 - Prot from shape changers
vs lycanthropes

Issue reported by Umbire:  when hero had Protection_from_shape_changers
extrinsic, a lycanthrope in human form that attacked could change into
critter form.  It would change back to human on its next move.

Prevent werecreatures from transforming from human form to critter form
if hero has Protection_from_shape_changers.  That attribute does not
prevent a human werecreature from summoning animal companions.

Fixes #1082
2023-07-15 12:20:47 -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
9052bd5099 fix #K3925 - u.ustuck of long worm tail
Don't allow stick/wrap/engulf attacks directed at long worm tails
to succeed.  Achieved by making sure that 'notonhead' is up do date
in a bunch of places and utilizing the fairly recent can't-{stick,wrap,
engulf}-unsolid-monsters code.

Should prevent a 'sanity_check' warning about being too far from
u.ustuck that would happen when holding the tail while the head was
not adjacent to the hero.

Also don't let pet ranged attacks from choosing a long worm's tail
as target.  They'll still be able to target long worms provided that
the head is lined up and not shielded by tail segment(s).
2023-05-20 15:34:32 -07:00
PatR
1c94bdac89 blindness overhaul
I was working on this at the time 3.6.0 was released and set it aside
until later.  Later has finally arrived.  Redo the Blind, Blinded,
Blindfolded,&c macros to make more complete use of intrinsic property
handling.  Blinded was being treated as a number which could be added
to or subtracted from; now that has to be done via TIMEOUT mask
because it has FROMOUTSIDE (OPTIONS:blind) and FROMFORM (poly'd into
!haseyes() form) bits included.  Object definitions for blindfold and
towel now specify the BLINDED property; overriding blindness via the
Eyes of the Overworld is accomplished via props[BLINDED].blocked.

Code generated for the scores of Blind and !Blind tests throughout
the program should be smaller.

One bug that has been fixed is that putting on the Eyes of the
Overworld cured permanent blindness (from OPTIONS:blind).  The
u.uroleplay.blind flag was cleared and stayed so after taking them
off.  Putting the Eyes on still breaks blind-from-birth conduct but
now blindness will resume when they are removed.

This was untested at the time it was set aside and is only lightly
tested now.  A large number of the changes here are just to switch
from Blinded to BlindedTimeout for current timed value and to call
set_itimeout() for setting a new value.
2023-04-27 14:53:28 -07: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
1a2d844a22 fix #K3902 - hug attacks against unsolid targets
Prevent hug attacks (owlbear, python, pit fiend, several others),
attacks for wrap damage (eel and kraken, trapper and lurker above),
attacks for stick-to damage (mimic, lichen), and attacks for digestion
damage (purple worm) from succeeding against unsolid monsters (ghosts,
lights, vortices, most elementals).

Polymorph of an engulf or hold target into unsolid form has been
addressed by a couple of previous updates.
2023-04-14 13:27:33 -07: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
nhmall
5f69dc6228 make attack result macros more distinguishable from makemon macros
Use the MM_ prefix only for the makemon macros, and change these five as follows:

 MM_MISS 0x0     -> M_ATTK_MISS      /* aggressor missed */
 MM_HIT 0x1      -> M_ATTK_HIT       /* aggressor hit defender */
 MM_DEF_DIED 0x2 -> M_ATTK_DEF_DIED  /* defender died */
 MM_AGR_DIED 0x4 -> M_ATTK_AGR_DIED  /* aggressor died */
 MM_AGR_DONE 0x8 -> M_ATTK_AGR_DONE  /* aggressor is done with their turn */

include/hack.h:#define NO_MM_FLAGS     0x000000L /* use this rather than plain 0 */
include/hack.h:#define MM_NOWAIT       0x000002L /* don't set STRAT_WAITMASK flags */
include/hack.h:#define MM_NOCOUNTBIRTH 0x000004L /* don't increment born count (for revival) */
include/hack.h:#define MM_IGNOREWATER  0x000008L /* ignore water when positioning */
include/hack.h:#define MM_ADJACENTOK   0x000010L /* acceptable to use adjacent coordinates */
include/hack.h:#define MM_ANGRY        0x000020L /* monster is created angry */
include/hack.h:#define MM_NONAME       0x000040L /* monster is not christened */
include/hack.h:#define MM_EGD          0x000100L /* add egd structure */
include/hack.h:#define MM_EPRI         0x000200L /* add epri structure */
include/hack.h:#define MM_ESHK         0x000400L /* add eshk structure */
include/hack.h:#define MM_EMIN         0x000800L /* add emin structure */
include/hack.h:#define MM_EDOG         0x001000L /* add edog structure */
include/hack.h:#define MM_ASLEEP       0x002000L /* monsters should be generated asleep */
include/hack.h:#define MM_NOGRP        0x004000L /* suppress creation of monster groups */
include/hack.h:#define MM_NOTAIL       0x008000L /* if a long worm, don't give it a tail */
include/hack.h:#define MM_MALE         0x010000L /* male variation */
include/hack.h:#define MM_FEMALE       0x020000L /* female variation */
include/hack.h:#define MM_NOMSG        0x040000L /* no appear message */

include/hack.h:#define MM_NOEXCLAM     0x400000L /* more sedate "<mon> appears." mesg for ^G */
include/hack.h:#define MM_IGNORELAVA   0x800000L /* ignore lava when positioning */
2023-03-19 12:19:34 -04:00
PatR
1c24f208f3 genetic engineer attacks
When a genetic engineer polymorphs someone it normally teleports away.
Also set mspec_used so that it can't polymorph someone [else] on its
next turn, it case of a no-teleport level or it happens to randomly
land adjacent to the target.
2023-03-17 16:00:44 -07:00
nhmall
de79240dea some comment spelling fixes 2023-03-16 22:27:01 -04:00
PatR
3a30e434d8 "<mon> hits [again]"
Add "again" to the hit message when an attack sequence has
consecutive attacks of same type and they hit.  A {bite, claw, claw}
sequence won't give that for first claw attack regardless of whether
the bite hits but will give it for the second claw attack when both
of the claw attacks hit.

The message sequence
|The fire ant bites!  The fire ant bites!  You're on fire!
or |The fire ant bites!  The fire ant bites!  You avoid harm.
when the first bite was for physical damage and the second was
for fire damage seemed a little confusing.

This changes that to be
|The fire ant bites!  The fire ant bites again!  You're on fire!
or |The fire ant bites!  The fire ant bites again!  You avoid harm.
It still isn't crystal clear that both bites are from a single
attack and that the second bite is for different type of damage
but I think it's an improvement.
2023-03-16 01:54:29 -07:00
PatR
01af084f43 non-digest engulfing
Be more consistent with the engulf attack feedback by creatures who
fold themselves around the victim (trapper, lurker above) rather than
swallow or directly engulf.

Replace an instance of a non-literal format string and the warnings
manipulation it needed with a literal one.
2023-03-13 12:49:22 -07:00
Pasi Kallinen
08a2a2a1a4 Saving grace
Once per game, if receiving a killing blow from above 90% HP,
allow the hero to survive with 1 HP.
2023-03-03 17:38:48 +02:00
nhmall
fbd9a7bae8 another update to the soundlib interface
sound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol,
             int32_t moreinfo);
    -- NetHack will call this function when it wants to pass text of
       spoken language by a character or creature within the game.
    -- text is a transcript of what has been spoken.
    -- gender indicates MALE or FEMALE sounding voice.
    -- tone indicates the tone of the voice.
    -- vol is the volume (1% - 100%) for the sound.
    -- moreinfo is used to provide additional information to the soundlib.
    -- there may be some accessibility uses for this function.

It may be useful for accessibility purposes too.

A preliminary implementation has been attempted for macsound to test
the interface on macOS. No tinkering of the voices has been done.

Use of the test implementation requires the following at build time with make.
    WANT_SPEECH=1
That needs to be included on the make command line to enable the test code,
otherwise just the interface update is compiled in.

I don't know for certain when AVSpeechSynthesizer went into macOS, but older versions
likely don't support it, and would just leave off the WANT_SPEECH=1.

If built with WANT_SPEECH=1, the 'voices' NetHack option needs to be enabled.

It was a bit strange, when I first started up the test, to hear Asidonhopo,
the shopkeeper, talking to me as I entered his shop and interacted with him.
2023-02-07 00:44:36 -05:00
Pasi Kallinen
8ec84ea7ff Higher chance of demon gating in Gehennom 2023-01-22 13:03:10 +02:00
nhmall
07d3b22b4e whitespace cleanup on files just modified 2023-01-20 14:28:33 -05:00
nhmall
8bbe9282aa add soundeffects hooks to core
Insert the calls to trigger a number of potential soundeffects
into the core.

If no additional soundlib support is integrated into the
build, then the Soundeffect macro (sndprocs.h) expands to nothing:

[#define Soundeffect(seid, vol)
]

If, however, at least one additional soundlib support is integrated
into the build, then the Soundeffect macro gets defined as this
in sndprocs.h:

[#define Soundeffect(seid, vol) \
    do {                                                              \
        if (!Deaf && soundprocs.sound_soundeffect                     \
            && ((soundprocs.sndcap & SNDCAP_SOUNDEFFECTS) != 0))      \
            (*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
    } while(0)
]

That macro definition checks for the hero not being Deaf; it checks
to ensure that the active soundlib interface has a non-null
sound_soundeffect() function pointer; and it checks to ensure
that the active soundlib interface has declared that it supports
soundeffects by setting the SNDCAP_SOUNDEFFECTS bit in its sndcap
entry. That just means that the interface routines are prepared to
accept and deal with the calls from the core, whether or not it
actually produces the desired soundeffect.
2023-01-20 14:20:08 -05:00
nhmall
ba5356603a yn()
A number of C compiler suites have a math.h library that includes a yn()
function name that conflicts with NetHack's yn() macro:
"The y0(), y1(), and yn() functions are Bessel functions of the second kind,
for orders 0, 1, and n, respectively. The argument x must be positive. The
argument n should be greater than or equal to zero. If n is less than zero,
there will be a negative exponent in the result."

At one point, isaac64.h included math.h, although that has since been removed.

Some libraries used in NetHack (Qt for one) do include math.h and that required
build work-arounds to avoid the conflict.

Rename the NetHack macro from yn() to y_n() and avoid the math.h conflict
altogether, eliminating the need for that particular work-around.
2023-01-12 16:04:40 -05:00
Michael Meyer
15274fcca1 Make paralysis intefere with seduction attempts
tinklebear on IRC noticed that a hero paralyzed by a floating eye was
still "charmed" and capable of "removing her armor" as part of a nymph's
theft attack.  The same thing was true of foocubus seduction: a
paralyzed hero was still able to respond to the questions about whether
particular pieces of armor should be removed (and also do whatever else
may be involved in a successful attack...).

I think paralysis should prevent both those things.  Nymph theft will
still work, unless she needs the hero's active cooperation in removing a
bulky piece of armor.  Foocubus attacks will be prevented entirely by
paralysis, making it interfere like unconsciousness already does.

Apply a similar constraint to hero vs monster seduction, as well.
2022-12-31 11:25:53 -08:00
PatR
53a4e3f80a unconscious hero vs Medusa
Reported directly to devteam by entrez:  a sleeping or unconscious
hero would still meet a monster's gaze attack even though those are
supposed to be eye-to-eye rather than just the monster looking at
you.  Don't meet the gaze when Unaware, despite the fact that the
hero isn't blind and vision remains in operation.

Initially being Unaware also blocked Medusa's gaze being reflected
but I changed things so that that still affects her.  It contradicts
the eye-to-eye aspect but is more consistent with her looking at a
blind hero who has reflection.
2022-12-20 14:44:19 -08:00
Pasi Kallinen
85137bb76a Fix skipping attacks if hero moved away
Recent change by me caused a bug where a monster was trying
to attack after hero was moved away by the previous attacks.
2022-12-07 21:51:50 +02:00
Pasi Kallinen
81fb185cea Recalc mon-hits-you distance variables
When a monster could first knock you back and then grab you,
the game would emit impossible, because the knockback moved you
but the distance variables used for the grab attack were not
updated.

Update the range variables within the loop iterating through
the monster attacks.
2022-12-01 19:57:24 +02:00
Michael Meyer
5cf6042ca4 Fix: potential use-after-free in expels()
An engulfing monster can expel you onto a level teleporter or other
level-changing trap, in which case it may (under highly specific
circumstances[1]) no longer have been in memory by the time mtmp->mx/my
were accessed to see whether the "Brrooaa" message should be printed.
It also doesn't make much sense to print that message by the time you've
already fallen through a portal, trapdoor, etc, onto another level, so I
think moving it before the spoteffects() call kills two birds with one
stone.

[1] The highly specific circumstances: you must die due to illness or
some other timeout (or generally die on your own turn rather than the
monsters' turn, since this ensures the level change isn't deferred until
the end of the turn), while engulfed above a level teleporter [or maybe
another similar trap -- I tested with a level teleporter], and be
lifesaved, while positioned such that the engulfer can't follow you
through the levelport after expulsion (e.g. surrounded by other
monsters).  It may happen under some other conditions too, but even if
so it's pretty rare and was tough to reproduce.
2022-11-30 14:54:05 -08:00