Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

This Week In Metascript Development (June 2024) - New Tags for Rolls, Line Breaks, and Template Parts, Retrieve all Items from a Table Roll

June 14 (10 months ago)

Edited June 14 (10 months ago)
timmaugh
Pro
API Scripter

Updates in this Week's Release

ZeroFrame is getting some key updates in this update, discussed in the messages that follow this one:

  • New tags for inline rolls, line breaks, and template parts
  • A way to extract all the table items from an inline roll that rolled against a rollable table multiple times

The new tags (including inline roll opening/closing tags, a new line tag, a carriage return tag, and opening/closing tags for template parts) can...

  • ...help build and format messages
  • ...help increase the readability of a complex command line that might require several metascript loops to complete
  • ...help provide a way to obscure syntax for downstream, dispatched commands spawned from your original message
  • ...other cool stuff

The ability to extract all returned items from a multi-roll against a rollable table can simplify the resolution of a given roll, presenting all items in one go.

The following posts discuss the syntax and usage for all of these new features.

EDIT: Also, a quick add-on property for Fetch, getting the "short" version of the sides property (removing the parameters from the file name)... i.e.:

  • @(selected.sides_short)
June 14 (10 months ago)
timmaugh
Pro
API Scripter

Inline Roll Brackets


Anywhere you would use inline roll brackets to designate a roll, you can now use these constructions, instead:

  FOR | USE
======|======
[[ | {&r}
]] | {&/r}


When are these detected

This tag is detected at the end of the metascript loop as the last operation prior to determining if another loop is required. In other words, it runs after all other metascripts, but prior to the un-deferring of the line and sending the message through another metascript loop.

IMPLICATION 1: Roll Deferral

Since these structures are detected after other metascripts do their work in the command line, they provide a way to defer a roll until after metascript constructions have time to resolve:

{&r} 1dget.TableMule.DamageModifier.@{selected|base_level}/get {&/r}

The above would use the base_level attribute (from the character associated with the selected token) as a look up value for a Muler table on the TableMule character. Imagine that the table translates ranges of the base_level attribute into dice types:

1=4
2-4=6
5-10=8
11-15=10
>=16=12

Since we need to wait on the resolution of the Muler get statement, we can't do this in normal inline roll brackets... those would be immediately detected by Roll20, and Roll20 would immediately try (and fail) to parse the roll, generating an error. By using these alternate meta-constructions, we give the metascripts time to resolve before letting the inline roll be detected.

IMPLICATION 2: Loop

Since these structures are detected prior to determining if we need to run another loop, they will, on their own, cause another loop to run, without any other metascript construction. This additional loop gives the roll a chance to resolve (detected and converted to standard Roll20 syntax at the end of the first loop, then that Roll20 syntax resolved at the beginning of the second loop):

!The roll is {&r}1d20{&/r} {&simple}

That command line has no other metascript construction (other than the SIMPLE tag, which is only detected at the end of all loops), yet it will process and present the roll in the final message.

IMPLICATION 3: Metascript Interaction

Since these constructions are detected after metascripts but before the message is sent back through the loop (to let the Roll20 parsers parse new inline rolls), you must think through the timing, and whether these alternate inline roll markers need to be deferred.

For instance, if your command line includes a Fetch construction:

@(selected.damage_roll)

...then during the Fetch processing, that formation is detected and expanded. If the result of this expansion is to leave damage roll, mentioned just above, in the command line:

{&r} 1dget.TableMule.DamageModifier.@{selected|base_level}/get {&/r}

However, this time we run into an issue. Since Fetch runs after Muler, Muler will not get another chance to resolve the get statement before the alternate roll markers are detected, replaced with Roll20 syntax ( [[ ... ]] ), and exposed to the Roll20 parsers. Muler will only resolve the get statement in the next loop, so we need to defer the alternate inline roll marker so that it isn't detected until the end of *that* loop. As with all metascript constructions that involve the {&} syntax, you can defer these tags with backslashes between the opening brace and the ampersand:

{\&r} 1dget.TableMule.DamageModifier.@{selected|base_level}/get {\&/r}


June 14 (10 months ago)
timmaugh
Pro
API Scripter

Carriage Returns and New Lines

Anywhere you want a carriage return or a new line, you can now use these constructions, instead:

 FOR             |  USE
=================|===========
carriage return | {&cr}
new line | {&nl}

The carriage return tag will result in a "double-spaced" line, while the new line tag will appear as a "single-space" return.

When are these detected?

These constructions are only detected and converted at the end of metascript processing, just prior to the message being released for other scripts or for the chat interface. They do not cause a new metascript loop, but are converted at the end of metascript processing regardless of whether other metascript work has been done.

Implication 1: Interaction with Standard Scripts

These are mostly intended for presentation (e.g., when the message is released to chat instead of continuing on to standard scripts), but they can be passed to other scripts, if the need presents. Be aware that the tag that is included in normal line breaks is the carriage return variation; this is the series of characters most scripts will look for to know where there is a line break. So if you want to simulate a line break as you let the command line continue to a standard script, this is likely the one you will want to use.

Implication 2: Interaction with Metascripts

Since these tags are detected at the end of metascript processing (like the {&simple} tag), they do not present much interference to other metascript constructions (for an example, see the post, below, on retrieving all table items from an inline roll).

One thing bears mentioning, however. Within a single message's loop cycle, these tags are only detected at the end of other metascript work. For those cases where the metascripts spawn another message (with a forselected operation or a ZeroFrame batch operation), the new messages are spawned *after* the metascript cycle completes.

Quick Explanation: Once the metascript work is completed, the message proceeds to the stack of standard scripts. The forselected handle of SelectManager and the double-braces of ZeroFrame are registered as standard script handles, ready to catch any message that begins that way. So the original message goes through a metascript loop cycle, then it's caught by the standard-speed handles. After this work is done to spawn new messages (for every selected token, in the case of SelectManager, or for every line in the case of ZeroFrame).

These new messages will have their *own* metascript phase, where metascripts will have the chance to do further work to them. Very likely *this* is where you want the carriage return or new line tags to be recognized (as part of presenting one of these outbound messages in the chat pane).

In order to have the carriage return or new line tags survive the original message's metascript phase (in order to be present for the outbound message's metascript phase), you will need to use the deferral opportunities afforded as a part of a forselected line or a ZeroFrame batch. Declare your deferral character, then use it to break up the tags by placing the character between the first opening brace and the ampersand.

forselected Deferral:

!forselected(^) ... {^& cr} ...

ZeroFrame Batch Deferral (line deferral option):

!{{
  (^) ... {^& nl}...
}}

ZeroFrame Batch Deferral (batch deferral option):

!{{(^)
  ...{^& cr}...
}}

Implication 3: Interaction with Roll Templates

These formations will work perfectly well in a roll template, provided that the command line begins with a bang (!). Obviously, messages that are intended to use a roll template are not typically built to use a bang since those messages would be sent to the API Moderator, where most people would be using the roll template for presentation purposes (e.g., hitting the chat output).

However, by simply beginning the line with a bang and also including the {&simple} or {&flat} tag in the command line, we can turn a roll template message first into a script message (to let the metascripts have a chance to modify the command line), then back into a standard chat message, where we output the roll template.

In that situation, where ZeroFrame will be outputting a roll templated message to chat, the carriage return and new line tags will produce line breaks of different size within the template without breaking the template.

June 14 (10 months ago)

Edited October 14 (6 months ago)
timmaugh
Pro
API Scripter

Template Parts (opening/closing double braces)

Anywhere you want to use a template part, you can now use these constructions, instead:

 FOR     |  USE
=========|===========
{{ | {&tp}
}} | {&/tp}

These can be useful if you need to hide a template part from Roll20 until after the metascripts have had a chance to modify the message.

When are these detected?

As with the line break characters in the previous post, these are only detected at the end of the metascript loop, just prior to the message being released to the chat or to a standard script. They do not cause a new metascript loop, but are converted at the end of metascript processing regardless of whether other metascript work has been done.

Implication 1: Interaction with Roll Templates

In order to have metascripts interact with a roll template, the message will need to start with a bang (!), and include a {&simple} or {&flat} tag somewhere in it. That will trigger the metascripts to take a look at the message. Since the intent of the message is to output a roll template, then at the end of the metascript loop, the message (and template) will be sent to the chat. Prior to this, these template part tags will resolve into their double-brace configurations. That means that when the final rendering of the message is sent to the chat output, the double-brace characters will be in the command line, and they will denote the closing or opening of template parts in the command.

For instance:

!&{template:default} {{name=Proof of Concept}} {{First=This is the first box{&/tp}{&tp}Second=This is the second box}}{&simple}


Implication 2: Interaction with ZeroFrame Batching

ZeroFrame batching wraps a series of commands in double-braces so that they can share rolls, queries, and variables between lines. Because double-braces are used as the boundaries for the batch, ZeroFrame offers "sub-able" options for each (opening and closing) if you need to include a set somewhere within the batch. These are discussed at the link.

While the new template part tags do provide another way to hide double-brace formations within a ZeroFrame batch, provided they are deferred (without deferral, they would be resolved to the double-brace text by the time the batch operation -- operating at standard script speed -- would see the message):

!{{(^)
  !token-mod{^&tp} --set currentside|1{^&/tp}
}}

...they do not allow for multiple-line sub commands the way the batch substitutions do. That is, this will NOT work:

!{{(^)
  !token-mod{^&tp}
    --set currentside|1
  {^&/tp}
}}

Instead, use the batching substitution variation:

!{{
  !token-mod({)
    --set currentside|1
  (})
}}

June 14 (10 months ago)
timmaugh
Pro
API Scripter

Retrieve All Table Items from Inline Roll

Consider the following roll:

[[ 4t[MaleNames] ]]

That roll will retrieve four items from the rollable table named "MaleNames." However, only one of the returned items will be displayed in the chat, with the others only visible if you hover over the roll result:


This can be less than ideal.

With ZeroFrame's new .items syntax, you can extract all of the returned table items in the roll. It works much the same as the .value syntax, in that you append it as a suffix to an inline roll, but where .value retrieves the single, displayed return from the roll (either the calculated number from a math-based roll or the displayed return from a table-roll -- e.g., the "Underpunch" name from the above image), the .items syntax will retrieve all items returned from the table.

[[ 4t[MaleNames] ]].items

The Delimiter

The default joining delimiter is a comma:


You can declare a different delimiting string of characters by placing them inside parentheses immediately following the .items:

[[ 4t[MaleNames] ]].items(|)

The above would use a pipe as the delimiter:

The following option shows using " -- " as the delimiter:

[[ 4t[MaleNames] ]].items( -- )

All characters between the parentheses are utilized as the delimiter, so if you need to include a closing parentheses in your delimiting string, you will need to enclose it in one of the three quotation mark enclosures:

" ... "  |  quotation marks
' ... ' | apostrophes
` ... ` | ticks

For instance, if you wanted to present each option in the list of returns as enclosed by their own set of parentheses, you could use this formation:

([[4t[MaleNames]]].items(") ("))

Which you should read as outer parentheses enclosing the roll:

( ... )

...(which are really the opening parentheses of the first return and the closing parentheses of the last return), and the roll being joined by everything between the quotation marks -- a closing parentheses and opening parentheses pair. That formation would produce something like:

You do not need to utilize quotation mark enclosures simply for a space.

You can combine the joining of the table items returned from a roll with the new ZeroFrame tags. This is helpful if, for instance, you want to see all of the returned items on their own line. For this you would use one of the line break tags mentioned in the previous post: {&cr} or {&nl}

[[4t[MaleNames]]].items({&cr})


Delimiter Deferral

As with the .value syntax, this retrieval of items from an inline roll happens whenever the .items syntax is detected as affixed to a roll which has resolved. ZeroFrame searches for this pattern once before the loop of metascripts begins, once after every metascript has had a chance to modify the message during each loop, and once again as one of the first things that is done when the message is released to other scripts or the chat output.

The previous example, using the new carriage return tag, works because the carriage return tag is resolved only at the very end of processing. In other words, the tag is still present in the line when it comes time for the items returned from the table need to be joined with the delimiter... so they are joined with a carriage return, the items display on different lines, and there was peace and celebration in the land.

On the other hand, a metascript construction that is a part of the delimiting string could be detected and processed before the roll is ready. For instance, if the roll was deferred for one loop cycle, a metascript construction in the delimiting string could be detected and processed in the meantime. This might not be what you want; you may wish, instead, to have the unresolved metascript construction be the delimiter between returned table items, so that it can resolve at a later point in the set of loop cycles.

If you want to expose constructions in your delimiter only at the point that the delimiter is used to link the returned table items, use a single delimiter character followed by a pipe before your delimiting text. What follows the pipe will be the delimiting text, so use your declared deferral character to break up text constructions and delay their detection:

[[4t[MaleNames]]].items(^|"@^(selected.delim)")

The same rules apply for wrapping the delimiting text in some form of quotation marks, which would allow you to include a closing parentheses (as the above example shows, utilizing a Fetch construction). In a similar vein, if your delimiting text would have a pipe as the second character, ZeroFrame will interpret the first character not as part of the delimiting text but as a deferral character. This is another time when you would want to use some quote-enclosure to wrap the delimiting text so that the pipe is instead considered part of the intended delimiting text.

As an example, consider the difference between:

[[ 4t[MaleNames] ]].items(^|Some^Text)

...and...

[[ 4t[MaleNames] ]].items("^|Some^Text")

The first option will interpret the caret as a deferral character, and use as the delimiter:

SomeText

The second option will interpret the entire string as the delimiting text:

^|Some^Text

When are these detected?

As mentioned, the .items syntax is detected anytime it is attached (as a suffix) to an inline roll that has processed and has a value assigned to it. If the associated roll is never resolved or does not exist, this construction will return "0". If the associated roll does resolve but does not have table items, this construction will instead return the value of the roll. For instance:

[[1d20]].items

...is functionally equivalent to...

[[1d20]].value

Implication 1: Recursion

Under normal circumstances, items returned from a table are not processed for further parsing. This is the reason you can't typically expect an inline roll in a returned table item to be detected and processed. Instead, you'll see the roll in your return:

Since the .items construction unpacks all table items returned from the roll, any syntax will be detectable for further parsing. This includes inline rolls (like "[[1d8]]"):


.../r or /roll syntax (like "/r 1d8"):


...or other metascript constructions (like "@(selected.token_name)" ):


Thus, if you are returning an item from a rollable table which, itself, is a call to another roll against a table, you can use the .items syntax within the table item to return the items from *that* roll. For example, if you roll against the table RandomAction and unpack the return:

[[1t[RandomAction]].item

...and your returned item reads:

[[ 4t[MaleNames] ]].items({&cr})

...then you will receive 4 names from the MaleNames table, concatenated with a carriage return between them.

June 14 (10 months ago)
timmaugh
Pro
API Scripter

Fetch Gets sides_short Property for Tokens

Previously, Fetch had been able to get the "sides" property of the token verbatim, returning a pipe-separated string of all the sides for a multi-sided token (i.e., one drawn from a rollable table). The addresses, themselves, would be URI encoded, turning things like a colon into %3A and a question mark into %3F, and they also had an extra parameter tacked onto the end as a sort of cache buster. The extra parameter on the end of the URL didn't interfere with a browser's ability to present the image, but it made it difficult to use a URL directly to reference the image.

With v2.1.1, Fetch now gets a new property representing the same pipe-separated list, but this time with the URI components decoded, and with the extra cache-busting parameter removed.

@(selected.sides_short)

Use it with any token identifier (selected, token ID, token name, etc.).