Background Speech/Conversations

Started by pixg, Thu 24/01/2013 10:21:40

Previous topic - Next topic

pixg

I have searched for posts about this and couldn't find any so i'll post this question myself..

I have various characters that i want to speak to themselves or each other as well as walk around in the background and have it not affect my character/gameplay any anyway.
at the moment i am using "SayBackground" and walk with no Eblocks attached to timers, this works quite well with the exception of the speech animation is not played also i can not figure out how to play a speech sound byte to hear them speaking when using "SayBackground".

here is an example of the codes i am using:

Code: AGS

function room_Load()
{
SetTimer(1, 400);
}

function room_RepExec()
{
  int i;
  if (IsTimerExpired(1)){
    i = Random(12);
    if (i == 0) cSweet.Walk(420, 438, eNoBlock, eWalkableAreas); 
    if (i == 1) cSweet.SayBackground("any cake a pound");
    if (i == 2) cSweet.Walk(317, 464, eBlock, eWalkableAreas);
    if (i == 3) cSweet.SayBackground("any bag of crisps a pound");
    if (i == 4) cSweet.Walk(200, 485, eNoBlock, eWalkableAreas);
    if (i == 5) cSweet.SayBackground("these fruit cakes are made by a well known shop, i'm not allowed to say sparks and darts");
    if (i == 6) cTax.Walk(656, 504, eNoBlock, eWalkableAreas); 
    if (i == 7) cTax.SayBackground("mumble mumble mumble");
    if (i == 8) cTax.Walk(463, 504,  eBlock, eWalkableAreas);
    if (i == 9) cTax.SayBackground("grumble grumble grumble");
    if (i == 10) cTax.Walk(697, 516, eNoBlock, eWalkableAreas);
    if (i == 11) cTax.SayBackground("thrumble dumble crumble");
    SetTimer(1, 300);
    }
    
    
    
}



if i just use "Say" instead of "SayBackground" the speech animation is played but the gameplay is interupted.

monkey0506

It may be a bit overkill for what you need, but there are some modules around for queued background speech which include speech animation. The QueuedSpeech module I wrote for this should be compatible with the latest versions of AGS, but does not support the new audio system, and relies on the old audio commands. It also allows you to include a normal-looking speech stamp in the command, but it actually plays that sound number, not a player-specific speech file.

Alternately, you could do what the modules all do and just handle the speech animation yourself. The basic idea for that is:

- Store the Overlay* returned from Character.SayBackground in a global pointer (you may need more than one for simultaneous background speech of course).
- If the global Overlay* is NOT null and is valid, then the Character is speaking (e.g., if ((ovSpeech != null) && (ovSpeech.Valid)) { ... }).
|-- If the Character is not animating, then you need to start them animating (if a speech view exists!, e.g., if (player.SpeechView) { ... })
|---- Lock the Character's view to their speech view (Character.LockView).
|---- Animate the Character, non-blocking, repeating (Character.Animate).
|-- Else, if the Character is animating, well then our work is done for now.
- Else, if the Overlay* is null or not valid, then the Character is no longer speaking
|-- If the Character is still locked into their speech view, unlock them (Character.UnlockView).

Speech files make background speech significantly more complicated because then the assumption is that the Overlay should persist for exactly the duration of the speech file. (AFAIK) AGS doesn't currently allow Character.SayBackground to use the normal speech files, so you would then have to sync it to an AudioClip which you would have to play and track manually. It's not actually incredibly difficult to do, but at that point you may just be better off using an existing module.

pixg

I have downloaded a module called "QueuedSpeech_2_2_BETA" I have not used a module before, there is no 'read me' file or '//help' within the script.
I have imported the script file into AGS, but i can't seem to figure out how to use it.

Khris

That module is almost 7 years old. Some of the stuff on the resource page is severely outdated; it's always better to search/browse the Modules & Plugins section here on the forums.

monkey0506

I usually include a documentation file (typically "XXX_Manual.txt") in the RAR archives I upload. The latest version (v3.5) is only compatible with AGS 3.2+ because it uses the new audio system. The link for the module v3.0 is also valid for AGS versions 3.1, 3.1.1, and 3.1.2. Both include in the RAR archive the file "QueuedSpeech_Manual.txt" which documents usage.

Just as a brief example though, of a queued background conversation:

Code: ags
function room_AfterFadein()
{
  cSweet.SayQueued("any cake a pound");
  cTax.SayQueued("mumble mumble mumble");
  cSweet.SayQueued("any bag of crisps a pound");
  cTax.SayQueued("grumble grumble grumble");
  cSweet.SayQueued("these fruit cakes are made by a well known shop, i'm not allowed to say sparks and darts");
  cTax.SayQueued("thrumble dumble crumble");
}


Note that this is very different from what you're doing in your original example in that this will simply run through the lines with each character taking a turn speaking (such as one might generally expect in a conversation).

Integrating the module into your original concept with the characters walking (randomly) to predestined points would look rather different:

Code: ags
function room_Load()
{
  SetTimer(1, 400);
}

function room_RepExec()
{
  if (IsTimerExpired(1))
  {
    SetTimer(1, 300);
    int i = Random(12);
    if (i % 2) // i is an odd number
    {
      if (!QueuedSpeech.IsQueueEmpty()) i--; // there is already background speech displayed that hasn't expired yet, do a walk instead
      else // no background speech displayed, show some
      {
        if (i == 1) cSweet.SayQueued("any cake a pound");
        else if (i == 3) cSweet.SayQueued("any bag of crisps a pound");
        else if (i == 5) cSweet.SayQueued("these fruit cakes are made by a well known shop, i'm not allowed to say sparks and darts");
        else if (i == 7) cTax.SayQueued("mumble mumble mumble");
        else if (i == 9) cTax.SayQueued("grumble grumble grumble");
        else if (i == 11) cTax.SayQueued("thrumble dumble crumble");
        return; // ignore the rest of this function
      }
    }
    // i is an even number, but we don't use else in case we modified the value of i above
    if (i == 0) cSweet.Walk(420, 438, eNoBlock, eWalkableAreas); 
    else if (i == 2) cSweet.Walk(317, 464, eBlock, eWalkableAreas); // is this intentionally eBlock?
    else if (i == 4) cSweet.Walk(200, 485, eNoBlock, eWalkableAreas);
    else if (i == 6) cTax.Walk(656, 504, eNoBlock, eWalkableAreas); 
    else if (i == 8) cTax.Walk(463, 504,  eBlock, eWalkableAreas); // this one too?
    else if (i == 10) cTax.Walk(697, 516, eNoBlock, eWalkableAreas);
  }
}


Presumably (from your first post) you don't specifically need multiple characters speaking in the background simultaneously, and the QueuedSpeech module does not support that. This example code specifically avoids that issue by diverting to a Walk statement if background speech is already displayed.

pixg

#5
Thanks for clearing up my code there, i'm still learning this stuff and it's my first time at anything like this.
your correct i don't need servel people talking at once, but i would like to be able to have a question and a reply, which i've tried to do like this:

}
function room_Load()
{
SetTimer(1, 400);
}
function room_RepExec()
{
  int i;
  if (IsTimerExpired(1)){
    i = Random(2);
   
   
    if (i == 0) cOliveman.SayQueued("Ow's business then Jewel's?");
                Wait (30);
                cJewlgirl.SayQueued("Nay so bad Olive");

    if (i == 1) cJewlgirl.SayQueued("We tried that looford market last week");
                Wait (30);
                cOliveman.SayQueued("oh right.. any good");
                Wait (30);
                cJewlgirl.SayQueued("It was Feckin Shite!");
    if (i == 2) cOliveman.SayQueued("Don't you wish Sweet Man would shut up sometimes?");
               Wait (30);
                cJewlgirl.SayQueued("I wish he'd feckin' DIE sometimes!");
   
        SetTimer(1, 300);
  }   
}



but that doesn't seem to work.

is there a better way to do this?
thanks again.

Khris

You can't just call a Wait(30); in there and expect it to get queued. What this code does is put the first String in the SayBackground queue, block the game for 0.75 seconds, then put the next String in the queue.

I don't know if the module supports pauses; you could try something like
Code: ags
 cJewlgirl.SayQueued("                                ");

pixg

I changed it to:

    if (i == 0) cOliveman.SayQueued("Ow's business then Jewel's?");
                cJewlgirl.SayQueued("Nay so bad Olive");
    if (i == 1) cJewlgirl.SayQueued("We tried that looford market last week");
                cOliveman.SayQueued("oh right.. any good");
                cJewlgirl.SayQueued("It was Feckin Shite!");
    if (i == 2) cOliveman.SayQueued("Don't you wish Sweet Man would shut up sometimes?");
                cJewlgirl.SayQueued("I wish he'd feckin' DIE sometimes!");


but the problem is, it seems completey random
e.g. the convo might start "it was feckin shite"
and then something else random, so the conversations don't make any sense.
instead of:  "i tried looford market"   "oh right any good?"    "it was feckin shite"



I'm trying to get a few questions and replys picked out at random, but i want them to make sense so it has to start with a question and then be followed by the correct reply.

Khris

Right, I completely missed this in your previous post.

If you want several commands' execution depend on whether a condition is true, you need to group them using curly brackets.
Code: ags
  if (i == 0) {
    cOliveman.SayQueued("Ow's business then Jewel's?");
    cJewlgirl.SayQueued("Nay so bad Olive");
  }

pixg

of course! thank you so much for nursing me through this, everything is exactly the way i want it to be now :)

SMF spam blocked by CleanTalk