Not sure how much help this is but I recalled overnight that the first room (room 2) in my Ruby Cast game had something like what you described. The old man starts moving his mouth before the words pop up on the screen. Unfortunately I don't have the original source code with me any more but I opened up the game in AGI Studio and the code below appears to be what controls that part of the game:
if (v41 == 1) {
set.loop(o1,1);
set.cel(o1,0);
start.cycling(o1);
v41 = 2;
}
if (v41 == 2) {
v42++;
if (v42 > 10) {
v42 = 0;
v41 = 3;
set.loop(o1,0);
set.cel(o1,0);
}
}
if (v41 == 3) {
v41 = 4;
reset(f15);
v21 = 4;
print.at("\"Ah, hgh, eh, hmpf, er ...\"",4,25,12);
v21 = 8;
print.at("\"Hah!! I almost forgot how to speak for a second there.\"",3,20,17);
v21 = 8;
print.at("\"Well, how you doing young son? Welcome to Adventure Park.\"",3,20,17);
v21 = 8;
print.at("\"Adventure Park? I thought this was a beach!!!\"",3,2,17);
}
if (v41 == 4) {
set.loop(o1,2);
set.cel(o1,0);
start.cycling(o1);
v41 = 5;
v42 = 0;
}
if (v41 == 5) {
v42++;
if (v42 > 10) {
v42 = 0;
v41 = 6;
set.loop(o1,0);
set.cel(o1,0);
}
}
if (v41 == 6) {
v21 = 8;
print.at("\"Good heavens no! It is far worse than that!\"",3,22,17);
v21 = 20;
print.at("\"You are now part of the game my friend. You can't leave until you "
"collect the fourteen gold coins and place them in the ruby cast.\"",2,15,23);
v21 = 26;
print.at("\"Of course, you'll find it much harder now that the equipment "
"isn't being maintained. Blow me down if the caretaker didn't just "
"up and jump off that cliff into the void.\"",2,10,28);
v21 = 8;
print.at("\"Darndest thing I ever did see! (Stupid git)\"",3,21,17);
v21 = 8;
print.at("\"So where abouts is the ocean?\"",3,2,17);
v21 = 20;
print.at("\"There is no ocean here young man. We only have a lake, a river "
"and a waterfall. This here is desert sand, not beach sand.\"",2,15,23);
v21 = 16;
print.at("\"By the way, I'm the gate keeper and I'm probably the only friend "
"you've got in this world.\"",3,17,23);
v21 = 8;
print.at("\"Good luck on your quest.\"",3,22,17);
observe.horizon(o0);
accept.input();
player.control();
v41 = 0;
reset(f48);
}
In the original source code I would have given the variables and flags more meaningful names. It looks like v41 is controlling what part of the sequence of movements it is up to. It looks like it uses different loops for different parts of the sequence. It starts with loop 1 and cycles through that and then when v42 (a second variable) is greater than 10 it stops cycling and switches to another loop. It then displays some of the dialog text between the two characters and after that it starts cycling through loop 2, sets v42 back to 0 and then increments v42 on each cycle, once again until it reaches 10, at which point it displays some more dialog text.
So it is using v42 to count how many game cycles the loop has cycled through and when it reaches a certain value then it stops the animation. I guess this is an alternative to end.of.loop. I suspect that the loops that it is cycling through are very short loops that simply open and close the mouth, so perhaps using end.of.loop felt a bit awkward to me to use for a short loop and I simply left it to cycle through the loop for ten cycles.