Another way is to pre-process your scripts for a sleep command.
For Example, assume you have the following script ...
Sub MySub()
DoSomething()
Sleep 5
DoSomething()
Sleep 3
DoSomething()
End Sub
Before you load the script into the MS ScriptControl, search for the Sleep function and break the code into diferent pieces. The previous sub would look something like this...
Sub MySub()
DoSomething()
Sleep 5
End Sub
Sub MySub_part1()
DoSomething()
Sleep 3
End Sub
Sub MySub_part2()
DoSomething()
End Sub
The next step is to replace the "sleep" command with a global function that's part of your game. The function is essentially a timer and it takes 2 paramters, the time to wait from the original "sleep" command and also the next function to call. The end result of the script would look something like this:
Sub MySub()
DoSomething()
EngineSleep 5, "MySub_part1"
End Sub
Sub MySub_part1()
DoSomething()
EngineSleep 3, "MySub_part2"
End Sub
Sub MySub_part2()
DoSomething()
End Sub
The "EngineSleep" command simply starts a timer in your program (it doesn't have to be a Timer object, you can keep track of elapsed time however you want) and after the time has elapsed it calls the next part of the sub. This prevents you from running out of stack space in the event that your "DoMainLoopStuff" executes more game code that calls a script with another sleep function. You would end up with something like this...
MainLoop
> Call Script
> Sleep
> DoMainLoopStuff
> Call Script
> Sleep
> DoMainLoopStuff
> Call Script....
This method won't work for functions though. However, having a "sleep" command in a function could lead to some really nasty bugs in your game. A function A that calls another function B that has a sleep command that you forgot about can make you wonder why function A takes so long to execute.