Custom speech GUI like in LSL6 possible?

Started by Dhelayan, Fri 17/05/2013 00:26:59

Previous topic - Next topic

Dhelayan

Hey there!

To get right to it: I basically want to make a speech GUI which behaves just like in Leisure Suit Larry 6.



What would be the best way of doing this? Would i have to make a complete new GUI (Non-text window) and seperate the portrait from it?

Thankies in advance,
Dhel <3

Phemar

Can you describe the behavior you're referring to? For those who can't remember the game off the top of our heads.

Dhelayan

Quote from: Phemar on Sat 18/05/2013 00:15:17
Can you describe the behavior you're referring to? For those who can't remember the game off the top of our heads.

Ah yes of course. Basically, the character's portrait (when talking) goes into the lower left corner, and the speech to the middle box. The right box will be left empty

Phemar

I just a looked up a video on youtube and I see what you're saying.

One of way doing it would be to just change the text on a label. From what I saw in the video the speech is never removed, so you could just set it and leave it.

Then when you call the function, check if it's the player and if it is then animate a button.

Of course, there's a bit more to it then that, but that's the basic idea.

cat

Best thing might be to write a custom Say function that encapsulates the label setting.

Dhelayan

Okay, i found a script on the forums that let's me display the speech where i want it. It basically makes a new command "cEgo.Speak" instead of Say.

Spoiler
Code: AGS
// new module script
#define SPEECH_BUTTON btnAnimation// The button where the speech animation will be drawn
#define SPEECH_LABEL lblSpeech // The lable where the text will be written
#define SPEECH_GUI gSpeech // The gui everythings on
#define TIMER_CLOSE 20 // The timer that will be used to close the gui.

bool mouse_is_pressed;

String old_text;
ViewFrame *firstFrame;

String ToSpaces(String s)
{
  String space = "";
  int i = 1;
  while(i != s.Length)
  {
    space = space.Append(" ");
    i ++;
  }
  return space;
}

function WriteText(String text, Character *speaker, bool append)
{
    // Stop the timer if the GUI is waiting to be closed.
  SetTimer(TIMER_CLOSE, 0);
  SetTimer(19, 0);
  
  // This prevents new text to be skipped when skipping speaker.Say(wait)
  mouse_is_pressed = true;
  
  String wait = ToSpaces(text);
  String append_text = text;
  
  if (append)
    append_text = String.Format("%s%s",old_text, text);
  
  //Shorten the time you have to wait when the whole text have been written out by half.
  if (wait.Length / 2 < 3)
      wait = "   ";
  else
      wait = wait.Truncate(wait.Length /2);
  //Comment out the above to use original time = wait longer
  
  int i;
  while (i <= text.Length)
  {
    if (!append)
        SPEECH_LABEL.Text = text.Truncate(i);
    else
        SPEECH_LABEL.Text = append_text.Truncate(old_text.Length + i);
    
    i ++;
    
    //Skip the writing, I want to read it now!
    if ((Mouse.IsButtonDown(eMouseLeft) || IsKeyPressed(eKeySpace)) && !mouse_is_pressed)
    {
      mouse_is_pressed = true;
      i = text.Length;
    }
    //Wait(20);
  }

  speaker.Say(wait);
  
  // Stop the animation
  if (speaker.ThinkView != 0)
      SPEECH_BUTTON.NormalGraphic = firstFrame.Graphic;
  
  old_text = append_text;
   
  //A little pause before closing, so if there's more to say, the gui won't get closed.
  SetTimer(TIMER_CLOSE, 10);
}

function Speak(this Character*, String say,  int loop, bool append)
{
  if (!SPEECH_GUI.Visible)
    SPEECH_GUI.Visible = true;
    
  SPEECH_LABEL.TextColor = this.SpeechColor;
  
  if (this.ThinkView != 0)
  {
    SPEECH_BUTTON.Animate(this.ThinkView, loop, this.SpeechAnimationDelay, eRepeat);
    firstFrame = Game.GetViewFrame(this.ThinkView, loop, 0);
  }
    
  WriteText(say, this, append);
}

function repeatedly_execute_always()
{
  if (!Mouse.IsButtonDown(eMouseLeft) && !IsKeyPressed(eKeySpace) && mouse_is_pressed)
mouse_is_pressed = false;
  
  if (IsTimerExpired(TIMER_CLOSE))
      SPEECH_GUI.Visible = false;}

Header:
// new module header

import function Speak(this Character*, String toSay, int loop = 0, bool append = false);
[close]

Now, my game will be fully voiced and right now, the script doesn't play any voice files of course. Is there any way to integrate the "&1" from the normal Say command into this new script?

Phemar

#6
I guess you could just incorporate a sound argument into the function, although this would use normal audio files. I'm not sure about using actual speech files.

It does seem a bit verbose to convert the whole string to spaces for the character to say. You could just use the formula ((text length / text reading speed) * game speed) to work out how the long the text should be displayed.

That's the formula AGS uses I believe.

Dhelayan

Quote from: Phemar on Thu 13/06/2013 00:26:56
I guess you could just incorporate a sound argument into the function, although this would use normal audio files. I'm not sure about using actual speech files.

It does seem a bit verbose to convert the whole string to spaces for the character to say. You could just use the formula ((text length / text reading speed) * game speed) to work out how the long the text should be displayed.

That's the formula AGS uses I believe.

I'm sure this does sound rather rational, but it's pretty much hiroglyphics for me XD I really need to get into coding .-.
If it's not too much to ask, could you explain what i would have to change in it to make it work that way?

Khris

#8
Phemar says you could add an argument to the function so you can use it like this:

  cEgo.Speak("Hello there!", aEgo0001);

where aEgo0001 is the sound you imported.
The big problem is that you cannot use the internal speech system ("&1 bla", auto-number speech lines, build voice script, speech.vox file, etc.), since this only works with Character.Say().

Which means you have to import all the speech files and name them yourself, then play them using standard audio commands.

Edit:
Ignore what I said, I assumed this is about non-blocking speech, but it's just about displaying text in a specific way.
The way to do this is to extract the &0?? part from the String and put it infront of the spaces used in the Say call. It's relatively simple and can be done by using String.indexOf and String.Substring.

Kitai

#9
Quote from: Khris on Thu 13/06/2013 16:03:17The big problem is that you cannot use the internal speech system ("&1 bla", auto-number speech lines, build voice script, speech.vox file, etc.), since this only works with Character.Say().

Which means you have to import all the speech files and name them yourself, then play them using standard audio commands.
Or perhaps you can run a SayBackground command at the same time so that it plays the audio if needed (you would then need to retrieve the overlay and move it to (screen_width, screen_height) for the text to be hidden)?

Edit: By the way, I fear that overriding the Say* commands don't affect the built-in dialog system's behavior.

Phemar

Actually, since you're using a Say command in there (the string of spaces) you could use that to play the speech. just format the string somehow. I can give you code later when I'm at home (I'm in a car at the moment).

Dhelayan

First of all, sorry for bumping this oooold thread!

I noticed the "Speak" option i posted in one of my posts isn't the best, since the Dialogues still use the Say command and just display the speech normally and not in the GUI that Speak uses. Is there a way to modify the default Say script somehow?

monkey0506

There's not a way to change the existing, built-in method short of delving into the engine's source code directly. I've never used either feature, but it might be possible to use Sierra-style speech with a custom text window GUI. I'm not sure on that.

But in any case, you could work-around dialogs using the built-in speech methods by disabling the "Say" option for every dialog option, and then using normal script calls in the dialog script (by indenting the code at least one space, for consistency sake I always use two spaces here) for all of the speech (including the original option text via Dialog.GetOptionText, and all in-dialog text). It removes the nicety that dialog scripts attempt to achieve (e.g., making it more like a play script rather than a programming script), but it's a way to functionally achieve what you're after.

SMF spam blocked by CleanTalk