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?]
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.
It looks like the Windows API call for PlaySound using SND_RESOURCE, from a
mingw32 built program, cannot find the resources that are
embeded into the .exe by the mingw32 resource compiler. That works fine
from visual studio.
For now, fall back to not using the SND_RESOURCE flag, use an ordinary
wav file name in the filesystem. Makefile.mingw32 has been modified
to copy the wav files to the binary directory along with the exe.
This probably won't be the final approach, but it will get things
working for now.
Use macOS AppKit framework routines for a first cut at a
macsound soundlib interface.
Requires WANT_MACSOUND=1 on build.
Nothing has been done to move the stock sounds into the resources
of a bundle, so after building, if you want to try the stock sounds
out:
cp sound/wav/*.wav ~/Library/Sounds
Because the NSSound macOS routines always do the search, supposedly
the following locations are searched in this order:
1. the application’s main bundle
2. ~/Library/Sounds
3. /Library/Sounds
4. /Network/Library/Sounds
5. /System/Library/Sounds
Although not specifically implemented as of yet, it may be pretty
close to being able to put soundeffects wav files (by se_ name)
into ~/Library/Sounds working for the SND_SOUNDEFFECTS_AUTOMAP feature.
Feedback is welcome. Contributions for improving it are even more
welcome.
The new soundlib supporting file is named
sound/macsound/macsound.m since it's got objective C in it.
Known bugs and glitches:
The Hero_playnotes on a set of 5 notes goes too fast, so there
needs to be a slight delay added between the note of a multi-note
play.
Expand windsound to support SNDCAP_USERSOUNDS (existing),
SNDCAP_SOUNDEFFECTS, SNDCAP_HEROMUSIC.
Place a small number of wav files into sound/wav that are considered
more specific to some game stuff in the core, namely: playing
instruments by the hero, squeaky board traps. The intention is that
those ones can be integrated into the game without requiring user
file deposits or mappings. Building soundlib support for sound/windsound
searches for them as resources, so they should "just work."
No actual instrument playback is available in the base sound/windsound
soundlib implementation (yet, at least), so it works around that in
a cheap way by using the note-variant wav sounds to concoct the
notes. There are better ways of doing music generation than that,
of course, but this will do in the early going. Any other soundlib
port (such as Qt) can probably easily do the exact same thing. If it
can play USER_SOUNDS, it can almost certainly use the
sound/wav/se_squeak*.wav and sound/wav/sound_*.wav files for
SND_HEROMUSIC and squeaky board sounds soundeffects.
A few of the se_ sounds in sound/wav are free yet licensed, and
there is a file called attributions.txt to meticulously attempt
to comply with the two license variations involved.
SND_SOUNDEFFECTS_AUTOMAP
If SND_SOUNDEFFECTS_AUTOMAP is defined, and a SND_LIB_ interface
that supports SNDPROC_SOUNDEFFECTS is also defined to integrate
soundlib support, the following gets added:
o If sounddir is defined (existing longstanding feature that's
been used with USER_SOUNDS for many, many years) any wav file
present in SOUNDDIR with a name that matches one of the defined
sound effects in include/sndproc.h will get played each time
that soundeffect comes up. So, just drop appropriate wav files
into sounddir and rename it to match.
No tedious config file entries are required to get soundeffects.
[ The only config file change required is to
set SOUNDDIR to point to your directory with the wav files.
Note: SOUNDDIR only works in your config file if NetHack
was built with USER_SOUNDS defined. ]
This is new so there may certainly be some bugs in here.
Please kindly report them if you encounter any.
For those that don't read C very well, these are the file names
that should trigger the SOUNDEFFECTS_AUTOMAP, assuming it is working.
se_faint_splashing.wav
se_crackling_of_hellfire.wav
se_heart_beat.wav
se_typing_noise.wav
se_hollow_sound.wav
se_rustling_paper.wav
se_crushing_sound.wav
se_splash.wav
se_chains_rattling_gears_turning.wav
se_smashing_and_crushing.wav
se_gears_turning_chains_rattling.wav
se_loud_splash.wav
se_lound_crash.wav
se_crashing_rock.wav
se_sizzling.wav
se_crashing_boulder.wav
se_boulder_drop.wav
se_item_tumble_downwards.wav
se_drain_noises.wav
se_ring_in_drain.wav
se_groans_and_moans.wav
se_scratching.wav
se_glass_shattering.wav
se_egg_cracking.wav
se_gushing_sound.wav
se_glass_crashing.wav
se_egg_splatting.wav
se_sinister_laughter.wav
se_blast.wav
se_stone_breaking.wav
se_stone_crumbling.wav
se_snakes_hissing.wav
se_loud_pop.wav
se_clanking_pipe.wav
se_sewer_song.wav
se_monster_behind_boulder.wav
se_wailing_of_the_banshee.wav
se_swoosh.wav
se_explosion.wav
se_crashing_sound.wav
se_someone_summoning.wav
se_rushing_wind_noise.wav
se_splat_from_engulf.wav
se_faint_sloshing.wav
se_crunching_sound.wav
se_slurping_sound.wav
se_masticating_sound.wav
se_distant_thunder.wav
se_applause.wav
se_shrill_whistle.wav
se_someone_yells.wav
se_door_unlock_and_open.wav
se_door_open.wav
se_door_crash_open.wav
se_dry_throat_rattle.wav
se_cough.wav
se_angry_snakes.wav
se_zap_then_explosion.wav
se_zap.wav
se_horn_being_played.wav
se_mon_chugging_potion.wav
se_bugle_playing_reveille.wav
se_crash_through_floor.wav
se_thump.wav
se_scream.wav
se_tumbler_click.wav
se_gear_turn.wav
se_divine_music.wav
se_thunderclap.wav
se_sad_wailing.wav
se_maniacal_laughter.wav
se_rumbling_of_earth.wav
se_clanging_sound.wav
se_mutter_imprecations.wav
se_mutter_incantation.wav
se_angry_voice.wav
se_sceptor_pounding.wav
se_courtly_conversation.wav
se_low_buzzing.wav
se_angry_drone.wav
se_bees.wav
se_someone_searching.wav
se_guards_footsteps.wav
se_faint_chime.wav
se_loud_click.wav
se_soft_click.wav
se_squeak.wav
se_squeak_C.wav
se_squeak_D_flat.wav
se_squeak_D.wav
se_squeak_E_flat.wav
se_squeak_E.wav
se_squeak_F.wav
se_squeak_F_sharp.wav
se_squeak_G.wav
se_squeak_G_sharp.wav
se_squeak_A.wav
se_squeak_B_flat.wav
se_squeak_B.wav
se_someone_bowling.wav
se_rumbling.wav
se_loud_crash.wav
se_deafening_roar_atmospheric.wav
se_low_hum.wav
se_laughter.wav
se_cockatrice_hiss.wav
se_chant.wav
se_cracking_sound.wav
se_ripping_sound.wav
se_thud.wav
se_clank.wav
se_crumbling_sound.wav
se_soft_crackling.wav
se_crackling.wav
se_sharp_crack.wav
se_wall_of_force.wav
se_alarm.wav
se_kick_door_it_shatters.wav
se_kick_door_it_crashes_open.wav
se_bubble_rising.wav
se_bolt_of_lightning.wav
se_board_squeak.wav
se_board_squeaks_loudly.wav
se_boing.wav
se_crashed_ceiling.wav
se_clash.wav
se_crash_door.wav
se_crash.wav
se_crash_throne_destroyed.wav
se_crash_something_broke.wav
se_kadoom_boulder_falls_in.wav
se_klunk_pipe.wav
se_kerplunk_boulder_gone.wav
se_klunk.wav
se_klick.wav
se_kaboom_door_explodes.wav
se_kaboom_boom_boom.wav
se_kaablamm_of_mine.wav
se_kaboom.wav
se_splat_egg.wav
se_destroy_web.wav
se_iron_ball_dragging_you.wav
se_iron_ball_hits_you.wav
se_lid_slams_open_falls_shut.wav
se_chain_shatters.wav
se_furious_bubbling.wav
se_air_crackles.wav
se_potion_crash_and_break.wav
se_hiss.wav
se_growl.wav
se_canine_bark.wav
se_canine_growl.wav
se_canine_whine.wav
se_canine_yip.wav
se_canine_howl.wav
se_feline_yowl.wav
se_feline_meow.wav
se_feline_purr.wav
se_feline_yip.wav
se_feline_mew.wav
se_roar.wav
se_snarl.wav
se_buzz.wav
se_squeek.wav
se_squawk.wav
se_squeal.wav
se_screech.wav
se_equine_neigh.wav
se_equine_whinny.wav
se_equine_whicker.wav
se_bovine_moo.wav
se_bovine_bellow.wav
se_wail.wav
se_groan.wav
se_grunt.wav
se_gurgle.wav
se_elephant_trumpet.wav
se_snake_rattle.wav
se_hallu_growl.wav
This needs further testing. At the moment only windsound has
this.
If nobody else looks into it for Qt, I'll take a look in a
few days.
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.
Groundwork for a more versatile interface for using
sound libraries. A lot of sound libraries work across
multiple platforms.
The current NetHack sound stuff is quite limited.
Binaries can have a variety of window ports linked into
them, and it makes sense to have something similar for
sound.
This tries to set things up in a more soundlib-centric way,
rather than inserting things in a platform-centric way.
It establishes a new top-level directory sound (akin to win
for the window interface routines, or "window-port") where
sound-related additions and sndprocs and support files can be
added and used across platforms.
The default interface is nosound and the 'nosound' interface
is in src/sounds.c
The interface for 'windsound', which contains the same minimal
USER_SOUNDS support using built-in routines that has been in the
windows port for a long time is added to
sound/windsound/windsound.c.
For now, the sound interface support for 'qtsound' has been added
to the existing Qt files win/Qt/qt_bind.h and win/Qt/qt_bind.cpp,
and a note has been placed in sound/qtsound/README.md to avoid
confusion.
New header file added: include/sndprocs.h.
Add a couple of redundant tests for 'shkp = shop_keeper()' yielding
Null to pacify the static analyzer.
Make the paired calls to shkp = shop_keeper() and inhishop(shkp) look
more consistent. Barring typos, the behavior hasn't been changed.
A mute shopkeeper shouldn't be able to verbally tell you the prices of
objects. For normal chatting, on the other hand, shk_chat can handle a
mute shopkeeper (by changing from speech to "indications" -- hand signs,
body language, etc), so allow execution to reach that even if the
shopkeeper is mute (in a silent polyform).
Also more generally allow a shopkeeper to continue chatting with normal
shopkeeper responses if polymorphed into another creature, since they
apparently retain their minds (are able to tell you prices, can
transact, etc).
This is mostly inspired by the fact shk_chat has extensive handling for
mute shopkeepers, but it was unreachable as far as I can tell. It is
also funny to think of a newt or something wriggling around to indicate
it's been making a lot of money lately.
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
^ ^
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() */
Issue reported by eakaye: the alternate hobbit chat message is a
complaint about dungeon conditions, given if its current HP is 10
or more less than its maximum HP. But since hobbits are level 1,
they will almost never have 10 HP so won't be alive to chat when
at max minus 10.
Keep the old behavior if maximum happens to be more than 10, but
give alternate feedback when less than max if max is 10 or less.
Fixes#890
The pull request included some changes that were neither accidental nor
unintentional, so only a subset of the changes from pull request #869
submitted by klorpa were manually applied.
behaviour -> behavior
speach -> speech
knowlege -> knowledge
incrments -> increments
stethscope -> stethoscope
staiway -> stairway
arifact -> artifact
extracing -> extracting
The uses of "iff" were left alone.
Close#869
Change the regex_error_desc() interface. Have the caller pass in
a pointer to a buffer of at least BUFSZ characters and have
regex_error_desc() populate that. No need for static buffers or
extra dynamic alloction.
Also, change it to never return Null. None of its callers were
checking for that and could have passed Null to config_error_add()
or raw_print(). printf("%s", NULL) produces "null" on OSX but other
systems would probably crash if a Null result ever actually occurred.
The error explanation returned by cppregex included a trailing period.
config_error_add() adds one, so the message ended up with two. Have
regex_error_desc() check for final period and strip it off if found.
(My test case used a menucolor pattern of "[" which triggers an error
about mismatched brackets.)
Reformat cppregex.cpp; treat 'extern "C" {' as if it isn't introducing
a nested block. Fix the '#include <hack.h>' that 'make depend' was
ignoring.
Add some basic functions to iterate through the monster list,
ignoring dead monsters. Mainly just to allow splitting up code
into discrete functions.
Not quite happy with the get_iter_mons_xy - should probably have
a pointer to iterator data struct, which gets passed through instead,
but this works for now.
Call growl even if you are deaf, because growling also
wakes up nearby monsters. Just make growl not show the message
if you can't hear or see the monster.
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);
| ^~~~~~~~~~~
Instead of returning ECMD_OK, the commands now return ECMD_CANCEL
when user declined to pick a direction or an object to act on.
Note that this can be ORed with ECMD_TIME, if the command still
took a turn.
For now this has no gameplay meaning.
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.
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’
sounds.c: In function ‘add_sound_mapping’:
sounds.c:1381:33: warning: ‘sprintf’ may write a terminating nul past the end of the destination [-Wformat-overflow=]
1381 | Sprintf(filespec, "%s/%s", sounddir, filename);
| ^
In file included from ../include/config.h:631,
from ../include/hack.h:10,
from sounds.c:5:
../include/global.h:274:24: note: ‘sprintf’ output 2 or more bytes (assuming 257) into a destination of size 256
274 | #define Sprintf (void) sprintf
sounds.c:1381:9: note: in expansion of macro ‘Sprintf’
1381 | Sprintf(filespec, "%s/%s", sounddir, filename);
| ^~~~~~~
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.
The short exclamations ("Gasp!", "Why?", &c) led to ambiguity
about which monster was vocalizing them. Use full sentences
which refer to the speaker. It can become quite a bit more
verbose but is less likely to lead to confusion. Perhaps it
should cut those off after a modest number of them have been
issued?
The code for peaceful monsters witnessing the hero attack another
peaceful monster and getting angry had a 20% of making them gasp in
surprise or exclaim "why?" in shock. It was only requiring them to
have humanoid shape rather than checking for speech capability, so
peaceful zruty or minotaur, possibly other animals, could exclaim
comprehensibly. Other things which shouldn't talk, like mummies,
would behave similarly.
This categorizes how a bunch of MS_foo types should react. It has
only been lightly tested.
Assuming you have the prerequisite packages, You can specify the
window ports to include on the make command line:
make WANT_WIN_QT=1 WANT_WIN_X11=1 WANT_WIN_CURSES=1 WANT_WIN_TTY=1 all
Prequisites for window ports beyond tty:
(some sample homebrew commands to obtain them shown but that is not the
only way):
xquartz for x11 support
brew install xquartz
Qt for Qt support
brew install Qt