ZeroFrame Batching FILE LOCATION:   My Personal Repo  (beta) - 1-click version will update after beta DEPENDENCIES :  ZeroFrame  requires  libInline  (available in one-click). UPDATE ABSTRACT:  ZeroFrame  (link to original forum thread), already useful as the organizer of metascripts, now has the ability to "batch-up" multiple command lines so that they are interpreted as a single command. This not only side-steps the  dropped-lines bug , it  presents new opportunities for roll re-use across what would have been separate command lines. IDEA CREDIT:  Big thanks to TheAaron for the initial suggestion for an easier way to handle multi-command macros! Introduction Roll20 gives you the opportunity to create "macros" of commands. These can either be stored as Collections Tab Macros or as Ability Macros (on a character sheet). However, sometime in the recent past the community  started reporting  that commands would be randomly dropped from multi-command messages, making the basic functionality unreliable if not unusable.  Plugger  (another metascript) had a clunky way of circumventing the problem, but it wasn't the easiest to use. With this update, ZeroFrame will restore basic Roll20 functionality, as well as deliver certain new benefits. Basic Syntax If you have a series of commands you have to execute together, simply wrap your existing macro like this: !{{   ...commands here... }} For instance, your finished macro might look like this: !{{   !token-mod --set bar1|-1   !Spawn --name|Giant Ape --offset|1,0 }} Deferral Characters Deferral characters let you "hide" certain constructions until an individual line is dispatched, making sure the construction is only evaluated once the message has been sent. Deferral characters are removed from the outbound command line before that command line is dispatched. You can include deferral characters in two places. Defer All To declare a string of characters as your deferral string and have it apply to every command in the set of batched commands, enclose it in parentheses immediately following the opening double-brace: !{{(^)   ...   ... }} That will remove the  ^  character from every command line prior to sending. Defer For Single Line To use a deferral string for only a single command line, enclose it in parentheses and include it at the start of the line (prior to any characters other than spaces): !{{   (^)...   ... }} That would, for only the one line, remove any  ^  characters found. Considerations You can use both kinds of escape characters (escaping for all lines and separately for a given line) together. Both escaping replacements will be applied (the escape-all deferral will happen, followed by any local deferral for a given line). Deferral strings (in either location) can be more than a single character: !{{(defer)   !script --@defer(selected.attribute) }} Example 1 This uses deferrals to make sure the roll in the second command isn't evaluated until the line is dispatched: !{{   !scriptOne --args   (^)!scriptTwo --roll [^[^2d20^]^] }} Example 2 Sabor has the ability to transfer health from one familiar to the other. The names of each familiar are stored in attributes on Sabor's character sheet (FamiliarOne, FamiliarTwo). This is the macro that would send the health to his first familiar. Each command in this set requires a different token to be selected when the command is evaluated (using the  {&select ...}  syntax of  SelectManager ). !{{(^)   !script --health|+1 {^&select @(@{Sabor|FamiliarOne}.token_id)}   !script --health|-1 {^&select @(@{Sabor|FamiliarTwo}.token_id)} }} (Requires SelectManager and  Fetch ) Syntax to Avoid Handling Double-Braces Due to the limitations of Roll20 parsing (parsing that happens before mods even get a hold of the message), you should not include double-closing braces in your message except for at the end of the batch of messages. For instance,  do not do this ; it will produce unexpected results: !{{   !script {{     --arg1     --arg2   }} }} To get around this issue, you can either convert the individual command to a single line so that it doesn't require the double-braces, or you can save it as its own ability/macro and then retrieve it using Fetch. !{{   %(Sabor.AbilityName) }} Even if you don't remove the double-braces from the  AbilityName  ability, this will work because Fetch retrieves the information  after  Roll20 has finished parsing the message. Do not retrieve a command line (that includes double-braces) using standard Roll20 syntax (ie, %{Sabor|AbilityName} ) because this happens  during  Roll20's parsing, and will introduce the same problem. Another option is to replace opening and closing double braces as follows: {{   =>   ({) }}   =>   (}) Those will allow the parser to continue without unexpected results, and will be replaced appropriately by ZeroFrame before the individual message is dispatched: !{{   !script ({)     --arg1     --arg2   (}) }} Handling Templates Roll templates naturally contain double-brace elements, so you should already be porting them out to their own element as discussed just previously. However, if you have multiple different templates you want to include in the same batch (ie, the default template for one command line, an attack template for another command line, etc.), you may need to use the ZeroFrame syntax instead of the standard Roll20 syntax. Basically... just swap the & and the { In other words, this: &{template:default} ...becomes: {&template:default} Then, you will likely need to defer that construction so that it only resolves when that individual command line is dispatched (so that it applies to the new message created by that command: !{{   (^){^&template:default} ... }} New Features You Gain Not only does this batching ability circumvent the problem of randomly dropped command lines from a multi-command macro, you gain some key abilities. Re-Using Rolls Since your original message hits the parser as a single command line (before ZeroFrame parses out individual commands), all of the rolls present in any of your individual commands are evaluated at once. ZeroFrame continues to make them available to all of the individually-dispatched messages. There is one caveat to this feature, and that is that your roll markers (ie, $[[0]] ) that would let you re-use a roll  within  a command line are also now referring to the same larger pool of shared rolls. So if you were converting a macro that started as this: !script1 --arg1 [[1d20]] !script2 --arg1 [[[[1d10]]d4]] --arg2 $[[0]] ...the original way that would be parsed is that the $[[0]] of the second line would refer to the 0th roll  of that line  (the nested [[1d10]]). Once you convert this macro to batch up these commands... !{{   !script1 --arg1 [[1d20]]   !script2 --arg1 [[[[1d10]]d4]] --arg2 $[[0]] }}   ...the roll indices change (all three rolls are now in the same message). In this formation, the $[[0]] of the second line would still refer to the 0th roll, however the pool of rolls now begins with the roll from the first line. You could solve this by deferring the roll in the first line to only be evaluated when the script1 line was dispatched (useful if you don't need to re-use the roll across multiple outbound commands): !{{   (^)!script1 --arg1 [^[^1d20^]^]      !script2 --arg1 [[[[1d10]]d4]] --arg2 $[[0]] }} Or you could solve it just by incrementing your subsequent roll markers (there is a single roll prior to script2, so roll markers appearing in this line should be incremented by 1): !{{   !script1 --arg1 [[1d20]]   !script2 --arg1 [[[[1d10]]d4]] --arg2 $[[1]] }} Re-Use All Meta Process Constructions (Definitions, Logic, Mules, etc.) Since your batched message is initially treated as a single message, it will pass through a ZeroFrame metascript loop, allowing any metascripts you have installed to take action on the message as a whole. This happens before each individual message is separated out and dispatched as its own message, with its own ZeroFrame loop. To put it in concrete terms, imagine a situation where you had a number of rolls across the message, and you had to re-use a specific roll in multiple places. You  could  go through the process of counting the many indices present in the message so that you used the correct one... only to have to recount it later if you edit the commands to add/remove rolls. A better option might be to use a definition (from  APILogic ) to capture the roll index no matter what it turns out to be, then use your defined term wherever you want to use that roll: !{{ {&define ([myroll][[@{selected|die_pool}d6]])}   !script1...   !script2...   !script3 --arg1 myroll   !script4 --arg1=[[1d20]] --dmg=myroll }} As a part of the metascript processing, APILogic would define the term  myroll  to refer to the appropriate roll marker (as returned from Roll20), then replace all instances of  myroll  elsewhere in the message. The same sharing-across-command-lines would exist for mules ( Muler ), selecting tokens (SelectManager), logical evaluations (APILogic), and other meta-operations that might be later added to the metascript toolbox.