Commit Graph

168 Commits

Author SHA1 Message Date
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
Michael Meyer
a15d517326 Refine ice fumbling effects vs mounted hero
Fumbling makes the hero fall from the saddle, but the justification was
weak if the only fumbling source is riding over ice (the messages were
things like "you drop the reins" which made more sense from magical
fumbling).  Make all fumbling from ice alone go into the ice-specific
"slip on the ice" block and add a chance to fall from your mount there.
If fumbling from another source while riding on ice, the hero will
always fall from his steed, since that's what happens on normal floor --
ice had actually been reducing this chance.
2023-12-04 14:40:16 -05:00
nhmall
d064ac2cda more cast style consistency 2023-11-13 20:31:02 -05:00
Pasi Kallinen
b1e3863b43 Stop occupation when timed levitation or choking issues a message 2023-09-30 21:15:20 +03: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
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
Pasi Kallinen
ffb61612e3 Option to create the character deaf
Allows creating your character permanently deaf,
for that added challenge.

Breaks saves.
2023-04-11 13:23:30 +03:00
Pasi Kallinen
aa83dadc1e Add stormy level flag
Which makes clouds create lightning bolts at random.
This flag is used on the plane of air.

Breaks saves and bones.
2023-03-17 20:13:32 +02:00
nhmall
de79240dea some comment spelling fixes 2023-03-16 22:27:01 -04:00
PatR
4021a63bcf wand/spell/breath killer reason
Extend "killed by the touch of death inflicted by <monster>" to buzz().
"Killed by a bolt of cold" becomes "killed by a bolt of cold zapped by
<monster>" or "killed by a blast of cold" becomes "killed by a blast
of cold exhaled by <monster>" and so forth.

More work than expected; the zap code isn't passed enough context.

BZ_M_WAND() was producing the wrong value for wands zapped by monsters.
2023-03-07 02:47:42 -08:00
PatR
4fd7d51cb2 fix #H2694 - egg hatching feedback
A bug report from ten and half years ago...
If a carried egg hatches, the message is
|<foo> drops from your pack.
and if tame, is followed by
|Its cries sound like {mommy,daddy}.
The latter was issued even when <foo> has no speech capability.

Replace "its cries sound like" with "its <vocalize>ing sounds like"
for suitable value of <vocalize>.

This adds two new monster sounds, MS_BELLOW and MS_CHIRP, also two
new sound effect codes, se_chirp and se_croc_bellow.

We had MS_SILENT for crocodile.  On wikipedia, crocodile is described
as the most vocal reptile.  Adult males make a load bellowing noise
and hatchlings make a chirping noise.

This changes crocodile, titanothere, and baluchitherium from MS_SILENT
to MS_BELLOW and baby crocodile from MS_SILENT to MS_CHIRP.  Chirp
might be appropriate for lizards and lizard-like amphibians but I've
left those as MS_SILENT.

[Noticed but not changed:  lizards and lizard-like amphibians aren't
flagged as oviparous.  Shouldn't they be?]
2023-02-25 07:02:19 -08: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
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
PatR
33a5dbff37 sleeping vs deafness
Another one from entrez: falling asleep tried to make the hero Deaf,
but was adding a negative value to the timeout.  A negative value
of bigger magnitude that the current timeout could produce weird
values when making that be negative and then stuffing it into an
unsigned field.

This applies a fix to sleep-causes-deafness bug but also disables
that, at least for the time being since nobody seemed to notice that
it wasn't working.  The fix might be noticeable so needs testing.

This also adjusts You_hear() so that if Deaf and sleeping are both
active, it will still yield "You dream that your hear ..." instead
having Deaf override that.
2022-12-20 15:23:40 -08:00
nhmall
02a48aa8cf split g into multiple structures
The consolidation of global variables from scattered source
files into decl.c and declared in decl.h was begun in 3.7.0.
Their placement in common files was done for centralized
initialization and potential re-initialization during a
"play again" scenario.

It wasn't really necessary for all of them to be housed in a
single huge structure to meet the "play again" requirement,
and the single huge structure has been a little unwieldy when
it comes to maintenance.

Following this commit, instead of one single extremely large structure
named 'g' to house all of the relocated global variables, they
are distributed into several ga through gz.

To make things easy for the developer, each variable is placed
into the struct corresponding to the starting letter of the variable.
That way, no lookup is required in order to know which struct houses
a particular variable, it is a simple match to the starting letter
for all the centralized global variables.

A global variable named 'amulets', would be found in ga.
    ga.amulets
     ^ ^
A global varable named 'move', would be found in gm.
    gm.moves
     ^ ^
A global variable named 'val_for_n_or_more' would be found in gv.
    gv.val_for_n_or_more
     ^ ^
A global variable named 'youmonst' would be found in gy.
    gy.youmonst
     ^ ^
2022-11-29 21:53:21 -05:00
nhmall
4b04b1e6ac expand support for noreturn declarations
Although gcc specifies support for declaring a function as
noreturn after the function name and parameters, other compilers
do so via an attribute at the start of the declaration. Add some
macro support for the attribute-at-the-beginning method:
  o MS Visual Studio compiler
  o Upcoming C23 standard (untested at this point)
2022-11-24 00:51:42 -05:00
nhmall
9e92fefdd8 keep propertynames static in timeout.c 2022-11-06 10:02:27 -05:00
nhmall
99a93fe50b some C99 changes
Instead of using index() macro defined to strchr, use C99 strchr.
Instead of using rindex() macro defined to strrchr, use C99 strrchr.

If you want to try building on a platform that doesn't offer those
two functions, these are available:
    define NOT_C99       /* to make some non-C99 code available */
    define NEED_INDEX    /* to define a macro for index()  */
    define NEED_RINDX    /* to define a macro for rindex() */
2022-10-29 10:54:25 -04:00
nhmall
817b4686ce Revert "move struct propname to a header file"
This reverts commit 402b2bf5c8.
2022-09-06 08:01:50 -04:00
nhmall
402b2bf5c8 move struct propname to a header file
In doing so, avoid repeated layout declaration in cmd.c
2022-09-06 07:22:55 -04:00
PatR
1a6456ad82 fix github issue #842 - lamp/lantern feedback
Issue reported by GorillaSapiens:  you get notified if a lamp burns
out even if you're blind at the time.

That is intended behavior; you can feel the heat or lack of heat
from a lamp or candle.  But the comment from copperwater pointed out
that you shouldn't be able to feel that for a brass lantern.

This suppresses the "power has run out" feedback if blind at the
time.  However, applying a lantern to turn it on or off still gives
the on/off feedback on the assumption that there's a switch and you
can feel its position.  When hero is blind and lantern is out of
power, trying to turn it on yields "nothing seems to happen".  It's
not completely consistent since you would feel the switch in its On
position but claiming that the lantern is on would be a lie.

The basic on and off messages referred to "lamp" even when using a
brass lantern.  I thought that that had been fixed a long time ago.

Fixes #842
2022-08-13 15:55:10 -07:00
Pasi Kallinen
f0774e0da4 Fix monster hiding under consumed candle 2022-07-26 22:53:57 +03:00
PatR
01209cab7a some new feedback for #timeout
Add a couple of non-timer, non-(property & TIMEOUT) timeout values
for the wizard-mode #timeout command: uswldtim and uinvault.  The
swallowed counter goes down and explusion or total digestion occurs
when it hits zero.  The in-vault counter goes up when you're in a
vault or the temporary corridor.  If you make it out of the vault-
and-corridor it gets reset to zero.
2022-07-21 00:54:51 -07:00
Pasi Kallinen
c4bd9db98c Fix monster hiding under candle burning away
Reveal the monster when the candle it was hiding under burned away.
2022-07-08 13:39:28 +03:00
nhmall
30b557f7d5 change xchar to other typedefs
One of the drivers of this change was that screen coordinates require a
type that can hold values greater than 127. Parameters to the window
port routines require a large type in order to be able to have values
a fair bit larger than COLNO and ROWNO passed to them, particularly for
their use to the right of the map window.

This splits the uses of xchar into 3 different situations, and adjusts
their type and size:

                        xchar
                          |
               -----------------------
               |          |          |
            coordxy     xint16     xint8

coordxy: Actual x or y coordinates for various things (moved to 16-bits).

xint16:  Same data size as coordxy, but for non-coordinate use (16-bits).

xint8:   There are only a few use cases initially, where it was very
         plain to see that the variable could remain as 8-bits, rather
         than be bumped to 16-bits.  There are probably more such cases
         that could be changed after additional review.

Note: This first changed all xchar variables to coordxy. Some were
reviewed and got changed to xint16 or xint8 when it became apparent that
their usage was not for coordinates.

This increments EDITLEVEL in patchlevel.h
2022-06-30 23:48:18 -04:00
PatR
8a092aef0e timer code readability
Something else noticed while looking for something unrelated.  The
original code is correct but I think the revised code is a little
easier to take in when looking at it.
2022-05-25 12:30:48 -07: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
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
nhmall
e4e65c4b8b whitelist several non-literal format strings
djgpp cross-compiler was griping about several.

This also removes these lines from sys/unix/hints/include/compiler.370.
    CFLAGS+=-Wno-format-nonliteral
    CCXXFLAGS+=-Wno-format-nonliteral

-Wformat-nonliteral should not be incompatible with the printf
argument-checking capabilities on literal format strings and there
shouldn't be any new warnings created.

-- &< --

artifact.c: In function 'artifact_hit':
artifact.c:1309:23: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1309 |                       mon_nam(mdef));
      |                       ^~~~~~~
artifact.c:1328:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1328 |                 pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you");
      |                 ^~~~~

ball.c: In function 'drop_ball':
ball.c:896:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  896 |                 pline(pullmsg, "pit");
      |                 ^~~~~
ball.c:899:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  899 |                 pline(pullmsg, "web");
      |                 ^~~~~
ball.c:904:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  904 |                 pline(pullmsg, hliquid("lava"));
      |                 ^~~~~
ball.c:908:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  908 |                 pline(pullmsg, "bear trap");
      |                 ^~~~~

dig.c: In function 'liquid_flow':
dig.c:747:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  747 |         pline(fillmsg, hliquid(typ == LAVAPOOL ? "lava" : "water"));
      |         ^~~~~

fountain.c: In function 'floating_above':
fountain.c:28:5: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   28 |     You(umsg, what);
      |     ^~~

invent.c: In function 'hold_another_object':
invent.c:1018:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1018 |                 pline(drop_fmt, drop_arg);
      |                 ^~~~~
invent.c:1073:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1073 |         pline(drop_fmt, drop_arg);
      |         ^~~~~
invent.c: In function 'silly_thing':
invent.c:1811:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1811 |         pline(silly_thing_to, word);
      |         ^~~~~

lock.c: In function 'pick_lock':
lock.c:375:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  375 |             pline(no_longer, "hold the", what);
      |                   ^~~~~~~~~
lock.c:379:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |             pline(no_longer, "reach the", "lock");
      |                   ^~~~~~~~~
lock.c: In function 'pick_lock':
lock.c:375:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  375 |             pline(no_longer, "hold the", what);
      |                   ^~~~~~~~~
lock.c:379:19: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |             pline(no_longer, "reach the", "lock");
      |                   ^~~~~~~~~
mcastu.c: In function 'cast_cleric_spell':
mcastu.c:670:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  670 |             pline(fmt, Monnam(mtmp), what);
      |             ^~~~~

mhitu.c: In function 'hitmsg':
mhitu.c:68:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   68 |             pline(pfmt, Monst_name);
      |             ^~~~~

mkobj.c: In function 'insane_object':
mkobj.c:2848:20: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2848 |         impossible(altfmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj),
      |                    ^~~~~~
mkobj.c:2852:20: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2852 |                    objnm);
      |                    ^~~~~

mon.c: In function 'mon_givit':
mon.c:1469:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1469 |         pline(msg, Monnam(mtmp));
      |         ^~~~~
mon.c: In function 'mondead':
mon.c:2485:33: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2485 |                                 | SUPPRESS_INVISIBLE), FALSE));
      |                                 ^

muse.c: In function 'mon_reflects':
muse.c:2438:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2438 |             pline(str, s_suffix(mon_nam(mon)), "shield");
      |             ^~~~~
muse.c:2445:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2445 |             pline(str, s_suffix(mon_nam(mon)), "weapon");
      |             ^~~~~
muse.c:2450:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2450 |             pline(str, s_suffix(mon_nam(mon)), "amulet");
      |             ^~~~~
muse.c:2458:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2458 |             pline(str, s_suffix(mon_nam(mon)), "armor");
      |             ^~~~~
muse.c:2464:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2464 |             pline(str, s_suffix(mon_nam(mon)), "scales");
      |             ^~~~~
muse.c: In function 'ureflects':
muse.c:2476:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2476 |             pline(fmt, str, "shield");
      |             ^~~~~
muse.c:2483:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2483 |             pline(fmt, str, "weapon");
      |             ^~~~~
muse.c:2487:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2487 |             pline(fmt, str, "medallion");
      |             ^~~~~
muse.c:2493:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2493 |             pline(fmt, str, uskin ? "luster" : "armor");
      |             ^~~~~
muse.c:2497:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2497 |             pline(fmt, str, "scales");
      |             ^~~~~

polyself.c: In function 'polyman':
polyself.c:201:5: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  201 |     urgent_pline(fmt, arg);
      |     ^~~~~~~~~~~~

potion.c: In function 'make_hallucinated':
potion.c:423:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  423 |             pline(message, verb);
      |             ^~~~~
potion.c: In function 'peffect_gain_level':
potion.c:1033:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1033 |                 You(riseup, ceiling(u.ux, u.uy));
      |                 ^~~
potion.c:1044:21: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1044 |                     You(riseup, ceiling(u.ux, u.uy));
      |                     ^~~

priest.c: In function 'intemple':
priest.c:487:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  487 |                 You(msg1, msg2);
      |                 ^~~

read.c: In function 'doread':
read.c:522:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  522 |         pline(silly_thing_to, "read");
      |         ^~~~~

shk.c: In function 'shk_names_obj':
shk.c:2576:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2576 |         pline(fmtbuf, obj_name, (obj->quan > 1L) ? "them" : "it", amt,
      |               ^~~~~~
shk.c:2579:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2579 |         You(fmt, obj_name, amt, plur(amt), arg);
      |         ^~~
shk.c: In function 'shk_chat':
shk.c:4506:13: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 4506 |             pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp));
      |             ^~~~~
shk.c: In function 'check_unpaid_usage':
shk.c:4633:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 4633 |         verbalize(fmt, arg1, arg2, tmp, currency(tmp));
      |         ^~~~~~~~~

sounds.c: In function 'dosounds':
sounds.c:66:21: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
   66 |                     pline(throne_msg[2], uhis());
      |                     ^~~~~
sounds.c:259:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  259 |                 You_hear(msg, halu_gname(EPRI(mtmp)->shralign));
      |                 ^~~~~~~~

timeout.c: In function 'choke_dialogue':
timeout.c:269:26: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  269 |                          body_part(NECK));
      |                          ^~~~~~~~~
timeout.c:274:17: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  274 |                 urgent_pline(str, hcolor(NH_BLUE));
      |                 ^~~~~~~~~~~~
timeout.c: In function 'levitation_dialogue':
timeout.c:339:26: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  339 |                          danger ? surface(u.ux, u.uy) : "air");
      |                          ^~~~~~
timeout.c: In function 'slime_dialogue':
timeout.c:379:34: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  379 |                     urgent_pline(buf, hcolor(NH_GREEN));
      |                                  ^~~
timeout.c:381:30: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
  381 |                 urgent_pline(buf, an(Hallucination ? rndmonnam(NULL)
      |                              ^~~

uhitm.c: In function 'hmon_hitmon':
uhitm.c:1398:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1398 |         pline(fmt, whom);
      |         ^~~~~
uhitm.c:1421:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1421 |         pline(fmt, whom);
      |         ^~~~~
uhitm.c: In function 'stumble_onto_mimic':
uhitm.c:5301:9: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 5301 |         pline(fmt, what);
      |         ^~~~~

../win/tty/wintty.c: In function 'tty_clear_nhwindow':
../win/tty/wintty.c:1649:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 1649 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_display_nhwindow':
../win/tty/wintty.c:2339:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2339 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_dismiss_nhwindow':
../win/tty/wintty.c:2432:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2432 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_destroy_nhwindow':
../win/tty/wintty.c:2477:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2477 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_curs':
../win/tty/wintty.c:2503:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2503 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_putsym':
../win/tty/wintty.c:2599:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2599 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_add_menu':
../win/tty/wintty.c:2967:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 2967 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_end_menu':
../win/tty/wintty.c:3032:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 3032 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
../win/tty/wintty.c: In function 'tty_select_menu':
../win/tty/wintty.c:3140:15: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
 3140 |         panic(winpanicstr, window);
      |               ^~~~~~~~~~~
2022-01-09 14:18:10 -05:00
Pasi Kallinen
48bca11d67 Accessibility: give message for created monsters
Always give a message when creating a detected monster
during gameplay (as opposed to during level creation).
To prevent the message, use the MM_NOMSG flag for makemon.

Most places already handled their own messaging, but there
were some, such as bag of tricks, create monster magic
and random monsters created during gameplay that didn't.
2022-01-06 14:06:49 +02:00
Pasi Kallinen
d53cd28d46 Make extended commands return defined flags
Instead of returning 0 or 1, we'll now use ECMD_OK or ECMD_TURN.
These have the same meaning as the hardcoded numbers; ECMD_TURN
means the command uses a turn.

In future, could add eg. a flag denoting "user cancelled command"
or "command failed", and should clear eg. the cmdq.

Mostly this was simply replacing return values with the defines
in the extended commands, so hopefully I didn't break anything.
2021-12-30 19:16:33 +02:00
PatR
4eb0592959 sickness countdown
Give messages when sickness countdown has nearly expired to warn
player that hero is dying and also so that death at the end doesn't
seem so abrupt after an arbitrary period with just "TermIll" and/or
"FoodPois" on the status line.

Also, abuse constitution each turn when Sick (either variation, but
not a double amount if both).
2021-12-22 19:36:52 -08:00
PatR
75fe21d00f more urgent_pline()'s
countdown messages for turning to stone or slime or being strangled
drowning
burning in lava
feeling feverish
changing form
2021-12-22 18:29:01 -08:00
PatR
0bc396282d additional urgent messages
Now I've remembered why I didn't follow through with these back when
I originally laid the groundwork.  New urgent messages:

 having an item of armor be destroyed
 having weapon be grabbed by a monster's bullwhip
 becoming engulfed
 being grabbed by an eel
 subsequently being drowned by an eel
 dying of petrification
 turning into slime then dying due to genocide
 dying due to fatal illness

There are lots more candidates.
2021-12-20 08:42:58 -08:00
PatR
e2ca016484 decaying globs of {ooze,pudding,slime}
Globs never rotted away but did become tainted after a relatively
short while, which seemed like a contradiction.  Change them to never
be tainted but shrink by 1 unit of weight approximately every 25
turns.  An ordinary glob (one that hasn't combined with any others)
starts out weighing 20 units, so it takes about 500 turns to vanish.
That's roughly twice as long as a corpse takes to rot away.

Shrinking globs give feedback when in hero's invent or in a container
in hero's inventory, but rarely (when going from an exact multiple
of 20 weight units; that is, from integral number of N globs to
N-1 + 19/20, or if weight reduction triggers an encumbrance change).
When a glob goes away completely, there is feedback for those two
circumstances and also for seeing the glob vanish from the floor.

I haven't touched how much nutrition eating a glob confers.  I have
changed formatting of glob names to use "small", "medium", "large",
"very large" instead of "small", [no adjective], "large", &c.  You
still need to have at least five globs coalesced together for the
adjective to become "medium", same amount as before.

I don't think EDITLEVEL needs to be modified but have incremented it
anyway to play things safe.
2021-11-06 18:24:36 -07:00
SHIRAKATA Kentaro
bfd79f5c9d use %lu for unsigned long
`curr->tid` is unsigned long, so use `%lu`.
2021-10-23 01:07:40 +09:00
nhmall
17165e3b92 melting ice timeout issues
Reported directly to devteam by entrez via email:
>
> I noticed some potential issues with (melting) ice:
>
>   * Digging down into ice, or setting a land mine on the ice and
>   triggering it, doesn't remove the melt_ice timeout, so it can result
>   in a sequence like dig down -> pit fills with water -> freeze water
>   -> freezing water tries to set melt_ice timeout -> duplicate timeout
>   impossible.  Or if you don't freeze the water again, melt_ice will
>   run on a non-ice surface, which might at least produce strange
>   messages.
>
>   * Setting a land mine on ice: melting ice doesn't do anything with
>   the trap, so there is still a land mine which you can trigger by
>   flying over the water (the land mine's trigger is also still
>   described as being 'in a pile of soil', despite being underwater at
>   this point).  Similar thing happens with bear traps.
>
>   * Not really related to _melting_ ice, but an exploding land mine
>   doesn't reset the typ from ICE to FLOOR (like normal digging does),
>   so it will result in a square with a pit that is also an ice square,
>   where the ice can melt under the pit and produce a combination
>   pit/moat.  If you then freeze the moat, the pit reappears on top of
>   the ice.
2021-10-16 22:22:33 -04:00
copperwater
f855fb5e45 Remove g.monstermoves
It's redundant with g.moves, so there is no more need for it.

Way, way back, it looks like g.moves and g.monstermoves can and did
desync, where g.moves would track the amount of moves the player had
gotten (and would therefore increase faster if the player were hasted)
and g.monstermoves would track the amount of monster move cycles, aka
turns. But this has not been the case for a long time, and they both
increment together in the same location in allmain.c. There are no
longer any cases where they will not be the same value.

This is a save-breaking change because it changes struct
instance_globals, but I have not updated the editlevel in this commit.
2021-08-28 16:22:38 -07:00
Pasi Kallinen
20cbadcf85 Unlock your quest by killing your quest leader
Allow killing your quest leader, just to make games winnable if you
converted before doing the quest.
Boost the quest leaders and give them some equipment. King Arthur
gets Excalibur. Killing quest leader gives really bad luck and
makes your god angry at you, and killing quest guardians gives
smaller penalties.

This is based on both the EvilHack implementation by
k21971 <keith.simpson1971@gmail.com>, and xNetHack
implementation by copperwater <aosdict@gmail.com>.
2021-05-23 11:11:58 +03:00
nhmall
5b1d668c44 enable -Wformat-nonliteral for linux and equivalent for windows compilers
Whitelist all the verified existing triggers:
makedefs.c: In function ‘name_file’
attrib.c: one compiler balks at a ? b : c for fmtstring
cmd.c: In function ‘extcmd_via_menu’
cmd.c: In function ‘wiz_levltyp_legend’
do.c: In function ‘goto_level’
do_name.c: In function ‘coord_desc’
dungeon.c: In function ‘overview_stats’
eat.c:  one compiler balks at a ? b : c for fmtstring
end.c:  one compiler balks at a ? b : c for fmtstring
engrave.c: In function ‘engr_stats’
hack:c one compiler balks at a ? b : c for fmtstring
hacklib.c: one compiler balks at a ? b : c for fmtstring
insight.c: one compiler balks at a ? b : c for fmtstring
invent.c: In function ‘let_to_name’
light.c: In function ‘light_stats’
mhitm.c: In function ‘missmm’
options.c: In function ‘handler_symset’
options.c: In function ‘basic_menu_colors’
options.c: In function ‘optfn_o_autopickup_exceptions’
options.c: In function ‘optfn_o_menu_colors’
options.c: In function ‘optfn_o_message_types’
options.c: In function ‘optfn_o_status_cond’
options.c: In function ‘optfn_o_status_hilites’
options.c: In function ‘doset’
options.c: In function ‘doset_add_menu’
options.c: In function ‘show_menu_controls’
options.c: In function ‘handle_add_list_remove’
pager.c: In function ‘do_supplemental_info’
pager.c: In function ‘dohelp’
region.c: In function ‘region_stats’
rumors.c: sscanf usage
sounds.c: In function ‘domonnoise’
spell.c: In function ‘dospellmenu’
timeout.c: In function ‘timer_stats’
topten.c: In function ‘outentry’, fscanf, sscanf, fprintf usage
windows.c: In function ‘genl_status_update’
zap.c: one compiler balks at a ? b : c for fmtstring
win/curses/cursstat.c: In function ‘curses_status_update’
win/tty/wintty.c: In function ‘tty_status_update’
win/win32/mswproc.c: In function ‘mswin_status_update’
2021-02-02 19:03:12 -05:00
nhmall
f963c5aca7 switch source tree from k&r to c99 2021-01-26 21:06:16 -05:00
nhmall
0c3b9642e4 pmnames mons gender naming plus a window port interface change
add MALE, FEMALE, and gender-neutral names for individual monster species
to the mons array. The gender-neutral name (NEUTRAL) is mandatory, the
MALE and FEMALE versions are not.

replace code uses of the mname field of permonst with one of the three
potentially-available gender-specific names.

consolidate some separate mons entries that differed only by species into a
single mons entry (caveman, cavewoman and priest,priestess etc.)

consolidate several "* lord" and "* queen/* king" monst entries into
their single species, and allow both genders on some where it makes some
sense (there is probably more work and cleanup to come out of this at some
point, and the chosen gender-neutral name variations are not cast in stone
if someone has better suggestions).

related function or macro additions:
    pmname(pm, gender) to get the gender variation of the permonst name. It
    guards against monsters that haven't got anything except NEUTRAL naming
    and falls back to the NEUTRAL version if FEMALE and MALE versions are
    missing.

    Ugender to obtain the current hero gender.
    Mgender(mtmp) to obtain the gender of a monster

While the code can safely refer directly to pmnames[NEUTRAL] safely in the
code because it always exists, the other two (pmnames[MALE] and
pmnames[FEMALE] may not exist so use:
    pmname(ptr, gidx)
      where -ptr is a permonst *
            -gidx is an index into the pmnames array field of the
             permonst struct
pmname() checks for a valid index and checks for null-pointers for
pmnames[MALE] and pmnames[FEMALE], and will fall back to pmnames[NEUTRAL] if
the pointer requested if the requested variation is unavailable, or if the
gidx is out-of-range.

Allow code to specify makemon flags to request female or male (via MM_MALE
and MM_FEMALE flags respectively)to makedefs, since the species alone doesn't
distinguish male/female anymore. Specifying MM_MALE or MM_FEMALE won't
override the pm M2_MALE and M2_FEMALE flags on a mons[] entry.

male and female tiles have been added to win/share/monsters.txt.
The majority are duplicated placeholders except for those that were
separate mons entries before. Perhaps someone will contribute artwork in the
future to make the male and female variations visually distinguishable.

tilemapping via has the MALE tile indexes in the glyph2tile[]
array produced at build time. If a window port has information that the
FEMALE tile is required, it just has to increment the index returned
from the glyph2tile[] array by 1.

statues already preserved gender of the monster through STATUE_FEMALE
and STATUE_MALE, so ensure that pmnames takes that into consideration.

I expect some refinement will be required after broad play-testing puts it to
the test.

    consolidate caveman,cavewoman and priest,priestess monst.c entries etc

This commit will require a bump of editlevel in patchlevel.h because it alters
the index numbers of the monsters due to the consolidation of some. Those
index numbers are saved in some other structures, even though the mons[] array
itself is not part of the savefile.

Window Port Interface Change

Also add a parameter to print_glyph to convey additional information beyond
the glyph to the window ports. Every single window port was calling back to
mapglyph for the information anyway, so just included it in the interface and
produce the information right in the display core.

The mapglyph() function uses will be eliminated, although there are still some
in the code yet to be dealt with.

win32, tty, x11, Qt, msdos window ports have all had adjustments done to
utilize the new parameter instead of calling mapglyph, but some of those
window ports have not been thoroughly tested since the changes.

Interface change additional info:

    print_glyph(window, x, y, glyph, bkglyph, *glyphmod)
            -- Print the glyph at (x,y) on the given window.  Glyphs are
               integers at the interface, mapped to whatever the window-
               port wants (symbol, font, color, attributes, ...there's
               a 1-1 map between glyphs and distinct things on the map).
            -- bkglyph is a background glyph for potential use by some
               graphical or tiled environments to allow the depiction
               to fall against a background consistent with the grid
               around x,y. If bkglyph is NO_GLYPH, then the parameter
               should be ignored (do nothing with it).
                -- glyphmod provides extended information about the glyph
               that window ports can use to enhance the display in
               various ways.
                    unsigned int glyphmod[NUM_GLYPHMOD]
               where:
                    glyphmod[GM_TTYCHAR]  is the text characters associated
                                          with the original NetHack display.

                    glyphmod[GM_FLAGS]    are the special flags that denote
                                          additional information that window
                                          ports can use.

                    glyphmod[GM_COLOR] is the text character
                                       color associated with the original
                                       NetHack display.

Support for including the glyphmod info in the display glyph buffer
alongside the glyph itself was added and is the default operation.
That can be turned off by defining UNBUFFERED_GLYPHMOD at compile time.
With UNBUFFERED_GLYPHMOD operation, a call will be placed to map_glyphmod()
immediately prior to every print_glyph() call.
2020-12-26 11:23:23 -05:00
PatR
7e87abb66f wizard mode buglet: simultaneous Lev+Fly timeout
Noticed while working on Qt status highlighting:  if levitation
and flying timed out at the same time, first Lev timeout called
float_down() which reported
 You have stopped levitating and are now flying.
and then Fly timeout left stale "Fly" on the status line due to
an optimization which got subverted.  ('was_flying' flag was
False due to Fly being blocked by Lev; that's correct behavior,
but the flag is effectively a cached value that becomes stale
when the Lev timeout code executes.)

The bug was wizard mode only because #wizintrinsic is the only
way to get timed flying.
2020-11-24 10:43:12 -08:00
Pasi Kallinen
22ca1ae4da Fix monster hiding under hatching egg staying hidden 2020-10-24 18:32:08 +03:00
Pasi Kallinen
aeb0ea65e3 Mild Zombie Apocalypse
When a zombie (or lich) kills a monster in melee without a weapon,
the monster can rise few turns later as a zombie.

The only creatures that can be zombified are ones that actually have
a zombie counterpart monster. A zombie cannot turn a jackal into
a zombie, for instance. But it could turn a shopkeeper into a human
zombie, or a dwarf king into a dwarf zombie.

Zombies will fight with monsters that can be turned into zombies.

Originally this was a SliceHack feature, but this is based on xNetHack
version of it, with some modifications.
2020-10-23 19:47:10 +03:00
PatR
3f81bd5af6 fix pull request #380 - turning into slime
The turn-to-slime countdown is one of the ones that uses turns/2
to stretch the sequence out longer and it was displaying the hero
as green slime when there was another turn before it happened.
(In theory anyway.  I could not get my hero to be shown as slime
and still have one move left, even when hasted.)

Make the hero mimic green slime starting on the last turn before
being polymorphed instead of next to last.

Fixes #380
2020-08-27 16:14:17 -07:00
nhmall
ac9ba38449 file header bump from "NetHack 3.6" to "NetHack 3.7" 2020-08-03 22:07:36 -04:00
PatR
22b4ed0be5 Lev vs Fly via #wizintrinsic
I noticed that Qt status showed both Lev and Fly at the same time
when they should be mutually exclusive (Levitation overrides Flying).
I wasted a bunch of time trying to track down a Qt problem but it
turned out to be a core issue.  If Flying is set first (which won't
happen if both are set in the same #wizinstrinsic operation), setting
Levitation via #wizintrinsic was attempting to update the flag that
indicates that Flying is blocked, but doing so too soon and failing.
Setting Lev via other means while Fly was already set didn't have
this problem so it wouldn't occur during normal play.

Also, #timeout lists timed properties which can have a timeout value
in normal play, then a separator, followed by properties that can
only become timed due to #wizintrinsic.  Move Displacement from the
second group to the first now that it can be obtained as a timed
value by eating a displacer beast corpse.
2020-08-01 06:11:20 -07:00
PatR
16562b2892 displacer beast as food
Make eating a displacer beast corpse or a tin of displacer beast
meat confer temporary Displacement lasting 6d6 turns.
2020-05-04 09:50:11 -07:00
PatR
09f9b3598f fix issue #339 - duplicate feature messages
while 'mention_decor' is enabled.  When stepping onto different
terrain and one or more objects remained on the new spot after
autopickup, describe_decor() was issuing its new-terrain message
right before look_here()'s similar under-the-objects message.  If
autopickup grabbed everything or there weren't any objects to begin
with, look_here() doesn't issue any dfeature (terrain) message.
describe_decor() isn't smart enought to know whether that is going
to happen.  Give look_here() a new flag argument so that its caller
can ask for the dfeature message to be skipped for the case where a
similar message has already been given.
2020-04-27 04:25:26 -07:00