Background speech issues (SOLVED)

Started by HillBilly, Sat 22/07/2006 16:20:47

Previous topic - Next topic

HillBilly

Hello,

I've been having some problems with backgroundspeech in AGS v.2.62. What I need is a character(CHIP) randomly mumbling lines while the main character(EGO) can walk around doing stuff. CHIP's talking animation needs to be displayed when he says something, and a sound clip needs to be played, since backgroundspeech don't support voices. Pablo has been so kind to help me out with a script, but unfortunately it still remains some difficulties. Here's the script in question:

Code: ags
           int time=120;
           
           int timer;
           int animating=0;
           int rand;
#sectionstart room_c  // DO NOT EDIT OR REMOVE THIS LINE
function room_c() {
  // script for room: Repeatedly execute       
       timer++;

if (animating==0) {
if (timer==time) {
  rand = Random(3);
  SetCharacterView(CHIP,23);
  AnimateCharacterEx(CHIP, 0, 5, 1, 0, 0);
  if (rand == 0) {
    PlaySound(13);
    DisplaySpeechBackground(CHIP, "Line1.");
  }
  if (rand == 1) {
    PlaySound(14);
    DisplaySpeechBackground(CHIP, "Line2.");
  }
  if (rand == 2) {
    PlaySound(15);
    DisplaySpeechBackground(CHIP, "Line3");
  }
  else if (rand == 3) {
    PlaySound(16);
    DisplaySpeechBackground(CHIP, "Line4.");
  }
  timer=0;
  animating=1;
}
}

if (timer==time) {
  DisplaySpeechBackground(CHIP, "");
  ReleaseCharacterView(CHIP);
  animating=0;
  timer=0;
}
}


Here's the different results of the scipt:

Keeping as it is - CHIP talks and plays the clip, but the talking animation lasts a bit too long. If the main character says something while CHIP does, the talking animation last very long. This is the main problem.

Adding "ReleaseCharacterView(CHIP);" After "DisplaySpeechBackground(CHIP,..." - Of course, now the talking animation won't play. Maybe if I had a way for it to wait until after the sound clip is finished playing, but I don't know how to do that.

Adding "ReleaseCharacterView(CHIP);" after every line EGO says - An unpractical solution, but it worked partly. If EGO talks at the same time as CHIP, CHIP's talking animation stops at the same time as EGO. Since they both say relative short lines, it worked okay. However, if EGO is talking and is "interrupted" by CHIP, I get this:

Quote
(ACI version 2.62.772)

Error: run_text_script1: error -6 (Error (line 672): Script appears to be hung (150001 while loop iterations without an update)) running function 'room_c'

I know, I shouldn't be using 2.62 because this could be solved in a jiffy in 2.72. I'd change if I could, so this will probably be my last game in 2.62.

Thanks.

EDIT: Fix'd some code.

Edit by strazer: Please post error messages in clear text so they show up in the forum search.

monkey0506

Quote from: HillBilly on Sat 22/07/2006 16:20:47
Code: ags
while(character[CHIP].animating) PlaySound(13);

This is (obviously) the problem (as it's the only while loop). The problem is that you have the animation set up to repeat:

Code: ags
AnimateCharacterEx(CHIP, 0, 5, 1, 0, 0); // int CHARID, int loop, int delay, int repeat, int direction, int blocking


So that the character is animating forever (until you manually stop it). Since you never stop the character animating, the while loop is run indefinitely and crashes the game. Perhaps this "while" should be an "if"?

HillBilly

Quote from: monkey_05_06 on Sat 22/07/2006 16:48:44
Quote from: HillBilly on Sat 22/07/2006 16:20:47
Code: ags
while(character[CHIP].animating) PlaySound(13);

This is (obviously) the problem (as it's the only while loop).

D'oh. I'm sorry, I was checking out if there was any .talking varibles, and forgot to remove it. It was not supposed to be there.

Quote from: monkey_05_06 on Sat 22/07/2006 16:48:44The problem is that you have the animation set up to repeat:

Code: ags
AnimateCharacterEx(CHIP, 0, 5, 1, 0, 0); // int CHARID, int loop, int delay, int repeat, int direction, int blocking


So that the character is animating forever (until you manually stop it). Since you never stop the character animating, the while loop is run indefinitely and crashes the game. Perhaps this "while" should be an "if"?

If I remove repeat, CHIP only plays the animation once, and stops at the last frame. And it stays there for aslong as the talking animation would loop.

monkey0506

Hmmm...funny the way I write things sometimes...

But...erm...now I'm confused. You said something about the while loop wasn't supposed to be there?

The way you called AnimateCharacterEx is fine BTW, I meant that because it repeats the while loop would run forever.

Ashen

This could be the best answer:
Quote from: HillBilly on Sat 22/07/2006 16:20:47
Adding "ReleaseCharacterView(CHIP);" After "DisplaySpeechBackground(CHIP,..." - Of course, now the talking animation won't play. Maybe if I had a way for it to wait until after the sound clip is finished playing, but I don't know how to do that.

If you've got no other sounds that're likely to play, you could use IsSoundPlaying. Since it sounds like you might have EGO speaking at the same time, you could try using PlaySoundEx to force Chip's speech to a specific channel, then use IsChannelPlaying to check if it's done (e.g. if (IsChannelPlaying(5) == 0 && character[CHIP].animating) ReleaseCharacterView(CHIP);).
I know what you're thinking ... Don't think that.

HillBilly

That worked for the normal talk. He now stops animating right when the text disappears. Unfortunately, it's not the same case when EGO interrupts him. Then the animation keeps looping for a while, and it loops even longer if the player, for example, clicks "look at" on an object again and again.

It seems that when the text disappears(as it does when it's interrupted by "normal" speech), it forgets about the rest of the code. I've tried adding if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ ReleaseCharacterView(CHIP); both before and after "DisplaySpeechBackground", but no luck.

If it makes any difference, the text itself could be sacrified. Aslong as the voice and animation is in sync, I'm happy.

Ashen

Pah, didn't think about that ...

You could also check EGO's current view against his speech view (character[EGO].view == character[EGO].talkview in 2.62, I think).

Thinking about it though, you should also be able to make use of the overlay functions (since BackgroundSpeech uses them too). Make a new int and assign it the overlay number of the background speech, e.g.:
Code: ags

           int line;
#sectionstart room_c  // DO NOT EDIT OR REMOVE THIS LINE
function room_c() {
  // script for room: Repeatedly execute       
// blah blah blah
    line = DisplaySpeechBackground(CHIP, "Line1.");
// yadda yadda yadda
    line = DisplaySpeechBackground(CHIP, "Line2.");
// etc


Then, you should be able to use IsOverlayValid(line) to check if Chip is 'speaking' and release the view as needed.
I know what you're thinking ... Don't think that.

HillBilly

Quote from: Ashen on Sat 22/07/2006 20:13:53
Then, you should be able to use IsOverlayValid(line) to check if Chip is 'speaking' and release the view as needed.

Where would I place this? I tried this:

Code: ags
  else if (rand == 3) {
    PlaySoundEx(16, 3);
    line = DisplaySpeechBackground(CHIP, "Line3.");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating && IsOverlayValid(line)){ 
    ReleaseCharacterView(CHIP);
    }
  }


But that seems illogical, and didn't work either. So I'm probably doing it the wrong way. I think I need this spoon-fed.

Ashen

It'd need to be a seperate check, like the if (timer == time) one, at the end of the rep_ex function - or possibly rep_ex_always, as it may be blocked by EGO's speech otherwise. It doesn't need to be linked with the IsChannelPlaying and character.animating conditions, since it's checking for something else (EGO interupting, rather than the speech finishing on it's own).
I know what you're thinking ... Don't think that.

HillBilly

#9
I think I understood you wrong. I tried this:

Code: ags
       timer++;

if (animating==0) {
if (timer==time) {
  rand = Random(3);
  SetCharacterView(CHIP,23);
  AnimateCharacterEx(CHIP, 0, 5, 1, 0, 0);
  if (rand == 0) {
    PlaySoundEx(13, 3);
    line = DisplaySpeechBackground(CHIP, "!");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  if (rand == 1) {
    PlaySoundEx(14, 3);
    line = DisplaySpeechBackground(CHIP, "!");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  if (rand == 2) {
    PlaySoundEx(15, 3);
    line = DisplaySpeechBackground(CHIP, "...");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  else if (rand == 3) {
    PlaySoundEx(16, 3);
    line = DisplaySpeechBackground(CHIP, ".");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  timer=0;
  animating=1;
}
}

if (timer==time) {
  if (IsOverlayValid(line)){
  DisplaySpeechBackground(CHIP, "");
  ReleaseCharacterView(CHIP);
  animating=0;
  timer=0;
}
}


and this

Code: ags
       timer++;

if (animating==0) {
if (timer==time) {
if (timer==time) {
  rand = Random(3);
  SetCharacterView(CHIP,23);
  AnimateCharacterEx(CHIP, 0, 5, 1, 0, 0);
  if (rand == 0) {
    PlaySoundEx(13, 3);
    line = DisplaySpeechBackground(CHIP, "!");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  if (rand == 1) {
    PlaySoundEx(14, 3);
    line = DisplaySpeechBackground(CHIP, "!");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  if (rand == 2) {
    PlaySoundEx(15, 3);
    line = DisplaySpeechBackground(CHIP, ".");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  else if (rand == 3) {
    PlaySoundEx(16, 3);
    line = DisplaySpeechBackground(CHIP, ".");
    if (IsChannelPlaying(3) == 0 && character[CHIP].animating){ 
    ReleaseCharacterView(CHIP);
    }
  }
  timer=0;
  animating=1;
}
}
}

  if (IsOverlayValid(line)){
  DisplaySpeechBackground(CHIP, "");
  ReleaseCharacterView(CHIP);
  animating=0;
  timer=0;
}


First code, CHIP didn't talk. Second code, CHIP wouldn't stop animating. :-\

HillBilly

Ashen helped me through some hardcore PM'ing. Here's the final code(works perfect):

Code: ags
  int time=120;
  int line= -1;         
  int timer;
  int animating=0;
  int rand;
function repeatedly_execute_always() {
  if (IsOverlayValid(line) || IsChannelPlaying(5)) { // If Text OR Sound is still valid
    if(animating == 1 && character[CHIP].animating == 0) {
      // If CHIP should be animating, but isn't - make him dance! (well, TALK, anyway)
      //(There's a vague chance channel 5 could be used by another game sound, and you don't want Chip to randomly animate then, do you...)
      SetCharacterView(CHIP,23);
      AnimateCharacterEx(CHIP, 0,5,0,0,0);
    }   
  }
  else if (line != -1 && IsChannelPlaying(5)==0) { // Text and Sound cleared, View not yet released
    ReleaseCharacterView(CHIP);
    animating = 0;
    timer = 0;
    line = -1;
  }
}
#sectionstart room_c  // DO NOT EDIT OR REMOVE THIS LINE
function room_c() {
  // script for room: Repeatedly execute       
      timer++;

  if (timer==time) {
if (line == -1) {
  rand = Random(3);
  SetCharacterView(CHIP,23);
  if (rand == 0) {
    PlaySoundEx(13, 5);
    line = DisplaySpeechBackground(CHIP, "line1.");
  }
  if (rand == 1) {
    PlaySoundEx(14, 5);
    line = DisplaySpeechBackground(CHIP, "line2.");
  }
  if (rand == 2) {
    PlaySoundEx(15, 5);
    line = DisplaySpeechBackground(CHIP, "line3.");
  }
  else if (rand == 3) {
    PlaySoundEx(16, 5);
    line = DisplaySpeechBackground(CHIP, "line4.");
  }
  timer=0;
  animating=1;
}
}
}

SMF spam blocked by CleanTalk