Macros:Branching and Looping/ja
INTERMEDIATE
THIS IS AN INTERMEDIATE ARTICLE
分岐と繰り返し
はじめに
このページでは、MapToolの分岐と繰り返しの構造について詳しく説明している。if() ブロック文を除いて、これらはすべて ロールオプション であり、ロールオプションの一般的な形式に従うべきである。
[option1[,option2]: body]
h
) to hide the default output of the loop or branch).これらは他のロールオプションと組み合わせる事ができる(下記の例文の中には、 Hidden Roll ロールオプション h
を使用し、繰り返しや分岐の出力を抑制しているものがあることに事に注意)
複数のロールオプションを1つの文中に組み合わせたいのであれば、各ロールオプションをコンマ(,)で区切り、ロールオプションの並べた最後にコロン(:)を置く事。いくつかの組合せ([if():] と [macro():] など)は予期しない結果を産み出す事に注意するように。
例えば、秘匿ロール HIDDEN とトークンオプション [token():] と繰り返しオプション [foreach():] を1文の中で組み合わせたい場合、次のように入力すると良い:
[h,token("JoeRandom"),foreach(item, TokensItemList): "This item's name is "+item+"!"]
分岐
IF オプション
初出: バージョン1.3.b46
この [if():] は上述の通りロールオプションであるが、処理内容はブロック形式の if() と似ている。
使用方法
[if(条件): 真の内容; 偽の内容]
- または
[if(条件): 真の内容]
true_body
or false_body
will be used, depending on the value of condition
. If the false_body
is not given but the condition
is false
(0
), then there is no output.条件
の値に従って、真の内容
もしくは偽の内容
が使用される。偽の内容
が与えられず、条件
が偽の場合は、何も出力されない。
例
[h:val=12]
[h,if(val == 12): newVal=12*12]
New Value = [r:newVal]
New Value = 144
が出力される。
注記
『if』の条件を評価する別の方法については、関数 if() を参照。ロールオプションは特定の順番で実行されることが保証されていない為、ロールオプション [if():] とロールオプション [macro():] は(うまく)組み合わせる事ができないことに注意。こういった使い方をする場合は if() 関数を使用する方が良いだろう。
SWITCH Option
Introduced: Version 1.3.b46
[switch():] chooses among several options and executes code based on the switch expression.
- Note that the
expression
is a regular expression, so metacharacters such as*
and()
will need to have backslashes in front of them if you want to match them literally.
Usage
[switch(expression):
case case1: body1;
case case2: body2;
default: default_body]
or with a code block:
[switch(expression), code:
case case1: {body1};
case case2: {body2};
default: {default_body}]
Example
[h:powerType="at-will"]
[switch(powerType):
case "at-will": "You may use this power as much as you like";
case "encounter": "You may only use this power once per encounter";
case "daily": "You may only use this power once per day"
]
Outputs You may use this power as much as you like
Using a code block:
[h:powerType="at-will"]
[switch(powerType), code:
case "at-will": {
[r:token.name]:<br>
[r:"You may use this power as much as you like"]
};
case "encounter": {
[r:token.name]:<br>
[r:"You may only use this power once per encounter"]
};
case "daily": {
[r:token.name]:<br>
[r:"You may only use this power once per day"]
};
]
Using regex:
[h:powerType=".*sword.*"]
[switch(powerType):
case "flail": "one-handed weapon; two-handed does Str*2 damage";
case "shortsword": "used for jabs, so is a puncturing weapon";
case "longsword": "a slashing weapon"
]
Outputs used for jabs, so is a puncturing weapon
. Notice that the first matching clause was the one that the [switch():] option found.
MACRO Option
Introduced: Version 1.3.b46
[macro():] runs the named macro, inserting its text into chat.
Usage
[macro("macro_name@location"): macro_arguments]
The called macro sees a variable called macro.args
which contains the value of macro_arguments
. The called macro can set a variable called macro.return
, which becomes available to the calling macro. Other than macro.return
, the called macro shares no variables with the calling macro.
Examples
[macro("getDamage@Lib:combat"): damageRoll]
Calls the macro getDamage
which resides on a library token called Lib:combat
, and passes the variable damageRoll
as an argument to the called macro.
Location Requirements
The location
can be one of the following:
TOKEN
- the currently impersonated token (use the wordTOKEN
, not the token's name)CAMPAIGN
- macros from the Campaign panel (the panel does not need to be open or visible on the screen)Library Token
- a Library Token in the current campaignthis
- if the macro is calling another macro in the same library,this
may be used instead of retyping the full library token name
Notes
When a token macro calls another macro, the macro instructions in the called macro are executed against the calling token (in other words, the macro uses properties available on the calling token and applies all results to that token), unless the focus is explicitly changed to another token via either a roll option, or the switchToken() function, or the getLibProperty() function.
Also, as of at least 1.3.b50, a variable must be given for macro_arguments
, or the
"Could not execute the command: Undefined function: MACRO"
error will result. However, the variable given as macro_arguments
doesn't have to be used.
TOKEN Option
Introduced: Version 1.3.b48
[token():] executes a series of instructions against a token specified in the argument rather than against the token running the macro.
This is a temporary change in the token that has the "focus" - only the instructions following the colon are applied to the designated token; following the end of that instruction block, operations resume being performed against the token running the macro.
To permanently switch (for the duration of the macro) the token against which macro commands are executed, see the switchToken() function.
Usage
[token(token_identifier): ]
Executes the roll against the token specified by token_identifier
, which can either be the token name or token id.
Examples
[h:target="Orc 5"]
[h,token(target): targetAC = getProperty("AC")]
Uses the getProperty() function to retrieve the property AC
from the token named "Orc 5"
, and assigns that value to the variable targetAC
. targetAC
can be used in future calculations, such as determining whether an attack hits. If the [token():] option was not used, the macro would have looked for the property AC
on the token currently running the macro. Note also that this function is considered trusted.
Looping
COUNT Option
Introduced: Version 1.3.b41
The [count():] option executes a statement for a specified number of times, storing the number of the current iteration in a variable called roll.count
.
Usage
[count(num): body]
[count(num, separator): body]
The roll.count
variable will take on values from 0
to (number of loops - 1)
. The optional separator (default ","
) is printed between each iteration.
Example
[h:numHits=3]
[count(numHits): Damage = Damage + 1d12]
This will iterate the Damage = Damage + 1d12
operation 3 times, separating the result of each iteration with the default separator (a comma). An optional second argument to [count():] allows the setting of a different separator.
FOR Option
Introduced: Version 1.3.b46
Executes a statement for a number of iterations based on a start and end value.
Usage
[for(var, start, end): body]
[for(var, start, end, stepsize): body]
[for(var, start, end, stepsize, separator): body]
The var
variable counts from start
to 1
short of end
during the loop (so the end
number will not be part of the loop). The optional stepsize
(default +1
) is added to var
at each iteration. The loop does not evaluate when var
reaches end
.
Example
[for(i,10,0,-2): "i is now " + i]
Counts down even numbers from 10 to 2.
FOREACH Option
Introduced: Version 1.3.b46
Iterates over the contents of a string list in the format "item1, item2, item3"
, the contents of a JSON Array, or the keys of a JSON Object.
Usage
[foreach(var, list): body]
[foreach(var, list, output_separator): body]
[foreach(var, list, output_separator, list_separator): body]
[foreach(var, jsonarray): body]
[foreach(var, jsonarray, output_separator): body]
[foreach(var, jsonobject): body]
[foreach(var, jsonobject, output_separator): body]
Example Using a List
[h: enemyList="Orcs, Goblins, Ogres, Trolls"]
[foreach(enemy, enemyList, "<br>"): "You really hate " + enemy]
Outputs:
You really hate Orcs You really hate Goblins You really hate Ogres You really hate Trolls
Example Using a JSON Array
[h: weapons = json.append("[]", "Longsword", "Dagger", "Bow")]
[foreach(wpn, weapons): wpn]
Outputs:
Longsword, Dagger, Bow
Example Using a JSON Object
[h: weaponData = json.set("{}",
"Name": "Longsword",
"Damage": "1d6",
"Type": "Slashing",
"Weight": 30,
)]
[foreach(field, weaponData): field]
Outputs:
Name, Damage, Type, Weight
If you really wanted to see the key and the data, try this:
[h: weaponData = json.set("{}",
"Name": "Longsword",
"Damage": "1d6",
"Type": "Slashing",
"Weight": 30,
)]
[foreach(field, weaponData):
field + ": " + json.get(weaponData, field)]
Outputs:
Name: Longsword, Damage: 1d6, Type: Slashing, Weight: 30
P.S.: Note the trailing comma after the Weight field in the json.set() function? It's ignored. But putting it in makes it easier to copy/paste new lines into the function...
WHILE Option
Introduced: Version 1.3.b46
Repeatedly executes a statement until a condition becomes false.
Usage
[while(condition): body]
[while(condition, separator): body]
Example
[h:num=10]
[while(num>=0): num = num-1]
Outputs 9,8,7,6,5,4,3,2,1
Code Execution
CODE
Introduced: Version 1.3.b46
The [code():] option is used in conjunction with looping / branching options to execute multiple statements within a single "block" of a loop or branch, allowing the creation of more complex loops and branches.
Usage
[code: { code_block }]
The code_block
is a collection of text and macro code, enclosed in a single {}
pair. Everything within the {}
is treated as a single block for the purposes of any looping or branching options.
Example
[h:num=5]
[while(num > 0), code:
{
This is iteration [r:num] <br>
There are [r:num-1] iterations left<br>
[num=num-1]
}]
Outputs:
This is iteration 5 There are 4 iterations left 4, This is iteration 4 There are 3 iterations left 3, This is iteration 3 There are 2 iterations left 2, This is iteration 2 There are 1 iterations left 1, This is iteration 1 There are 0 iterations left 0
NOTE: the digit output at the beginning of each line is an artifact of the [while():] loop's evaluation of num
- since this roll does not have the [h:] option active, the result of that evaluation is displayed.
Nested CODE Blocks
To nest code:{}
blocks, use a second [code():] option, like so:
[h:d20roll=1d20]
[h:attackRoll=d20roll+AttackBonus]
[h,if(attackRoll >= 16),code:
{
[if(d20roll == 20),code:
{
The attack is a critical hit!
[h:damage=critDamage]
};
{
The attack is a hit!
[h:damage=regDamage]
}]
};
{
The attack misses!
}]
MapTool can only handle two levels of nested code.
Additions
Conditional Operators:
>
- Greater than<
- Less than>=
- Greater than or equal to<=
- Less than or equal to==
- Equal to!=
- Not equal
Logical Operators:
&&
- And||
- Or
It is important to note that the Equal condition operator must be two equal signs. If you are checking for a text string, place quotes around the text.
Operator Precedence:
( )
- Parentheses are always done first; they can be nested!
- Logical NOT&&
- Logical AND||
- Logical OR