ユーザー定義ステートメント (Creator-Defined Statements CDS) は独自のステートメントを Ren'Py に追加出来るようにします。これにより現在の文法ではサポートされない機能が追加出来ます。
CDS は直接的な同等の Python コードより柔軟です。
例えば、ランダムに1行の台詞を所得します :
label introduction:
python:
greetings = ['Hello.', 'Welcome.', 'Can I help you?']
greeting = renpy.random.choice(greetings)
"[greeting]"
Ren'Py のパーサーでは Python ブロック内で何が起こり、どのように実行されるはずか予め分かりません。実行までこのコードにできることはなく、例外が発生するとエラーとなります。
CDS を使用すれば次のことができます。 :
パースされた文法の妥当性確認 (例えば、 renpy.random.choice に送られるリストの要素が妥当なテキストか確認します)
実行時の不正なデータの無視 (クリティカルでない関数に対しては、例外を投げるよりも実行をスキップする方がしばしばよいです)
Displayable の予測 (関数が使用する場合)
Lint 実行中の追加情報の掲示 (実行時エラーが無視されるなら、ここでレポートとして受け取られます)
例えば、上記のような動作は CDS では次のように書けます。 :
python early:
def parse_random(lexer):
subblock_lexer = lexer.subblock_lexer()
choices = []
while subblock_lexer.advance():
with subblock_lexer.catch_error():
statement = subblock_lexer.renpy_statement()
choices.append(statement)
return choices
def next_random(choices):
return renpy.random.choice(choices)
def lint_random(parsed_object):
for i in parsed_object:
renpy.check_text_tags(i.what)
renpy.register_statement(
name="random",
block=True,
parse=parse_random,
next=next_random,
lint=lint_random,
)
random
がステートメントとして利用できるようになります。 :
label introduction:
random:
"Hello."
"Welcome."
"Can I help you?"
CDS の使用は実行の安全を保証しませんが、あなたのステートメントのコードが良ければ、その分 Ren'Py はあなたがそれに何を期待しているか "理解" できます。
ユーザー定義ステートメント (CDS) は次のルールに準拠しなければなりません :
python early
ブロックで定義されなければならない
ユーザー定義ステートメントはそれが定義されたファイル内では使用不能です。
CDS を含むファイルはそれを使用するどのファイルよりも先にロードされる必要があります( Ren'Py のファイルロードはそのパスのユニコーン順なので、 CDS を含むファイル名に 01 やその他小さな数値の接頭辞を付けると良いです)
ユーザー定義ステートメントは renpy.register_statement()
関数を使用して登録されます。この関数は CDS 内の処理を実行する他の関数を受け取ります。
ここでは新しいステートメント line
を作成し、クォーテーションを付けずにテキストを指定できるようにしています。
line e "These quotes will show up," Eileen said, "and don't need to be backslashed."
parse 関数には、パースのための字句解析されたコンテンツが送られます。 execute 関数はパースされたコンテンツに対して操作を実行するべきです。 lint 関数は、パースされたコンテンツにエラーがあればそれを報告します。
python early:
def parse_smartline(lexer):
who = lexer.simple_expression()
what = lexer.rest()
return (who, what)
def execute_smartline(parsed_object):
who, what = parsed_object
renpy.say(eval(who), what)
def lint_smartline(parsed_object):
who, what = parsed_object
try:
eval(who)
except Exception:
renpy.error("Character not defined: {}".format(who))
tte = renpy.check_text_tags(what)
if tte:
renpy.error(tte)
renpy.register_statement(
"line",
parse=parse_smartline,
execute=execute_smartline,
lint=lint_smartline,
)
renpy.
register_statement
(name, parse=None, lint=None, execute=None, predict=None, next=None, scry=None, block=False, init=False, translatable=False, execute_init=None, init_priority=0, label=None, warp=None, translation_strings=None, force_begin_rollback=False, post_execute=None, post_label=None, predict_all=True, predict_next=None) linkこれはユーザー定義ステートメントを登録します。
これはステートメントを開始する名前のスペース区切りのリストか、または空の文字列にして新しいデフォルトステートメントを定義します ( デフォルトステートメントは say ステートメントを置き換えるでしょう )。
False なら、ステートメントはブロックを使用しません。 True ならブロックを使用し、 そのブロックの解釈は lexer に任せます。文字列 "script" なら、ブロックは一つ以上の Ren'Py スクリプト言語を含むものとして解釈されれます。文字列 "possible" なら、パース関数でブロックを使用するか決定します。
これは Lexer オブジェクトを引数に受け取る関数です。この関数はステートメントを解析し、任意のオブジェクトを返すべきです。このオブジェクトは他のすべての関数に引数として渡されます。
これはステートメントをチェックするために呼び出され、 parse から返されたオブジェクトを引数として渡されます。 renpy.error()
を呼び出してエラーを報告するとよいでしょう。
これはステートメントが実行されると呼び出される関数で、 parse から返されたオブジェクトを引数として渡されます。
これは初期化時の優先度 0 に呼び出される関数です。
これはステートメントに使用される画像を予測するために呼び出される関数で、 parse から返されたオブジェクトを引数として渡されます。 ステートメントに使用される displayable のリストを返すべきです。
これは次のステートメントを決定するために呼び出される関数です。
block が "script" でないなら、これには parse 関数から返されたオブジェクトが引数に渡されます。 block が "script" ならそのブロックの最初のステートメントの名前のオブジェクトが追加の引数に渡されます。
この関数はジャンプ先のラベルを指定する文字列、ブロックへ制御を移すなら第二引数、この後のステートメントに制御を移すなら None を返すべきです。
ステートメントのラベルを決定する関数です。返した文字列がステートメントのラベルとして使用され、その他のラベル同様に呼び出しやジャンプが出来ます。
ステートメントがワープ中に実行されるかを決定する関数です。関数が存在し、 True を返せばワープ中に実行され、そうでなければ実行されません。
Ren'Py 内部で使用されます。
このステートメントが初期化時にのみ実行されるべきなら True です ( ステートメントが init ブロック内になければ自動的に init 0 ブロックに配置されます)。これは execute_init 関数に加えて execute 関数を呼び出します。
init ブロックの初期化優先度の整数値です。
パースされたブロックを引数に呼び出される関数で、翻訳可能として報告される文字列のリストを返します。
これは menu
や call screen
のようなファストスキップを停止するステートメントでは True にするべきです。
次のステートメントの一部として実行される関数です( post_execute 関数の追加により RPYC ファイルの内容が変化するため、強制コンパイルが必要になります )。
post_execute ステートメントのラベルを決定する関数です。返した文字列がステートメントのラベルとして使用され、その他のラベル同様に呼び出しやジャンプが出来ます。これを使用して他と被らないリターンポイントを作成できます。
True なら、このステートメントと次のステートメントのすべての sub-parse を予測します。
これはこのステートメントの次のステートメントのラベルを引数とする関数です。
これは次に実行するステートメントを予測するために呼び出されるべきです。ラベルか SubParse オブジェクトのリストを返します。 predict_all が True だと呼び出されません。
Lexer オブジェクトのインスタンスを受け取ってカスタムステートメントをパースする関数です。
Lexer
linkerror
(msg) linkパラメータ: | msg (str) -- 検出したパースエラーのリストに追加されるメッセージです。 |
---|
検出されたパースエラーのリストに(現在位置とともに) msg を追加します。これは現在のステートメントのパースを停止しますが、以降のパースは妨げません。
require
(thing, name=None) linkthing のパースを試み、出来なければエラーを返します。
thing が文字列なら、 match()
を使用してそれをパースしようとします。
そうでなければ、 thing はこの lexer オブジェクトの引数無しで呼び出される他のメソッドでなければいけません。
name が指定されなければ、メソッド名が (文字列であるなら thing が) メッセージに使用され、そうでないければ name が使用されます。
eol
() link戻り値: | lexerが行の末端に達していれば True を返し、そうでなければ False を返します。 |
---|---|
戻り値の型: | bool |
expect_eol
() link行の末端に達していなければエラーを投げます。
expect_noblock
(stmt) linkこのステートメントがブロックを使用しないと示すために呼び出されます。ブロックが発見されると、例外が投げられます。 stmt はエラーとともにメッセージに追加される文字列です。
expect_block
(stmt) linkこのステートメントが空でないブロックを必要とする示すために呼び出されます。 stmt はエラーとともにメッセージに追加される文字列です。
has_block
() link戻り値: | 現在行に空でないブロックがあれば True 、そうでなければ False です。 |
---|---|
戻り値の型: | bool |
match
(re) link任意の正規表現文字列にマッチします。
何かをマッチさせる lexer のすべてのステートメントは、この関数と同様な方法で実装されています。最初に空白をスキップし、その行に対してマッチするかを試みます。マッチが成功すればマッチしたテキストが返され、そうでなければ None が返され、 Lexer は変更されません。
keyword
(s) linkキーワードとして s にマッチします。
name
() link名前にマッチしますが組み込みのキーワードにはマッチしません。
word
() link戻り値: | マッチされた単語のテキストです。 |
---|---|
戻り値の型: | str |
キーワードを含むどのような単語にもマッチします。
image_name_component
() link画像名にマッチします。単語と違い画像名は数字で始められます。
string
() link文字列にマッチします。
integer
() link戻り値: | 整数を含む文字列 |
---|---|
戻り値の型: | str |
整数にマッチします。
float
() link戻り値: | 浮動小数点を含む文字列 |
---|---|
戻り値の型: | str |
浮動小数にマッチします。
label_name
(declare=False) linkラベル名または、absolute, relative にマッチします。 declare が True なら、グローバルラベルが設定されます ( ステートメントは label 関数からラベルを返す必要あるためにそうしているだけで、これはは実際にはラベルを宣言しないことに注意してください)。
simple_expression
() link単純式にマッチし、それを文字列として返します。これはしばしば変数名を期待する時に使用されます。結果の変更は推奨されません。正しいアクションは future(訳注: python3互換モジュールのこと?) で結果を評価することです。
delimited_python
(delim) link':' のような delim で終わる Python 式にマッチします。これはしばしばデリミタまでを条件として期待する場合に使用されます。結果の変更は推奨されません。正しいアクションは future(訳注: python3互換モジュールのこと?) で結果を評価することです。デリミタの前に行端に達すればエラーを投げます。
arguments
() linkこれは引数リストの丸括弧の前に呼び出されなければなりません。引数リストが確認されなければ None を返し、そうでなければ引数を表すオブジェクトを関数呼び出しに渡します。このオブジェクトには scope 辞書を省略可能な引数にとる evalute
メソッドがあり、1番目が位置引数のタプル、二番目がキーワード引数の辞書であるタプルを返します。
rest
() link空白をスキップし、行の残りを返します。
checkpoint
() link現在の lexer の状態を表現する opaque オブジェクトを返します。
revert
(o) linko が checkpoint() から返されたオブジェクトなら、 lexer の状態を checkpoint() が呼び出されたときにまで戻します ( これはバックトラッキングのために使用されます )。
subblock_lexer
() link戻り値: | 現在行と対応するブロックに対する Lexer |
---|
advance
() linkサブブロック lexer 内で次の行に解析を進めます。一行目を解析できるようにするために、一行目よりも前で呼び出される必要があります。そのブロック内の行に進めれば、 True を返し、末端を越えていれば False を返します。
renpy_statement
() linkRen'Py スクリプトステートメントとして現在行をパースし、不可能ならエラーを生成します。このメソッドは get_next() から返されたり renpy.jump()
、 renpy.call()
に渡される opaque オブジェクトを返します。このオブジェクトはステートメントのパース結果としてを除いて保存されるべきではありません。
ステートメントがこの処理を完了すると、制御はユーザー定義ステートメントの次のステートメント( post_execute を使用して作成されたステートメントもありえます)に渡されます。
renpy_block
(empty=False) linkこれは現在ブロックの残りの行を Ren'Py スクリプトとしてパースし、ブロックの最初のステートメントに対応する SubParse を返します。そのブロック内で実行されるすべてのステートメントとともにブロックが処理されると、制御はこのユーザー定義ステートメントの次のステートメントに渡されます。
これは現在のブロックをパースすることに注意してください。。現在のステートメントのサブブロックをパースしたい場合は、以下のようにしてください。
def mystatement_parse(l):
l.require(':')
l.expect_eol()
l.expect_block("mystatement")
child = l.subblock_lexer().renpy_block()
return { "child" : child }
True なら、空のブロックもパースされます( 空のブロックは pass
ステートメントのみのブロックに相当します)。
False なら、空のブロックでエラーとなります。
catch_error
() linkこれは with ステートメントと共に使用され、そのコンテキストブロック内で Lexer エラーをキャッチしてレポートし、次のブロックに続ける context decorator です。
こちらは1つのサブブロック内での複数のエラーをどのようにレポートするかの例です。
def mystatement_parse(l):
l.require(':')
l.expect_eol()
l.expect_block("mystatement")
strings = [ ]
ll = l.subblock_lexer()
while ll.advance():
with ll.catch_error():
strings.append(ll.require(ll.string))
ll.expect_noblock("string inside mystatement")
ll.expect_eol()
return { "strings" : strings }
これらの関数は lint 関数を記述するのに便利です。
s 内部のテキストタグが正しいかチェックします。エラーがあればエラー文字列を、なければ None を返します。
renpy.
error
(msg) linkユーザーに対して文字列 msg をエラーとして表示します。
renpy.
try_compile
(where, expr, additional=None) link式をコンパイルし、エラーがあればそれを lint.txt に書き出します。
式が見つかる場所を指定する文字列です。 "where で expr を評価できません。 " のような形式でエラーメッセージを生成するために使用されます。
コンパイルを試みる式です。
指定すると、エラーメッセージへの追加情報となる行になります。
renpy.
try_eval
(where, expr, additional=None) link式の評価を試み、 失敗すると lint.txt にエラーを書き込みます。
式が見つかる場所を指定する文字列です。 "where で expr を評価できません。 " のような形式でエラーメッセージを生成するために使用されます。
評価を試みる式です。
指定すると、エラーメッセージへの追加情報となる行になります。