-
Notifications
You must be signed in to change notification settings - Fork 2
TAS Movie Script Tutorial
The movie scripts accepted for UniTAS are lua 5.2 scripts, and this tutorial won't cover how lua works, but it should be simple to understand how it works with other tutorials on lua
To start off, we'll make a simple TAS that just presses the space bar every frame for 3 seconds
MOVIE_CONFIG = {
fps = 60
}
for i = 1, 30 * 3 do
key.hold("Space")
adv()
key.release("Space")
adv()
end
Let's break this down
MOVIE_CONFIG = {
fps = 60
}
This is the configuration for the movie, and it's required to be defined before the first adv
call
You can check out what's possible to configure in the TAS Movie API page
key.hold("Space")
adv()
key.release("Space")
adv()
This is the main part of the script, and in this case, key.hold
and key.release
are the methods that are used to hold and release a keyboard key
and adv
is the method that is used to advance the frame in the movie
If your script looks like this
-- first frame
adv()
-- second frame
The first frame is ran BEFORE the adv()
call, and the second frame is ran AFTER the adv()
call, in total, the script will run for 2 frames
If you want to check out what other methods are available, you can check out the TAS Movie API page
Now let's make a TAS that will hold space if the fps goes below 30, and release space if the fps goes above 30
MOVIE_CONFIG = {
fps = 60
}
function concurrent_method()
if env.fps < 30 then
key.hold("Space")
else
key.release("Space")
end
end
concurrent.register(concurrent_method)
adv(30)
env.fps = 10
adv(30)
Let's break this down
function concurrent_method()
if env.fps < 30 then
key.hold("Space")
else
key.release("Space")
end
end
This is the concurrent method, and it will be ran concurrently with the main script coroutine
This itself wouldn't do anything, so we need to register it
concurrent.register(concurrent_method)
This will register the concurrent method, and it will be ran before the main adv()
call
By default, registering a method will immidiately run it on that line, but you can change the behaviour by passing a second argument
adv(30)
env.fps = 10
adv(30)
To finish off our code, here we're frame advancing 30 frames, and setting the fps to 10, and frame advancing 30 frames again
This makes it so the concurrent method will hold space at the second adv()
call
A concurrent method will run indefinitely every env()
, unless manually stopped or the script is stopped
Purpose of the concurrent method is to automate inputs in the background of the TAS
As a real world example, you can have a concurrent method that will press the jump button if the player lands on the ground, making it so the player will jump automatically
You can also register a method that will run after the main adv()
call
concurrent.register(concurrent_method, true)
Unlike the default behavior, registering a method with the second argument being true
will not immidiately run it on that line
What if you want the concurrent method to run only once?
In that case, you can use concurrent.register_once
, which has the same arguments as before
concurrent.register_once(concurrent_method)
The main scope is a coroutine in disguise, where the adv()
call is the coroutine.yield()
call, and normally you can't yield if its not in a coroutine
However the main scope is secretly wrapped in a method as a coroutine like this
-- main script
key.hold("Space")
adv()
key.release("Space")
adv()
Into this
return function()
-- main script
key.hold("Space")
adv()
key.release("Space")
adv()
end
You can change this behavior by setting MOVIE_CONFIG.is_global_script
to true
MOVIE_CONFIG = {
is_global_script = true
}
This will make the main script not wrapped in a coroutine, and you must instead return a function that will be ran as the main script like this
return function()
-- main script
key.hold("Space")
adv()
key.release("Space")
adv()
end
Concurrent methods are also coroutines, and you can yield in them
If you have a method like so registered as a concurrent method on pre-advancing
function concurrent_method() end
You can think of the script running like this
concurrent_method()
adv()
concurrent_method()
adv()
However if you have a method like so registered as a concurrent method on post-advancing
function concurrent_method() end
concurrent.register(concurrent_method, true)
You can think of the script running like this
adv()
concurrent_method()
adv()
concurrent_method()