LockView/Animate not working in Dialog after changing SpeechView - SOLVED

Started by Wogoat, Thu 10/04/2025 10:05:21

Previous topic - Next topic

Wogoat

I've got a dialog where I want a character to change SpeechView frequently, and has a few incidental animations (most notably a sort of shocked reaction) I am initiating using LockView followed by Animate, with code in the room to UnlockView when the animation has completed.

The incidental animation works great any number of times until I change the SpeechView (either through the Character.SpeechView or Set-Speech-view commands) at which point it doesn't trigger properly.

I can't figure out how to work around this.

I have some examples of my code here:

First an example of how I'm calling the incidental surprised animation from the Dialog script.
Code: ags
cEgo: If you left when you said you did, not only had the drum not fallen yet, but you couldn't have even been here when it did!  
  cSkitt.LockView(20);
  cSkitt.Animate(0,2,eOnce,eNoBlock);
cSkitt: Waaaaaaaah!
cEgo: We know that the drum fell between Eden leaving last night and returning today.

When the animation completes, it returns to the previous view due to this code in the room.
Code: ags
function repeatedly_execute_always()
{
  if (!cSkitt.Animating && (cSkitt.View == 20) && (cSkitt.Frame == 8))
  {
    cSkitt.UnlockView();
  }
}

However, once the dialog passes any point where the SpeechView is changed, this stops working. It continues playing the SpeechView until no characters are speaking, then goes to the first frame of the locked view. It returns to the SpeechView when the character speaks but keeps returning to the locked view after, and the view seems stuck on the first frame. I can't figure out where the error is.

Are there limitations to changing SpeechView in the midst of a Dialog, or any other thoughts as to why this may be happening?
------------------------------------
It's Gravy!

Khris

The Animate call is non-blocking but you have a .Say() immediately after that. How exactly does that play out in-game?
Which frames are used when the character says "Waaaaaaaah!"?

Also, a better way to approach this might be for you to describe the desired goal, because this sounds suspiciously like an xy problem.

Wogoat

View 20 is an 8 frame animation of the character reacting in shock. The intent is that it plays this and then returns to the normal speaking animation due to the Unlock command in the room code.

The reason it is non-blocking is that I want the animation to play when the subsequent line of dialog appears on the screen and not waiting for the animation to complete before displaying the line.

It works great if I do it any time before changing the SpeakView in the Dialog script, I. An even trigger it multiple times.  But if I use those same two lines of code in the Dialog script any time after setting cSkitt.SpeechView it no longer works.
------------------------------------
It's Gravy!

Wogoat

I believe I was mistaken about it working as well as I thought because initially the SpeechView was set to 0 and cSkitt only had a NormalView assigned. He appeared like a still image (akin to how characters usually appear in a visual novel or dating sim) and animated for the reaction. But once I set a SpeechView (whether within the script or from the character editor outside of runtime) the code no longer works at all, the SpeechView takes priority even over the LockView command.

Is there a way to briefly play a specific animation instead of the SpeechView even while the character is speaking?

Or alternately to have an animation that doesn't loop back to the beginning but rather loops back to, say, frame 9 of the animation. (this method I could make a speaking animation that includes the reaction at the beginning, and change the speech animation back to the version without the 8 frame shocked animation before the next line of dialogue, making that portion of the animation only appear once)
------------------------------------
It's Gravy!

Khris

Right, I'm not sure rep_ex_always runs during dialogs. You'll probably have to turn on the respective option in General Settings / Dialog for that but I'm too lazy to check this myself.

Anyway, I'd use a different approach. Speech animation is hard-coded by AGS to either use a loop's frames in order or to use specific frames for specific letters.
To achieve a custom animation, you need to use SayBackground(). Something like this:

Code: ags
function Skitt_Shocked(String message) {
  Overlay* skitt_speech = cSkitt.SayBackground(message);
  cSkitt.LockView(SKITT_SHOCKED);
  cSkitt.Animate(cSkitt.Loop, 2, eOnce, eBlock);
  cSkitt.LockView(SKITT_TALK);
  cSkitt.Animate(cSkitt.Loop, 2, eRepeat, eNoBlock);
  while (skitt_speech.IsValid) Wait(1);
  cSkitt.UnlockView();
}

In your dialog script, use
Code: ags
  Skitt_Shocked("Waaaaaaaah!");

Wogoat

That works, thanks a bunch.

I also figured an alternate solution that suits my needs well now that I better understand what is going on.

repeatedly_execute_always does run during dialogs, it's one of the few things that does which is why I used that function. I changed it to this:

Code: ags
function repeatedly_execute_always()
{
  if ((cSkitt.Frame == 8) && (cSkitt.Loop == 4))
  {
    cSkitt.Loop = 0;
  }
}

And, since Skitt has a variety of Views I want to use throughout the conversation based on his current expression, I put the shocked animation in loop 4 of any view of Skitt's that needs to call it and this code returns to loop 0 when the animation has reached the last frame. This way it still treats it as a talking animation so it plays well with the built in speech behavior.
------------------------------------
It's Gravy!

SMF spam blocked by CleanTalk