From: nhmall Date: Tue, 7 Feb 2023 05:44:36 +0000 (-0500) Subject: another update to the soundlib interface X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fbd9a7bae8f9d9eb51d2e83955a5ea7bb9f252c6;p=nethack another update to the soundlib interface sound_verbal(char *text, int32_t gender, int32_t tone, int32_t vol, int32_t moreinfo); -- NetHack will call this function when it wants to pass text of spoken language by a character or creature within the game. -- text is a transcript of what has been spoken. -- gender indicates MALE or FEMALE sounding voice. -- tone indicates the tone of the voice. -- vol is the volume (1% - 100%) for the sound. -- moreinfo is used to provide additional information to the soundlib. -- there may be some accessibility uses for this function. It may be useful for accessibility purposes too. A preliminary implementation has been attempted for macsound to test the interface on macOS. No tinkering of the voices has been done. Use of the test implementation requires the following at build time with make. WANT_SPEECH=1 That needs to be included on the make command line to enable the test code, otherwise just the interface update is compiled in. I don't know for certain when AVSpeechSynthesizer went into macOS, but older versions likely don't support it, and would just leave off the WANT_SPEECH=1. If built with WANT_SPEECH=1, the 'voices' NetHack option needs to be enabled. It was a bit strange, when I first started up the test, to hear Asidonhopo, the shopkeeper, talking to me as I entered his shop and interacted with him. --- diff --git a/doc/sound.txt b/doc/sound.txt index b70755eff..3d88e9cd7 100644 --- a/doc/sound.txt +++ b/doc/sound.txt @@ -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 -- diff --git a/include/decl.h b/include/decl.h index 7a81872dc..4a89d1492 100644 --- a/include/decl.h +++ b/include/decl.h @@ -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 */ }; diff --git a/include/extern.h b/include/extern.h index 05b5eaea3..2ef0ad09b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 ### */ diff --git a/include/flag.h b/include/flag.h index 7edec9119..5a99da206 100644 --- a/include/flag.h +++ b/include/flag.h @@ -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 */ diff --git a/include/hack.h b/include/hack.h index 327849ac5..b53f78b4a 100644 --- a/include/hack.h +++ b/include/hack.h @@ -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 diff --git a/include/optlist.h b/include/optlist.h index b71417d8c..69d6bfe18 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -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) diff --git a/include/sndprocs.h b/include/sndprocs.h index 9460a143a..a095d7f75 100755 --- a/include/sndprocs.h +++ b/include/sndprocs.h @@ -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 diff --git a/sound/macsound/macsound.m b/sound/macsound/macsound.m index 9fd37a22e..37360b7de 100644 --- a/sound/macsound/macsound.m +++ b/sound/macsound/macsound.m @@ -11,6 +11,12 @@ /* #import */ #import +#define SPEECH_SOUNDS +#ifdef SPEECH_SOUNDS +#import +#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) { diff --git a/sound/windsound/windsound.c b/sound/windsound/windsound.c index aec6942a9..01e05b7e0 100644 --- a/sound/windsound/windsound.c +++ b/sound/windsound/windsound.c @@ -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) { } diff --git a/src/apply.c b/src/apply.c index 6c992c7f4..7d8c93b5d 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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.", diff --git a/src/artifact.c b/src/artifact.c index 216c08e93..5f56d9ecf 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -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; } diff --git a/src/cmd.c b/src/cmd.c index d2aab6345..df96c79ff 100644 --- 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); diff --git a/src/decl.c b/src/decl.c index 60efafcbe..3af274ae5 100644 --- a/src/decl.c +++ b/src/decl.c @@ -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 */ }; diff --git a/src/dig.c b/src/dig.c index da86bce26..ef9ca03c9 100644 --- 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); diff --git a/src/do_name.c b/src/do_name.c index ba1b35257..68f66567a 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -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)) diff --git a/src/dokick.c b/src/dokick.c index c310833c5..7869cec66 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -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"); } diff --git a/src/hack.c b/src/hack.c index 47f213fad..ea15c795e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -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 diff --git a/src/hacklib.c b/src/hacklib.c index 2ad8d6c66..d616cd819 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -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){ diff --git a/src/lock.c b/src/lock.c index d17320cd9..77ca57e8c 100644 --- a/src/lock.c +++ b/src/lock.c @@ -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 !" */ diff --git a/src/mail.c b/src/mail.c index a73e0dcd4..09daa427b 100644 --- a/src/mail.c +++ b/src/mail.c @@ -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); diff --git a/src/mcastu.c b/src/mcastu.c index fdb297113..c1390e091 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -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); diff --git a/src/mhitu.c b/src/mhitu.c index a7158cd5d..9d4e9ee6e 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -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" diff --git a/src/minion.c b/src/minion.c index 1f7e67e9c..28ea2f059 100644 --- a/src/minion.c +++ b/src/minion.c @@ -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; diff --git a/src/mkobj.c b/src/mkobj.c index cdfb405a6..62de763dd 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -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); diff --git a/src/mon.c b/src/mon.c index 7871587d8..53bbc7508 100644 --- 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 { diff --git a/src/monmove.c b/src/monmove.c index ee087099a..1eecb905b 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -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; } diff --git a/src/mplayer.c b/src/mplayer.c index 30870c89d..c5b99af40 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -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)]); diff --git a/src/muse.c b/src/muse.c index 5507fcc68..eb95611c6 100644 --- a/src/muse.c +++ b/src/muse.c @@ -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!"); diff --git a/src/pickup.c b/src/pickup.c index 0fc66b480..183080b47 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -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); diff --git a/src/pline.c b/src/pline.c index 473d06ebb..2552647df 100644 --- a/src/pline.c +++ b/src/pline.c @@ -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); } diff --git a/src/potion.c b/src/potion.c index 83acf51db..54968fb6a 100644 --- a/src/potion.c +++ b/src/potion.c @@ -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!"); diff --git a/src/pray.c b/src/pray.c index b7b4e609d..2f9be4e6c 100644 --- a/src/pray.c +++ b/src/pray.c @@ -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 */ diff --git a/src/priest.c b/src/priest.c index b1075961e..12471408c 100644 --- a/src/priest.c +++ b/src/priest.c @@ -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) { diff --git a/src/quest.c b/src/quest.c index c9fcbfc53..c1029c263 100644 --- a/src/quest.c +++ b/src/quest.c @@ -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; diff --git a/src/read.c b/src/read.c index 7c0a83418..76790e192 100644 --- a/src/read.c +++ b/src/read.c @@ -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; diff --git a/src/rumors.c b/src/rumors.c index 8b41a3feb..ccecad594 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -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; diff --git a/src/shk.c b/src/shk.c index 75dbbd06b..6512df649 100644 --- 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) { /* ", 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", diff --git a/src/sit.c b/src/sit.c index 876f03444..cfc6afd70 100644 --- 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) { diff --git a/src/sounds.c b/src/sounds.c index 269d37ed4..c4eeca169 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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*/ diff --git a/src/teleport.c b/src/teleport.c index 28db803d9..70d4b50f3 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -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"); diff --git a/src/timeout.c b/src/timeout.c index 53d28a410..80fdd6d07 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -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; diff --git a/src/uhitm.c b/src/uhitm.c index d3c9ae26c..9b802d727 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -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) diff --git a/src/vault.c b/src/vault.c index 8f18519da..90a930756 100644 --- a/src/vault.c +++ b/src/vault.c @@ -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 */ } diff --git a/src/wizard.c b/src/wizard.c index fd3af1d73..44619396c 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -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 */ diff --git a/sys/unix/hints/include/multisnd1-pre.370 b/sys/unix/hints/include/multisnd1-pre.370 index 45cf1b1b6..909a02fef 100644 --- a/sys/unix/hints/include/multisnd1-pre.370 +++ b/sys/unix/hints/include/multisnd1-pre.370 @@ -17,6 +17,12 @@ #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 diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index c4b9246a9..01718b9b2 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -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 # diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index 6ee5fbf92..1c507efe5 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -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 */ diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h index 9bdaf9cf3..b0b9f4f3a 100644 --- a/win/Qt/qt_bind.h +++ b/win/Qt/qt_bind.h @@ -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: