#freeze
TITLE:応用スクリプト(Ver16.8.1)

#contents

////////////////////////////////////////////////////////////////
~

*変数を知ろう[#app01]
項目参照:[[変数>commands/var#var]]・[[保存変数>commands/var#datavar]]・[[全域変数>commands/var#globalvar]]・[[臨時全域変数>commands/var#temp_globalvar]]
>「スクリプト例1」
>
変数 hensu = 100
>
変数 hensu = 120
>//ここで変数値が「120」になる。
>
>
「スクリプト例2」
>
変数 hensu = 100
>
変数 hensu += 10
>//ここで変数値が「110」になる。
>
>
「スクリプト例3」
>
変数 hensuStr = "変数でございます"
>
>
「スクリプト例4」
>
変数 hensu = (120 * 1.0)
>//変数値は「120.000000」になる。
<
-変数は、以下の表をモデルとして説明されます。
|~変数名|hensu|
|~変数値|100|
変数とは「なんらかの名前に値を持たせて、その名前を指定すれば個別に値の設定や変更ができるようにするもの」と書き表せます。
--上のモデルにおいては、コマンド「変数 hensu = 100」を設定して、「hensu」という名前(変数名)に「100」という数値を持たせています。
''値は常に直近のものが適用される''ので、たとえばこの次に同じ「hensu」という変数名を用いて、コマンド「変数 hensu = 120」を設定すると、「hensu」が持つ数値は「100」ではなく「120」となります。
|~変数名|hensu|
|~変数値|100|
↓「変数 hensu = 120」
|~変数名|hensu|
|~変数値|120|
--変数値(変数の持つ値)には''テキストを用いることも可能です''。
ただし、この場合には変数値の先頭と末尾に「"」を付与することが必要となります(この場合の「"」はテキストとして扱われません)。たとえば、コマンド「変数 hensuStr = "変数でございます"」は、以下のモデルで表されます。
|~変数名|hensuStr|
|~変数値|変数でございます|
--「値を変更する」ためには、変数に対して四則演算を行います。
たとえば、変数名「hensu」の持つ値が数値の「100」であるとして、コマンド「変数 hensu += 10」を設定すると、10が加算され、変数名「hensu」の持つ値は「110」になります。
|~変数名|hensu|
|~変数値|100|
↓「変数 hensu += 10」
|~変数名|hensu|
|~変数値|110|
演算子を変えれば、減算・乗算・除算も可能です。
また、テキストに対して加算(テキスト結合)も可能です。
|~変数名|hensuStr|
|~変数値|変数でございます|
↓「変数 hensuStr += "わ"」
|~変数名|hensuStr|
|~変数値|変数でございますわ|
なお、''数値とテキストとで加算を行うことはできません''。
--''数値は、整数値で設定してから演算に整数値を使用し続ける限りにおいて整数として扱われ、小数値が介入した時点からは小数値として扱われます''。
小数値を整数値に戻すには、LVN関数「lvRoundToInteger」「lvFloor」を用います。
-変数値には「数値」「文字列」「真偽値」「LIST」「HASHMAP」というタイプが存在し、''設定時点でのタイプは以降に変更することができません''。
たとえば、タイプを数値に設定した変数は、以降常に数値のみを持ちます。文字列を持たせようとするとエラーとなります。
-コマンド「変数」で設定した変数は、''設定時のスクリプト内でのみ使用できます''。
--新たにスクリプトを読み込む(設定時のスクリプトがスタック最上位でなくなる)と、コマンド「変数」で設定された既存の変数は''すべて一時的に無効化されます''。
新たなスクリプト上では過去に設定したものと同じ変数名を使用することができます。
ただし、''変数が抹消されるわけではない''ため、設定時のスクリプトがスタック最上位に戻れば再度使用することができます。
--コマンド「スクリプト終了」によってスクリプトが抹消された場合には、そのスクリプトで設定した変数が''すべて抹消されます''。
--上記の無効化や抹消を回避したい場合には、コマンド「臨時全域変数」を用いて変数を設定します。
臨時全域変数はスクリプトをまたいで使用することができ、ロードや再起動で抹消されます。
-セーブデータ毎に値を持つような変数を設定する場合には、コマンド「保存変数」を用います。
保存変数は''セーブ時にセーブデータへ記録され、ロード時にはセーブデータに記録された値で再設定されます''。
-一般変数、臨時全域変数、保存変数は、エンジン終了とともに抹消されます(セーブデータ内の変数は対象外)。
この初期化を回避したい場合には、コマンド「全域変数」を用います。
全域変数はコマンド「全域変数保存」を適用するか、セーブをすることによって、フォルダ「SaveData」内の「global.xml」に保存されます。
全域変数は起動時に再設定されますが、ロード時には再設定されません。
-コンピューターにおける変数は、浮動小数点演算のもたらす10進数表現の制限によって近似値が用いられることがあります。
したがって、途中計算も含めて、''可能な限り小数の計算を回避する''ことが推奨されます。
--2進数で演算を行うコンピューターでは、数値は2のn乗(nは整数)刻みで表現されます。
あるコンピューターが2の-10乗まで表現することができると仮定すると、最も精細な10進数の小数値は2~(-10)=0.0009765625です。
さて、この場合において、精細度未満の10進数(例:0.0009765621)は表現することはできません。したがって、切り上げか切り捨てとなります。
また、そもそも2のマイナス乗で表現できない数値も存在します(例:0.3)。
これらはすべて近似値で扱われるようになるため、それが積み上がれば有意な誤差となります。



////////////////////////////////////////////////////////////////////////////////////////////////



*変数を代入しよう[#app02]
項目参照:[[変数>commands/var#var]]
>「スクリプト例1」
>
変数 hensu = 100
>
文字速度 (hensu)
>//「文字速度 100」が適用されます。
文字速度 {{hensu}}
>//「文字速度 100」が適用されます。
>
>
「スクリプト例2」
>
変数 hensuStr = "変数です"
>
文字 word1 100 100 100 mojimoji.ttf 40 (hensuStr)
>//「文字 word1 100 100 100 mojimoji.ttf 40 "変数です"」が適用されます。
>
>
「スクリプト例3」
>
変数 hensuStr = "変数です"
>
文字 word1 100 100 100 mojimoji.ttf 40 "{{hensuStr}}"
>//「文字 word1 100 100 100 mojimoji.ttf 40 "変数です"」が適用されます。
<
-変数はただ演算をするだけではなく、スクリプトにおいて利用することもできます。
以下では、その利用方法のひとつ、「変数の代入」について説明します。
-前述のように、変数値には「数値」と「文字列」があります。そして、いずれの場合でも、変数名が存在します。
そして、''「()」または「{{}}」で変数名を囲む''ことで、変数値を代入することができます。
--数値に対しては、「()」「{{}}」のいずれにおいても、値が整数であれば整数が、小数であれば小数が代入されます。
---変数名「hensu」が数値「100.000000」を持っている場合において、スクリプトのコマンド行に「(hensu)」と記述すると、その記述は「(hensu)」ではなく「100.000000」として扱われるようになります。
したがって、この場合において、コマンド「文字速度 (hensu)」を設定すれば、それはコマンド「文字速度 100.000000」として扱われます。
---変数名「hensu」が数値「100」を持っている場合において、スクリプトに「{{hensu}}」と記述すると、その記述は「{{hensu}}」ではなく「100」として扱われるようになります。
したがって、この場合において、コマンド「文字速度 {{hensu}}」を設定すれば、それはコマンド「文字速度 100」として扱われます。
--テキストに対しては、「()」を用いると「"」で囲まれたものが代入されますが、「{{}}」を用いるとテキストのみが代入されます。
---変数名「hensuStr」がテキスト「変数です」を持っている場合において、スクリプトのコマンド行に「(hensuStr)」と記述すると、その記述は「(hensuStr)」ではなく「"変数です"」として扱われるようになります。
したがって、この場合において、コマンド「文字 word1 100 100 100 mojimoji.ttf 40 (hensuStr)」を設定すれば、それはコマンド「文字 word1 100 100 100 mojimoji.ttf 40 "変数です"」として扱われます。
---変数名「hensuStr」がテキスト「変数です」を持っている場合において、スクリプトに「{{hensuStr}}」と記述すると、その記述は「{{hensuStr}}」ではなく「変数です」として扱われるようになります。
したがって、この場合において、コマンド「文字 word1 100 100 100 mojimoji.ttf 40 "{{hensuStr}}"」を設定すれば、それはコマンド「文字 word1 100 100 100 mojimoji.ttf 40 "変数です"」として扱われます。
--''テキストに対しては「{{}}」による代入のみが使用でき、「()」による代入は使用することができません(コマンドの設定項目「テキスト」内でも同様)''。
したがって、たとえば「文字 word1 100 100 100 mojimoji.ttf 40 "(hensuStr)"」は、「(hensuStr)」が文字列として扱われて、「変数です」の代入にはなりません。
-''代入は「{{}}」から「()」の順に処理されます''。したがって、原則として「{{}}」の中に「()」を用いることは無く、二重代入は「()」の中に「{{}}」を用いて実現させます。
-代入は、ゲームの進行や状況、設定に応じて変化しうるような''コマンドの設定項目において用いることが多いです''。
ただし、すでに設定を終えているコマンドは、変数値が変更されただけではその変更をコマンドに反映しません。したがって、''変数値の変更を反映させるためには、そのコマンドを再設定する必要があります''。
''変数の代入は、あくまでコマンドの設定時において効果を発揮するものである''ということに注意しましょう。
--コマンド「変数式確認機」を用いることで変数値の変化に追従する表示を実装することは可能ですが、処理の衝突等に注意する必要があり、技術水準は高めになります。



////////////////////////////////////////////////////////////////////////////////////////////////



*変数を要素にして条件分けをしよう[#app03]
項目参照:[[もし>commands/var#if]]
>「スクリプト例」
>
"いつかそうなっても、変わらずにいてやるからな。\w
変数 flag1 = 1
>
(中略)
>
ボタン btn1 400 200 80 ジャンプ scenario1a.txt
ボタン文字 btn1 font1.ttf 20 "無理なんだろうか"
ボタン btn2 600 200 80 ジャンプ scenario1b.txt
ボタン文字 btn2 font1.ttf 20 "おまえだけならできる"
もし (flag1 == 1) ボタン btn3 400 400 80 ジャンプ scenario1c.txt
もし (flag1 == 1) ボタン文字 btn3 font1.ttf 20 "約束だからな"
>//「flag1」の変数値が1であれば、コマンド「ボタン btn3 400 400 80 ジャンプ scenario1c.txt」「ボタン文字 btn3 font1.ttf 20 "約束だからな"」が適用されます。
<
-条件分岐は、ゲームにおいて一般的に用いられる機能です。ノベルゲームにおいても、進行度によってストーリーや機能の解放を行う作品があります。
そのような分岐は、変数とコマンド「もし」を併用することで実装できます。
-分岐は変数を用いて判定を行います。
''変数が条件に合致する場合と合致しない場合のそれぞれに対してコマンドを割り振る''というのが、コマンド「もし」の動作となります。
--物語のある部分を読めば、その後に隠し選択肢が表示されるようにしたいという場合を想定しましょう。
まずは、“ある部分”の直後にフラグとして適当な変数を設定します。この説明においては、コマンド「変数 flag1 = 1」と設定しておきます。
それから、選択肢を表示するスクリプト行に移動し、コマンド「もし (flag1 == 1) ボタン btn3 400 400 80 ジャンプ scenario1c.txt」(コマンド「タッチ素材設定」は設定済としています)と設定します。
すると、“ある部分”を読んだ直後に変数名「flag1」の変数値は1となり、選択肢のスクリプト行で「flag1 == 1」の条件に合致するため、コマンド「ボタン btn3 400 400 80 ジャンプ scenario1c.txt」が設定されるようになります。
この場合においては、条件に合致しない場合に設定されるコマンドが指定されていないので、もし変数名「flag1」の変数値が1ではない、または変数名「flag1」を持つ変数が存在しない場合には、特に動作することなく次の行へ移ります。
-複雑な分岐を作ろうとすると、条件や分岐先を見失いやすくなります。
頭の中で考えるだけではなく、時には樹形図等のアナログな方法も用いて、分岐とその条件を把握しておくようにしましょう。



////////////////////////////////////////////////////////////////////////////////////////////////



*正規表現に触れてみよう[#app04]
項目参照:[[命名について>command#command1a1]]
外部参照:[[正規表現の構文>https://msdn.microsoft.com/ja-jp/library/cc392020.aspx]]
>「スクリプト例1」
>
絵 ~save_d1 sc1.png 50 50 60
ボタン ~save_slot1 slot.png slotmo.png slotmo.png 600 80 80 セーブ 1
ボタン ~save_delete1 sdb.png sdbmo.png sdbmo.png 680 75 80 セーブ削除 1
>
(中略)
>
アウト ~save.*
>//「~save_d1」「~save_slot1」「~save_delete1」が退場します。
>
>
「スクリプト例2」
>
絵 ~save_d1 sc1.png 50 50 60
ボタン ~save_slot1 slot.png slotmo.png slotmo.png 600 80 80 セーブ 1
ボタン ~save_delete1 sdb.png sdbmo.png sdbmo.png 680 75 80 セーブ削除 1
絵 ~save bar1.png 50 400 70
>
(中略)
>
アウト ~save.+
>//「~save_d1」「~save_slot1」「~save_delete1」が退場します。「~save」は退場しません。
>
>
「スクリプト例3」
>
マクロ "【(.*)】" "変数 nvar = \"$1\""
>
【ひしあ】
>
文字 txtbox_namestr 100 520 150 fontom.ttf 28 "{{nvar}}"
>//コマンド「文字 txtbox_namestr 100 520 150 fontom.ttf 28 "ひしあ"」が適用されます。
<
-コマンドの対象名を指定する際に、多数の個体を指定しなければならない場合があります。
たとえば、コンフィグ画面やセーブ・ロード画面では数十個の個体を設定することになるでしょうが、その画面の個体のみをすべて退場させたい場合において、通常はすべての個体名を記述することが必要になります。
しかし、そのような面倒を解消する方法として、「個体の命名時において、正規表現に適した命名をする」というものがあります。
-正規表現とは、ここでは一般法則に基づく正しい表現という意味ではなく、「システムが各種の条件を考慮しつつ文字列を判別できるようにするために、システム上の規則に従う表現」という意味です。
正規表現を用いることで、「特定の文字や単語を含まないものすべて」「数字を持つ文字列すべて」などの条件を表すことができ、これを対象の複数指定が可能なコマンドの対象名に用いることができます。
そのような条件に適合させやすいような処理として、''個体名に共通部分を持たせておくとよい''でしょう(コンフィグ画面の個体の先頭には「c_」を用いる等)。
-正規表現では、メタ文字と呼ばれる特殊文字''「.」「^」「$」「[]」「*」「+」「!」「?」「|」「()」''を用います。メタ文字は、正規表現として使われる場合には普通の文字ではなくなります。したがって、''メタ文字を普通の文字として用いたい場合には、その記号の直前に「\」を記述する必要があります''(例:コマンド「アウト \^btnace」)。
-以下では、メタ文字の持つ意味を紹介します。
--''「.」:改行文字を除く任意の文字1個''
改行文字「\n」を除くあらゆる文字の1個を表します。
たとえば、「end.」は「end」の後方にあらゆる文字を取り、「ends」「endo」「end1」などを表します。
--''「^」:先頭''
この記号以降の文字列が先頭に存在することを表します(「[]」との併用時においては別の意味を持ちます)。
たとえば、「^st」は「st」を先頭に取り、「start」「strike」「stock」などを表します。
--''「$」:末尾''
この記号以前の文字列が末尾に存在することを表します。
たとえば、「ly$」は「ly」を末尾に取り、「likely」「lily」「cheerfully」などを表します。
--''「[]」:中の文字のいずれか1個''
囲んだ文字のいずれか1個を表します。囲んだ文字が複数あるとしても、表すのは1個となります。
メタ文字を囲むこともできますが、扱いは普通の文字と同じになります(「\」「]」は例外的にメタ文字扱いになります)。
また、「0-9」はすべての数字を、「a-c」はすべての英小文字を、「A-Z」はすべての英大文字を一気に指定できます。
たとえば、「[春夏秋冬]」は「春」「夏」「秋」「冬」のいずれか1個を表します。
「A-[0-9]」は「A-0」「A-8」「A-5」などを表し、「[A-Z]703」は「C703」「X703」「L703」などを表します。
「room[0-9A-Z]」は「room」の後方に数字または英大文字を1個取り、「room2」「roomD」などを表します。
--''「*」:直前の文字1個が存在しない・直前の文字1個の任意回数の繰り返し''
この記号の直前の文字1個に関して、それが存在しない、またはそれが任意回数繰り返し存在していることを表します。
たとえば、「うわあ*」は「あ」を取らないか任意の個数取り、「うわ」「うわあああ」「うわああああああああ」などを表します。
--''「+」:直前の文字1個の任意回数の繰り返し''
この記号の直前の文字1個が任意回数繰り返し存在していることを表します。
たとえば、「うわあ+」は「あ」を任意の個数取り、「うわあ」「うわあああ」「うわああああああああ」などを表します。
--''「?」:直前の文字1個が存在しない・直前の文字1個がその箇所で複数個連続して存在しない''
この記号の直前の文字1個に関して、それが存在しない、またはそれが1個だけ存在していることを表します。
たとえば、「うわあ?」は「あ」を取らないか1個だけ取り、「うわ」「うわあ」を表します。
「cakes?」は「?」を取らないか1個だけ取り、「cake」「cakes」を表します。
--''「|」:複数文字列の区別''
この記号を挿入することによって、その前後で文字列を区切ることができます。
たとえば、「mine|craft|x|japan」は「mine」「craft」「x」「japan」のいずれも表します。
--''「()」:複数文字のグループ化''
囲んだ文字列を1個単位として扱います。これによって、1個の文字に対して意味を持つメタ文字と文字列とを組み合わせることが可能になります。
また、囲んだ文字列は記憶され、記憶された文字列は「$x」(xは数値)へ1回限りで代入されます。「x」には、代入したい文字列を記憶した順番を記述します。
なお、「()」が代入ではなく記憶のために用いられるのは、「()」をテキストで用いている場合に限られます。
たとえば、「(イェイ)+」は「イェイ」を任意の個数取り、「イェイ」「イェイイェイ」「イェイイェイイェイイェイイェイイェイ」などを表します。この場合において、「イェイイェイ$1」は「イェイイェイイェイ」を表します。
-以下では、メタ文字の組み合わせやバックスラッシュの使用等によって可能な条件付けの一部を紹介します。
--''「.*」:文字が存在しない・すべての文字・すべての文字列''
「.*」は、文字が存在しない・すべての文字・すべての文字列のいずれかを表します。
これを用いれば、「特定の文字や単語を含むすべての個体名」「先頭または末尾に特定の文字や単語を持つすべての個体名」「ある部分のみにあらゆる文字を許容する個体名」を表現できます。
ただし、''「.*」の箇所に文字を持たない場合も含まれる''ことに留意する必要があります。
---''「特定の文字や単語を含むすべての個体名」''
これは“特定の文字や単語”の先頭と末尾のそれぞれに「.*」を付与することで表現できます。
たとえば、「単語『save』を含むすべての個体名」は、「.*save.*」と表現します。
---''「先頭または末尾に特定の文字や単語を持つすべての個体名」''
これは“特定の文字や単語”の末尾に「.*」を付与すれば「先頭に特定の文字や単語を持つすべての個体名」を、先頭に「.*」を付与すれば「末尾に特定の文字や単語を持つすべての個体名」を表現できます。
たとえば、「先頭に『c_』を持つすべての個体名」は、「c_.*」と表現します。
---''「ある部分のみにあらゆる文字を許容する個体名」''
これは“ある部分”に「.*」と記述することで表現できます。
たとえば、「『ch_』と『_10』との間になんらかの文字があるか、またはそこに文字が存在しないという個体名」は、「ch_.*_10」と表現します。
--''「.+」:すべての文字・すべての文字列''
「.+」は、すべての文字・すべての文字列のいずれかを表します。
これを用いれば、「特定の文字や単語を含むすべての個体名」「先頭または末尾に特定の文字や単語を持つすべての個体名」「ある部分のみにあらゆる文字を許容する個体名」を表現できます。
---''「特定の文字や単語を先頭と末尾以外に含むすべての個体名」''
これは“特定の文字や単語”の先頭と末尾のそれぞれに「.+」を付与することで表現できます。
たとえば、「単語『save』を先頭と末尾以外に含むすべての個体名」は、「.+save.+」と表現します。
---''「先頭または末尾に特定の文字や単語を持つすべての個体名」''
これは“特定の文字や単語”の末尾に「.+」を付与すれば「先頭に特定の文字や単語を持つすべての個体名」を、先頭に「.+」を付与すれば「末尾に特定の文字や単語を持つすべての個体名」を表現できます。
たとえば、「先頭に『c_』を持つすべての個体名」は、「c_.+」と表現します。
---''「ある部分のみにあらゆる文字を許容する個体名」''
これは“ある部分”に「.+」と記述することで表現できます。
たとえば、「『ch_』と『_10』との間になんらかの文字がある個体名」は、「ch_.+_10」と表現します。
--''「[^]」:文字の除外''
「[^]」は、「[^」と「]」とで囲んだ文字以外の文字であることを表します。
これは「[]」による文字の表現の否定形であり、「^」が単独の場合と異なる意味になっています。
たとえば、「l_[^d]」は「l_」の後方にd以外の文字1個を取り、「l_a」「l_p」などを表します。
「t_[^0-9]」は「t_」の後方に数字以外の文字1個を取り、「t_b」「t_K」などを表します。
--''「\d」:任意の数字1個''
「\d」は、任意の数字1個を表します。「[0-9]」と同じ意味です。
--''「\D」:数字以外の任意の文字1個''
「\D」は、数字以外の文字1個を表します。「[^0-9]」と同じ意味です。
--''「\s」:空白1個''
「\s」は、スペースやタブ等の空白1個を表します。
--''「\w」:単語用の文字1個''
「\w」は、単語で用いられる文字1個を表します。「_」(アンダースコア)も含まれますが、空白は含まれません。
--''「(?!)」:除外''
「(?!」のあとに特定の文字や単語を記述し、その末尾を「)」で閉じると、「特定の文字や単語を含まない」という条件を表現できます。
これと「.*」とを併用すれば、「特定の文字や単語を含まないすべての個体名」「先頭・末尾に特定の文字や単語を含まないすべての個体名」「ある部分のみに特定の文字や単語以外を持つ、あるいはそこに文字を持たない個体名」を表現できます。
ただし、この正規表現は''テキスト内でのみ適用可能です''。したがって、「"」で前後から挟んでおく必要があります。
---''「特定の文字や単語を含まないすべての個体名」''
“特定の文字や単語”を「(?!」と「)」とで囲み、先頭と末尾にそれぞれ「.*」を付与すれば、「特定の文字や単語を含まないすべての個体名」を表現できます。
たとえば、「文字『a』を含まないすべての個体名」は、「.*(?!a).*」と表現します。
---''「先頭・末尾に特定の文字や単語を含まないすべての個体名」''
“特定の文字や単語”を「(?!」と「)」とで囲み、その直後に「.*」を付与して、それを先頭に記述すれば「先頭に特定の文字や単語を含まないすべての個体名」を表現でき、末尾に記述すれば「末尾に特定の文字や単語を含まないすべての個体名」を表現できます。
たとえば、「文字『a』を先頭に含まないすべての個体名」は、「(?!a).*」と表現します。
---''「ある部分のみに特定の文字や単語以外を持つ、あるいはそこに文字を持たない個体名」」''
“特定の文字や単語”を「(?!」と「)」とで囲み、その直後に「.*」を付与して、それを“ある部分”に記述すれば、「ある部分のみに特定の文字や単語以外を持つ、あるいはそこに文字を持たない個体名」を表現できます。
たとえば、「『title_』と『_01』との間に『end』を持たないすべての個体名」は、「title_(?!end).*_01」と表現します。
-それでは、コマンドにおける具体的な使用例を挙げるので、理解の確認をしてみましょう。
--''「セーブ画面の個体のみをすべて退場させる」''
この場合には、個体の個体名を設定する際において、先頭に「save」と記述するよう統一したうえで、退場させる時のコマンドは「アウト save.*」と記述します。
--''「BGM以外の個体をすべて退場させる」''
コマンド「背景音」には個体名の設定項目がありませんが、エンジン上では「vn_sysBGM」という個体名が与えられます。
したがって、「BGM以外のすべての個体」は、「(?!vn_sysBGM).*」と表現します(他の個体の個体名に「vn_sysBGM」を用いないよう注意しましょう)。
そして、BGM以外のすべての個体を退場させるコマンドは「アウト "(?!vn_sysBGM).*"」となります。
--''「特定の選択肢のみを残す」''
選択肢のボタンの個体名において、先頭に「optn_」と記述し、直後には1~4の数字を用いて、4つの選択肢を表示しているとしましょう。
この場合において、たとえば個体名「optn_3」のみを保持して残りを退場させるコマンドは「アウト "optn_(?!3).*"」となります(コマンド「アウト "optn_(?!3)\d"」でも可能ですが、これに関しては外部参照をお願いします)。



////////////////////////////////////////////////////////////////////////////////////////////////



*マクロ機能を使ってスクリプト記述を簡略化しよう[#app05]
項目参照:[[マクロ>commands/script#macro]]
>「スクリプト例」
>
マクロ "dfco" "100 200 50"
>
(中略)
>
絵 ch1 ch1_1.png dfco
>//コマンド「絵 ch1 ch1_1.png 100 200 50」が設定されます。
>
(中略)
>
絵 ch2 ch2_1.png dfco
>//コマンド「絵 ch2 ch2_1.png 100 200 50」が設定されます。
<
-多くの作品において、スクリプトはシナリオよりも記述量が増えます。大量のコマンド、設定項目、テキストを記述するうちに、「まったく同じ記述を何度も行っている」という状況があるかもしれません。
そのような場合において大いに効果を発揮するのがマクロ機能です。
-マクロ機能とは、''「スクリプト上に存在する特定の文字列を異なる文字列に置換する」''というものです。
コマンドの設定以降のスクリプト文においては、特定の文字列が登場する度に置換が行われ、その結果がスクリプトとして反映されます。
したがって、特にコマンドの設定項目において頻繁に用いられる単語や数値にマクロ機能を適用すると、スクリプトの記述量を減らすことができます。
-マクロには「マクロ(通常マクロ)」「コマンドマクロ」「文字マクロ」が存在します。
--通常マクロは、すべての記述において変換を行います。
--コマンドマクロは、コマンド行において行頭または設定項目にコマンドを渡せる箇所においてのみ変換を行うコマンドで、それ以外のコマンド行内の箇所やテキスト行においては変換を行いません。
--文字マクロは、テキスト行およびコマンド「文字」「文字窓」の初期テキスト値においてのみ変換を行うコマンドで、一般のコマンド行においては変換を行いません。
-コマンド「マクロ」においては、「変換対象」と「変換結果」を設定します。
--設定以降、スクリプト上で記述するのは「変換対象」です。
これには''できるだけ短く、かつスクリプト上において他のどのような文字列とも重複しない文字列''を用いるとよいでしょう。
なぜなら、変換対象の範囲はスクリプト上の記述(コメントを除く)のすべて、すなわちテキストもコマンドも範囲に含まれるからです。
したがって、コマンドの記述を対象にしたつもりが、テキストにも同様の文字列が存在し、文字窓に変換結果が表示されるということが起こりえます。
--エンジンの動作に反映されるのは「変換結果」です。
処理としては変数の代入に類似しており、「変換対象」の文字列を「変換結果」の文字列で置換します。
--通常マクロと文字マクロは、変換対象・変換結果のいずれにおいても、記述に正規表現を用いることができます。
「.*」を用いる際にはその汎用性に注意しましょう。
-マクロ機能の活用例として、「まったく同じ座標・レイヤーに画像を何度も表示する」というものを挙げて説明します。
たとえば、座標とレイヤーを順に「100 200 50」として、コマンド「絵」を、画像素材を変えつつ何度も設定することにしましょう。ここでコマンド「マクロ "dfco" "100 200 50"」を予め設定しておくと、それ以降のスクリプトに「絵 [適当な個体名] [適当な画像素材ファイル名] dfco」と記述すれば、コマンド「絵 [適当な個体名] [適当な画像素材ファイル名] 100 200 50」として処理されます。
うまく変換対象と変換結果とを記述すれば、スクリプトの記述量が減ります。「()」や「{{}}」の記述を必要とする変数の代入よりも記述がさらに簡潔になるので、ぜひ活用しましょう。



////////////////////////////////////////////////////////////////////////////////////////////////



*コマンド「スクリプト」に備わる機能「関数」を使おう[#app06]
項目参照:[[スクリプト>commands/script#script]]・[[栞>commands/script#bookmark]]
>「スクリプト例」
>
栞 kansu _dainyu1 _dainyu2 _dainyu3
>//「_dainyu1」「_dainyu2」「_dainyu3」が引数名となります。
>
文字 {{_dainyu3}} 100 (_dainyu1) 70 font10.otf 20 "{{_dainyu2}}"
>
スクリプト終了
>
(以下、別スクリプト)
>
スクリプト basis.txt kansu 200 "関数とはこういうものです" "usage"
>//コマンド「文字 usage 100 200 70 font10.otf 20 "関数とはこういうものです"」が設定されます。
<
-コマンド「スクリプト」は「スクリプトを参照するコマンド」です。
そして、コマンド「スクリプト」には特殊な参照方法:「関数」が存在します。
-関数機能とは、コマンド「栞」において設定する引数名に対して、コマンド「スクリプト」を用いて値を代入し、さらにコマンド「栞」の存在するスクリプトにおいて引数の持つ値を代入値として用いるというものです。
--通常のコマンド「スクリプト」では目的スクリプトの目的栞名までを指定しますが、ここで栞名以降にスペースを挿入して設定項目を追加してゆくと、それが順番に「引数の代入値」となってゆきます。
たとえば、コマンド「スクリプト basis.txt kansu 200 "関数とはこういうことです" "usage"」を設定すれば、引数の代入値は順に数値「200」、文字列「関数とはこういうものです」、文字列「usage」と設定されます。
---数値は数値として渡され、「"」で囲んだ文字列は文字列として渡されますが、''ただの文字列を記述した場合には、それを変数名として扱い、その変数の持つ変数値が引数に渡されます''。
--通常のコマンド「栞」では、栞名のみを設定しますが、ここで栞名以降にスペースを挿入して設定項目を追加してゆくと、それが順番に「引数名」となり、コマンド「スクリプト」で設定した代入値が順に代入されてゆきます。
たとえば、スクリプトファイル「basis.txt」内に、コマンド「栞 kansu _dainyu1 _dainyu2 _dainyu3」を設定しておくものとします。
この場合において、コマンド「スクリプト basis.txt kansu 200 "関数とはこういうものです" "usage"」を設定すると、引数名「_dainyu1」には数値「200」、「_dainyu2」には文字列「関数とはこういうものです」、「_dainyu3」には文字列「usage」が代入されます。
--代入された引数値は、栞以降のスクリプトにおいて引数名を代入値として指定すれば代入することができます。
たとえば、スクリプトファイル「basis.txt」内の、コマンド「栞 kansu _dainyu1 _dainyu2 _dainyu3」を記述してある行以降で、コマンド「文字 {{_dainyu3}} 100 (_dainyu2) 70 font10.otf 20 "{{_dainyu2}}"」を設定しておきます。
この場合において、コマンド「スクリプト basis.txt kansu 200 "関数とはこういうものです" "usage"」を設定すると、コマンドは「文字 usage 100 200 70 font10.otf 20 "関数とはこういうものです"」となります。
-関数は変数の代入に類似していますが、''引数値を代入値できるのは参照先スクリプト上の参照範囲のみである''という違いがあります。
したがって、「スクリプト終了」「スクリプト終了原点回帰」「script_fin」と記述されたスクリプト行を読込んで参照元のスクリプトへ戻れば、参照元のスクリプト上で引数名を指定しても代入は行われません。
-関数機能は、''状況によって設定項目の値が変わるコマンドを繰り返し設定する場合''において用いると効果的です。
また、設定項目の値が変わるコマンドの数が多く、引数値の代入が複数のコマンドに分散しているほど、関数機能の効率は良くなります。



////////////////////////////////////////////////////////////////////////////////////////////////



*マクロと関数機能とを組み合わせよう[#app07]
>「スクリプト例」
>
(スクリプト「cf.txt」)
>
栞 cset _name _co
>
もし (_name == "デイヴィッド") 変数 namestr = "david"
もし (_name == "エリー") 変数 namestr = "elly"
もし (_name == "アルバート") 変数 namestr = "albert"
>
もし (_co == "左") 変数 co = 300
もし (_co == "中央") 変数 co = 600
もし (_co == "右") 変数 co = 900
>
絵0 ch_{{namestr}} {{namestr}}.png (co) 50 90
>
イン ch_{{namestr}} 500
>
(別スクリプト)
>
マクロ "キャラ絵\s+(\w+)\s+(\w+)" "~スクリプト cf.txt cset \"$1\" \"$2\""
>//「キャラ絵」の後のスペースに設定する値がスクリプト「cf.txt」の栞「cset」に引数値として渡されます。
>
(中略)
>
キャラ絵 エリー 中央
>//コマンド「スクリプト cf.txt cset "エリー" "中央"」が設定され、コマンド「絵0 ch_elly elly.png 600 50 90」「イン ch_elly 500」が適用されます。
>
(中略)
>
キャラ絵 デイヴィッド 右
>//コマンド「スクリプト cf.txt cset "デイヴィッド" "右"」が設定され、コマンド「絵0 ch_david david.png 900 50 90」「イン ch_david 500」が適用されます。
>
(中略)
キャラ絵 アルバート 左
>
>//コマンド「スクリプト cf.txt cset "アルバート" "左"」が設定され、コマンド「絵0 ch_albert albert.png 300 50 90」「イン ch_albert 500」が適用されます。
<
-スクリプトの簡略化の方法として、ここまでで「正規表現」「マクロ」「関数」を扱えるようになっていることでしょう。そして「変数」と「条件分岐」についても理解が広く及んだことと思われます。
ここまで来たのならば、これらすべてを組み合わせて、スクリプトを最も簡略化された形へと進化させましょう。
-スクリプト例を参照してください。
関数のスクリプト(cf.txt)においては、「引数値による条件分岐での変数値設定」「コマンドへの変数値の代入」が行われています。
別スクリプトにおいては、「マクロの設定」「マクロにおける関数の使用」「正規表現による値の継承」「引数に対する値の設定」が行われています。
以下では、それぞれの動作に関するスクリプト記述の解説を行います。
--''「引数値による条件分岐での変数値設定」''
引数名は変数名と同様に扱うことができるため、引数名を用いて条件式を書くことができます。
今回の場合では、日本語でのマクロ記述と、個体名や素材のファイル名を英字にすることとを両立させるための方法として、''日本語の引数値による条件分岐で、対応する変数に英字の文字列を変数値として設定させています''。
--''「コマンドへの変数値の代入」''
今回の場合では、日本語で引数値を設定することによって、引数値をそのまま代入するとファイル名などへの対応が問題となる可能性があるため、引数値を変数へ設定しなおしてから代入を行っています。
--''「マクロの設定」''
マクロでは変換対象・結果の両方をテキストで記述します。したがって、変換結果のほうにコマンドを記述することも可能です。
''コマンドへの変換を行うマクロを設定する際には、コマンド名の前に「~」を置く''ようにしましょう。こうすることで、マクロの変換対象の文字列が文字窓表示用のテキストとして扱われるのを防ぐことができます。
--''「マクロにおける関数の使用」''
マクロの変換結果にコマンド「スクリプト」を記述して関数を用いる際に、引数値にテキストを用いることがあるかと思われます。その際には、''「"」の直前に「\」を付与して「\"」と記述しましょう''。
もしも「\"」と記述しなかった場合には、引数値の先頭の「"」までがマクロの変換結果として認識され、以降の記述が無効となります。
--''「正規表現による値の継承」''
今回の場合では、二つの「(\w+)」による文字列の記憶を行い、「$1」「$2」を用いてそれらを順に継承しています。
この項目のスクリプト例は正規表現を活用しているので、不明な点がある場合には、正規表現の項目へ戻ってしっかりと確認してください。
--''「引数に対する値の設定」''
今回の場合では、引数名「_name」「_co」に対して順にテキスト「"$1"」「"$2"」を引数値に設定しています。
先述の理由から、引数値の記述は「\"$1\"」「\"$2\"」となっています。