More Branching Options/ja
INTERMEDIATE
THIS IS AN INTERMEDIATE ARTICLE
はじめに
これはマクロの分岐オプションの中でも「高度」な [macro():] についてのガイドだ。
MACRO: 他のマクロを実行する
マクロを書くとき、特に複雑なものを書くときに一番いいのは、すっきりと簡潔なものにして、必要以外の処理だけに絞ることだ。例えば、トークンに技能を与えるマクロを既に持っているとしたら、、攻撃の命中判定やダメージ・トークンを記録するといった機能をそのマクロに追加するべきではない。技能だけにするのだ。
こういう、つまり比較的小さな機能のみを持つようにするやり方は、中身を理解しやすいし、見通しもよくなる(し、何かおかしなことが起こったときに修理もしやすい)。さらに、メモリの使用量も減らせるから、stack overflow errorsや、よくある実行速度の低下を起こさないで済む。
だが、これを実践するためには複数のマクロを連携させる必要があるが、それはどうやったらできるだろうか? 当然だが何か起こるたびに自分でいちいちボタンを押すなんてごめんだよね? そこで [macro():] ロール・オプションの出番だ。
どんなことをするのか?
[macro():] ロール・オプションは、あるマクロ(呼び出し側)が別のマクロ(呼び出され側)のマクロを起動できるようにする。呼び出し側マクロは呼び出され側マクロに情報を送り、その呼び出され側マクロでこの情報を処理し、だいたいは編集して、それからもし必要なら呼び出され側から呼び出し側に別の情報を送り返す。
どうしてそんなものを使わなきゃならないの?
このオプションが便利なのは以下の三つの場合だ: 第一に、通常行っている処理とは別の処理を時々やらなければならない場合。第二に、みんなで使うマクロが欲しいとき。第三に、この中でも一番強力な使い道だが、自分自身以外の複数のトークンを操作したいとき、だ。この場合、呼び出され側のマクロを頻繁に使うことになる。なぜなら、呼び出され側のマクロにしかできないことがあるからだ。
複数箇所から共通の処理を呼び出す
HitPoints
property). How many ways can you think a token might get damaged?第一の利点について見てみよう。例として、Sample Ruleset に合わせてトークンにダメージを与えるマクロを考えてみる(つまり、トークンの属性値を参照し、そのトークンのHitPoints
属性値からダメージ分を減らすマクロだ)。そのトークンがダメージがどれほど沢山のパターンでダメージを受ける可能性があるか分かるかな?
- It could get damaged by an attack from an enemy
- It could get damaged by an attack from a friend (accidental or otherwise)
- It could get damaged by falling
- It could be damaged by a trap
- 敵の攻撃
- 味方の攻撃(事故だったり、そうでなかったり)
- 落下
- 罠
HitPoints
to be reduced, but each also has some special processing to determine just how much HP reduction takes place (it's not important what the special processing is at the moment). ありとあらゆるパターンがありうる。さて、ダメージを扱うマクロを三つ持っているとしよう。このマクロはそれぞれEnemy Attack、Friendly Fire、Environmental Damageと呼ばれている。それぞれのマクロはどれも対象となるトークンの HitPoints
を減らすが、どれだけ減らすかはマクロごとに別の特別の処理を持っている(この特別な処理の中身は、今は重要ではない)。
HitPoints
. Consider a couple alternatives - you can:三つのマクロがあるが、共通の要素を持っている。そのどれもが最後にはトークンの HitPoints
を減らすということだ。いくつか選択肢を考えてみよう。こういうことが考えうる:
- Write each macro separately, including the calculations to reduce
HitPoints
; or - Write a fourth macro, containing just the calculations to reduce
HitPoints
, and have the three damage handler macros call that fourth to handle the final calculations.
- それぞれ
HitPoints
を減らす部分を含むマクロを別々に書く - 単に
HitPoints
を減らすだけの第四のマクロを書き、ダメージを扱うその他三つのマクロからこの第四のマクロを 呼び出し て、最終的な計算を行う
最初の選択肢の利点は、マクロの数が三つで済むことだ。だが、逆に考えると、もしそのマクロに何かの間違いがあることに気づいたらどうなるだろうか? 書き直すべき箇所が三ヶ所あることになる。二番目の選択肢では、ダメージを与えるマクロだけを修正すればいい。
みんながやる作業
上の例に基づいてマクロを作っていくと、みんなで使うようなマクロ(攻撃、防御、ダメージを受ける、ダメージから回復するなどは誰もが使うだろう)が沢山あった場合、みんなが呼び出して使うマクロが一そろいあればよくて、新しいトークンがマップ上に生まれるたびにそこに全てのマクロをコピーしなくて済む。
そんなわけで、あなたは自分のゲーム用の「ライブラリ」を作ろうと思うかも知れない(どんなゲームかはさておき)。そしてそれから、自分のトークンを作って、ライブラリ上のマクロを呼び出すマクロだけを載せておくのだ。
必ずしもマクロの総数が減らせるとは限らないということに気づいた人もいるだろう。それぞれのトークンにはライブラリを呼び出すためのマクロが必要だ。だが、あなたが(手間隙かけて)作る本当に複雑な部分のマクロは一ヶ所にまとめておくことができるのだ。そしてエラーがあったなら、その一ヶ所を修正するだけで済む。もし全てのトークンにありとあらゆるマクロをコピーしておくのだとしたら、エラーを修正するには一つ残らず全てのトークンを修正しなければならないのだ。
他のトークンに対する操作と、信頼されたマクロ
一般に、トークンがマクロを実行したり呼び出したりするときには、実行に必要な属性値や変数はそのマクロを実行しているトークン上にあるものと想定している。従って、勇者ボークがマクロ・ライブラリの中のあるマクロを呼び出した場合、そのマクロは勇者ボーク上のものに対して処理を行うものと考える。
しかし、勇者ボークにとってそれでは都合が悪い場合もある。おそらく、勇者ボークは一匹のトロールを剣でぶん殴って、そのダメージをトロールに適用して欲しいのかも知れない(だから、そのダメージが自分に対して適用されるなんてことは絶対あって欲しくないはずだ!)。彼に必要なのは、自分のではなく、トロールのトークンに対して効果を及ぼすようなマクロのはずだ。
さて、ここで問題になるのは、これまでも言ってきたとおり、プレイヤー・トークンに載っている昔ながらのマクロでは、これができないのだ。例えば、プレイヤー・トークン上のマクロは NPC トークンの属性値を操作できない。他のトークンへのアクセスは許されていないのだ。この事自体には納得してもらえると思う。プレイヤーたちに NPC の属性値を見られては困るからだ。さらに言えば、プレイヤー・トークンのマクロは他のトークンの値を変更することはできない。NPC に攻撃をかける前にそいつの装甲値をゼロに下げられるようでは困るからだ。
だが、そうは言っても、他のトークンに対して多少何かをしたいよね? その対応として信頼されたマクロの概念が考案された。信頼されたマクロとは、そのマクロを呼び出したトークン以外のトークンの属性値を操作するなどの、他のマクロにはできないことが可能なマクロのことだ。
どうやって使うの?
[macro():] はロール・オプションなので、これまで見てきた他のロール・オプションと同じように、行の先頭に置き、最後はコロンで終わる。[macro():]の基本書式は以下の通り:
[MACRO("macroName@Lib:token"): macro_arguments]
[MACRO("マクロ名@Lib:token"): マクロの引数]
上の例の中にあるパーツは以下の通りだ:
- The opening and closing square brackets ([ ]), which surround all macro commands in MapTool
- The word "MACRO" (it does not have to be capitalized; that's done to keep it noticeable!), which is just the name of this particular roll option
- macroName: this is the name of the macro you wish to call
- @: this is used in the same sense as in an email address - it means "at"
- Lib:token: this is the Library Token that contains the macro you wish to call. Library tokens are a complex subject, but you can think of them as a single token that holds a "library" of macros, that can be called by other tokens or call each other.
- macro_arguments: an argument is a programming term for information that you send to a function (or in this case, a macro) that you want the function to do something to. If you had a function that added two numbers together, the numbers you send to it would be the "arguments" to that function.
- MapToolが持つあらゆるコマンドを囲む、一組の大カッコ([ ])
- "MACRO" というワード(大文字でなくても構わない。目立つようにこうしてあるだけだ)。これはこのロール・オプションの名前だ。
- マクロ名: これはあなたがこのマクロにつけた名前だ。
- @: これはメールアドレスと同じ使い方だ。意味は「at(=~の場所の)」だ。
- Lib:token: これは呼び出したいマクロを持つLibrary Tokenだ。ライブラリ・トークンは複雑だが、複数のマクロの「ライブラリ」を持つ一つのトークンと見なすことができる。このトークンは他のトークンを呼び出したり、逆に他のトークンから呼び出されたりできる。
- マクロの引数: 引数はプログラミングの用語で、何か仕事をさせたい関数(ここではマクロ)にあなたが与える情報のことだ。例えば二つの数を足し合わせる関数があるとしたら、あなたがその関数に与える二つの数が、その関数の「引数」ということになる。
そんなわけで、上に挙げたコマンドの例では、「ライブラリ・トークンLib:tokenの中にあるマクロ名というマクロを実行しろ。そのマクロにはマクロの引数を与えろ」と指示したことになる。プログラミング用語ではこれを、「マクロの呼び出し」とか、「マクロ呼び出しの生成」と呼ぶ。
[MACRO():]
.次では [MACRO():]
の使い方を理解するためにいくつか実例を挙げてみる。
引数と戻り値を扱う
プログラミング用語で言う関数とは、上で簡単に述べたようにいくつかの引数を受け取り、その引数について何らかの処理をして、それから呼ばれた場所に値を返すもののことだ。マクロのロール・オプションは厳密には関数ではないが、使い方はほぼ同じだ。他のマクロを呼び出し、引数を与える。その呼び出されたマクロは(あなたがそのように書いておけば)呼び出したマクロに値を返すことがある。
マクロを呼び出す場合には、好きな変数、文字列、数値を引数にすることができる(つまり、マクロの引数と書いてある部分は、変数、文字列、数値に好きに置き換えることができ、それが呼び出すマクロに渡される)。例えば、こういう例を考えてみよう:
- There is a Library Token called "'Lib:MT which has a macro called Use Power.
- You have a token for Bork the Brave, which has a macro called Shield Bash. This is one of Bork's powers.
- You want to send the name of the power to Use Power, which will run the standard procedures to resolve the use of a power.
- Lib:MTという名前のLibrary Tokenがあり、その中にはUse Powerというマクロがあるとする。
- 勇者ボークのトークンがあって、そのトークンはShield Bashというマクロを持っている。これはボークのパワーの一つだ。
- Use Powerマクロに対してパワーの名前を渡したい。このマクロはパワーの使うときの標準処理を行ってくれる。
ボークのマクロが Lib:MTのUse Powerマクロを呼び出すには、以下のコマンドを持つShield Bashマクロを作成しなければならない。
[macro("Use Power@Lib:MT"): "Shield Bash"]
[macro("Use Power@Lib:MT"): "Shield Bash"]
よろしい。これでマクロUse Powerに情報を渡すことができた。ところで…Use Powerマクロの方はこの情報をどういうふうに認識するのだろうか?
特殊変数 macro.args
macro.args
is created. This variable is visible (that is, can be accessed, changed, or read) only by the macro being called, and it contains whatever you substituted in for macro_arguments. So, in our example above, macro.args
is equal to "Shield Bash". So, for example, in the macro Use Power, you might have a line that says:マクロを呼び出すと、macro.args
という特殊変数が生成される。これは呼び出された側のマクロだけから見える(つまり、アクセス、変更、読み出しが可能な)変数で、マクロの引数の部分に入れたものがすべて格納されている。だから上の例で言うなら、macro.args
は"Shield Bash"と等しいことになる。なので、例えば、Use Powerマクロの中にはこういう部分があるはずだ:
[h:powerName = macro.args]
[h:powerName = macro.args]
macro.args
, and assign it to the variable powerName
." From then on out, the variable powerName
will have the value "Shield Bash" (if we continue our example from above). Note that you don't have to do this - you can also just refer to macro.args
wherever you need to.ここでは、「このマクロでは、macro.args
の値を読み出し、これを変数powerName
に代入しろ」と言っていることになる。これ以降、変数powerName
は"Shield Bash"という値を取る(上の例のままになっていれば、だが)。なお、必ずしもこの通りにしなくても良いという点には注意。必要ならどこででも macro.args
を参照していい。
macro.args
like any other variable - it can read it, it can change it, it can add it to something - anything you would do with a variable. You could even ignore it!ここで、呼び出されたマクロは他の変数と全く同じように macro.args
を使うことができる。読み出しても、変更しても、他の何かと連結させてもいい。他の変数に出来ることなら何でもしていい。何なら全く使わなくても構わないんだ。
もちろんこの情報は、呼び出し側から呼び出される側への一方通行になる。では、その反対方向に情報を渡したい(つまり、値を返したい)ときにはどうしようか?
特殊変数 macro.return
macro.args
. You can output text to chat and update token properties, even. But you migh also want the results of all that processing to be sent back to the calling macro - maybe you use it to create part of a string, and you need to send that piece back to be assembled into the final output you want to send to chat. 呼び出され側のマクロの中では、 macro.args
にさまざまな処理を加えることができる。テキストをチャットに出力し、トークンの属性値を更新したりも。だが、関数の中で行われた処理の結果を呼び出し側のマクロに送り返したりもしたいんじゃないだろうか。おそらく、それを文字列の一部として組み込み、最後にチャットに出力するようにするのに使えるだろう。
macro.return
, which will be sent back to the calling macro. Assume, then, that the macro Use Power creates a variable called powerResultText
that needs to be sent back to Bork's macro Shield Bash before it finishes. To do this, somewhere at the end of Use Power, you'd add this line:この場合、返したい値をmacro.return
に代入すればうまくいく。この変数は呼び出し側のマクロに返されるのだ。では、Use PowerマクロがpowerResultText
という変数を生成したとして、それを戦士ボークのShield Bashマクロへ、それが実行を終える前に返さなければならないのだと考えよう。これを行うには、Use Powerマクロのどこかにこういう部分を追加する必要があるだろう:
[h:macro.return = powerResultText]
[h:macro.return = powerResultText]
macro.return
will be equal to whatever powerResultText
is set to, and Shield Bash can then use the variable macro.return
for further processing.ここで、特殊変数macro.return
の値はpowerResultText
と同じになる。そしてShield Bashマクロはこのmacro.return
を使って処理を続けることができるのだ。
二つのマクロを並べて見てみる
macro.args
and macro.return
variables. Make sure to check out the Sample Ruleset if you're not familiar with some of the various game terms. Also, note that these are not complete macros that include all of the possible classes and powers in the game, but a sampling to illustrate the use of [MACRO():]
. 以下の例はこれまでに述べてきた二つのマクロだ。マクロの呼び出しや、二つの変数macro.args
と macro.return
を説明するために二つ並べておいた。
もしまだゲームの用語に不慣れなら、Sample Rulesetで確認してほしい。また、ここにあるのは、ゲーム内に登場するすべてのクラスやパワーを網羅したマクロの完成品ではなく、[MACRO():]
の説明のためのサンプルだという点に留意してほしい。
Shield Bash Macro | Use Power Macro |
---|---|
<!-- Call the Use Power macro -->
[MACRO("Use Power@Lib:MT"): "Shield Bash"]
<!-- Receive the variable macro.return after Use Power has finished processing.-->
[h:hitValue = macro.return]
<!-- Use IF to check the value of hitValue, and choose an option -->
[h,if(hitValue == 1),CODE:
{
[damageRoll = floor((1d6+Strength)/2)]
[special = "Roll 1d6. On a 4 or better, the foe is stunned for three rounds."]
};
{
[damageRoll = "None"]
[special = "No special effect."]
}]
<!-- Display the Damage result and special effect -->
<b>Damage: </b> [r:damageRoll]<br>
<b>Special: </b> [r:special] |
<!-- Receive macro arguments -->
[h:powerName = macro.args]
<!-- Do a switch to find the power's Attack Bonus -->
[h,switch(powerName):
case "Sword": attackBonus = 2;
case "Bow": attackBonus = 0;
case "Shield Bash": attackBonus = -1;]
<!--Make the Attack Roll-->
[h:attackRoll = 1d20 + Strength + attackBonus]
<!-- Check to see if the attack succeeds (a roll of 15 or higher is a hit) -->
[h,if(attackRoll >= 15),CODE:
{
[successText = "a success!"]
[hit = 1]
};
{
[successText = "a failure."]
[hit = 0]
}]
<!--Display the attack result and the success, and then send
back the success info for final processing-->
The [r:powerName] attack is [r:successText].<br>
[h:macro.return=hit] |
Shield Bash マクロ | Use Power マクロ |
---|---|
<!-- Use Power マクロを呼び出す -->
[MACRO("Use Power@Lib:MT"): "Shield Bash"]
<!-- Use Powerの実行が終わるまえに、変数 macro.return を受け取る -->
[h:hitValue = macro.return]
<!-- IF を使って変数 hitValue の値をチェックし、オプションを選ぶ -->
[h,if(hitValue == 1),CODE:
{
[damageRoll = floor((1d6+Strength)/2)]
[special = "1d6を振り、4以上が出たら敵一体が3ラウンドの間気絶する"]
};
{
[damageRoll = "None"]
[special = "特殊効果なし"]
}]
<!-- ダメージの結果と特殊効果を表示する -->
<b>ダメージ: </b> [r:damageRoll]<br>
<b>特殊効果: </b> [r:special] |
<!-- マクロ引数を受け取る -->
[h:powerName = macro.args]
<!-- パワーの Attack Bonus を決めるために switch を使う -->
[h,switch(powerName):
case "Sword": attackBonus = 2;
case "Bow": attackBonus = 0;
case "Shield Bash": attackBonus = -1;]
<!-- 攻撃ロールを行う -->
[h:attackRoll = 1d20 + Strength + attackBonus]
<!-- 攻撃が成功したかどうか判定する(出目が15以上なら命中) -->
[h,if(attackRoll >= 15),CODE:
{
[successText = "命中!"]
[hit = 1]
};
{
[successText = "はずれ!"]
[hit = 0]
}]
<!-- 攻撃の結果と成否を表示し、最後の処理を行うために成否の情報を返す -->
The [r:powerName] の攻撃は [r:successText].<br>
[h:macro.return=hit] |