]> granicus.if.org Git - nethack/commitdiff
another update to the soundlib interface
authornhmall <nhmall@nethack.org>
Tue, 7 Feb 2023 05:44:36 +0000 (00:44 -0500)
committernhmall <nhmall@nethack.org>
Tue, 7 Feb 2023 05:44:36 +0000 (00:44 -0500)
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.

48 files changed:
doc/sound.txt
include/decl.h
include/extern.h
include/flag.h
include/hack.h
include/optlist.h
include/sndprocs.h
sound/macsound/macsound.m
sound/windsound/windsound.c
src/apply.c
src/artifact.c
src/cmd.c
src/decl.c
src/dig.c
src/do_name.c
src/dokick.c
src/hack.c
src/hacklib.c
src/lock.c
src/mail.c
src/mcastu.c
src/mhitu.c
src/minion.c
src/mkobj.c
src/mon.c
src/monmove.c
src/mplayer.c
src/muse.c
src/pickup.c
src/pline.c
src/potion.c
src/pray.c
src/priest.c
src/quest.c
src/read.c
src/rumors.c
src/shk.c
src/sit.c
src/sounds.c
src/teleport.c
src/timeout.c
src/uhitm.c
src/vault.c
src/wizard.c
sys/unix/hints/include/multisnd1-pre.370
sys/unix/hints/macOS.370
win/Qt/qt_bind.cpp
win/Qt/qt_bind.h

index b70755eff4d0e6aff4d9c5acc94a489f225ef872..3d88e9cd7801e6d0b80e1bd9b0518404d4bbcae2 100644 (file)
@@ -90,6 +90,9 @@ There are 4 distinct types of sound sound_triggers used by NetHack.
                                  (ambience_upate), likely with a different
                                  hero proximity value.
 
+    SOUND_TRIGGER_VERBAL         Invoked by the core when someone (or something)
+                                 is speaking.
+
 
 The types of sound sound_triggers supported by a particular soundlib
 implementation are specified in that library's soundlib file, which is usually
@@ -109,17 +112,20 @@ the sound_triggers field of the sound_procs struct:
         void (*sound_play_usersound)(char *filename, int32_t volume,
               int32_t usidx);
         void (*sound_ambience)(int32_t ambienceid, int32_t ambience_action,
-               int32_t hero_proximity);
+              int32_t hero_proximity);
+        void (*sound_verbal)(char *text, int32_t gender, int32_t tone,
+              int32_t vol, int32_t moreinfo);
     };
 
-A sound library integration support file can implement one, two, three or
-four of the sound trigger types. The more types of sound_triggers the
+A sound library integration support file can implement one, two, three, four,
+five, or six of the sound trigger types. The more types of sound_triggers the
 soundlib implements, the more full-featured the sound experience will be
 during the game.
 
 The values can be or'd together in the sound_triggers field initialization.
     SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
         | SOUND_TRIGGER_ACHIEVEMENTS | SOUND_TRIGGER_SOUNDEFFECTS
+        | SOUND_TRIGGER_AMBIENCE | SOUND_TRIGGER_VERBAL
 
 
 II.  Interface Specification
@@ -248,6 +254,18 @@ sound_ambience(int32_t ambienceid, int32_t ambience_action,
        If the distance of the hero from the source of the ambience does
        matter, then a distance value will be in hero_proximity.
 
+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 or NEUTRAL (either MALE
+       or FEMALE) 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.
+
 
 III.  Global variables
 
@@ -264,6 +282,11 @@ gc.chosen_soundlib
 ga.active_soundlib
 a usersound mappings reference
 
+iflags.sounds is the master on/off swith to control whether any audio
+is produced by the soundlib interface
+
+iflags.voice is the master on/off switch for voices produced by
+the soundlib interface.
 
 IV.   Other related routines
 
@@ -360,14 +383,15 @@ use the following guidelines:
            SOUNDID(myprefix),
            SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
               | SOUND_TRIGGER_ACHIEVEMENTS |SOUND_TRIGGER_SOUNDEFFECTS
-              | SOUND_TRIGGER_AMBIENCE,
+              | SOUND_TRIGGER_AMBIENCE | SOUND_TRIGGER_VERBAL,
            myprefix_init_nhsound,
            myprefix_exit_nhsound,
            myprefix_achievement,
            myprefix_soundeffect,
            myprefix_hero_playnotes,
            myprefix_play_usersound,
-           myprefix_ambience),
+           myprefix_ambience,
+           myprefix_verbal),
        };
 
    The first entry in this structure should be the SOUNDID(myprefix)
@@ -526,6 +550,8 @@ static void sample_hero_playnotes(int32_t, const char *, int32_t);
 static void sample_play_usersound(char *, int32_t, int32_t);
 static void sample_ambience(int32_t ambienceid, int32_t ambience_action,
                             int32_t hero_proximity);
+static void (*sound_verbal)(char *text, int32_t gender, int32_t tone,
+              int32_t vol, int32_t moreinfo);
 
 struct sound_procs sample_procs = {
     SOUNDID(sample),
@@ -539,6 +565,7 @@ struct sound_procs sample_procs = {
     sample_hero_playnotes,
     sample_play_usersound,
     sample_ambience,
+    sample_verbal
 };
 
 static void
@@ -588,5 +615,11 @@ sample_ambience(int32_t ambienceid, int32_t ambience_action,
 {
 }
 
+static void
+sample_verbal(char *text, int32_t gender, int32_t tone,
+              int32_t vol, int32_t moreinfo)
+{
+}
+
 /* end of sample.c */
 -- >8 --
index 7a81872dcb5cb9688c21d1bd3a05f254c82ae39d..4a89d1492be1d1d492e7aa28d2170320266a2900 100644 (file)
@@ -1588,6 +1588,9 @@ struct instance_globals_v {
     coordxy *viz_rmax;   /* max could see indices */
     boolean vision_full_recalc;
 
+    /* new stuff */
+    struct sound_voice voice;
+
     boolean havestate;
     unsigned long magic; /* validate that structure layout is preserved */
 };
index 05b5eaea3b861bb8bc98d1730e483e22e2375561..2ef0ad09ba1eb9f804b96b931bbf1ab55cfbfdac 100644 (file)
@@ -1012,6 +1012,7 @@ extern char *strip_newline(char *);
 extern char *stripchars(char *, const char *, const char *);
 extern char *stripdigits(char *);
 extern char *eos(char *);
+extern const char *c_eos(const char *);
 extern unsigned Strlen_(const char *, const char *, int);
 extern boolean str_start_is(const char *, const char *, boolean);
 extern boolean str_end_is(const char *, const char *);
@@ -2620,6 +2621,8 @@ extern char *get_sound_effect_filename(int32_t seidint,
                                        char *buf, size_t bufsz, int32_t);
 #endif
 extern char *base_soundname_to_filename(char *, char *, size_t, int32_t);
+extern void set_voice(struct monst *, int32_t, int32_t, int32_t); 
+extern void sound_speak(const char *);
 
 /* ### sp_lev.c ### */
 
index 7edec9119d1000ddae9158eb5a3e75216cde344d..5a99da20692f8c3e80d55ca8b572b8f73ba08b80 100644 (file)
@@ -277,6 +277,7 @@ struct instance_flags {
     long hilite_delta;        /* number of moves to leave a temp hilite lit */
     long unhilite_deadline; /* time when oldest temp hilite should be unlit */
 #endif
+    boolean voices;           /* enable text-to-speech or other talking */
     boolean zerocomp;         /* write zero-compressed save files */
     boolean rlecomp;          /* alternative to zerocomp; run-length encoding
                                * compression of levels when writing savefile */
index 327849ac5513de2eca0cfe69e8c53983d67c4674..b53f78b4a4598b918ff158857aa0b4caad25a58f 100644 (file)
@@ -497,6 +497,8 @@ typedef uint32_t mmflags_nht;     /* makemon MM_ flags */
 #define OVERRIDE_MSGTYPE 2
 #define SUPPRESS_HISTORY 4
 #define URGENT_MESSAGE   8
+#define PLINE_VERBALIZE 16
+#define PLINE_SPEECH    32
 
 /* get_count flags */
 #define GC_NOFLAGS   0
index b71417d8c47e820563ea2956a0ea031ec92b015c..69d6bfe18316da8627b4ce29bde0051fb567ebe3 100644 (file)
@@ -662,6 +662,8 @@ static int optfn_##a(int, int, boolean, char *, char *);
     NHOPTC(video_height, Advanced, 10, opt_in, set_gameview,
                 No, Yes, No, No, NoAlias, "video height")
 #endif
+    NHOPTB(voices, Advanced, 0, opt_in, set_in_game,
+                Off, Yes, No, No, NoAlias, &iflags.voices, Term_Off)
 #ifdef TTY_TILES_ESCCODES
     NHOPTB(vt_tiledata, Advanced, 0, opt_in, set_in_config,
                 Off, Yes, No, No, NoAlias, &iflags.vt_tiledata, Term_False)
index 9460a143af2fa20a03f71c8be8a26b5b8e34b07d..a095d7f75bb237125ace1f565c948ee035788d76 100755 (executable)
@@ -53,6 +53,18 @@ struct sound_procs {
     void (*sound_play_usersound)(char *filename, int32_t volume, int32_t idx);
     void (*sound_ambience)(int32_t ambience_action, int32_t ambienceid,
                            int32_t proximity);
+    void (*sound_verbal)(char *text, int32_t gender, int32_t tone,
+                         int32_t vol, int32_t moreinfo);
+};
+
+struct sound_voice {
+    int32_t serialno;
+    int32_t gender;
+    int32_t tone;
+    int32_t volume;
+    int32_t moreinfo;
+    struct monst *mon;
+    const char *nameid;
 };
 
 extern struct sound_procs sndprocs;
@@ -67,7 +79,8 @@ extern struct sound_procs sndprocs;
 #define SOUND_TRIGGER_ACHIEVEMENTS 0x0004L
 #define SOUND_TRIGGER_SOUNDEFFECTS 0x0008L
 #define SOUND_TRIGGER_AMBIENCE     0x0010L
-                            /* 27 free bits */
+#define SOUND_TRIGGER_VERBAL       0x0020L
+                            /* 26 free bits */
 
 extern struct sound_procs soundprocs;
 
@@ -334,6 +347,15 @@ enum ambiences {
     amb_noambience,
 };
 
+enum voice_moreinfo {
+    voice_nothing_special,
+    voice_talking_artifact = 0x0001,
+    voice_deity            = 0x0002,
+    voice_oracle           = 0x0004,
+    voice_throne           = 0x0008,
+    voice_death            = 0x0010
+};
+
 enum achievements_arg2 {
     sa2_zero_invalid, sa2_splashscreen, sa2_newgame_nosplash, sa2_restoregame,
     sa2_xplevelup, sa2_xpleveldown, number_of_sa2_entries
@@ -396,8 +418,6 @@ SoundAchievement(0, sa2_xpleveldown, level);
             (*soundprocs.sound_hero_playnotes)((instrument), (str), (vol));  \
     } while(0)
 
-/*  void (*sound_achievement)(schar, schar, int32_t); */
-
 /* Player's perspective, not the hero's; no Deaf suppression */
 #define SoundAchievement(arg1, arg2, avals) \
     do {                                                                      \
@@ -406,6 +426,21 @@ SoundAchievement(0, sa2_xpleveldown, level);
             (*soundprocs.sound_achievement)((arg1), (arg2), (avals));         \
     } while(0)
 
+/* sound_speak is in sound.c */
+#define SoundSpeak(text) \
+    do {                                                                     \
+        if ((gp.pline_flags & (PLINE_VERBALIZE | PLINE_SPEECH)) != 0         \
+            && soundprocs.sound_verbal && iflags.voices                      \
+            && ((soundprocs.sound_triggers & SOUND_TRIGGER_VERBAL) != 0))    \
+            sound_speak(text);                                               \
+    } while(0)
+
+/* set_voice is in sound.c */
+#define SetVoice(mon, tone, vol, moreinfo) \
+    do {                                                                     \
+        set_voice(mon, tone, vol, moreinfo);                                 \
+    } while(0)
+
 /*  void (*sound_achievement)(schar, schar, int32_t); */
 
 #ifdef SOUNDLIBONLY
@@ -420,6 +455,8 @@ SoundAchievement(0, sa2_xpleveldown, level);
 #define Soundeffect(seid, vol)
 #define Hero_playnotes(instrument, str, vol)
 #define SoundAchievement(arg1, arg2, avals)
+#define SoundSpeak(text)
+#define SetVoice(mon, tone, vol, moreinfo)
 #ifdef SOUNDLIBONLY
 #undef SOUNDLIBONLY
 #endif
index 9fd37a22e339084abe450f2d90f4a5b7602b59d6..37360b7de664c0a1377f36ab0b788aff7edc34ce 100644 (file)
 /* #import <Foundation/Foundation.h> */
 #import <AppKit/AppKit.h>
 
+#define SPEECH_SOUNDS
+#ifdef SPEECH_SOUNDS
+#import <AVFoundation/AVFoundation.h>
+#endif
+
+
 /*
  * Sample sound interface for NetHack
  *
@@ -27,9 +33,11 @@ static void macsound_soundeffect(char *, int32_t, int32_t);
 static void macsound_hero_playnotes(int32_t, const char *, int32_t);
 static void macsound_play_usersound(char *, int32_t, int32_t);
 static void macsound_ambience(int32_t, int32_t, int32_t);
-
+static void macsound_verbal(char *, int32_t, int32_t, int32_t, int32_t);
 static int affiliate(int32_t seid, const char *soundname);
 
+
+
 /*
  * Sound capabilities that can be enabled:
  *    SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
@@ -40,7 +48,10 @@ static int affiliate(int32_t seid, const char *soundname);
 struct sound_procs macsound_procs = {
     SOUNDID(macsound),
     SOUND_TRIGGER_HEROMUSIC | SOUND_TRIGGER_SOUNDEFFECTS
-        | SOUND_TRIGGER_ACHIEVEMENTS,
+        | SOUND_TRIGGER_ACHIEVEMENTS
+#ifdef SND_SPEECH
+        | SOUND_TRIGGER_VERBAL,
+#endif
     macsound_init_nhsound,
     macsound_exit_nhsound,
     macsound_achievement,
@@ -48,6 +59,7 @@ struct sound_procs macsound_procs = {
     macsound_hero_playnotes,
     macsound_play_usersound,
     macsound_ambience,
+    macsound_verbal,
 };
 
 static void
@@ -312,6 +324,36 @@ macsound_play_usersound(char *filename UNUSED, int volume UNUSED, int idx UNUSED
 
 }
 
+#ifdef SND_SPEECH
+#define SPEECHONLY
+#else
+#define SPEECHONLY UNUSED
+#endif
+
+static void
+macsound_verbal(char *text SPEECHONLY, int32_t gndr SPEECHONLY, int32_t tone_of_voice UNUSED, int32_t vol UNUSED, int32_t moreinfo UNUSED)
+{
+#ifdef SND_SPEECH
+    NSMutableString *speechstring;
+    AVSpeechUtterance *text2speechutt;
+    AVSpeechSynthesizer *synthesizer;
+    synthesizer = [[AVSpeechSynthesizer alloc]init];
+    speechstring = [NSMutableString stringWithUTF8String:text];
+    text2speechutt = [AVSpeechUtterance speechUtteranceWithString:speechstring];
+    text2speechutt.rate = 0.50f;
+    text2speechutt.pitchMultiplier = 0.8f;
+    text2speechutt.postUtteranceDelay = 0.2f;
+    text2speechutt.volume = (float) vol / 100;
+    if (gndr > 0)
+        text2speechutt.voice = [AVSpeechSynthesisVoice voiceWithIdentifier:@"com.apple.ttsbundle.siri_female_en-GB_compact"];
+    else
+        text2speechutt.voice = [AVSpeechSynthesisVoice voiceWithIdentifier:@"com.apple.ttsbundle.siri_male_en-GB_compact"];
+
+    [synthesizer speakUtterance:text2speechutt];
+#endif  /* SND_SPEECH */
+}
+
 static int
 affiliate(int32_t id, const char *soundname)
 {
index aec6942a9f4c82587c27be599fe69a868c4d97c3..01e05b7e084ad72c6b96765551c38dfeabb2679a 100644 (file)
@@ -25,6 +25,9 @@ static void windsound_hero_playnotes(int32_t instrument, const char *str, int32_
 static void windsound_play_usersound(char *, int32_t, int32_t);
 static void windsound_ambience(int32_t ambienceid, int32_t ambience_action,
                                int32_t hero_proximity);
+static void windsound_verbal(char *text, int32_t gender, int32_t tone,
+                             int32_t vol, int32_t moreinfo);
+
 
 /* supporting routines */
 static void adjust_soundargs_for_compiler(int32_t *, DWORD *, char **);
@@ -34,7 +37,7 @@ struct sound_procs windsound_procs = {
     SOUNDID(windsound),
     SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_SOUNDEFFECTS
         | SOUND_TRIGGER_HEROMUSIC | SOUND_TRIGGER_AMBIENCE
-        | SOUND_TRIGGER_ACHIEVEMENTS,
+        | SOUND_TRIGGER_ACHIEVEMENTS | SOUND_TRIGGER_VERBAL,
     windsound_init_nhsound,
     windsound_exit_nhsound,
     windsound_achievement,
@@ -42,6 +45,7 @@ struct sound_procs windsound_procs = {
     windsound_hero_playnotes,
     windsound_play_usersound,
     windsound_ambience,
+    windsound_verbal,
 };
 
 static void
@@ -110,7 +114,13 @@ windsound_achievement(schar ach1, schar ach2, int32_t repeat)
 
 static void
 windsound_ambience(int32_t ambienceid, int32_t ambience_action,
-                int32_t hero_proximity)
+                   int32_t hero_proximity)
+{
+}
+
+static void
+windsound_verbal(char *text, int32_t gender, int32_t tone,
+                 int32_t vol, int32_t moreinfo)
 {
 }
 
index 6c992c7f402d12e406f378c62a28bd5662af2b3f..7d8c93b5d3c3729e1442875eceb7cc4364cea8c5 100644 (file)
@@ -1409,11 +1409,15 @@ use_candle(struct obj **optr)
             pline_The("new %s magically %s!", s, vtense(s, "ignite"));
         else if (!otmp->lamplit && was_lamplit)
             pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes");
-        if (obj->unpaid)
+        if (obj->unpaid) {
+            struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
+
+            SetVoice(shkp, 0, 80, 0);
             verbalize("You %s %s, you bought %s!",
                       otmp->lamplit ? "burn" : "use",
                       (obj->quan > 1L) ? "them" : "it",
                       (obj->quan > 1L) ? "them" : "it");
+        }
         if (obj->quan < 7L && otmp->spe == 7)
             pline("%s now has seven%s candles attached.", The(xname(otmp)),
                   otmp->lamplit ? " lit" : "");
@@ -1563,8 +1567,11 @@ catch_lit(struct obj *obj)
         if (obj->otyp == POT_OIL)
             makeknown(obj->otyp);
         if (carried(obj) && obj->unpaid && costly_spot(u.ux, u.uy)) {
+            struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
+
             /* if it catches while you have it, then it's your tough luck */
             check_unpaid(obj);
+            SetVoice(shkp, 0, 80, 0);
             verbalize("That's in addition to the cost of %s %s, of course.",
                       yname(obj),
                       (obj->quan == 1L) ? "itself" : "themselves");
@@ -1640,7 +1647,9 @@ use_lamp(struct obj *obj)
             if (obj->unpaid && costly_spot(u.ux, u.uy)
                 && obj->age == 20L * (long) objects[obj->otyp].oc_cost) {
                 const char *ithem = (obj->quan > 1L) ? "them" : "it";
+                struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
 
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("You burn %s, you bought %s!", ithem, ithem);
                 bill_dummy_object(obj);
             }
@@ -1685,10 +1694,13 @@ light_cocktail(struct obj **optr)
         Blind ? "" : "  It gives off a dim light.");
 
     if (obj->unpaid && costly_spot(u.ux, u.uy)) {
+        struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
+
         /* Normally, we shouldn't both partially and fully charge
          * for an item, but (Yendorian Fuel) Taxes are inevitable...
          */
         check_unpaid(obj);
+        SetVoice(shkp, 0, 80, 0);
         verbalize("That's in addition to the cost of the potion, of course.");
         bill_dummy_object(obj);
     }
@@ -2141,12 +2153,20 @@ use_tinning_kit(struct obj *obj)
         /* Mark tinned tins. No spinach allowed... */
         set_tin_variety(can, HOMEMADE_TIN);
         if (carried(corpse)) {
-            if (corpse->unpaid)
+            if (corpse->unpaid) {
+                struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
+
+                SetVoice(shkp, 0, 80, 0);
                 verbalize(you_buy_it);
+            }
             useup(corpse);
         } else {
-            if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge)
+            if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge) {
+                struct monst *shkp = shop_keeper(*in_rooms(corpse->ox,
+                                                 corpse->oy, SHOPBASE));
+                SetVoice(shkp, 0, 80, 0);
                 verbalize(you_buy_it);
+            }
             useupf(corpse, 1L);
         }
         (void) hold_another_object(can, "You make, but cannot pick up, %s.",
index 216c08e93e6c32d8a39258c130576f0d37f778b7..5f56d9ecfc39af0f68849200fae30557f76f1c47 100644 (file)
@@ -2001,6 +2001,7 @@ arti_speak(struct obj *obj)
     if (!*line)
         line = "NetHack rumors file closed for renovation.";
     pline("%s:", Tobjnam(obj, "whisper"));
+    SetVoice((struct monst *) 0, 0, 80, voice_talking_artifact);
     verbalize1(line);
     return;
 }
index d2aab63456710c5a1a96973ea56d301d0f3ce865..df96c79ff84b3ab464abbf817b544b615deaf163 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -6557,6 +6557,12 @@ yn_function(
         else
             cmdq_clear(CQ_CANNED); /* 'res' is ESC */
     } else {
+#ifdef SND_SPEECH
+        if ((gp.pline_flags & PLINE_SPEECH) != 0) {
+            sound_speak(query);
+            gp.pline_flags &= ~PLINE_SPEECH;
+        }
+#endif
         res = (*windowprocs.win_yn_function)(query, resp, def);
         if (addcmdq)
             cmdq_add_key(CQ_REPEAT, res);
index 60efafcbef6732dfa5409f0695a03f792088c669..3af274ae5ab7276aa1d1b47bed9ec881ea997f71 100644 (file)
@@ -825,6 +825,7 @@ const struct instance_globals_v g_init_v = {
     UNDEFINED_PTR, /* viz_rmin */
     UNDEFINED_PTR, /* viz_rmax */
     FALSE, /* vision_full_recalc */
+    UNDEFINED_VALUES,  /* voice */
     TRUE, /* havestate*/
     IVMAGIC  /* v_magic to validate that structure layout has been preserved */
 };
index da86bce26ca3fffe01c0abebf3ab36e62a5b4867..ef9ca03c98b5a32dd8225377ac0d60b8c1f8a5b0 100644 (file)
--- a/src/dig.c
+++ b/src/dig.c
@@ -1251,6 +1251,7 @@ watch_dig(struct monst *mtmp, coordxy x, coordxy y, boolean zap)
             mtmp = get_iter_mons(watchman_canseeu);
 
         if (mtmp) {
+            SetVoice(mtmp, 0, 80, 0);
             if (zap || gc.context.digging.warned) {
                 verbalize("Halt, vandal!  You're under arrest!");
                 (void) angry_guards(!!Deaf);
index ba1b352574369db7ea1a4d841d49db11e456e09a..68f66567a619191a1e3db42c75d0e5fc8d3cd550 100644 (file)
@@ -1316,8 +1316,10 @@ do_mgivenname(void)
     } else if (mtmp->isshk
                && !(Deaf || helpless(mtmp)
                     || mtmp->data->msound <= MS_ANIMAL)) {
-        if (!alreadynamed(mtmp, monnambuf, buf))
+        if (!alreadynamed(mtmp, monnambuf, buf)) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("I'm %s, not %s.", shkname(mtmp), buf);
+        }
     } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk
                || mtmp->data == &mons[PM_GHOST]) {
         if (!alreadynamed(mtmp, monnambuf, buf))
index c310833c560811b19a3319aa352cf977b6386b73..7869cec667414a6f6c264036102f6627180d5891 100644 (file)
@@ -327,6 +327,7 @@ ghitm(register struct monst *mtmp, register struct obj *gold)
                 if (!robbed)
                     make_happy_shk(mtmp, FALSE);
             } else {
+                SetVoice(mtmp, 0, 80, 0);
                 if (mtmp->mpeaceful) {
                     ESHK(mtmp)->credit += value;
                     You("have %ld %s in credit.", ESHK(mtmp)->credit,
@@ -335,6 +336,7 @@ ghitm(register struct monst *mtmp, register struct obj *gold)
                     verbalize("Thanks, scum!");
             }
         } else if (mtmp->ispriest) {
+            SetVoice(mtmp, 0, 80, 0);
             if (mtmp->mpeaceful)
                 verbalize("Thank you for your contribution.");
             else
@@ -346,6 +348,7 @@ ghitm(register struct monst *mtmp, register struct obj *gold)
                out of the vault.  If he did do that, player
                could try fighting, then weasle out of being
                killed by throwing his/her gold when losing. */
+            SetVoice(mtmp, 0, 80, 0);
             verbalize(umoney ? "Drop the rest and follow me."
                       : hidden_gold(TRUE)
                         ? "You still have hidden gold.  Drop it now."
@@ -373,13 +376,16 @@ ghitm(register struct monst *mtmp, register struct obj *gold)
             }
 
             if (!mtmp->mpeaceful) {
+                SetVoice(mtmp, 0, 80, 0);
                 if (goldreqd)
                     verbalize("That's not enough, coward!");
                 else /* unbribeable (watchman) */
                     verbalize("I don't take bribes from scum like you!");
             } else if (was_angry) {
+                SetVoice(mtmp, 0, 80, 0);
                 verbalize("That should do.  Now beat it!");
             } else {
+                SetVoice(mtmp, 0, 80, 0);
                 verbalize("Thanks for the tip, %s.",
                           flags.female ? "lady" : "buddy");
             }
index 47f213fade25d1359d4c8193bdcfafb3cb1b742d..ea15c795e76122b39bc91eee88427f4381a9bf00 100644 (file)
@@ -3172,6 +3172,7 @@ check_special_room(boolean newlev)
             struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno);
 
             if (oracle) {
+                SetVoice(oracle, 0, 80, 0);
                 if (!oracle->mpeaceful)
                     verbalize("You're in Delphi, %s.", gp.plname);
                 else
index 2ad8d6c66969a4c425e1b54d2560713ab5feba10..d616cd8198fa79f4d198e8373774a668cf0ca441 100644 (file)
@@ -26,6 +26,7 @@
         char *          stripdigits     (char *)
         unsigned        Strlen_         (const char *str, const char *, int)
         char *          eos             (char *)
+        const char *    c_eos           (const char *)
         boolean         str_start_is    (const char *, const char *, boolean)
         boolean         str_end_is      (const char *, const char *)
         int             str_lines_maxlen (const char *)
@@ -224,6 +225,14 @@ eos(register char *s)
     return s;
 }
 
+const char *
+c_eos(const char *s)
+{
+    while (*s)
+        s++; /* s += strlen(s); */
+    return s;
+}
+
 /* like strlen(3) but returns unsigned and panics if string is unreasonably long */
 unsigned
 Strlen_(const char *str, const char *file, int line){
index d17320cd9023297a2015a4e3926d8c2b29237ea9..77ca57e8c68f274acb159ccaba6bd25a26366bb9 100644 (file)
@@ -552,11 +552,13 @@ pick_lock(
         if (mtmp && canseemon(mtmp) && M_AP_TYPE(mtmp) != M_AP_FURNITURE
             && M_AP_TYPE(mtmp) != M_AP_OBJECT) {
             if (picktyp == CREDIT_CARD
-                && (mtmp->isshk || mtmp->data == &mons[PM_ORACLE]))
+                && (mtmp->isshk || mtmp->data == &mons[PM_ORACLE])) {
+                SetVoice(mtmp, 0, 80, 0);
                 verbalize("No checks, no credit, no problem.");
-            else
+            } else {
                 pline("I don't think %s would appreciate that.",
                       mon_nam(mtmp));
+            }
             return PICKLOCK_LEARNED_SOMETHING;
         } else if (mtmp && is_door_mappear(mtmp)) {
             /* "The door actually was a <mimic>!" */
index a73e0dcd479dc950491c17d51d6b47c973e6bc37..09daa427b42b4f0f19b4b68fd282cee218214f84 100644 (file)
@@ -332,6 +332,7 @@ md_rush(struct monst *md,
         if (fx == tx && fy == ty)
             break;
 
+        SetVoice(md, 0, 80, 0);
         if ((mon = m_at(fx, fy)) != 0) /* save monster at this position */
             verbalize1(md_exclamations());
         else if (u_at(fx, fy))
@@ -363,6 +364,7 @@ md_rush(struct monst *md,
         remove_monster(fx, fy);
         place_monster(md, fx, fy); /* display md with text below */
         newsym(fx, fy);
+        SetVoice(md, 0, 80, 0);
         verbalize("This place's too crowded.  I'm outta here.");
         remove_monster(fx, fy);
 
@@ -403,6 +405,7 @@ newmail(struct mail_info *info)
         goto go_back;
 
     message_seen = TRUE;
+    SetVoice(md, 0, 80, 0);
     verbalize("%s, %s!  %s.", Hello(md), gp.plname, info->display_txt);
 
     if (info->message_typ) {
@@ -413,8 +416,10 @@ newmail(struct mail_info *info)
         if (info->response_cmd)
             new_omailcmd(obj, info->response_cmd);
 
-        if (!next2u(md->mx, md->my))
+        if (!next2u(md->mx, md->my)) {
+            SetVoice(md, 0, 80, 0);
             verbalize("Catch!");
+        }
         display_nhwindow(WIN_MESSAGE, FALSE);
         obj = hold_another_object(obj, "Oops!", (const char *) 0,
                                   (const char *) 0);
index fdb2971134b18ef5cb358cbb0086c4856ac0b931..c1390e09195fc75847a0de96198ac976661dfa2d 100644 (file)
@@ -419,6 +419,7 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum)
         if (!count) {
             ; /* nothing was created? */
         } else if (mtmp->iswiz) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("Destroy the thief, my pet%s!", plur(count));
         } else {
             boolean one = (count == 1);
index a7158cd5dec22d50cd2186959b26e505381e6930..9d4e9ee6ef4cf9be73e05750359e6509ddee46da 100644 (file)
@@ -1866,6 +1866,7 @@ doseduce(struct monst *mon)
                                  " looks pretty.  May I have it?\"", ring,
                                  xname, simpleonames, "ring");
                 makeknown(RIN_ADORNMENT);
+                SetVoice(mon, 0, 80, 0);
                 if (y_n(qbuf) == 'n')
                     continue;
             } else
@@ -1896,6 +1897,7 @@ doseduce(struct monst *mon)
                                  " looks pretty.  Would you wear it for me?\"",
                                  ring, xname, simpleonames, "ring");
                 makeknown(RIN_ADORNMENT);
+                SetVoice(mon, 0, 80, 0);
                 if (y_n(qbuf) == 'n')
                     continue;
             } else {
@@ -1969,6 +1971,7 @@ doseduce(struct monst *mon)
     if (uarm || uarmc) {
         if (!Deaf) {
             if (!(ld() && mon->female)) {
+                SetVoice(mon, 0, 80, 0);
                 verbalize("You're such a %s; I wish...",
                           flags.female ? "sweet lady" : "nice guy");
             } else {
@@ -2112,6 +2115,7 @@ doseduce(struct monst *mon)
         if (cost > umoney)
             cost = umoney;
         if (!cost) {
+            SetVoice(mon, 0, 80, 0);
             verbalize("It's on the house!");
         } else {
             pline("%s takes %ld %s for services rendered!", noit_Monnam(mon),
@@ -2146,6 +2150,7 @@ mayberem(struct monst *mon,
     if (Deaf) {
         pline("%s takes off your %s.", seducer, str);
     } else if (rn2(20) < ACURR(A_CHA)) {
+        SetVoice(mon, 0, 80, 0); /* y_n a.k.a. yn_function is set up for this */
         Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str,
                 (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
         if (y_n(qbuf) == 'n')
@@ -2155,6 +2160,7 @@ mayberem(struct monst *mon,
 
         Sprintf(hairbuf, "let me run my fingers through your %s",
                 body_part(HAIR));
+        SetVoice(mon, 0, 80, 0);
         verbalize("Take off your %s; %s.", str,
                   (obj == uarm)
                      ? "let's get a little closer"
index 1f7e67e9cec075a7d25df1f00531b3048f93ee3e..28ea2f059de4aa678531a356b68d01b1518f51d2 100644 (file)
@@ -241,6 +241,7 @@ summon_minion(aligntyp alignment, boolean talk)
             else
                 You_feel("%s booming voice:",
                          s_suffix(align_gname(alignment)));
+            SetVoice(mon, 0, 80, 0);
             verbalize("Thou shalt pay for thine indiscretion!");
             if (canspotmon(mon))
                 pline("%s appears before you.", Amonnam(mon));
@@ -464,6 +465,7 @@ lose_guardian_angel(struct monst *mon) /* if null, angel hasn't been created yet
         if (canspotmon(mon)) {
             if (!Deaf) {
                 pline("%s rebukes you, saying:", Monnam(mon));
+                SetVoice(mon, 0, 80, 0);
                 verbalize("Since you desire conflict, have some more!");
             } else {
                 pline("%s vanishes!", Monnam(mon));
@@ -496,6 +498,7 @@ gain_guardian_angel(void)
             pline("A voice booms:");
         else
             You_feel("a booming voice:");
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thy desire for conflict shall be fulfilled!");
         /* send in some hostile angels instead */
         lose_guardian_angel((struct monst *) 0);
@@ -504,6 +507,7 @@ gain_guardian_angel(void)
             pline("A voice whispers:");
         else
             You_feel("a soft voice:");
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou hast been worthy of me!");
         mm.x = u.ux;
         mm.y = u.uy;
index cdfb405a66aab62e443dd58dd18aa9b37bf4fc54..62de763ddd7a9d6f2a66951f151dbb993e8d3cf4 100644 (file)
@@ -784,6 +784,8 @@ costly_alteration(struct obj *obj, int alter_type)
     case OBJ_INVENT:
         if (learn_bknown)
             set_bknown(obj, 1);
+        if (shkp)
+            SetVoice(shkp, 0, 80, 0);
         verbalize("You %s %s %s, you pay for %s!",
                   alteration_verbs[alter_type], those, simpleonames(obj),
                   them);
@@ -793,6 +795,8 @@ costly_alteration(struct obj *obj, int alter_type)
         if (learn_bknown)
             obj->bknown = 1; /* ok to bypass set_bknown() here */
         if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
+            if (shkp)
+                SetVoice(shkp, 0, 80, 0);
             verbalize("You %s %s, you pay for %s!",
                       alteration_verbs[alter_type], those, them);
             bill_dummy_object(obj);
index 7871587d8d00f563b2af6d79c37e569c9fd418ca..53bbc7508e6b3f2e96140b6555f711a5fcd99c16 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -3710,6 +3710,7 @@ peacefuls_respond(struct monst *mtmp)
             buf[0] = '\0';
             if (humanoid(mon->data) || mon->isshk || mon->ispriest) {
                 if (is_watch(mon->data)) {
+                    SetVoice(mon, 0, 80, 0);
                     verbalize("Halt!  You're under arrest!");
                     (void) angry_guards(!!Deaf);
                 } else {
index ee087099a2fe11f75cc4ae2d333912b1778ec565..1eecb905bc4008553cdf641e70276f3a6628c0d3 100644 (file)
@@ -96,9 +96,10 @@ mon_yells(struct monst* mon, const char* shout)
         if (canspotmon(mon)) {
             pline("%s yells:", Amonnam(mon));
         } else {
-            Soundeffect(se_someone_yells, 75);
+            /* Soundeffect(se_someone_yells, 75); */
             You_hear("someone yell:");
         }
+        SetVoice(mon, 0, 80, 0);
         verbalize1(shout);
     }
 }
@@ -404,6 +405,7 @@ monflee(
                     pline("%s flees from the painful light of %s.",
                           Monnam(mtmp), lsrc);
                 } else {
+                    SetVoice(mtmp, 0, 80, 0);
                     verbalize("Bright light!");
                 }
             } else {
@@ -1313,8 +1315,10 @@ m_move(register struct monst* mtmp, register int after)
 
 #ifdef MAIL_STRUCTURES
     if (ptr == &mons[PM_MAIL_DAEMON]) {
-        if (!Deaf && canseemon(mtmp))
+        if (!Deaf && canseemon(mtmp)) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("I'm late!");
+        }
         mongone(mtmp);
         return MMOVE_DIED;
     }
index 30870c89dd80bb4b49711b62170c69747c29f0c5..c5b99af404576302935555e170cd1ba7bb226f91 100644 (file)
@@ -368,6 +368,7 @@ mplayer_talk(register struct monst* mtmp)
     if (mtmp->mpeaceful)
         return; /* will drop to humanoid talk */
 
+    SetVoice(mtmp, 0, 80, 0);
     verbalize("Talk? -- %s", mtmp->data == &mons[gu.urole.mnum]
                                 ? same_class_msg[rn2(3)]
                                 : other_class_msg[rn2(3)]);
index 5507fcc6888b229a9b5c005385d37478aeedce3e..eb95611c6ed13c30797520426f81469f145a063e 100644 (file)
@@ -104,6 +104,7 @@ precheck(struct monst *mon, struct obj *obj)
                 pline("%s speaks.", vis ? Monnam(mtmp) : Something);
                 /* I suspect few players will be upset that monsters */
                 /* can't wish for wands of death here.... */
+                SetVoice(mtmp, 0, 80, 0);
                 if (rn2(2)) {
                     verbalize("You freed me!");
                     mtmp->mpeaceful = 1;
@@ -1730,11 +1731,13 @@ use_offensive(struct monst *mtmp)
         return (DEADMONSTER(mtmp)) ? 1 : 2;
     } /* case MUSE_SCR_EARTH */
     case MUSE_CAMERA: {
-        if (Hallucination)
+        if (Hallucination) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("Say cheese!");
-        else
+        } else {
             pline("%s takes a picture of you with %s!",
                   Monnam(mtmp), an(xname(otmp)));
+        }
         gm.m_using = TRUE;
         if (!Blind) {
             You("are blinded by the flash of light!");
index 0fc66b480285d9209de40a4f3b05d69d400dd1b4..183080b47d0fc7a02e115b10b6d667724e145840 100644 (file)
@@ -2196,6 +2196,7 @@ reverse_loot(void)
             coffers = otmp;
 
         if (coffers) {
+            SetVoice((struct monst *) 0, 0, 80, 0);
             verbalize("Thank you for your contribution to reduce the debt.");
             freeinv(goldob);
             (void) add_to_container(coffers, goldob);
index 473d06ebbb526266d49e2ccc2031323e44d6587c..2552647df27981df6e7c14418b36c8bc6c0a350f 100644 (file)
@@ -74,8 +74,8 @@ putmesg(const char *line)
     if ((gp.pline_flags & SUPPRESS_HISTORY) != 0
         && (windowprocs.wincap2 & WC2_SUPPRESS_HIST) != 0)
         attr |= ATR_NOHISTORY;
-
     putstr(WIN_MESSAGE, attr, line);
+    SoundSpeak(line);
 }
 
 static void vpline(const char *, va_list);
@@ -192,8 +192,11 @@ vpline(const char *line, va_list the_args)
     (void) strncpy(gp.prevmsg, line, BUFSZ), gp.prevmsg[BUFSZ - 1] = '\0';
     if (msgtyp == MSGTYP_STOP)
         display_nhwindow(WIN_MESSAGE, TRUE); /* --more-- */
-
  pline_done:
+#ifdef SND_SPEECH
+    /* clear the SPEECH flag so caller never has to */
+    gp.pline_flags &= ~PLINE_SPEECH;
+#endif
     --in_pline;
 }
 
@@ -386,11 +389,13 @@ verbalize(const char *line, ...)
     char *tmp;
 
     va_start(the_args, line);
+    gp.pline_flags |= PLINE_VERBALIZE;
     tmp = You_buf((int) strlen(line) + sizeof "\"\"");
     Strcpy(tmp, "\"");
     Strcat(tmp, line);
     Strcat(tmp, "\"");
     vpline(tmp, the_args);
+    gp.pline_flags &= ~PLINE_VERBALIZE;
     va_end(the_args);
 }
 
index 83acf51dbc8c47870b7e16a7b9b0494f68255d5b..54968fb6a329153b96542ebd7bb0b58fb5f2b521 100644 (file)
@@ -2720,6 +2720,7 @@ djinni_from_bottle(struct obj *obj)
         chance = (chance == 0) ? rn2(4) : 4;
     /* 0,1,2,3,4:  b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */
 
+    SetVoice(mtmp, 0, 80, 0);
     switch (chance) {
     case 0:
         verbalize("I am in your debt.  I will grant one wish!");
index b7b4e609d425e0fc2e7bafa5982f70350024ef9b..2f9be4e6cdc65841d5ffa8e0615cf393530a931c 100644 (file)
@@ -660,10 +660,12 @@ god_zaps_you(aligntyp resp_god)
         }
         if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) {
             /* one more try for high altars */
+            SetVoice((struct monst *) 0, 0, 80, voice_deity);
             verbalize("Thou cannot escape my wrath, mortal!");
             summon_minion(resp_god, FALSE);
             summon_minion(resp_god, FALSE);
             summon_minion(resp_god, FALSE);
+            SetVoice((struct monst *) 0, 0, 80, voice_deity);
             verbalize("Destroy %s, my servants!", uhim());
         }
     }
@@ -715,6 +717,7 @@ angrygods(aligntyp resp_god)
                   ? "hast strayed from the path"
                   : "art arrogant",
               gy.youmonst.data->mlet == S_HUMAN ? "mortal" : "creature");
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou must relearn thy lessons!");
         (void) adjattrib(A_WIS, -1, FALSE);
         losexp((char *) 0);
@@ -735,6 +738,7 @@ angrygods(aligntyp resp_god)
     case 7:
     case 8:
         godvoice(resp_god, (char *) 0);
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou durst %s me?",
                   (on_altar() && (a_align(u.ux, u.uy) != resp_god))
                       ? "scorn"
@@ -811,6 +815,7 @@ gcrownu(void)
     switch (u.ualign.type) {
     case A_LAWFUL:
         u.uevent.uhand_of_elbereth = 1;
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("I crown thee...  The Hand of Elbereth!");
         livelog_printf(LL_DIVINEGIFT,
                        "was crowned \"The Hand of Elbereth\" by %s",
@@ -821,6 +826,7 @@ gcrownu(void)
         in_hand = u_wield_art(ART_VORPAL_BLADE);
         already_exists = exist_artifact(LONG_SWORD,
                                         artiname(ART_VORPAL_BLADE));
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou shalt be my Envoy of Balance!");
         livelog_printf(LL_DIVINEGIFT, "became %s Envoy of Balance",
                        s_suffix(u_gname()));
@@ -832,6 +838,7 @@ gcrownu(void)
         what = (((already_exists && !in_hand) || class_gift != STRANGE_OBJECT)
                 ? "take lives"
                 : "steal souls");
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou art chosen to %s for My Glory!", what);
         livelog_printf(LL_DIVINEGIFT, "was chosen to %s for the Glory of %s",
                        what, u_gname());
@@ -1187,9 +1194,11 @@ pleased(aligntyp g_align)
             if (!u.uevent.uopened_dbridge && !u.uevent.gehennom_entered) {
                 if (u.uevent.uheard_tune < 1) {
                     godvoice(g_align, (char *) 0);
+                    SetVoice((struct monst *) 0, 0, 80, voice_deity);
                     verbalize("Hark, %s!", (gy.youmonst.data->mlet == S_HUMAN)
                                                ? "mortal"
                                                : "creature");
+                    SetVoice((struct monst *) 0, 0, 80, voice_deity);
                     verbalize(
                        "To enter the castle, thou must play the right tune!");
                     u.uevent.uheard_tune++;
@@ -1293,6 +1302,7 @@ pleased(aligntyp g_align)
                     u.ublessed++;
                 pline(msg, "my protection");
             }
+            SetVoice((struct monst *) 0, 0, 80, voice_deity);
             verbalize("Use it wisely in my name!");
             break;
         }
@@ -1525,6 +1535,7 @@ offer_real_amulet(struct obj *otmp, aligntyp altaralign)
         pline("An invisible choir sings, and you are bathed in radiance...");
         godvoice(altaralign, "Mortal, thou hast done well!");
         display_nhwindow(WIN_MESSAGE, FALSE);
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize(
           "In return for thy service, I grant thee the gift of Immortality!");
         You("ascend to the status of Demigod%s...",
@@ -2472,6 +2483,7 @@ altar_wrath(coordxy x, coordxy y)
                     : "Despite your deafness, you seem to hear",
               align_gname(altaralign),
               !Deaf ? "?) whispers" : " say");
+        SetVoice((struct monst *) 0, 0, 80, voice_deity);
         verbalize("Thou shalt pay, infidel!");
         /* higher luck is more likely to be reduced; as it approaches -5
            the chance to lose another point drops down, eventually to 0 */
index b1075961ef2c13c8b1e489598a39893ecc22a32f..12471408cf6943df831219747e9ad2c2d7da35c6 100644 (file)
@@ -464,6 +464,7 @@ intemple(int roomno)
             msg1 = buf;
         }
         if (msg1 && can_speak && !Deaf) {
+            SetVoice(priest, 0, 80, 0);
             verbalize1(msg1);
             if (msg2)
                 verbalize1(msg2);
@@ -586,6 +587,7 @@ priest_talk(struct monst *priest)
             priest->mcanmove = 1;
         }
         priest->mpeaceful = 0;
+        SetVoice(priest, 0, 80, 0);
         verbalize1(cranky_msg[rn2(3)]);
         return;
     }
@@ -593,6 +595,7 @@ priest_talk(struct monst *priest)
     /* you desecrated the temple and now you want to chat? */
     if (priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE)
         && !has_shrine(priest)) {
+        SetVoice(priest, 0, 80, 0);
         verbalize(
               "Begone!  Thou desecratest this holy place with thy presence.");
         priest->mpeaceful = 0;
@@ -621,18 +624,22 @@ priest_talk(struct monst *priest)
         pline("%s asks you for a contribution for the temple.",
               Monnam(priest));
         if ((offer = bribe(priest)) == 0) {
+            SetVoice(priest, 0, 80, 0);
             verbalize("Thou shalt regret thine action!");
             if (coaligned)
                 adjalign(-1);
         } else if (offer < (u.ulevel * 200)) {
             if (money_cnt(gi.invent) > (offer * 2L)) {
+                SetVoice(priest, 0, 80, 0);
                 verbalize("Cheapskate.");
             } else {
+                SetVoice(priest, 0, 80, 0);
                 verbalize("I thank thee for thy contribution.");
                 /* give player some token */
                 exercise(A_WIS, TRUE);
             }
         } else if (offer < (u.ulevel * 400)) {
+            SetVoice(priest, 0, 80, 0);
             verbalize("Thou art indeed a pious individual.");
             if (money_cnt(gi.invent) < (offer * 2L)) {
                 if (coaligned && u.ualign.record <= ALGN_SINNED)
@@ -648,6 +655,7 @@ priest_talk(struct monst *priest)
                    && (!(HProtection & INTRINSIC)
                        || (u.ublessed < 20
                            && (u.ublessed < 9 || !rn2(u.ublessed))))) {
+            SetVoice(priest, 0, 80, 0);
             verbalize("Thou hast been rewarded for thy devotion.");
             if (!(HProtection & INTRINSIC)) {
                 HProtection |= FROMOUTSIDE;
@@ -656,6 +664,7 @@ priest_talk(struct monst *priest)
             } else
                 u.ublessed++;
         } else {
+            SetVoice(priest, 0, 80, 0);
             verbalize("Thy selfless generosity is deeply appreciated.");
             if (money_cnt(gi.invent) < (offer * 2L) && coaligned) {
                 if (strayed && (gm.moves - u.ucleansed) > 5000L) {
index c9fcbfc53f47ec0277736c1453c0ed232845ab33..c1029c26321f9ef9c0dfbda0bc129b70a6f8e1c5 100644 (file)
@@ -396,6 +396,7 @@ prisoner_speaks(struct monst *mtmp)
         /* Awaken the prisoner */
         if (canseemon(mtmp))
             pline("%s speaks:", Monnam(mtmp));
+        SetVoice(mtmp, 0, 80, 0);
         verbalize("I'm finally free!");
         mtmp->mstrategy &= ~STRAT_WAITMASK;
         mtmp->mpeaceful = 1;
index 7c0a834184056a6d0eaf76e1dd1e14798858276b..76790e192548823879d26496c9038e5bbe4be437 100644 (file)
@@ -2733,6 +2733,7 @@ do_genocide(
                      */
                     if (Verbose(3, do_genocide))
                         pline("A thunderous voice booms through the caverns:");
+                    SetVoice((struct monst *) 0, 0, 80, voice_deity);
                     verbalize("No, mortal!  That will not be done.");
                 }
                 continue;
index 8b41a3febc526c35c44281e393b13c212313dcf8..ccecad59452835d213d97eb6f33daab50d9eebe1 100644 (file)
@@ -546,6 +546,7 @@ outrumor(
               (!rn2(4) ? "offhandedly "
                        : (!rn2(3) ? "casually "
                                   : (rn2(2) ? "nonchalantly " : ""))));
+        SetVoice((struct monst *) 0, 0, 80, voice_oracle);
         verbalize1(line);
         /* [WIS exercized by getrumor()] */
         return;
index 75dbbd06b63cd52a7a9a2eba76e17707b1e59579..6512df64978080eb728d0e12f6bb2f629dc75c60 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -483,15 +483,17 @@ u_left_shop(char *leavestring, boolean newlev)
          * Try to intimidate him into paying his bill
          */
         boolean not_upset = !eshkp->surcharge;
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize(not_upset ? "%s!  Please pay before leaving."
                                 : "%s!  Don't you leave without paying!",
                       gp.plname);
-        else
+        } else {
             pline("%s %s that you need to pay before leaving%s",
                   Shknam(shkp),
                   not_upset ? "points out" : "makes it clear",
                   not_upset ? "." : "!");
+        }
         return;
     }
 
@@ -673,31 +675,37 @@ u_entered_shop(char* enterstring)
 
     if (Invis) {
         pline("%s senses your presence.", Shknam(shkp));
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("Invisible customers are not welcome!");
-        else
+        } else {
             pline("%s stands firm as if %s knows you are there.",
                   Shknam(shkp), noit_mhe(shkp));
+        }
         return;
     }
 
     rt = gr.rooms[*enterstring - ROOMOFFSET].rtype;
 
     if (ANGRY(shkp)) {
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("So, %s, you dare return to %s %s?!", gp.plname,
                       s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
-        else
+        } else {
             pline("%s seems %s over your return to %s %s!",
                   Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
                   noit_mhis(shkp), shtypes[rt - SHOPBASE].name);
+        }
     } else if (eshkp->surcharge) {
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("Back again, %s?  I've got my %s on you.",
                       gp.plname, mbodypart(shkp, EYE));
-        else
+        } else {
             pline_The("atmosphere at %s %s seems unwelcoming.",
                       s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
+        }
     } else if (eshkp->robbed) {
         if (!Deaf) {
             Soundeffect(se_mutter_imprecations, 50);
@@ -708,15 +716,17 @@ u_entered_shop(char* enterstring)
                   Shknam(shkp), noit_mhis(shkp));
         }
     } else {
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            set_voice(shkp, 0, 80, 0);
             verbalize("%s, %s!  Welcome%s to %s %s!", Hello(shkp), gp.plname,
                       eshkp->visitct++ ? " again" : "",
                       s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
-        else
+        } else {
             You("enter %s %s%s!",
                 s_suffix(shkname(shkp)),
                 shtypes[rt - SHOPBASE].name,
                 eshkp->visitct++ ? " again" : "");
+        }
     }
     /* can't do anything about blocking if teleported in */
     if (!inside_shop(u.ux, u.uy)) {
@@ -746,27 +756,31 @@ u_entered_shop(char* enterstring)
                 if (!Blind)
                     makeknown(DWARVISH_MATTOCK);
             }
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize(not_upset
                               ? "Will you please leave your %s%s outside?"
                               : "Leave the %s%s outside.",
                           tool, plur(cnt));
-            else
+            } else {
                 pline("%s %s to let you in with your %s%s.",
                       Shknam(shkp),
                       not_upset ? "is hesitant" : "refuses",
                       tool, plur(cnt));
+            }
             should_block = TRUE;
         } else if (u.usteed) {
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize(not_upset ? "Will you please leave %s outside?"
                                     : "Leave %s outside.",
                           y_monnam(u.usteed));
-            else
+            } else {
                 pline("%s %s to let you in while you're riding %s.",
                       Shknam(shkp),
                       not_upset ? "doesn't want" : "refuses",
                       y_monnam(u.usteed));
+            }
             should_block = TRUE;
         } else {
             should_block =
@@ -794,14 +808,16 @@ pick_pick(struct obj* obj)
         /* if you bring a sack of N picks into a shop to sell,
            don't repeat this N times when they're taken out */
         if (gm.moves != pickmovetime) {
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("You sneaky %s!  Get out of here with that pick!",
                       cad(FALSE));
-            else
+            } else {
                 pline("%s %s your pick!",
                       Shknam(shkp),
                       haseyes(shkp->data) ? "glares at"
                                           : "is dismayed because of");
+            }
         }
         pickmovetime = gm.moves;
     }
@@ -1688,16 +1704,18 @@ dopay(void)
             update_inventory(); /* Done in dopayobj() if itemize. */
     }
     if (!ANGRY(shkp) && paid) {
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("Thank you for shopping in %s %s%s",
                       s_suffix(shkname(shkp)),
                       shtypes[eshkp->shoptype - SHOPBASE].name,
                       !eshkp->surcharge ? "!" : ".");
-        else
+        } else {
             pline("%s nods%s at you for shopping in %s %s%s",
                   Shknam(shkp), !eshkp->surcharge ? " appreciatively" : "",
                   noit_mhis(shkp), shtypes[eshkp->shoptype - SHOPBASE].name,
                   !eshkp->surcharge ? "!" : ".");
+        }
     }
     return ECMD_TIME;
 }
@@ -1763,6 +1781,7 @@ dopayobj(
         } else if (quan < bp->bquan && !consumed) { /* partly used goods */
             obj->quan = bp->bquan - save_quan;      /* used up amount */
             if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("%s for the other %s before buying %s.",
                       ANGRY(shkp) ? "Pay" : "Please pay",
                       simpleonames(obj), /* short name suffices */
@@ -2449,22 +2468,27 @@ special_stock(
                           Shknam(shkp),
                           (obj->spe < 7) ? "horrified" : "concerned");
                 } else {
+                    SetVoice(shkp, 0, 80, 0);
                     verbalize("No thanks, I'd hang onto that if I were you.");
-                    if (obj->spe < 7)
+                    if (obj->spe < 7) {
+                        SetVoice(shkp, 0, 80, 0);
                         verbalize(
                              "You'll need %d%s candle%s to go along with it.",
                                 (7 - obj->spe), (obj->spe > 0) ? " more" : "",
                                   plur(7 - obj->spe));
+                    }
                     /* [what if hero is already carrying enough candles?
                        should Izchak explain how to attach them instead?] */
                 }
             } else {
-                if (!Deaf && !muteshk(shkp))
+                if (!Deaf && !muteshk(shkp)) {
+                    SetVoice(shkp, 0, 80, 0);
                     verbalize("I won't stock that.  Take it out of here!");
-                else
+                } else {
                     pline("%s shakes %s %s in refusal.",
                           Shknam(shkp), noit_mhis(shkp),
                           mbodypart(shkp, HEAD));
+                }
             }
         }
         return TRUE;
@@ -2885,6 +2909,7 @@ addtobill(
                 Strcat(buf, "; only");
             }
             obj->quan = 1L; /* fool xname() into giving singular */
+            set_voice(shkp, 0, 80, 0);
             pline("%s %ld %s %s %s%s.\"", buf, ltmp, currency(ltmp),
                   (save_quan > 1L) ? "per"
                                    : (contentscount && !obj->unpaid)
@@ -2895,14 +2920,16 @@ addtobill(
             obj->quan = save_quan;
         }
     } else if (!silent) {
-        if (ltmp)
+        if (ltmp) {
+            set_voice(shkp, 0, 80, 0);
             pline_The("list price of %s%s%s is %ld %s%s.",
                       (contentscount && !obj->unpaid) ? the_contents_of : "",
                       the(xname(obj)),
                       (contentscount && obj->unpaid) ? and_its_contents : "",
                       ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : "");
-        else
+        } else {
             pline("%s does not notice.", Shknam(shkp));
+        }
     }
 }
 
@@ -3299,10 +3326,12 @@ sellobj(
     eshkp = ESHK(shkp);
 
     if (ANGRY(shkp)) { /* they become shop-objects, no pay */
-        if (!Deaf && !muteshk(shkp))
+        if (!Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("Thank you, scum!");
-        else
+        } else {
             pline("%s smirks with satisfaction.", Shknam(shkp));
+        }
         subfrombill(obj, shkp);
         return;
     }
@@ -3314,9 +3343,11 @@ sellobj(
             offer += cgold;
         if ((eshkp->robbed -= offer < 0L))
             eshkp->robbed = 0L;
-        if (offer && !Deaf && !muteshk(shkp))
+        if (offer && !Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize(
   "Thank you for your contribution to restock this recently plundered shop.");
+        }
         subfrombill(obj, shkp);
         return;
     }
@@ -3633,8 +3664,10 @@ shkcatch(
         /* if it is the shk's pos, you hit and anger him */
         && (shkp->mx != x || shkp->my != y)) {
         if (mnearto(shkp, x, y, TRUE, RLOC_NOMSG) == 2
-            && !Deaf && !muteshk(shkp))
+            && !Deaf && !muteshk(shkp)) {
+            SetVoice(shkp, 0, 80, 0);
             verbalize("Out of my way, scum!");
+        }
         if (cansee(x, y)) {
             pline("%s nimbly%s catches %s.", Shknam(shkp),
                   (x == shkp->mx && y == shkp->my) ? "" : " reaches over and",
@@ -3901,8 +3934,10 @@ litter_scatter(
              * a slang connotation which could be applicable if hero
              * has Passes_walls ability.
              */
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("Get your junk out of my wall!");
+            }
             unplacebc(); /* pick 'em up */
             placebc();   /* put 'em down */
         }
@@ -4155,20 +4190,24 @@ shk_move(struct monst *shkp)
         }
         if (eshkp->following) {
             if (strncmp(eshkp->customer, gp.plname, PL_NSIZ)) {
-                if (!Deaf && !muteshk(shkp))
+                if (!Deaf && !muteshk(shkp)) {
+                    SetVoice(shkp, 0, 80, 0);
                     verbalize("%s, %s!  I was looking for %s.", Hello(shkp),
                               gp.plname, eshkp->customer);
+                }
                 eshkp->following = 0;
                 return 0;
             }
             if (gm.moves > gf.followmsg + 4) {
-                if (!Deaf && !muteshk(shkp))
+                if (!Deaf && !muteshk(shkp)) {
+                    SetVoice(shkp, 0, 80, 0);
                     verbalize("%s, %s!  Didn't you forget to pay?",
                               Hello(shkp), gp.plname);
-                else
+                } else {
                     pline("%s holds out %s upturned %s.",
                           Shknam(shkp), noit_mhis(shkp),
                           mbodypart(shkp, HAND));
+                }
                 gf.followmsg = gm.moves;
                 if (!rn2(9)) {
                     pline("%s doesn't like customers who don't pay.",
@@ -4289,13 +4328,15 @@ shopdig(register int fall)
     if (!fall) {
         if (lang == 2) {
             if (!Deaf && !muteshk(shkp)) {
-                if (u.utraptype == TT_PIT)
+                SetVoice(shkp, 0, 80, 0);
+                if (u.utraptype == TT_PIT) {
                     verbalize(
                        "Be careful, %s, or you might fall through the floor.",
                               flags.female ? "madam" : "sir");
-                else
+                } else {
                     verbalize("%s, do not damage the floor here!",
                               flags.female ? "Madam" : "Sir");
+                }
             }
         }
         if (Role_if(PM_KNIGHT)) {
@@ -4480,8 +4521,9 @@ pay_for_damage(const char* dmgstr, boolean cant_mollify)
         if (MON_AT(x, y)) {
             if (!animal) {
                 if (!Deaf && !muteshk(shkp)) {
-                    Soundeffect(se_angry_voice, 75);
+                    /* Soundeffect(se_angry_voice, 75); */
                     You_hear("an angry voice:");
+                    SetVoice(shkp, 0, 80, 0);
                     verbalize("Out of my way, scum!");
                 }
                 wait_synch();
@@ -4506,16 +4548,19 @@ pay_for_damage(const char* dmgstr, boolean cant_mollify)
             if (animal && !helpless(shkp))
                 yelp(shkp);
         } else if (pursue || uinshp || !um_dist(x, y, 1)) {
-            if (!Deaf)
+            if (!Deaf) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("How dare you %s my %s?", dmgstr,
                           dugwall ? "shop" : "door");
-            else
+            } else {
                 pline("%s is %s that you decided to %s %s %s!",
                       Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
                       dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door");
+            }
         } else {
             if (!Deaf) {
                 pline("%s shouts:", Shknam(shkp));
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("Who dared %s my %s?", dmgstr,
                           dugwall ? "shop" : "door");
             } else {
@@ -4559,12 +4604,14 @@ pay_for_damage(const char* dmgstr, boolean cant_mollify)
         }
     } else {
         if (!animal) {
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("Oh, yes!  You'll pay!");
-            else
+            } else {
                 pline("%s lunges %s %s toward your %s!",
                       Shknam(shkp), noit_mhis(shkp),
                       mbodypart(shkp, HAND), body_part(NECK));
+            }
         } else
             growl(shkp);
         hot_pursuit(shkp);
@@ -4675,12 +4722,14 @@ price_quote(struct obj *first_obj)
     } else if (cnt == 1) {
         if (!cost) {
             /* "<doname(obj)>, no charge" */
+            SetVoice(shkp, 0, 80, 0);
             verbalize("%s!", upstart(buf)); /* buf contains the string */
         } else {
             /* print cost in slightly different format, so can't reuse buf;
                cost and contentsonly are already set up */
             Sprintf(buf, "%s%s", contentsonly ? the_contents_of : "",
                     doname(first_obj));
+            SetVoice(shkp, 0, 80, 0);
             verbalize("%s, price %ld %s%s%s", upstart(buf), cost,
                       currency(cost), (first_obj->quan > 1L) ? " each" : "",
                       contentsonly ? "." : shk_embellish(first_obj, cost));
@@ -4769,17 +4818,21 @@ shk_chat(struct monst* shkp)
               noit_mhe(shkp), eshk->robbed ? "non-paying" : "rude");
     } else if (eshk->following) {
         if (strncmp(eshk->customer, gp.plname, PL_NSIZ)) {
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("%s %s!  I was looking for %s.",
                       Hello(shkp), gp.plname, eshk->customer);
+            }
             eshk->following = 0;
         } else {
-            if (!Deaf && !muteshk(shkp))
+            if (!Deaf && !muteshk(shkp)) {
+                SetVoice(shkp, 0, 80, 0);
                 verbalize("%s %s!  Didn't you forget to pay?",
                           Hello(shkp), gp.plname);
-            else
+            } else {
                 pline("%s taps you on the %s.",
                       Shknam(shkp), body_part(ARM));
+            }
         }
     } else if (eshk->billct) {
         register long total = addupbill(shkp) + eshk->debit;
@@ -4946,6 +4999,7 @@ check_unpaid_usage(struct obj* otmp, boolean altusage)
     }
 
     if (!Deaf && !muteshk(shkp)) {
+        SetVoice(shkp, 0, 80, 0);
         verbalize(fmt, arg1, arg2, tmp, currency(tmp));
         exercise(A_WIS, TRUE); /* you just got info */
     }
@@ -5311,6 +5365,7 @@ globby_bill_fixup(struct obj* obj_absorber, struct obj* obj_absorbed)
                || (floor_absorber && !costly_spot(x, y)))) {
         amount = bp->price;
         bill_dummy_object(obj_absorbed);
+        SetVoice(shkp, 0, 80, 0);
         verbalize("You owe me %ld %s for my %s that you %s with your%s",
                   amount, currency(amount), obj_typename(obj_absorbed->otyp),
                   ANGRY(shkp) ? "had the audacity to mix" : "just mixed",
index 876f03444ce60a95fbe1c9bb47030ee14c563c32..cfc6afd705ba2149568bd61e0263a18404b5147b 100644 (file)
--- a/src/sit.c
+++ b/src/sit.c
@@ -87,6 +87,7 @@ throne_sit_effect(void)
 
                 /* Magical voice not affected by deafness */
                 pline("A voice echoes:");
+                SetVoice((struct monst *) 0, 0, 80, voice_throne);
                 verbalize("Thine audience hath been summoned, %s!",
                           flags.female ? "Dame" : "Sire");
                 while (cnt--)
@@ -96,6 +97,7 @@ throne_sit_effect(void)
         case 8:
             /* Magical voice not affected by deafness */
             pline("A voice echoes:");
+            SetVoice((struct monst *) 0, 0, 80, voice_throne);
             verbalize("By thine Imperious order, %s...",
                       flags.female ? "Dame" : "Sire");
             do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */
@@ -103,6 +105,7 @@ throne_sit_effect(void)
         case 9:
             /* Magical voice not affected by deafness */
             pline("A voice echoes:");
+            SetVoice((struct monst *) 0, 0, 80, voice_throne);
             verbalize(
                       "A curse upon thee for sitting upon this most holy throne!");
             if (Luck > 0) {
index 269d37ed4f416eb550894a7cf87874af37a96c71..c4eeca1692d999f12f1d7e8f6becde1e724fa27f 100644 (file)
@@ -116,12 +116,12 @@ zoo_mon_sound(struct monst *mtmp)
 {
     if ((mtmp->msleeping || is_animal(mtmp->data))
         && mon_in_room(mtmp, ZOO)) {
-        int hallu = Hallucination ? 1 : 0;
+        int hallu = Hallucination ? 1 : 0, selection = rn2(2) + hallu;
         static const char *const zoo_msg[3] = {
             "a sound reminiscent of an elephant stepping on a peanut.",
             "a sound reminiscent of a seal barking.", "Doctor Dolittle!",
         };
-        You_hear1(zoo_msg[rn2(2) + hallu]);
+        You_hear1(zoo_msg[selection]);
         return TRUE;
     }
     return FALSE;
@@ -523,6 +523,7 @@ beg(register struct monst* mtmp)
     } else if (mtmp->data->msound >= MS_HUMANOID) {
         if (!canspotmon(mtmp))
             map_invisible(mtmp->mx, mtmp->my);
+        SetVoice(mtmp, 0, 80, 0);
         verbalize("I'm hungry.");
     } else {
         /* this is pretty lame but is better than leaving out the block
@@ -1058,9 +1059,10 @@ domonnoise(register struct monst* mtmp)
         }
     } break;
     case MS_ARREST:
-        if (mtmp->mpeaceful)
+        if (mtmp->mpeaceful) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("Just the facts, %s.", flags.female ? "Ma'am" : "Sir");
-        else {
+        else {
             static const char *const arrest_msg[3] = {
                 "Anything you say can be used against you.",
                 "You're under arrest!", "Stop in the name of the Law!",
@@ -1151,6 +1153,7 @@ domonnoise(register struct monst* mtmp)
     if (pline_msg) {
         pline("%s %s", Monnam(mtmp), pline_msg);
     } else if (mtmp->mcan && verbl_msg_mcan) {
+        SetVoice(mtmp, 0, 80, 0);
         verbalize1(verbl_msg_mcan);
     } else if (verbl_msg) {
         /* more 3.6 tribute */
@@ -1158,9 +1161,11 @@ domonnoise(register struct monst* mtmp)
             /* Death talks in CAPITAL LETTERS
                and without quotation marks */
             char tmpbuf[BUFSZ];
-
             pline1(ucase(strcpy(tmpbuf, verbl_msg)));
+            SetVoice((struct monst *) 0, 0, 80, voice_death); 
+            sound_speak(tmpbuf);
         } else {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize1(verbl_msg);
         }
     }
@@ -1652,6 +1657,7 @@ struct sound_procs nosound_procs = {
     (void (*)(int32_t, const char *, int32_t)) 0, /* hero_playnotes */
     (void (*)(char *, int32_t, int32_t)) 0,       /* play_usersound */
     (void (*)(int32_t, int32_t, int32_t)) 0,      /* ambience       */
+    (void (*)(char *, int32_t, int32_t, int32_t, int32_t)) 0, /* verbal */
 };
 
 /* The order of these array entries must match the
@@ -1813,8 +1819,8 @@ static void nosound_achievement(schar, schar, int32_t);
 static void nosound_soundeffect(int32_t, int32_t);
 static void nosound_play_usersound(char *, int32_t, int32_t);
 static void nosound_ambience(int32_t, int32_t, int32_t);
-{
-}
+static void nosound_verbal(char *text, int32_t gender, int32_t tone,
+                           int32_t vol, int32_t moreinfo);
 
 static void
 nosound_init_nhsound(void)
@@ -1851,6 +1857,12 @@ nosound_ambience(int32_t ambienceid, int32_t ambience_action,
                 int32_t hero_proximity)
 {
 }
+
+static void
+nosound_verbal(char *text, int32_t gender, int32_t tone,
+               int32_t vol, int32_t moreinfo)
+{
+}
 #endif
 
 #ifdef SND_SOUNDEFFECTS_AUTOMAP
@@ -2236,4 +2248,68 @@ base_soundname_to_filename(
     return buf;
 }
 
+#ifdef SND_SPEECH
+#define SPEECHONLY
+#else
+#define SPEECHONLY UNUSED
+#endif
+
+void
+set_voice(struct monst *mtmp SPEECHONLY, int32_t tone SPEECHONLY, int32_t volume SPEECHONLY, int32_t moreinfo SPEECHONLY)
+{
+#ifdef SND_SPEECH
+    int32_t gender = (mtmp && mtmp->female) ? FEMALE : MALE;
+
+    if (gv.voice.nameid)
+        free((genericptr_t) gv.voice.nameid);
+    gv.voice.gender = gender;
+    gv.voice.serialno = mtmp ? mtmp->m_id 
+                             : ((moreinfo & voice_talking_artifact) != 0)  ? 3
+                                 : ((moreinfo & voice_deity) != 0) ? 4 : 2;
+    gv.voice.tone = tone;
+    gv.voice.volume = volume;
+    gv.voice.moreinfo = moreinfo;
+    gv.voice.nameid = (const char *) 0;
+    gp.pline_flags |= PLINE_SPEECH; 
+#endif
+}
+
+void
+sound_speak(const char *text SPEECHONLY)
+{
+#ifdef SND_SPEECH
+    const char *cp1, *cp2;
+    char *cpdst;
+    char buf[BUFSZ + BUFSZ];
+
+    if (!text || (text && *text == '\0'))
+        return;
+    if (iflags.voices && soundprocs.sound_verbal
+        && (soundprocs.sound_triggers & SOUND_TRIGGER_VERBAL)) {
+        cp1 = text;
+        cpdst = buf;
+        cp2 = c_eos(cp1);
+        cp2--;  /* last non-NUL */
+        *cpdst = '\0';
+        if ((gp.pline_flags & PLINE_VERBALIZE) != 0) {
+            if (*cp1 == '"')
+                cp1++;
+            if (*cp2 == '"')
+                cp2--;
+        }
+        /* cp1 -> 1st, cp2 -> last non-nul) */
+        if ((unsigned)(cp2 - cp1) < (sizeof buf - 1U)) {
+            while (cp1 <= cp2) {
+                *cpdst = *cp1;
+                cp1++;
+                cpdst++;
+            }
+            *cpdst = '\0';
+        }
+        (*soundprocs.sound_verbal)(buf, gv.voice.gender, gv.voice.tone,
+                                   gv.voice.volume, gv.voice.moreinfo); 
+    }
+#endif
+}
+
 /*sounds.c*/
index 28db803d935c1ddaa2bdc75b222b24f8c9d12b14..70d4b50f350e052fa0ae63898135ea25f97a1557 100644 (file)
@@ -1016,6 +1016,7 @@ level_tele(void)
         }
         if (newlev <= -10) {
             You("arrive in heaven.");
+            SetVoice((struct monst *) 0, 0, 80, voice_deity);
             verbalize("Thou art early, but we'll admit thee.");
             gk.killer.format = NO_KILLER_PREFIX;
             Strcpy(gk.killer.name, "went to heaven prematurely");
index 53d28a41099c46ba14ce68bc43b658e63e31c86d..80fdd6d07f738154f0a7baba71b3b805d22e90cc 100644 (file)
@@ -1016,6 +1016,7 @@ hatch_egg(anything *arg, long timeout)
                       siblings ? "Their" : "Its",
                       flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
             } else if (mon->data->mlet == S_DRAGON && !Deaf) {
+                SetVoice(mon, 0, 80, 0);
                 verbalize("Gleep!"); /* Mything eggs :-) */
             }
             break;
index d3c9ae26c56ed8ed396a02deb65fab8bd17639ed..9b802d7270aeab731a3dcfd0e59e8eb698be40ce 100644 (file)
@@ -3937,8 +3937,10 @@ mhitm_ad_heal(struct monst *magr, struct attack *mattk, struct monst *mdef,
             mhm->damage = 0;
         } else {
             if (Role_if(PM_HEALER)) {
-                if (!Deaf && !(gm.moves % 5))
+                if (!Deaf && !(gm.moves % 5)) {
+                    SetVoice(magr, 0, 80, 0);
                     verbalize("Doc, I can't help you unless you cooperate.");
+                }
                 mhm->damage = 0;
             } else
                 hitmsg(magr, mattk);
@@ -4090,8 +4092,11 @@ mhitm_ad_dgst(struct monst *magr, struct attack *mattk UNUSED,
             mhm->done = TRUE;
             return;
         }
-        if (Verbose(4, mhitm_ad_dgst) && !Deaf)
+        if (Verbose(4, mhitm_ad_dgst) && !Deaf) {
+            /* Soundeffect? */
+            SetVoice(magr, 0, 80, 0);
             verbalize("Burrrrp!");
+        }
         mhm->damage = mdef->mhp;
         /* Use up amulet of life saving */
         if ((obj = mlifesaver(mdef)) != 0)
index 8f18519dabe8e19fef5402eb1d33e3d8ba7e06f7..90a930756ce4d8048cc77b03204f4747b9d1a04f 100644 (file)
@@ -442,8 +442,10 @@ invault(void)
 
         if (u.uswallow) {
             /* can't interrogate hero, don't interrogate engulfer */
-            if (!Deaf)
+            if (!Deaf) {
+                SetVoice(guard, 0, 80, 0);
                 verbalize("What's going on here?");
+            }
             if (!spotted)
                 pline_The("other presence vanishes.");
             mongone(guard);
@@ -452,9 +454,11 @@ invault(void)
         if (U_AP_TYPE == M_AP_OBJECT || u.uundetected) {
             if (U_AP_TYPE == M_AP_OBJECT
                 && gy.youmonst.mappearance != GOLD_PIECE)
-                if (!Deaf)
+                if (!Deaf) {
+                    SetVoice(guard, 0, 80, 0);
                     verbalize("Hey!  Who left that %s in here?",
                               mimic_obj_name(&gy.youmonst));
+                }
             /* You're mimicking some object or you're hidden. */
             pline("Puzzled, %s turns around and leaves.", mhe(guard));
             mongone(guard);
@@ -464,10 +468,12 @@ invault(void)
             /* [we ought to record whether this this message has already
                been given in order to vary it upon repeat visits, but
                discarding the monster and its egd data renders that hard] */
-            if (Deaf)
+            if (Deaf) {
                 pline("%s huffs and turns to leave.", noit_Monnam(guard));
-            else
+            } else {
+                SetVoice(guard, 0, 80, 0);
                 verbalize("I'll be back when you're ready to speak to me!");
+            }
             mongone(guard);
             return;
         }
@@ -498,6 +504,7 @@ invault(void)
                     if (!Blind)
                         pline("%s waves goodbye.", noit_Monnam(guard));
                 } else {
+                    SetVoice(guard, 0, 80, 0);
                     verbalize(
                          "Oh, yes, of course.  Sorry to have disturbed you.");
                 }
@@ -509,6 +516,7 @@ invault(void)
                         pline("%s mouths something and looks very angry!",
                               noit_Monnam(guard));
                 } else {
+                   SetVoice(guard, 0, 80, 0);
                    verbalize(
                            "Back from the dead, are you?  I'll remedy that!");
                 }
@@ -520,18 +528,22 @@ invault(void)
             }
             return;
         }
-        if (Deaf)
+        if (Deaf) {
             pline("%s doesn't %srecognize you.", noit_Monnam(guard),
                     (Blind) ? "" : "appear to ");
-        else
+        } else {
+            SetVoice(guard, 0, 80, 0);
             verbalize("I don't know you.");
+        }
         umoney = money_cnt(gi.invent);
         if (!umoney && !hidden_gold(TRUE)) {
-            if (Deaf)
+            if (Deaf) {
                 pline("%s stomps%s.", noit_Monnam(guard),
                       (Blind) ? "" : " and beckons");
-            else
+            } else {
+                SetVoice(guard, 0, 80, 0);
                 verbalize("Please follow me.");
+            }
         } else {
             if (!umoney) {
                 if (Deaf) {
@@ -539,6 +551,7 @@ invault(void)
                         pline("%s glares at you%s.", noit_Monnam(guard),
                               gi.invent ? "r stuff" : "");
                 } else {
+                   SetVoice(guard, 0, 80, 0);
                    verbalize("You have hidden gold.");
                 }
             }
@@ -549,8 +562,10 @@ invault(void)
                           noit_Monnam(guard), noit_mhis(guard),
                           noit_mhis(guard));
             } else {
+                SetVoice(guard, 0, 80, 0);
                 verbalize(
                     "Most likely all your gold was stolen from this vault.");
+                SetVoice(guard, 0, 80, 0);
                 verbalize("Please drop that gold and follow me.");
             }
             EGD(guard)->dropgoldcnt++;
@@ -705,8 +720,10 @@ gd_mv_monaway(struct monst *grd, int nx, int ny)
     struct monst *mtmp = m_at(nx, ny);
 
     if (mtmp && mtmp != grd) {
-        if (!Deaf)
+        if (!Deaf) {
+            SetVoice(grd, 0, 80, 0);
             verbalize("Out of my way, scum!");
+        }
         if (!rloc(mtmp, RLOC_ERR | RLOC_MSG) || MON_AT(nx, ny))
             m_into_limbo(mtmp);
     }
@@ -897,9 +914,11 @@ gd_move(struct monst *grd)
         return -1; /* teleported guard - treat as monster */
 
     if (egrd->witness) {
-        if (!Deaf)
+        if (!Deaf) {
+            SetVoice(grd, 0, 80, 0);
             verbalize("How dare you %s that gold, scoundrel!",
                       (egrd->witness & GD_EATGOLD) ? "consume" : "destroy");
+        }
         egrd->witness = 0;
         grd->mpeaceful = 0;
         return -1;
@@ -916,6 +935,7 @@ gd_move(struct monst *grd)
                         u_carry_gold ? (!umoney ? "drop that hidden gold and "
                                                 : "drop that gold and ")
                                      : "");
+                SetVoice(grd, 0, 80, 0);
                 if (egrd->dropgoldcnt || !u_carry_gold)
                     verbalize("I repeat, %s", buf);
                 else
@@ -926,8 +946,10 @@ gd_move(struct monst *grd)
             if (egrd->warncnt == 7) {
                 m = grd->mx;
                 n = grd->my;
-                if (!Deaf)
+                if (!Deaf) {
+                    SetVoice(grd, 0, 80, 0);
                     verbalize("You've been warned, knave!");
+                }
                 grd->mpeaceful = 0;
                 mnexto(grd, RLOC_NOMSG);
                 levl[m][n].typ = egrd->fakecorr[0].ftyp;
@@ -953,8 +975,10 @@ gd_move(struct monst *grd)
                 gd_letknow(grd);
                 return -1;
             } else {
-                if (!Deaf)
+                if (!Deaf) {
+                    SetVoice(grd, 0, 80, 0);
                     verbalize("Well, begone.");
+                }
                 egrd->gddone = 1;
                 return gd_move_cleanup(grd, semi_dead, FALSE);
             }
@@ -983,6 +1007,7 @@ gd_move(struct monst *grd)
                         pline("%s holds out %s palm demandingly!",
                               noit_Monnam(grd), noit_mhis(grd));
                 } else {
+                    SetVoice(grd, 0, 80, 0);
                     verbalize("Drop all your gold, scoundrel!");
                 }
                 return 0;
@@ -992,6 +1017,7 @@ gd_move(struct monst *grd)
                         pline("%s rubs %s hands with enraged delight!",
                               noit_Monnam(grd), noit_mhis(grd));
                 } else {
+                    SetVoice(grd, 0, 80, 0);
                     verbalize("So be it, rogue!");
                 }
                 grd->mpeaceful = 0;
@@ -1017,8 +1043,10 @@ gd_move(struct monst *grd)
     }
     if (um_dist(grd->mx, grd->my, 1) || egrd->gddone) {
         if (!egrd->gddone && !rn2(10) && !Deaf && !u.uswallow
-            && !(u.ustuck && !sticks(gy.youmonst.data)))
+            && !(u.ustuck && !sticks(gy.youmonst.data))) {
+            SetVoice(grd, 0, 80, 0);
             verbalize("Move along!");
+        }
         restfakecorr(grd);
         return 0; /* didn't move */
     }
index fd3af1d733b33d105353d65a2bb46377ec3b9871..44619396c4262df61150cc044110664ee1f5a43f 100644 (file)
@@ -738,6 +738,7 @@ resurrect(void)
         set_malign(mtmp);
         if (!Deaf) {
             pline("A voice booms out...");
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("So thou thought thou couldst %s me, fool.", verb);
         }
     }
@@ -810,21 +811,26 @@ cuss(struct monst *mtmp)
     if (Deaf)
         return;
     if (mtmp->iswiz) {
-        if (!rn2(5)) /* typical bad guy action */
+        if (!rn2(5)) /* typical bad guy action */
             pline("%s laughs fiendishly.", Monnam(mtmp));
-        else if (u.uhave.amulet && !rn2(SIZE(random_insult)))
+        } else if (u.uhave.amulet && !rn2(SIZE(random_insult))) {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("Relinquish the amulet, %s!",
                       random_insult[rn2(SIZE(random_insult))]);
-        else if (u.uhp < 5 && !rn2(2)) /* Panic */
+        } else if (u.uhp < 5 && !rn2(2)) { /* Panic */
+            SetVoice(mtmp, 0, 80, 0);
             verbalize(rn2(2) ? "Even now thy life force ebbs, %s!"
                              : "Savor thy breath, %s, it be thy last!",
                       random_insult[rn2(SIZE(random_insult))]);
-        else if (mtmp->mhp < 5 && !rn2(2)) /* Parthian shot */
+        } else if (mtmp->mhp < 5 && !rn2(2)) { /* Parthian shot */
+            SetVoice(mtmp, 0, 80, 0);
             verbalize(rn2(2) ? "I shall return." : "I'll be back.");
-        else
+        } else {
+            SetVoice(mtmp, 0, 80, 0);
             verbalize("%s %s!",
                       random_malediction[rn2(SIZE(random_malediction))],
                       random_insult[rn2(SIZE(random_insult))]);
+        }
     } else if (is_lminion(mtmp)
                && !(mtmp->isminion && EMIN(mtmp)->renegade)) {
         com_pager("angel_cuss"); /* TODO: the Hallucination msg */
index 45cf1b1b65dcbcdf23cd9b53bcee751e5cac31ce..909a02fef4f45ee409433979bef8137480ae81e7 100644 (file)
 #LFLAGS += -lm
 #endif   # WANT_TESTSOUND
 
+ifeq "$(HAVE_SNDLIB)" "1"
+ifeq "$(WANT_SPEECH)" "1"
+SNDCFLAGS+= -DSND_SPEECH
+endif   # WANT_SPEECH
+endif   # HAVE_SNDLIB
+
 # HAVE_SNDLIB or NEEDS_SND_USERSOUNDS or NEEDS_SND_SEAUTOMAP 
 # would have to be set prior to this. Any of them could have
 # been set just above, or they could have been set in
index c4b9246a98f52f2fca27112e6c5383499d4e1114..01718b9b23681f64981c2e3b0e40f3aa268d8b44 100755 (executable)
@@ -164,6 +164,9 @@ SNDCFLAGS+= -DSND_LIB_MACSOUND
 SNDLIBSRC = ../sound/macsound/macsound.m
 SNDLIBOBJ = macsound.o
 LFLAGS += -framework AppKit
+#ifdef WANT_SPEECH
+LFLAGS += -framework AVFoundation
+#endif
 endif
 
 #
index 6ee5fbf92f927bd0d2d120831fde29b20a1e4559..1c507efe52b437c4c60a11bebcdd396376a511c2 100644 (file)
@@ -1065,6 +1065,9 @@ void NetHackQtBind::qtsound_hero_playnotes(int32_t instrument UNUSED, const char
 void NetHackQtBind::qtsound_ambience(int32_t ambienceid UNUSED, int32_t ambience_action UNUSED, int32_t proximity UNUSED)
 {
 }
+void NetHackQtBind::qtsound_verbal(char *text UNUSED, int32_t gender UNUSED, int32_t tone UNUSED, int32_t vol UNUSED, int32_t moreinfo UNUSED)
+{
+}
 #endif
 
 #if defined(USER_SOUNDS) && !defined(QT_NO_SOUND)
@@ -1186,6 +1189,7 @@ struct sound_procs qtsound_procs = {
     nethack_qt_::NetHackQtBind::qtsound_hero_playnotes,
     nethack_qt_::NetHackQtBind::qtsound_play_usersound,
     nethack_qt_::NetHackQtBind::qtsound_ambience,
+    nethack_qt_::NetHackQtBind::qtsound_verbal,
 };
 #endif /* SND_LIB_QTSOUND and !QT_NO_SOUND */
 
index 9bdaf9cf3297690ba1a2e18fa6d94b01e33ac3a8..b0b9f4f3a4f338214556595d2b7fdedd9eea686d 100644 (file)
@@ -103,6 +103,7 @@ public:
         static void qtsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume);
         static void qtsound_play_usersound(char *, int32_t, int32_t);
         static void qtsound_ambience(int32_t, int32_t, int32_t);
+        static void qtsound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol, int32_t moreinfo);
 #endif
 
 private: