eratohoまとめ

ERB編集における代表的なエラー

このページではeramakerおよびEmueraで利用されるERBファイルの作成や改造にあたり様々なエラーや不具合が発生するということをここで晒して、後進の人たちの参考にしょうというものである。
なお、基本的にはeramaker基準ではあるが、Emueraでのエラーも記述する。
また、この項はERBの基本的な構文を理解していることを前提に書かれている。まずは各種構文講座に目を通しておこう。

なお、開発用ツールまとめで紹介されている各種ツールを利用すると基本的なミスを発見しやすくなるので是非導入しておこう。ただしTALENTの参照ミスや死に分岐など一部のエラーは発見できないので油断は禁物、自分の目で見直してしっかり確認するようにしたい。
また、前もって上のページで紹介されている各種構文講座を読んで内容を理解しておくと初歩的なミスを未然に防げるだろう。

以下の例などで[EOF]はそこでファイルが終わってることを示し、[CR]は改行を示し、□は全角の空白(スペース)を示す。いずれもここの字面どおりに入力すればいいものというわけではないので注意。またメモ帳は特に[CR]と□が分からないことに注意のこと。




ループの閉じ忘れ

 適切にインデントを設定していないことによりみずらいソースを記述してしまうと往々にしてこういう事態になってしまう。
 具体的には、
IF A == 2
^  IF B == 3
^  IF C == 4
^  ^   PRINTL Aが2でBが3でCが4です。
^  ELSE
^  ^   PRINTL Aが2でBが3ですがCは4ではないです。
^  ENDIF
^  PRINT Aが2でBが3ではないです。
ELSE
ENDIF
 上の例では3つ目のIFのインデントが適切でないため、ENDIFがひとつ不足してしまっている。これを実行すればエラーで動かなくなってしまう。
 つまり、人間は往々にしてミスしやすいので見やすいようにしっかりインデントをしておこうということである。



ループの閉じすぎ

 ENDIFが足りないから文句言われるのならば、いっぱいおけばいいじゃないなんてことももちろんない。ちゃんと適切に配置すべきである。
IF A == 2
^  IF B == 3
^  ^  PRINTL Aは2でBは3です。
^  ENDIF
^  ENDIF
ENDIF
 これなら大丈夫だろ?と思われるかもしれないが、eramaker(もしくはEmuera)内部ではつじつまが合わないことが起こると予期せぬ挙動により変なところでエラー落ちしたりフラグを破壊したりとその後の構文が全て実行されなくなったりとろくなことにならない。



SIF文にENDIFを付けてしまいました

 SIF文はその直後の1行だけで完結するのでENDIFで閉じる必要はない。これはむしろ、IF文として作ったあとにそれをSIF文に直したときにその後方のENDIFを消し忘れておこってしまうケースがありうる。
SIF A == 2
^   PRINTL Aは2です。
ENDIF
 まあ、最後にもう一度見直すとか何らかのチェッカーを通せば分かると思われるけど。ともかく、注意すべきである。



SIF文に複数の行を収めようとしてしまう

 前述の通りSIF文はその直後の1行だけで完結する。つまりIF~ENDIFと同じノリで複数行をSIF文で分岐させることはできない。これはSIF文で作った分岐に新たに処理を加える際にやらかしやすい。
SIF TALENT:MASTER:117
^   A += 100
^   B += 100
 上記の例の場合、B += 100はTALENT:MASTER:117の有無に関係なく必ず実行されてしまう。チェッカーの類では検出出来ないミスなので十分注意したい。
SIF TALENT:MASTER:117
^   A += 100
SIF TALENT:MASTER:117
^   B += 100
このように書けば一応意図通りに実行されるが、それなら最初からIF文を使って書いた方が早いしわかりやすい。
そもそも、SIF文を使わないことが最善の対策だろう。


ELSEIF を ELSE としてしまう/ ELSE IF としてしまう

 IF~ELSE~ENDIF文においてときどき以下のようなことを記述してしまってエラーを出すことがあるかもしれない。
IF TALENT:120
^   PRINTL オトコですぜ。
ELSE TALENT:121
^   PRINTL ふたなってます。
ELSE IF TALENT:122 || TALENT:123
^   PRINTL そのうち生えるかも?
ENDIF
 さて、上の例で2つのELSEはいずれもエラーだったりする。最初のはIFを忘れた例。二番目のはELSEとIFが分離しちゃった例。
 ELSEには条件文をつけられない仕様なので、どちらも正常に判定されない。
 いずれにせよこういうことがないようにすべき。



お前はもう死んでいる分岐

 IF~ELSE~ENDIF構文においてやりかねない過ちのひとつが「死に分岐」である。それ自体はエラー落ちしたりすることはないかもしれないがなるべくならそういうことはないほうがいい。
IF TALENT:120 == 1 || TALENT:121 == 1
^   PRINTL ペニスあるぜ!
ELSEIF TALENT:120 == 1
^   PRINTL オトコだぜ!
ENDIF
 さて、上の例でELSEIF TALENT:120 == 1の行が成り立って実行されることは絶対にない。つまりこの部分は「死に分岐」である。
 なぜなら、TALENT:120が存在する時点で最初のIFが実行されてしまい、次のELSEIFの判定が実行されることはないからだ。
IF TALENT:120 == 1 && TALENT:121 == 1
^   PRINTL オトコだしふたなりだぜ。
ELSEIF TALENT:120 == 1
^   PRINTL オトコだぜ!
ENDIF
 では上のようにしたら?
 もちろん、これなら下のELSEIFの条件は「死に分岐」ではなくなる。だが…、オトコでなおかつふたなりっていったいなに?これは仕様上ありえない条件なので最初のIF文が「死に分岐」となっている。
 「オトコ」「ふたなり」が両立する世界なら「死に分岐」ではないので、こっちのに関しては背景設定や世界観などを考慮しなければならないがこういう「死に分岐」にも注意すべき。




助手を見る前にまずは助手が存在するかを確かめよう

 eramakerにおいて、キャラ登録番号は全て0を含む自然数であり負の数はありえない。
 ただしASSIが存在しない場合、空白は代入できないので一時的に-1が代入される。
 そのため、助手がいない状態で助手の番号や状態を確認しようとすると「第1引数(-1)はキャラ登録番号の範囲外です」と表示されエラーになってしまう。
 何らかの形で助手を参照する場合、必ずその条件式の前にIF ASSI > 0という条件式を組み、助手が存在しない場合を弾くようにしよう。
IF ASSI >= 0
^   SIF TALENT:ASSI:0 == 1
^   ^   PRINTL 助手は処女です。
ENDIF
 また口上テンプレでは特定のキャラが助手をしているという条件式で助手の番号をY1と仮定してあることがある。
 上記の通りASSIには自然数しか入れないので、IF ASSI:NO == Y1という式があるとエラーになってしまう。
 通常この部分はコメントアウトしてあるはずなので、助手番号を指定しない場合は行頭の;を外さずそのままにしておこう。



eramakerは短絡評価なんてしない

 EmueraにおいてはIF文の短絡評価が実装されているが、eramakerには実装されていない。なので少々回りくどい構文を組む必要がある。特に便利な拡張文法を使えるEmuera専用バリアントで製作したあとにeramakerバリアントで製作すると往々にしてこのあたりをすっとばしてしまいがち。
SIF ASSI >= 0 && TALENT:ASSI:0
^   PRINTL 助手は処女です。
 上の例はEmueraならばASSIが-1(存在しない)場合、IFが成り立たないことが明白なのでその後方のTALENT:ASSI:0を評価せず無視する。そのため存在しない助手の能力を参照しようとして起きるエラーにより止まることはない。
 だが、eramakerの場合IF文の条件はみんなチェックしてしまうので、助手が存在しないときも助手のTALENTを参照しようとしてエラーが発生してしまう。
 そのため前項で説明したようにまず助手の有無を判定し、助手が存在する場合のみTALENTなどを参照するという手順が必要。



ASSIPLAYは助手の有無までは考慮しない

 多くのバリアントではASSIPLAYが真(中に数字が入っている)ならば助手調教中でことを表わしているが、ASSIPLAY自体は通常の変数でありASSIPLAYと助手調教中の関連はERBレベルで実装しているに過ぎない。そのため次のように「ASSI >= 0」の代わりとして使うのは少々危険である。
SIF ASSIPLAY && TALENT:ASSI:0 == 0 
 このコードはEmueraを用いれば多くのバリアントで意図通りに動作するが、ASSIPLAYと助手調教の関連を実装していないバリアントではエラーとなる。次のようにASSIが配列の範囲内であることをチェックする必要がある。
SIF ASSI >= 0 && ASSIPLAY && TALENT:ASSI:0 == 0
 makerでは短絡評価を行わないので、ASSI >= 0のチェックを次のように外側に持って行く必要がある。
IF ASSI >= 0
^   IF ASSIPLAY && TALENT:ASSI:0 == 0
^   ENDIF
ENDIF
 もっとも、「SIF ASSIPLAY && TALENT:ASSI:0 == 0 」がエラーとなる可能性があるバリアントではASSIPLAYの意味が違っているので、エラーは出なくとも意図通りには動かないだろう。



!= 0は-1も含まれる

 『!=』は『○○を含まない』という条件式で、つまりその数値以外の全数値が真になる。
 実はこの時負の値も範囲に含まれているので、例えばASSI != 0(助手が「あなた」ではない)ならば助手がいない時(ASSI == -1)も真と判定されるのだ。
 これが原因で範囲指定を通過した結果、後の部分でエラーを吐くこともあるので注意。
 なお、IF TALENT:0のように省略した文型で条件式を書いた場合、eramaker内部ではIF TALENT:0 != 0と解釈される。
 つまり負の値も真になるので、IF ASSIという条件式では助手がいない時を弾くことができないので注意。きちんとIF ASSI > 0と書こう。



REPEATループに注意

 REPEAT文は繰り返しの処理に便利である。ただし、勘違いしている人がいるかもしれない。
REPEAT 4
^   SIF COUNT == 4
^   ^   PRINTL 4番目
REND
 上の文において、4番目がPRINTされることは決してありえない。なぜならREPEAT 4とはCOUNTが1から4まで繰り返されるのではなくて、0から3まで繰り返されるのである。すなわちREPEAT nのnは繰り返し回数であって、COUNTの最終値から-1を引いたものが最後のループだからである。
 これを知らないといろいろと死に分岐を作ってしまうので注意だ。
 あ、あとループ終了だからって、RENDでなくてENDIFで閉じるなんて斬新なことをしてもいけない。REPEATはRENDでしか、IFはENDIFでしか閉じられない。



二重REPEAT文

 REPEAT文はCOUNTという専用の変数を制御に使いますが、COUNT自体はプログラム全体で同時に一つしか使用できないので、REPEAT文が入れ子になった二重REPEATはeramakerでは実行されません。
 しかし、REPEAT~RENDの間でCALL命令を使ってREPEAT文を実行する関数を呼び出すと、二重REPEATなREPEAT文を作ることが出来ます。
REPEAT 10
^  CALL FUNC
REND
@FUNC
REPEAT 3
REND
 二重REPEAT文を作ってしまうと、内側のREPEAT文により外側のREPEAT文の情報が上書きされ、最悪の場合無限ループになります。例えば上の例は、@FUNCの終わりでは必ずCOUNTが3になるので、呼び出し元のREPEAT文から脱出することが出来ません。
 関数を呼び出す際にCOUNTを別の変数へ待避すれば問題は起きませんが、eramakerでは確実な待避先が存在しないので、根本的な解決は出来ません。Emueraであれば、LOCAL変数を待避先に使うか、REPEAT文をLOCAL変数をカウンタにしたFOR~NEXT文に置き換えることで解決します。



コメント行に注意

 コメント行は適切に配置・記述してあれば、デバグや改造の助けになるが、ときどき失敗することがある。たとえばコメント行を記したつもりでついうっかり先頭の;を忘れてしまったり消してしまったりした場合である。
 もちろん、そのときは基本的にそこでエラー落ちするわけだが、コメント内容によってはそうでない場合もある。例えば、

 ・こうしたかった
;デバグのときはここで以下のとおりにすればお金は減らない
;なおMONEY:1は掛かった経費とする
;MONEY:1 = 0
MONEY -= MONEY:1

 これが下のようになってしまうと

 ・実際の記述
;デバグのときはここで以下のとおりにすればお金は減らない
;なおMONEY:1は掛かった経費とする
MONEY:1 = 0
MONEY -= MONEY:1

 ERB文法的には間違っていないので下の記述でもエラー落ちはしない。だが、内部挙動は全然違っているため作者が望むとおりの結果は得られていない。こういうバグもまた恐ろしいものである。
 開発用ツールまとめで紹介されているEmuera開発用サクラエディタ設定ファイル集などを使って色分けし、コメント行かどうか一目で判断できるようにしておくと便利。



PRINTFORM の FORM は大切です。

 よくあるのが%CALLNAME:MASTER%などの名前を表示するときに下のようにしてしまうことである。
PRINTL %CALLNAME:MASTER%は%CALLNAME:TARGET%を抱いた
 %CALLNAME:MASTER%は文字型変数であるのでそれの内容を表示するためにはPRINT(文をそのまま表示)ではなくPRINTFORM(変数を変換して表示)を使用しなければならない。ちなみに上の例だと
%CALLNAME:MASTER%は%CALLNAME:TARGET%を抱いた
 と表示されてしまう。
 基本的にPRINTFORMはPRINTの完全上位互換なので、よくわからなければPRINTFORMを使っておけばよい。
 また無印、L、Wの使い分けだが、PRINTFORMは改行なしで表示も止まらない、PRINTFORMLは改行ありだが止まらず次の行も表示、PRINTFORMWは改行してその行で表示を止めるというのを覚えておこう。



(関数が)かぶった!?

 eramakerでは同じ名前の関数を複数定義してもエラーは起きません。そのため、関数名を被らせてしまうと、何もエラーは出ないけど、何かがおかしいという一番困った状況に陥ります。
 同名の関数をCALLなどで呼び出した場合の優先順位は、ファイル読み込み順に依存します。同一ファイル内では、ファイルの先頭に近い方が呼び出されます。ファイルの読み込み順はeramakerではファイルシステムに依存しますが、Emueraではコンフィグである程度は制御が可能です。
 なお、RR系列の口上呼び出しはこの仕様を利用しています。
 また、イベント関数は複数同じものがあってもすべて実行する仕様(#SINGLEがある場合は特殊)になってます。イベント関数がどれであるか?というのはwikiのほかの記述や本家の記述を参考にしてください。



RANDの使い方

 RAND(乱数選出)は特に口上を書く際によく使われる便利な構文だが、使うときに気をつけるべき点がある。
 まずRAND:Xで選出される数値は0~(X-1)の間で、Xの数値が選ばれることはない。つまりIF RAND:3 == 3という分岐を作っても絶対に条件が満たされない死に分岐となってしまう。
 また、以下のようなミスも行いやすい。
IF RAND:3 == 0
 PRINTFORMW 「あ」
ELSEIF RAND:3 == 1
 PRINTFORMW 「い」
ELSEIF RAND:3 == 2
 PRINTFORMW 「う」
ENDIF
 一見それぞれ1/3の確率で表示されるようにみえるが、実際はこの書き方では等確率にはならない。RANDは利用ごとに乱数を選出し直すため、この場合「あ」が表示される確率は1/3、「い」が表示される確率は(1-1/3)×1/3=2/9、「う」が表示される確率が{1-(1/3+2/9)}×1/3=4/27となり、8/27の確率で何も表示されなくなってしまう。
 等確率で表示されるようにしたい場合、以下のどちらかの形式で書く必要がある。
IF RAND:3 == 0
 PRINTFORMW 「あ」
ELSEIF RAND:2 == 0
 PRINTFORMW 「い」
ELSE
 PRINTFORMW 「う」
ENDIF
これならば「あ」が1/3、「い」が(1-1/3)×1/2=1/3、「う」が残り1/3となり、同じ1/3の確率で表示される。
変数を利用する場合は以下のようになる。ただし変数が本体やパッチがその部分の処理で使用しているものとバッティングしないように注意。
A = RAND:3
IF A == 0
 PRINTFORMW 「あ」
ELSEIF A == 1
 PRINTFORMW 「い」
ELSE
 PRINTFORMW 「う」
ENDIF



最後の改行は重要だ。

 eramakerにおいては、ERBファイルにせよCSVファイルにせよ、最終行は読まれない。つまり、一番最後は改行してから終了しよう。
 以下はとあるERBファイルの末尾である。最終行のENDIFできっちり終わっている。
IF RESULT == 0
^    CALL REPLAY_GAME
ELSEIF RESULT != 1
^    GOTO INPUT_LOOP
ENDIF[EOF]
 さて、上の例。Emueraなら何の問題もないが、eramakerの場合、一番最終行のENDIFが認識できずにエラーになってしまう。必ずENDIFのあと改行してから保存しよう。そうすればエラーにならない。すなわち、
IF RESULT == 0
^    CALL REPLAY_GAME
ELSEIF RESULT != 1
^    GOTO INPUT_LOOP
ENDIF[CR]
[EOF]
 とすればOKである。



命令文や条件文は半角空白で区切る。

 各命令文の後ろには必ず半角スペースを入れる必要がある。
 わかりやすいようこの項では半角スペースを_、全角スペースを□と表記するが、実際書く時は「_」ではなく「 」と書くように。
PRINTL_ロードします
 下の例は両方ともeramakerが正常に解釈できずエラーが出てしまう。
 前者はPRINTLの後に空白がないため、後者はPRINTLの後に半角ではなく全角スペースを入れているため、PRINTLを命令文だと認識できないからである。
PRINTLロードします
PRINTL□ロードします
 また、複数の条件文を並べる場合も、それぞれの間に半角スペースを入れなければならない。
○:IF_TALENT:85_&&_TALENT:88
×:IF_TALENT:85□&&TALENT:88
 このエラーが出ても警告だけで落ちないことが多いが、結果的にIF-ENDIF関係が崩れたりして以降の動作が不安定になり意図せぬフラグ破壊などが起こってしまうかもしれない。




GOTOで飛ぶと自分がいた場所を忘れます。

 入力した数字や特定の条件で分岐先を決め分岐させる際、入れ子で構文を書くのではなく独自関数やラベルを使って独立項目として管理する方法がある。
 複雑な分岐でも全体を把握しやすくなるメリットがあるのだが、この時一つ注意することがある。
 $で始まるラベルを使いGO TO命令でそのラベルへ飛ばした場合、eramakerではこの時自分が今まで自分がどこに居たのかを忘れてしまうのだ。
 その為、元のIF構文の外にラベルをおくと元の場所に戻れなくなってしまうので致命的なエラーが発生することがある。
 ラベルを使うのは意図しない数字を入力した時に選択画面へ戻すような単純な処理だけにし、分岐先で再度分岐を発生させるような複雑な処理を行うつもりならば@で始まる関数として扱いCALLで呼び出した方がいいだろう。



eramakerはERBフォルダ内のERBファイルとCSVフォルダ内のCSVファイルを読み込む

 CSVファイルやERBファイルの実体はテキストファイルだが、だからといって普通のテキストファイルと同じように~~~.TXTという名前で作ってはいけない。
 eramakerやEmueraではCSVファイルとERBファイル以外は認識しないので、それに構文が書いてあっても存在しないことになってしまうからだ。
 またeramakerはCSVフォルダ直下とERBフォルダ直下しか読み込まないため、CSVファイルやERBファイルをサブフォルダ内に保存してもやはり無視されてしまう(Emueraならば「サブディレクトリを検索する」オプションをYESにすることで認識させることが可能)
 なお、eramakerやEmueraは起動時に認識できるファイルをファイル名や中身に関係なく全て読み込む。
 改造などをする時にバックアップのつもりで同じフォルダ内にコピーしていると関数が衝突してしまうので、バックアップは必ず別のフォルダに保存しよう。
 書き換えた後eramakerやEmueraを再起動させないと改造結果が反映されないことも忘れないように。
 さて、ここで、ERBとかCSVとかTXTがマイ コンピュータやエクスプローラなどで表示されない環境の人に強く警告しておこう。それらはファイルの属性を表す拡張子であるが、いかなる理由であれ「表示させる」ことを強く推奨する。というか義務化していいぐらいだ。
 拡張子というのはそのファイルの属性の一部を示すとても重要なものであり、WINDOWSの初期設定においてはなぜか表示されない設定になっている場合があるが、そのままでは非常に不便で危険で他人にも迷惑であるので必ず表示させておこう。拡張子を表示させる方法はWINDOWSのVERSIONごとに異なるが例えばXPの場合、マイ コンピュータやエクスプローラのフォルダオプションの表示タグの詳細設定から「登録されている拡張子は表示しない」という項目のチェックを外せばいい。



EmueraであってもCSVを読み込むときは注意


 前項のとおり、Emueraにおいて、コンフィグ設定の「サブディレクトリを検索する」オプションがYesのときにはCSVファイルだって問題なくサブディレクトリを読む…わけではない。
 CSVファイルはちゃんとCSVフォルダ直下に置かないと読んでくれない。これはEmueraの仕様なので仕方がない。



CharaXX.CSVを読むのはADDCHARAするときだけ


 キャラcsvを書き換えて再起動しても、既に居るキャラのデータは書き換わりません。一見不便に見えますが、キャラcsvはキャラクターの初期ステータスを定義しているものなので、既存のキャラがcsvに同期してしまうと、「せっかく上げたレズっ気が下がった」などということが起こります。でも、eramaker(とEmuera)はそんなことしない。話の分かる奴です。
 また、この仕様を使えば、とあるキャラを初期状態に戻したい場合、ちまちまとフラグを弄るのではなく、ADDCHARAして、入れ替えて、古い方をDELCHARAすればあら不思議、元通りというテクニックも使える。ただまあ、これはTARGETやその他周辺変数はそれに応じて書き換える必要があるのだけれど…。



CFLAG:999は避けよう

このwikiのeramaker変数情報にeramakerで利用できる要素数の範囲が書かれているが、一つ注意することがある。
実はeramakerには、CFLAG:999のような配列変数の最後の要素が0で無い場合、セーブ・ロード後にデータが破壊されるバグがあるのだ。
なので実際に使えるのは要素数-2まで(CFLAGならば998まで)と考えよう。
なおEmueraではこのバグが修正されている。VariableSize.CSVを利用することで要素数そのものも増やせるのでEmuera専用バリアントならば安心して使っていい。



CSVファイルをExcelで編集してはいけません。


PCにOfficeなどがインストールされ、CSVファイルがExcelなどの表計算ソフトに関連付けられている人も多いだろう。
だがeramakerバリアントのCSVファイルは必ずテキストエディタで編集するようにしよう。
Excelは自分が処理しやすいよう段落分けなどの記号を勝手に追加するので、eramakerで正常に読めなくなってしまうことがあるからだ。
といってもCSVファイルの関連付けそのものをテキストエディタに変更すると都合の悪い人も多いはずなので、ファイルを右クリックした時に表示されるコンテキストメニューの『送る』にテキストエディタを登録するか、ファイルの種類の設定でテキストエディタから開く項目を作っておくといいだろう。



RAND:0に注意しよう。


RAND:0とすると、eramakerでは0を返す。だが、Emueraではエラー落ちしてしまう。単純な問題に思えるが、たとえば、RAND:変数として、その変数が別のところで代入・計算されてからその処理に来た場合、Emueraでは必ず直前にその変数が0より大きい数であることを確認しておくべきであろう。



TALENT:0(処女)による分岐について。


俗に言う初体験時の口上を書く際にやってしまいがちなのがTALENT:0(処女)やEXP:0(V経験)の有無で分岐させようとするミスだ。
それのどこが悪いのか?と疑問に思う人も多いだろうが、バイブや性交などのように処女喪失するコマンドの場合、基本的にほとんどのバリアントで処女喪失処理→口上呼び出しという処理順になっているため、口上が呼び出される時点で既に処女が失われV経験も加算されているので分岐には使えないのだ。
そんな時の口上を書きたい場合は、V経験が加算済みであることを逆手にとってEXP:0 == 1を条件に使うようにしよう。
もちろん処女喪失するコマンド以外の場面ならば普通にTALENT:0を分岐条件に使っても構わない。



まだまだ何かありそうだ。

 以上の例のほかにもまだまだありそうなので気づいたらどんどん加筆していく予定である。







タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2010年03月09日 09:03