{ "name": "Meta Macros", "script": "compile.js", "version": "1.1", "previousversions": ["1.0"], "description": "# Meta Macros\n\nThis script extends the Roll20 macro \"language\" by enabling:\n\n* comments `\/\/ like this one`\n* multi-line commands, indicated by `\\` at end of line\n* textual inclusion of other macros using `$include macroname`\n* **textual substitution macros** like\n`$attack(hit,dam) = \/me hits AC [[1d20+{hit}]] for [[1d8+{dam}]] damage`\n\nMacros written in this extended format can be cross-compiled into standard Roll20 macros for execution.\n\nNote that the term *macro* in the Roll20 context refers to scripts containing multiple commands.\nWe use the term *meta-macro* to refer to C-style macros (i.e. textual substitution rules).\n\n## Syntax\n\n#### Comments\n\nWhenever two forward-slashes `\/\/` are encountered, the remainder of the line is treated as a comment and stripped.\n\n#### Multi-line commands\n\nWhenever a backslash `\\` is encountered at the end of a line, the backslash will be stripped and the line will be concatenated with the following line.\n\n#### Including macros\n\nThe `$include macroname` command (which must appear on a line of its own) will cause the content of the macro `macroname` to be included in the current macro, in place of the `$include` command.\nAn exception to this is that if a macro has previously been included, it won't be included again (this prevents infinite circular includes).\n\n#### Meta-macros\n\nMeta-macro definitions take the format\n\n```\n$name(param_0, ..., param_n) = body\n```\n\nwhere `name`, `param_0` ... `param_n` are identifiers, i.e., non-empty strings consisting of alpha-numberic characters and\/or `_`.\nFor meta-macros without any parameters, the `(` brackets `)` can be omitted.\n\nAfter a meta-macro has been defined, any occurrance of `$name(arg_0, ..., arg_n)` will be replaced with the `body` of the meta-macro definition.\nHere any occurance of `{param_0}` ... `{param_n}` in `body` will be replaced with `arg_0` ... `arg_n`, respectively.\nIf `arg_0` ... `arg_n` contain any meta-macro invocations, these will be resolved first.\nIf the number of arguments does not match the number of parameters in the meta-macro definition, missing arguments will be treated as the empty string, while extra arguments will be discarded.\nFor meta-macro invocations without any arguments, the `(` brackets `)` can be omitted.\n\nIf the `body` in a meta-macro definition contains any meta-macro invocations, these will be resolved at the time of definition (this prevents infinite circular resolution).\nAs a result the order of meta-macro definitions matters:\n\n```\n$attack = [[1d20+$bab]]\n$bab = 5\n\/me hits AC $attack\n```\n\nwill compile into `\/me hits AC [[1d20+$bab]]` as `$bab` was undefined at the time `$attack` was defined.\n\n#### Numerical evaluation (since 1.1)\n\nWhen using the `:=` operator in a meta-macro definition, the body will be evaluated numerically. Supports `(` brackets `)`, operators `+`, `-`, `*` and `/`, and functions `ceil` and `floor`. Evaluation takes place after substitution, so care must be taken about operator precedence as usual:\n\n```\n$pow = 1 + floor(10/4)\n$dam := 2 * $pow\n```\n\nwill first substitute the body of `$dam` to `2 * 1 + floor(10/4)` and then evaluate it to `4`.\n\n## Example\n\n\\_inc\\_stats:\n\n```\n$bab = 6 \/\/ base attack bonus\n$str = 5 \/\/ strength modifier\n```\n\nattack:\n\n```\n$include _inc_stats\n$pow = floor(1+$bab\/4) \/\/ power attack\n$hit(mod) = [[1d20cs>19+[[$bab+$str-$pow{mod}]]]]\n$dam(dice,str_mult,bonus) = [[{dice}+[[floor($str{str_mult}){bonus}]]]]\n\/\/ main hand attack gets full strength bonus and power attack\n$att_main(hit_mod) = $hit({hit_mod}) AC for $dam(1d8,,+2*$pow) damage\n\/\/ offhand attack is light weapon => half strength bonus and no power attack\n$att_off(hit_mod) = $hit({hit_mod}) AC for $dam(1d6,*0.5) damage\n\n&{template:default} {{name=Full Attack}} \\\n{{1st (MH) = $att_main}} \\\n{{2nd (MH) = $att_main(-5)}} \\\n{{1st (OH) = $att_off}} \\\n{{2nd (OH) = $att_off(-5)}}\n```\n\nHere macro *attack* will compile into\n\n```\n&{template:default} {{name=Full Attack}} {{1st (MH) = [[1d20cs>19+[[6+5-floor(1+6\/4)]]]] AC for [[1d8+[[floor(5)+2*floor(1+6\/4)]]]] damage}} {{2nd (MH) = [[1d20cs>19+[[6+5-floor(1+6\/4)-5]]]] AC for [[1d8+[[floor(5)+2*floor(1+6\/4)]]]] damage}} {{1st (OH) = [[1d20cs>19+[[6+5-floor(1+6\/4)]]]] AC for [[1d6+[[floor(5*0.5)]]]] damage}} {{2nd (OH) = [[1d20cs>19+[[6+5-floor(1+6\/4)-5]]]] AC for [[1d6+[[floor(5*0.5)]]]] damage}}\n```\n\nwhich can be executed as normal.\n\n## Chat commands\n\nNote that all compilation will replace any existing content of the target macro.\n\n#### Compile a specific source macro into a target macro\n\nThe `!compile sourceMacro targetMacro` command will compile `sourceMacro` into `targetMacro`.\n\n#### Compile a specific source macro\n\nThe `!compile sourceMacro` command will compile `sourceMacro` into `_sourceMacro_`.\n\n#### Compile all source macros\n\nThe `!compile all` command will compile all macros which (1) do not start with `_`, and (2) contain extension-specific code.\n\nTo avoid unnecessary compilation of include files, it is recommended to start their name with `_`, e.g. `_inc_common_macros`.\n\n## Known issues\n\n#### Escaping special characters\n\nThere is currently no way to escape characters `$`, `\/` or `\\` to ensure they are treated as normal characters.\nAs a workaround, you can define meta-macros for this:\n\n```\n$dollar = $\n$empty =\nThe $dollar()empty command evaluates to the empty string.\nThis \/$empty\/ is not a comment.\nAnd this is not a \\$empty\nmulti-line command.\n```\n\n#### String literals\n\nString literals `\"like this one\"` in the macro text do not receive special treatment. This means that e.g.\n\n```\n\/w \"Guy with\/\/weird name\" Hello weirdo!\n```\n\nwill be compiled into\n\n```\n\/w \"Guy with\n```\n\n#### Compile all\n\nThe `!compile all` command will consider a script to contain extension-specific code if any line in that script starts with `$`,\neven if this line is not an `$include` statement or meta-macro definition.", "authors": "Henning Koehler", "roll20userid": 470716, "useroptions": [], "dependencies": [], "modifies": { "macro": "write" }, "conflicts": [] }