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: wildcard selection, batch operations, global variables, delay

1683751514
timmaugh
Pro
API Scripter
The metascripts, being a toolbox of various functionalities spread over a handful of different scripts, sometimes don't get the proper announcement of new features or capabilities on any individual basis. They are intended to work together with themselves and with other scripts, so I figure I will try this format of presenting new features -- where I'll roll them up into a single message. So, with that said, let's get to what you can do with them, now: SelectManager Wildcard Selection SelectManager always gave you the ability to use the {&select} tag to virtually select tokens, or to use the {&inject} tag to virtually add to the selected tokens for a given message. Both tags take a comma-separated list of token identifiers. The identifiers could be a name or an ID, and could be manually typed in or returned via Roll20 syntax of @{selected|token_id} or @{target|token_id}. {&select Bob, -M1234567890abcdef, @{selected|token_id} } With v1.0.13, any of those identifiers can now also take wildcards. You can use an asterisk (*) for "0 or more characters here", and you can use a question mark (?) for "any single character here". You can use multiple instances of these wildcards in the same identifier: MadrigalStreetLight* ...would select all light tokens named for being on Madrigal Street (imagine that they were all numbered). Skel*Horde1_* ...would select all tokens named something like "SkeletonHorde1_1", "SkeletonHorde1_2", etc. Flame?Dancer* ...would select all tokens named something like "Flame Dancer", "Flame_Dancer", "Flame-Dancer", with or without a numerical index trailing their name, but it would not select a token named "FlameDancer" because there is no character between "Flame" and "Dancer". Full Regex If you're more adventurous and comfortable with regex statements (ECMA version), you can supply the source and flags for a regex statement as your identifier. The regex must be bounded by forward slashes, and the flags should follow immediately after the trailing slash. Most of the time, the  i  flag (case-insensitive) will be the only flag you'll need: /.*?Horde1/i ...would match anything containing the string "Horde1_" (case-insensitive due to the flag,  i ). This would catch: SkeletonHorde1_1 SkeletonHorde1_2 GoblinHorde1_1 Goblinhorde1_2 Goblin_Horde1_3 GoblinMaster_horde1 etc. Using with forselected Selecting tokens with the {&select} tag happens at meta-speed, meaning they are there for whatever standard script you want to run (TokenMod, ChatSetAttr, GroupCheck, etc.). SelectManager's own  forselected  handle runs at standard-speed, so pairing the two becomes a way of quickly selecting tokens and operating over them with individual results. For example, this command will quickly select all of the light tokens named after the pattern "Floor1Lights_#", and TokenMod will set them all to the same randomized values: !token-mod --set emits_bright_light|on emits_low_light|on bright_distance|[[1d10]] low_distance|[[1d20]] {&select Floor1Lights*} However, the following forselected line issuing the same TokenMod command provides randomized results to each light: !forselected  token-mod --set emits_bright_light|on emits_low_light|on bright_distance|[[1d10]] low_distance|[[1d20]] {&select Floor1Lights*} ZeroFrame Batching Commands Technically, batching operations have been live and available for a couple of weeks. I wrote an  initial post  about the feature and wrote up more information in the  ZeroFrame wiki article , but I figured I'd give it its moment in the spotlight in this format, as well. The basic idea is that you can take a multi-line command and enclose it in  !{{ ... }} , like this: !{{   ...command 1 here   ...command 2 here   ...etc. }} The idea is that you turn a multi-line command into a single command, which bypasses the Roll20 bug where sometimes lines are missed/dropped. It also means that you can share rolls between command lines in a way not previously available. If you have a reason to use double-braces within the double-braces of the batch set, replace the double braces as follows: {{    =>  ({) }}    =>  (}) ZeroFrame Global Variables This one, too, has been available for a couple of weeks, but it never got a specific mention despite me using it to help a few people on the forum. Using the {&global} tag, you can define term-definition pairs for subsequent text replacement: {&global ([term] definition) } {&global ([term1] definition1) ([term2] definition2) } Global variables are useful for keeping track of roll results when you are unsure of what a roll's final roll index will be: {&global ([theRoll] [[2d20kh1]]) } ...or for preserving the value of a roll query so that later metascript loops have access to the resulting data: {&global ([armorMod] ?{Armor Mod|1|2|3|4|5} } This post  shows a way to use a global variable to preserve the the ability to use multiple lines within a set of double braces when you have to include another set of double braces in that section. Typically, the first closing set of double braces would end the "template part" that is defined by double open & closed braces. By using a global variable, you can sidestep the problem and continue editing the command across multiple lines. The  ZeroFrame wiki article  has a ton more information about global variables and how to use them. ZeroFrame Delay Messages As of ZeroFrame v1.1.6 (in the queue for next week's script merge), you can delay a message just by including the {&delay} tag: !token-mod --set bar1|[[1d20]] {&delay 2} The delay tag takes a numerical value representing the number of seconds to delay the command line. This can be a whole number or a decimal. What Cannot Be Delayed Roll20 constructions that are detectable in the line will be processed by the Roll20 parsers before ZeroFrame gets the chance to delay the message. Things like inline rolls, character attribute or ability retrieval, macro retrieval, token property retrieval, and roll queries -- if detectable -- will all be filled with the corresponding piece of game information prior to the command line being delayed. Deferral Because of the above fact, the delay tag also allows you to designate a deferral string to prevent other constructions from being detected too early. After removing the delay tag from the command line, the deferral string is removed from what remains, exposing the constructions to detection after the delay window expires. Designate deferral strings by enclosing them in parentheses immediately following the word "delay" in the delay tag: {&delay(^) 1.2} The above would use the caret character as a deferral string, allowing you to use it to break up other formations. A good use for deferrals might be retrieving sheet information that is potentially in the process of being updated at the point where the command line is first dispatched. By delaying the command line and deferring the detection of the sheet call, you can be sure to get the updated information: !token-mod --set bar1|[^[^1d20 + @^{Battery|power} ^]^] {&delay(^) 1} The above would delay the TokenMod command from running for (at least) 1 second (actual delay depends on processor load). Then the deferral character is removed, and the line is reexamined for syntax constructions. At that point, the inline roll is detectable, as is the attribute retrieval (for  power  on the character  Battery ). If the power attribute had updated during that 1s delay, you would get the new value. You can use deferral strings to pause the detection of any Roll20 construction, however roll queries are only prompted the one time at the top of the processing, so they will not work short of the ability to start a new message (for instance, from a chat button). You can also use deferral strings to pause the detection of metascript constructions (such as Fetch statements, Muler get statements, or SelectManager select statements), though you should remember that if you have a metascript construction within an inline roll, the roll itself will need to be slowed beyond the delayed deferral, typically with a ZeroFrame deferral (backslash). For example, the above TokenMod command, if rewritten to use a Fetch retrieval for the  power  attribute, would require the inline roll to be deferred further: !token-mod --set bar1|[^\][^\]1d20 + @^(Battery.power) \^]\^] {&delay(^) 1} Delay with Batched Messages If you include an un-deferred delay in a batch message: !{{   !setattr --sel --HooliganState|On --HooliganDuration|[[1d10]]   !token-mod --set name|Hooligan bar1|$[[0]] {&delay 1} }} ...that will be detected and processed for the top level, batching message. In other words, processing for all delay-able constructions in the batch message will be delayed. If, on the other hand, you only need to delay processing for a single line, use the batch deferral character (see the Batch section, above), to defer the delay tag, itself: !{{   !setattr --sel --HooliganState|On --HooliganDuration|[[1d10]]   (~)!token-mod --set name|Hooligan bar1|$[[0]] {~&delay 1} }} The above example would delay the TokenMod command (only) by 1s, giving the ChatSetAttr command time to finish, if necessary. A Note on Timing Messages in a batch dispatch follow one on the other at the point that they are received by ZeroFrame. If ZeroFrame has three batched command lines it needs to send, it will send the first and then wait to send the second until it receives the first message back from Roll20. It will wait to send the third message until it receives the second back from Roll20. For this reason, if you delay one of the message in the chain, subsequent messages will also be delayed in terms of  resolution  (actual parsing of the constructions in the line will have already happened for all detectable constructions, but the line will not be dispatched for resolution until the previous has been received). Any construction that needs to be obscured from the parsers until the command line is actually dispatched and under consideration should be hidden by use of a delay deferral string. Also, the subsequent message is sent at the point that it is received back from the delayed-dispatch, but it will only be fully resolved after metascript processing and any standard script processing that might follow. For this reason, you might find need to delay a message -- as I did, above, delaying the TokenMod command until after ChatSetAttr had a chance to set the attribute value.
1683751535
timmaugh
Pro
API Scripter
Examples Here are a couple of animated behaviors I mocked up using these new metascript features. Are these necessarily the way you'll want to use these features? Probably not. A custom script that did either would probably work better. However, these do showcase the versatility of the new functions, and the power of metascripts as a whole. Token Formations This one uses some batching, selecting with wildcards, selecting with regex, and iterated automation of TokenMod. Explanation of the setup and the text of the abilities used is in the pinned comment of the video: Formations - Using Metascripts to Automate TokenMod Flickering Lights This one uses batching, selection with wildcards, if/then logic, and a randomized delay to automate TokenMod. The automation is handled via a SelectManager forselected command, giving each torch or brazier an independent light value. Again, explanation of the setup and the text of the abilities used is in the pinned comment of the video: Flickering Lights - Using Metascripts to Automate TokenMod
1683816100
timmaugh
Pro
API Scripter
Narration The Aaron recently released a Narrate script that places text in the center of the map and pulls players there to see it. Using metascripts, we can automate that to change from one "chapter" to the next. Setup and commands are in the pinned comment of the video. Narration with Metascript Automation
1683848492
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
These are amazing! I will need to do a deep dive on them. I particularly like the formations.
1683854877
timmaugh
Pro
API Scripter
Thanks, Keith! I intended to add a conditional check to see if the token to be moved doesn't have a particular marker, or has some bar greater than 0... Some way to know that it's not incapacitated. Now I wonder if it might be better to expand the {&select} tag further to allow selection by bar value, marker presence, or marker value. That way you wouldn't even be selecting tokens that were marked with an x, for example... Or with a bar=0.