call文

call 文は、別のトークや関数をその場で呼び出します。 呼び出された側が出力したセリフは、call を書いた位置にそのままつながります。

書き方

call 名前

名前 にはトーク名か関数名を書きます。引数のリストや () は付けません。

トークを呼ぶ

イベント名に限らず、任意の名前でトークを定義できます。 それを call で呼び出せます。

挨拶 => {
    湊: こんにちは。
}

OnBoot => {
    call 挨拶
    湊: 今日もよろしくお願いします。
}

出力は \0こんにちは。今日もよろしくお願いします。 のように、call した位置に展開されます。 話者が同じ間はスコープタグ(\0)が繰り返されないので、呼ばれたトークのセリフと call の後のセリフは、そのままつながります。 話者が変わったときは、通常どおりタグが入ります。

呼ばれたトークは、通常のイベントと同じように次の処理が行われます。

  • 同じ名前のトークが複数あれば、条件フィルタ(if(...))で絞り込んだうえで、ランダムにひとつ選ばれます
  • 選ばれたトークが return で値を返すと、その値もセリフとして出力されます
挨拶 if((save.訪問回数 ?? 0) == 0) => {
    湊: はじめまして。
}

挨拶 => {
    湊: また会いましたね。
}

すべての候補が除外されたとき

call したトークの候補が、if(...) によってすべて除外されると、何も出力されません。 このときは「候補が全てcondで除外され、何も出力されませんでした」という notice が記録されます。

関数を呼ぶ

func で定義した関数も call で呼べます。 関数の中でセリフを書いていれば、その出力が call の位置に出ます。 return で返した値も、出力に加わります。

func 挨拶する() {
    湊: こんにちは。
}

OnBoot => {
    call 挨拶する
}

call は引数を渡せません。引数付きで呼びたいときは、次の 名前(引数) の書き方を使います。

名前() の書き方

文の位置(行の先頭)に 名前(引数) と書くと、call 名前 とほぼ同じ動作になります。 トークでも関数でも呼べ、関数には引数を渡せます。

func add(a, b) {
    湊: ${a}と${b}
}

OnBoot => {
    add(1, 2)          // 湊: 1と2
}

log(...) のようなビルトイン関数を文の位置に書いた場合は、副作用だけが実行され、戻り値は出力されません。

OnBoot => {
    log('起動しました')   // 何も出力されない
    湊: こんにちは。
}

呼び出す名前は、ユーザー定義の関数、トーク、ビルトイン関数の順に探されます。

なお、${挨拶する()} や let v = 挨拶する() のように式の中で書いた場合は、 戻り値が値として使われます。セリフの出力は call や文位置の 名前() のときだけです。

動的なcall

変数に入っている文字列を名前として呼ぶこともできます。 reference.0(SSPから渡されたreference)のように、実行時に名前が決まる場合に使えます。

OnBoot => {
    let target = "挨拶"
    call target       // 「挨拶」トークを呼ぶ
}

変数の値が文字列でないか空のときは、変数名そのものがトーク名・関数名として探されます。 その名前のトークも関数も存在しない場合は、何も起こりません。 定義されていない名前を call すると、静的チェックで notice が出ます (動的callの場合は無視して構いません)。

call OnUpdate.OnTypo のようなドット付きの名前は、call reference.0 などの動的callと見分けられないため、 通常は静的チェックの対象外です。ただし、OnUpdate.OnDownloadBegin のように同じ「OnUpdate.」で始まるトークが 定義されているのに、その名前だけが無い場合は、打ち間違いの可能性が高いとして notice が出ます。

呼び出しの深さ

call の入れ子(トークが別のトークを呼ぶ、関数が関数を呼ぶ)は、深さ約100が上限です(正確には、最初の呼び出しから数えて101段目までです)。 上限を超えた呼び出しは実行されません。