A framework for your writing your own script to streamline logging memory values and outputting them in TAStudio and saving and loading them with branches as well as script starting and closing.
Version 0.95, not fully done yet. Runs in Bizhawk 2.11
Version 0.95, not fully done yet. Runs in Bizhawk 2.11
Not working
Branch action undo and branch reordering, it messes up the files and logs.
Features
GUI
It consists of a dropdown list with the branches and the time difference compared to the current section start, a number below 0 means the branch is faster than the current input.
The list is opened by clicking the '▲'-button and clicking on an item from the list selects the given branch as the branch to compare against.
Next to it are '-' and '+'-button to just decrement and increment the branch index by 1.
The 'Best'-button selects the branch with the shortest time between the section start marker and the section end marker, with the same notes as the the current section markers.
Finally the text next to it is the current section start markers text with the time difference to the selected branch at the end, a value below 0 means the current input is faster.
The list is opened by clicking the '▲'-button and clicking on an item from the list selects the given branch as the branch to compare against.
Next to it are '-' and '+'-button to just decrement and increment the branch index by 1.
The 'Best'-button selects the branch with the shortest time between the section start marker and the section end marker, with the same notes as the the current section markers.
Finally the text next to it is the current section start markers text with the time difference to the selected branch at the end, a value below 0 means the current input is faster.
Sections
Sections are marker that don't start its note with "-" or aren't empty. Name the markers individualy - like "Level 1 Key", "Level 2 Key" and so on, or the section find algorithm might fail.
The sections are used to offset the index for relative branch comparison and to display the time difference.
The sections are used to offset the index for relative branch comparison and to display the time difference.
Logs
A log consists of its name, a function how to retrieve the logs values from games memory and a list containing each logged value.
Branch Logs
When saving a branch the current values are saved into a branch log. And loading a branch loads the branch logs values into the current log.
Old Logs
The old logs are the logs with the values from the last input change, which means the old logs are only updated with current logs values when playing back over ungreenzone frames.
It also gets updated by loading branches.
It also gets updated by loading branches.
Printers
Those define how to output the values from the logs into TAStudio cells as text and as color.
How to write a script
Since this is a framework, it is not meant to be run in the Lua Console, instead you need to write your own script.
It is surpsingly easy to write a script!
Firstly start from this:
It is surpsingly easy to write a script!
Firstly start from this:
require("TAStudioLogger") -- Or navigate with relatives paths to to the folder where TAStudioLogger is
-- Write your loggers below here:
-- Write your printers below here:
InitializeLogger() -- Needed to load files and setting up variables and callbacks
while true do
UpdateLogger() -- Logs values
emu.yield()
end
Adding a logger
The Loggers take the form "AddLogger(<loggername>, <addressexpression>)".
'loggername' is just a string. It's the name of the logger to be used in the AddPrinter function.
'loggername' is just a string. It's the name of the logger to be used in the AddPrinter function.
'addressexpression' is either a function that returns a number - in most cases from a memory.read_.. function,
a number of the adress (returns 1 byte unsigned only),
or a string with shorthand expression: "<size>@<address>",
where 'size' is the size of the address (same as in memory.read_.. functions for Bizhawk) and 'address' is the memory address to log.
There are string shorthand form expressions for:
a number of the adress (returns 1 byte unsigned only),
or a string with shorthand expression: "<size>@<address>",
where 'size' is the size of the address (same as in memory.read_.. functions for Bizhawk) and 'address' is the memory address to log.
There are string shorthand form expressions for:
- "<addr1>+<addr2>" for adding two values - value1+value2,
- "<addr1>#<addr2>" for multiplying the first value by 256 and then add the second value - value1*256+value2,
- "<addr1>+<addr2>#<addr3>" for adding the first two values, multiplying by 256, then add the third value - (value1+value2)*256+value3
Examples:
AddLogger("XSpeed", function() return memory.read_s16_le(0x000D56) end)
AddLogger("MidAirFlag", 0x000D7B)
AddLogger("YSpeed", "s16_le@0x000D5A")
AddLogger("XPosition", "u16_le@0x000C29+u8@0x000D61#u8@0x000D50")
Adding a printer
Printers are written as follows: "AddPrinter(<columnname>, <valueexpression>[, <colorexpression>][, <textexpression>][, <digits>])".
'columnname' is the name of the new column added to TAStudio by the script or an existing button column.
'valueexpression' can be
- just a string of the name of one of your Loggers,
- a function that takes 'index' as a parameter and returns a number, like:
function(index) return GetBranchLogValue("XPosition", index) end.%%%
- or a shorthand form string like "<shorthand>,<logname>[,<norm>]",
where 'shorthand' is the function. It can be of the following:- "diff" for 'Difference' function, difference to last frame; e.g.: "diff,XVel"
- "branchval" for 'GetBranchLogValue' function, value from the log in the selected branch; e.g.: "branchval,XVel"
- "branchdiff" for 'BranchDifference' function, difference to last frame in the selected branch log; e.g.: "branchdiff,XPos"
- "branchcomp" for 'BranchCompare' function, subtracts the value in the branch log from the current log; e.g.: "branchcomp,XPos"
- "relbranchcomp" for 'RelativeBranchCompare' function, does BranchCompare, but with marker offsets, if a marker with the same note is found in the branch; e.g.: "relbranchcomp,XPos"
- "oldval" for 'GetOldLogValue' function, value from previous playback, the values also change from branch loading; e.g.: "oldval,XVel"
- "olddiff" for 'OldLogDifference' function, difference to last value from the previous playback; e.g.: "olddiff,XPos"
- "oldcomp" for 'OldLogCompare' function, subtracts the value in the old log from the current log; e.g.: "oldcomp,XPos"
'logname' is the name of one of your logs, so is the optional parameter 'norm'.
You can normalize - multiply the return value of above functions by the sign of 'norm' - by adding a 3rd parameter, e.g.: "branchcomp,XPos,XVel"
You can normalize - multiply the return value of above functions by the sign of 'norm' - by adding a 3rd parameter, e.g.: "branchcomp,XPos,XVel"
'colorexpression' can be
- an number 0xAARRGGBB, a string "#AARRGGBB" expressing a color value or from the predefined Colors table - Colors.white, gray, red, green, blue, yellow, magenta, cyan, orange, purple.
- a table with log values as the key and a color as the value, e.g.:
colortable = { }
colortable[1] = 0xFFE0E0E0
colortable[3] = 0xFFE04090
colortable[8] = 0xFFFF1050
- a function that takes 'value', 'index' as parameters and returns a color, e.g.:
function(value, index) if value == 15 then return Color(index, 0xFF8080FF ) end end
- or the shorthand form string in the form "<condition[,param]>;<function[,params]>;<defaultcolor>". The functions are
- ColorGradient function, "gradient,<maxvalue>[,<startcolor>][,<endcolor>][,<minvalue>][,<exponent>]"
for example "gradient,20,0xFFFF0000,0xFF00FF00,1.15,5", use "gradientabs" for absolute values, - "table,<tablename>" e.g.: "table,colortable". The table must be global.
- ColorGradient function, "gradient,<maxvalue>[,<startcolor>][,<endcolor>][,<minvalue>][,<exponent>]"
Additionally another parameter 'defaultcolor' can be passed in the shorthand form string to decide which color to use when the returned value is nil, e.g.: "gradient,50;0xFFFFEEEE".
'textexpression' is optional,
- if left out or passed nil as the parameter it displays the value of the 'valueexpression',
- a string that is printed, useful with the conditional expression further down,
- a table with log values as the key and a color as the value, e.g.:
texttable = { }
colortable[1] = "stand"
colortable[3] = "walk"
colortable[8] = "jump"
- a function that takes 'value' as a parameter and 'index' optionally and returns a string, like:
function(value) return value < 15 and "invincible" or "" end
- a shorthand form string in the form of "<condition[,param]>;<function[,param]>"
- "modform[,param]" to display the log values as <value>/<param>..":"..<value>%<param>. If left out 'param' is 256
- "modformh[,param]" to display modform as hexadecimal,
- "modformdh[,param]" to display only the remainder as hexadecimal, those functions have an optional parameter for the divisor, e.g.: "modformh,16"
- "hex[,param]" to display the value as hexadecimal, with an optional parameter for the size, e.g.: "hex,4".
- "table,<tablename>" e.g.: "table,exttable". The table must be global.
- or pass in 'false' as a boolean to display no text.
Text wont be displayed in button columns.
Furthermore both 'colorexpression' and 'textexpression' as a shorthand form string can have an additional expression at the beginning to have a condition when to print text or color the cell.
Options for that are:
Options for that are:
- "onchange" to output when the value from the 'valueexpression' has changed sinced the last frame.
- "when[,param]" to output when the value from the 'valueexpression' is equal to 'param', default 0.
- "whennot[,param]" to output when the value from the 'valueexpression' is not equal to 'param', default 0.
- "whenabove[,param]" to output when the value from the 'valueexpression' is above 'param', default 0.
- "whenbelow[,param]" to output when the value from the 'valueexpression' is below 'param', default 0.
When one of those expression used alone for the textexpression shorthand form, it will display the value from valueexpression under the given condition. Like those:
- "when,1;0xFF8040FF;0xFFFFFFFF" colors the cell when the value is 1 otherwise the cell is colored white.
- "whenabove;dmg" prints "dmg" in the cell when the value is above 0.
- "whennot" prints the values from 'valueexpression' when the value is not 0.
Examples:
AddPrinter("XVel", "XVel", "gradientabs,704,0xFFFF0000,0xFF00FF00,0,1.5", nil, 4)
AddPrinter("dXV", "diff,XSpeed,XSpeed", "whennot;gradient,64,0xFFFF0000,0xFF00FF00,-64;0xFFFFFFFF", "onchange" ,3)
AddPrinter("P1 Y", "WeaponsOnScreen", weaponcolors)
A finished script might look like this: UserFiles/Info/639020550928746688