Need assistance with setting a narrator screen message with voice

Started by Gal Shemesh, Wed 21/06/2023 11:21:46

Previous topic - Next topic

Gal Shemesh

Hi everyone,

Sorry if this was asked before but I just can't find an exact thread about this issue.

I'm trying to make a Sierra "King's Quest 5/6" style game, where apart from regular character speech, there's an 'invisible' narrator that gives text information to the player upon looking / doing stuff, within a text box like the "Display" function. The thing I don't get is how to make this text box to show along with voice speech in the background, and that the speech will be based on the voice pack the game is set to run with.

I managed to import a voice sound to the engine and used its name with .play() and put it before the Display("string") line of code, but it's only for 1 language and it keeps playing even when the player interrupts and closes the text box. Besides, it's more complicated to work that way as I'll have to import all sound files to the engine. It also lacks the ability to pick sound files based on different languages. So I prefer to use speech as it pulls the sounds from the external Speech folder and its sub-folders for other langauges.

So I read a bit online and found that some are suggesting to use an invisible character as the narrator, and to position it in the center of the screen for presenting the text. So I tried it - after finding out that I can't use the 'cNarrator' script name for the character as it's already defined in the engine as a special character for dialogues, I gave my new narrator character the script name 'cNar'. I managed to achieve what I want, placing the narrator character in the middle of the screen and passing text and speech to it which works great in all languages. The only problem is that I don't want the text to be shown as speech text above its head but in a text box with a frame and all, that will also pause the game when shown, just like the "Display" function.

UPDATE:
I've just managed to write the code this way which is almost great, but the message displays only after the sound finish playing. The '&1' is the first sound file of the cNar character, pulled from either the 'Speech' folder for English or from the sub-folder 'Speech\Hebrew' for Hebrew:

Code: ags
function cEgo_Look()
{
  cNar.say("&1") & Display("Damn, you're looking good!");
  
}


Would appreciate some help.

Many thanks!
Gal Shemesh,
goldeng

Khris

EDIT:
Disregard my post; Display() supports voice speech out of the box. By calling game.narrator_speech = -1;, the game will use voice files starting with NARR.

---

You probably need a custom function for this.

Code: ags
void Narrate(int cue, String text) {
  AudioChannel* ch = Game.PlayVoiceClip(cNar, cue);
  Display(text);
  if (ch != null) ch.Stop();
}

Add this to the Global header to be able to call the function from room scripts:
Code: ags
import void Narrate(int cue, String text);

Now call it like this: Narrate(1, "King Graham finally got rid of Cedric.");

Edit:
& is the bitwise and operator, it does not really do anything here.
Edit 2: NPE fix

Gal Shemesh

Thanks a million, @Khris! :) It works great when I have a voice file in the Speech folder and also in sub-folders for other languages.

The only problem I found is that if I use the calling syntax as a placeholder when I haven't recorded voices yet for all the text lines, then the 'ch.Stop();' makes the game crash. So I put it within an if statement that checks if 'ch' is NOT equal to 'null'. So now if I don't have a sound file in the Speech folder yet the game continues.

Code: ags
void Narrate(int cue, String text) {
  AudioChannel* ch = Game.PlayVoiceClip(cNar, cue);
  Display(text);
  if (ch != null) {
  ch.Stop();
  }
}
Gal Shemesh,
goldeng

Snarky

I think this check is also necessary even if you do have a voice clip, in case the player doesn't click away the Display box until the clip has already finished playing.

Edit: No, I forgot that AudioChannels are persistent, and that if you get back a valid pointer, it will never turn into a null.

Gal Shemesh

Actually, since the text is shown like a 'Display()' fuction, the player can't do anything as long as the message is on the screen but to click in order to close the message and skip that bit. Which is fine for me.
Gal Shemesh,
goldeng

Gal Shemesh

I will appreciate help on something similar to what you mentioned, @Snarky.

I've been tweaking the function with some 'if statements' so it will make sence with the 3 setting modes of 'Voice and Text / Text Only / Voice Only', as the modes did not affect the function and it always showed the text and played the sound no matter what setting was picked from the settings panel.

The new issue I'm facing now is when I set the game to 'Voice Only', as the speech sound plays without showing the text box on screen and the game keeps running in the background. Is there a way to make the function to sort of pause the game, the same as how the regular 'character.say()' function works which changes the mouse cursor to an hour-glass as long as the sound is playing, and that when it's done the control automatically returns to the player? The player should also have an option to skip the playing sound and get control back upon click.
Gal Shemesh,
goldeng

Snarky

#6
I don't think there is any way to freeze the game in exactly the same way that Display() does (which is a "harder" pause than the other blocks in AGS), but it should be possible to make it wait in the same way as speech does, by... actually playing it as a speech line in that case:

Code: ags
  if(Speech.VoiceMode == eSpeechVoiceOnly && IsSpeechVoxAvailable())
    cNar.Say(String.Format("&%d",cue));

Crimson Wizard

I believe that Display (and all its functions family) can play voice precisely the same way as Say command does, if you call your voice files NARRXXXX.

Correction: Display uses a character index set by game.narrator_speech. It equals default player char on startup, but if this value is -1, then it will use NARRX files.

See here: https://adventuregamestudio.github.io/ags-manual/Gamevariables.html

Code: ags
Display("&1 Bla bla bla");
will play voice file 1.

EDIT: the manual should be updated, this essential information needs to be added to "Display" article, and also to "Voice speech" article

Gal Shemesh

Quote from: Snarky on Wed 21/06/2023 14:17:26I don't think there is any way to freeze the game in exactly the same way that Display() does (which is a "harder" pause than the other blocks in AGS), but it should be possible to make it wait in the same way as speech does, by... actually playing it as a speech line in that case:

Code: ags
  String cueString = String.Format("&%d",cue);
  if(Speech.VoiceMode == eSpeechVoiceOnly && IsSpeechVoxAvailable())
    cNar.Say(cueString);
Wow, that works just as expected! Thanks!!

Quote from: Crimson Wizard on Wed 21/06/2023 14:28:51I believe that Display can play voice precisely the same way as Say command does, if you call your voice files NARRXXXX.

Correction: you need to use DisplayAt for this, or DisplayAtY, as these functions act more similar to Say, being not as ultimately blocking as Display.
I will be glad to check this out - but does it work out-of-the-box or requires to have the custom Narrate function in the script header as well? And when writing the built-in Display() function, should I write it this way for calling the speech files:
Code: ags
Display(&1 "some string.")
?
Gal Shemesh,
goldeng

Crimson Wizard

@Gal Shemesh I corrected my reply once more after you replied, with example, please re-read it again.

Gal Shemesh

Quote from: Crimson Wizard on Wed 21/06/2023 14:44:34@Gal Shemesh I corrected my reply once more after you replied, with example, please re-read it again.
Yes, just saw it and was in the middle of modifying my previous reply. Thanks a lot! I also agree that this should be in the manual. I'm trying for hours to find heads and tails in the manual on these topics but it's currently lack of them, that's why I asked for help. Much appreciate all your help, from both of you! :)
Gal Shemesh,
goldeng

Gal Shemesh

Quote from: Crimson Wizard on Wed 21/06/2023 14:28:51I believe that Display (and all its functions family) can play voice precisely the same way as Say command does, if you call your voice files NARRXXXX.

Correction: Display uses a character index set by game.narrator_speech. It equals default player char on startup, but if this value is -1, then it will use NARRX files.

See here: https://adventuregamestudio.github.io/ags-manual/Gamevariables.html

Code: ags
Display("&1 Bla bla bla");
will play voice file 1.

EDIT: the manual should be updated, this essential information needs to be added to "Display" article, and also to "Voice speech" article
Can you please direct me to where / how to define the 'game.narrator_speech' variable to -1?
Gal Shemesh,
goldeng

Khris

Just put
Code: ags
  game.narrator_speech = -1;

in game_start (or the first room's room_Load).

Regarding the syntax error in Display(&1 "Bla bla bla"): Display is a function that expects a string as first argument. You can't just put arbitrary characters in between the parens. The &1 belongs at the start of the string, exactly as with the Say command.

Gal Shemesh

Quote from: Khris on Wed 21/06/2023 15:16:24Just put
Code: ags
  game.narrator_speech = -1;

in game_start (or the first room's room_Load).

Regarding the syntax error in Display(&1 "Bla bla bla"): Display is a function that expects a string as first argument. You can't just put arbitrary characters in between the parens. The &1 belongs at the start of the string, exactly as with the Say command.
Thanks! It works great. Only difference compared to @Snarky script is that on 'Voice Only' mode the cursor remains as it was instead of changing to the hour-glass, and once the sound finished playing you actually have to make another click before the mouse cursor can return to interact with the environment; I just moved the mouse to the top edge to see if it can interact with the top bar icons in the Sierra style game and it doesn't pull the icons until I click on the mouse.
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Wed 21/06/2023 15:32:37on 'Voice Only' mode the cursor remains as it was instead of changing to the hour-glass, and once the sound finished playing you actually have to make another click before the mouse cursor can return to interact with the environment;

This sounds like a bug in the engine.

Crimson Wizard

Quote from: Crimson Wizard on Wed 21/06/2023 15:38:51
Quote from: Gal Shemesh on Wed 21/06/2023 15:32:37on 'Voice Only' mode the cursor remains as it was instead of changing to the hour-glass, and once the sound finished playing you actually have to make another click before the mouse cursor can return to interact with the environment;

This sounds like a bug in the engine.


Clarifying after some tests.

Cursor keeps its previous view during Display always, that's a normal behavior.

Display has to be removed with a player's input is a standard behavior, controlled by "game.skip_display" variable.

There's a problem with Display which plays a voice in a "Voice only mode". The issue is a lack of visual cues.
With speech you see a "wait" cursor, and optionally an animating character (SpeechView). With Display you won't see anything.

I guess this might be a reason to skip Display by a timer too when in "Voice only" mode. But this is not a high priority, as there are other workarounds, and alternatives to Display as well.

Gal Shemesh

Thanks @Crimson Wizard for all the testing. So you don't think that it's a bug after all in 'Voice Only' mode? I mean, it's weird that the pointer remains as if it's ready for hovering on hotspots and for revealing the top icon bar when it actually don't work until you click on the mouse - that is after the sound finished playing. All the other statements about the normal behaviors you mentioned are understandable.

Anyway with your, @Khris and @Snarky's kind help I managed to almost finish a basic upgraded template. I just have to work on the Hebrew font so it won't be a font of another game - currently it's Simon the Sorcerer's font in both English and Hebrew. Here's a short video describing what I've been working on: Upgraded Template Video

A summary of what was changed:
1. The template is a multilanguage - based on English and has a Hebrew translation file.
2. Updated 256 characters font that contains both English and Hebrew character sets.
3. Ability to switch between Voice and Text for both English and Hebrew are in the in-game settings panel.
4. Speech folder contains all English voices and Speech\Hebrew contains all Hebrew voices.
5. Display() messages are set to be shown based on the 'Narrate(int cue, String text)' method for adding narration voices, which are based on an invisible cNarr character.
6. Fix for showing the wait / hour-glass cursor when on 'Voice Only' mode, using @Snarky assistance with the String cueString = String.Format("&%d",cue); line in Global Header.

Let me know what you think, and of course suggestions to make it better are very much welcome.
Also, kindly let me know where would be the suitable place to upload the complete template once I finish working on it, so users with multilanguage game in mind could use it as a starting point.

Thanks
Gal Shemesh,
goldeng

Gal Shemesh

Hi guys,

I have another query on this topic regarding the IsSpeechVoxAvailable function.

I made this temporary hotkey for checking if I have any speech vox files in my game:

Code: ags
if (keycode == eKeyReturn)
{
  Display("IsSpeechVoxAvailable %d", IsSpeechVoxAvailable());
}

However, even if I'm running a game without any sound files in the Speech folder, the IsSpeechVoxAvailable returns the value 1 as if there are. What I'm trying to do is to make a condtion that checks if there are no speech files available when the game is launched, and if so then the Speech.VoiceMode will be changed to eSpeechTextOnly.

Same as if the players click on the Voice button in the Settings panel for changing the voice modes - if there is no speech files available I wish to show them a message saying that, and perhaps with some link that they need to access for downloading the speech packs from.

Thanks
Gal Shemesh,
goldeng

Crimson Wizard

Quote from: Gal Shemesh on Sun 09/07/2023 12:24:41However, even if I'm running a game without any sound files in the Speech folder, the IsSpeechVoxAvailable returns the value 1 as if there are.

Is speech.vox present in Compiled folder?

Gal Shemesh

Nope. I have manually removed these files to be on the safe side from both the Data and Windows folders within the Compile directory. If I either run the game for a quick test from the editor or select to build all files where there is no speech files in the Speech folder, no VOX files get created, yet IsSpeechVoxAvailable remains to be equal to 1.

If I add a speech file and hit F5 for a quick test, the speech file plays in the game, though no VOX file gets created in the folders unless I selected to build all files - not sure if that's the correct behavior...
Gal Shemesh,
goldeng

SMF spam blocked by CleanTalk