-
Notifications
You must be signed in to change notification settings - Fork 11
Script File Syntax
-
byte(address)
- the 8-bit value at the specified address -
word(address)
- the 16-bit value at the specified address -
dword(address)
- the 32-bit value at the specified address -
bit0(address)
- the least significant bit of the specified address -
bit1(address)
- the second least significant bit of the specified address -
bit2(address)
- the third least significant bit of the specified address -
bit3(address)
- the fourth least significant bit of the specified address -
bit4(address)
- the fifth least significant bit of the specified address -
bit5(address)
- the sixth least significant bit of the specified address -
bit6(address)
- the seventh least significant bit of the specified address -
bit7(address)
- the most significant bit of the specified address -
low4(address)
- the four least significant bits of the specified address -
high4(address)
- the four most significant bits of the specified address -
prev(accessor(address))
- the value of the specified address from the previous frame (accessor is one of the above - i.e.byte
)
-
left + right
- adds numerical values or concatenates string values -
left - right
- subtracts the second value from the first value -
left * right
- multiplies numerical values -
left / right
- divides the first value by the second value, the remainder is discarded -
left % right
- calculates the remainder when the first value is divided by the second value
-
left == right
- the two values are equal -
left != right
- the two values are not equal -
left > right
- the first value is greater than the second value -
left >= right
- the first value is greater than or equal to the second value -
left < right
- the first value is less than the second value -
left <= right
- the first value is less than or equal to the second value
left
must be a memory address or a function that evaluates to a memory address
right
may be a memory address, a constant, or a function that evaluates to a memory address or constant
-
left && right
- both conditions must be true -
left || right
- either condition must be true -
!left
- the condition must be false
left
and right
must be comparisons or functions that evaluate to comparisons
Operators are evaluated in this order (within a level, operators are evaluated left to right as they're read from the expression):
- Parentheses
- Multiplication, division, and modulus
- Addition and subtraction
- Comparisons
- Not
- And
- Or
The following statement:
N + M * A < B && C > X || D / G * H > Y + Z
Would be interpreted as:
(((N + (M * A)) < B) && (C > X)) || (((D / G) * H) > (Y + Z))
It is particularly important to understand how this affects the creation of alt groups:
A == N && B == X || B == Y
Because AND has higher precedence than OR, the interpreter sees:
(A == N && B == X) || (B == Y)
Which is two alt groups and no core group. An achievement must have a core group, so this will generate a parsing error. You can use parentheses to force a different order. What was intended was:
A == N && (B == X || B == Y)
Here, A == N
becomes the core group and there are two alt groups: B == X
and B == Y
.
name = value
name
must start with a letter or underscore and may contain additional letters, numbers or underscores.
value
may be a numerical constant, string constant, or expression.
The expression will not be evaluated until the variable is used, which allows variables to be assigned to function calls, memory accessors, or logical comparisons to be evaluated later.
Variables allow storage of values for for later use. They may be assigned constant or calculated values. Variables within a function (including function parameters) are only accessible within the function. Variables outside a function may be used inside or outside of functions. Variables may not be referenced before they are defined.
name = [ value1, value2 ]
An array is a variable that stores multiple values. Arrays are accessed using square brackets. Indices are zero-based, so to access the first item of the array, use name[0]
.
name = { key: value, key: value }
A dictionary is a special type of variable that maps integer values to other values - typically string constants.
key
may be a numerical constant or a variable or function call that evaluates to a numerical constant.
Dictionaries can be accessed or modified using square brackets: value = name[key]
. name[key] = value
function name(parameters) { code }
A function is a reusable piece of code that may have slightly different behavior controlled by parameters that are passed to the function.
A function may return anything that can be assigned to a variable (numerical or string constants, or an expression to be evaluated later)
This shorthand defines a function that just returns the specified expression.
function name(parameters) => expression
Functions are called by using the function name in an expression. Parameters may be passed by index or key.
variable = name(parameter1, parameter2)
variable = name(p1 = parameter1, p2 = parameter2)
for key in dictionary { code }
Executes the specified code for each key in the provided dictionary.
for item in array { code }
Executes the specified code for each item in the provided array.
for index in range(start, stop, [step]) { code }
Executes the specified code for each integer in the inclusive range between start
and stop
. If step
is not specified, it's value is 1. range(1, 5)
is equivalent to [1,2,3,4,5]
and range(1, 5, 2)
is equivalent to [1,3,5]
.
if (condition) { code }
if (condition) { code } else { code }
Allows arbitrary execution of code. Typically used inside functions or loops to change behavior based on parameter or loop index values.
// This is a comment
Anytime the interpreter finds a double slash, the rest of the current line is ignored.
always_true()
Defines the clause "1==1". Typically only used to move a PauseIf/ResetIf to an alt group:
byte(0x1234) == 8 && (always_true() || (never(byte(0x2345) == 12) && unless(byte(0x3456) == 6)))
This allows the achievement (core group) to trigger while the never
is paused by the unless
.
always_false()
Defines the clause "0==1". Typically used for constructing alt chains:
trigger = always_false()
for test in tests
trigger = trigger || test
achievement(..., trigger = trigger)
If more than two alt groups exist, the always_false
group will be removed from the final achievement code, but you can't OR conditions together without a starting condition.
achievement(title, description, points, trigger)
Defines a new achievement with the specified title
(string), description
(string), points
(integer), and trigger
.
trigger
is an expression with one or more comparisons.
function current_board() => byte(0x0088)
function current_player() => byte(0x008C)
function trigger_win_game() => current_board() == 0x8B && current_player() == 0
achievement(
title = "Score!", description = "Win a game with at least 600 points", points = 25,
trigger = trigger_win_game() && byte(0x0573) >= 0xF6 // 0x0573 is hundreds place of score
)
First, a couple of helper functions are defined to make the code easier to read. Because all functions are inlined and evaluated on use, this expands to:
trigger = byte(0x0088) == 0x8B && byte(0x008C) == 0 && byte(0x0573) >= 0xF6
Achievement triggers support four special helper functions:
-
repeated(count, comparison)
- adds a HitCount to the condition - the specified comparison must be true forcount
frames to trigger the achievement -
once(comparison)
- shorthand forrepeated(1, comparison)
- the specified comparison must have been true at one point, but is not required to currently be true to trigger the achievement. -
never(comparison)
- this becomes a ResetIf - if the comparison is ever true, any HitCounts in the achievement are reset to 0. -
unless(comparison)
- this becomes a PauseIf - the achievement is not processed while this condition is true.
comparison
does not support logical operators, except in the case of OR with repeated
and once
, for which the result is a chain of AddHits conditions with the specified HitCount appearing on the final condition.
rich_presence_display(format_string, parameters...)
Defines the Rich Presence script. Only one string may be defined per script - if called multiple times, the last one will win.
format_string
is a string with zero or more placeholders that will be evaluated by the emulator at runtime.
For each placeholder a parameter must be defined using the rich_presence_
helper functions:
rich_presence_value(name, expression, format)
rich_presence_lookup(name, expression, dictionary)
name
is the name to associate to the placeholder.
expression
is a memory accessor, arithmetic expression, or a function that evaluates to a memory access or arithmetic expression.
dictionary
is the key to value map used to convert the result of expression
into a string.
format
is one of the following:
-
VALUE
- number (default) -
SECS
- the value is a number of seconds that should be formatted as MM:SS -
FRAMES
- the value is a number of frames that should be converted to seconds and displayed asMM:SS
-
POINTS
- the value should be displayed as a six digit score value followed by the word 'POINTS' -
MILLISECS
- the value is a number of hundredths of a second and should be displays asMM:SS.FFF
function lives() => byte(0x05D4) + 1
function stage() => byte(0x003A)
stages = { 1: "Downtown", 2: "Sewers" }
rich_presence_display("{0}, {1} lives",
rich_presence_lookup("Stage", stage(), stages),
rich_presence_value("Lives", lives())
)
rich_presence_conditional_display(condition, format_string, parameters...)
Defines a conditional Rich Presence display string. When executing the Rich Presence script, each condition is examined in order. If the condition is matched, that display string will be used. If no conditions are matched, the default display string will be used. You must still provide a default display string by calling rich_presence_display
.
Has the same structure as rich_presence_display
with the additional condition
parameter. condition
must evaluate to one or more conditions.
rich_presence_conditional_display(is_title_screen(), "Title Screen")
rich_presence_display("Playing Battle {0} in {1}",
rich_presence_value("Battle", current_level()),
rich_presence_lookup("Landscape", current_landscape(), landscapes)
)
leaderboard(title, description, start, cancel, submit, value, format)
Defines a Leaderboard script. title
and description
must be strings.
start
, cancel
, and submit
are trigger expressions similar to the achievement
's trigger
parameter, except OR conditions (||
) are not supported.
value
is a memory accessor, arithmetic expression, or a function that evaluates to a memory access or arithmetic expression.
format
is one of the following:
-
VALUE
- number (default) -
SECS
- the value is a number of seconds that should be formatted as MM:SS -
FRAMES
- the value is a number of frames that should be converted to seconds and displayed asMM:SS
-
POINTS
- the value should be displayed as a six digit score value followed by the word 'POINTS' -
MILLISECS
- the value is a number of hundredths of a second and should be displays asMM:SS.FFF