4. トーク

里々の * で始まる文(トーク)は、湊では 名前 => { … } です。同じ名前を複数書くとその中から1つが選ばれる、という基本は里々と同じです。違うのは、選び方の設定がないこと、ジャンプ(>)がないこと、呼び出しの種類が3つあることです。

同名トークからの選ばれ方

あいさつ => {
    湊: おはよう。
}

あいさつ => {
    湊: こんにちは。
}

あいさつ => {
    湊: こんばんは。
}

OnBoot => {
    call あいさつ
}
\0おはよう。\e
\0こんにちは。\e
\0こんばんは。\e

OnBoot の中から call あいさつ で呼ぶと、3つの あいさつ のうち1つが選ばれます。

選び方は固定(一巡するまで同じものを選ばない)

里々では、$文「○」の重複回避 で「無効(完全ランダム)」「直前」「有効(一巡)」「降順」「昇順」を選べました。里々の既定はランダムで、同じものが続くこともあります。

湊は、常に「一巡するまで同じものを選ばない」で固定です。設定で変えることはできません。

  • 3つあれば、3回呼ぶ間に全部が1回ずつ出ます。周回の境目でも、同じものが連続しません。
  • 名前ごとに独立して管理されます。OnRandomTalk も、call で呼ぶトークも同じ扱いです。
  • 候補がちょうど2つのときは、最初の1回だけがランダムで、あとは交互になります(A、B、A、B、…)。「同じものを続けない」規則のため、順序が固定されるのです。
  • この状態は保存されません。ゴーストを起動し直すと、最初からやり直しです。
  • config.toml に shuffle_reset という項目がありますが、現在の実装では読まれていません。値を変えても動作は変わりません。

順番に出したい(里々の「降順」「昇順」)場合や、完全ランダムにしたい場合は、6. 単語群にあるように、配列と rand() で自分で書きます。

採用条件は if(...)

里々の *トーク名【タブ】条件式 に当たるのが、トーク名 if(条件式) => です。

OnRandomTalk if(save.好感度 < 10) => {
    湊: こんにちは。
}

OnRandomTalk if(save.好感度 >= 10) => {
    湊: 仲良くなりましたね。
}

OnSetFavor => {
    global save.好感度 = 10
}
\0こんにちは。\e
(204)
\0仲良くなりましたね。\e

条件式は、トークが呼ばれるたびに評価されます。条件が真のものだけが候補になり、その中から選ばれます。

  • 条件式の書き方は if 文と同じです(== != < >= && || ! と括弧)。里々のように全角記号は使えません。
  • 里々の条件式は「0以外なら真」でした。湊の条件式は真偽で判断されます。空文字列・0・空の配列・null・false が偽で、それ以外は真です。文字列の "0" は真です(5. 変数)。
  • 条件が付けられるのはトーク定義だけです。里々のように、単語群や > の行に条件を付けることはできません。
  • 条件式の中で発生した「存在しないキー」などの通知は、作者向けのログに出ません。条件が偽になるだけです。

候補が全部除外されたら

すべての候補の条件が偽のとき、何も出力されません。SSPのイベントなら、応答は 204(何もしない)です。

OnRandomTalk if(false) => {
    湊: 出ません。
}
(204)

ランダムトークが無言になっても、エラーは出ません。条件なしのトークを1つは用意しておくと安全です。

ジャンプ(>)は call と return で書く

里々の > は、指定したトークにジャンプします。戻ってきません。

*OnBoot
>初回【タブ】(訪問回数)==1
>通常

初回のときは 初回 だけが実行され、続く >通常 は実行されません。

湊の call は呼んだ先が終わったら戻ってきます。ジャンプにするには、call のあとに return を書いて、そこで終わらせます。

OnBoot => {
    global save.訪問回数 += 1
    if (save.訪問回数 == 1) {
        call 初回
        return
    }
    call 通常
}

初回 => {
    湊: はじめまして。
}

通常 => {
    湊: おかえりなさい。
}
\0はじめまして。\e
\0おかえりなさい。\e

return を書かないと、初回 のあとに 通常 も続けて出ます。里々から機械的に置き換えるときに、一番忘れやすい点です。

呼び出しの3つの形

里々の (トーク名) に当たるものが、湊では3つあります。

書き方意味
call トーク名そのトークを実行し、出力をその場に流す
${トーク名()}そのトークを実行し、結果を文字列として取り出す
トーク名()文の位置に置くと call トーク名 と同じ
運勢 => {
    return "大吉"
}

OnBoot => {
    湊: 今日は${運勢()}です
    湊: 今日は
    call 運勢
}
\0今日は大吉です\n今日は大吉\e
  • ${運勢()} は、文字列の途中に埋め込めます。里々の 今日は(運勢)です に当たります。
  • call 運勢 は、その場所に出力を差し込みます。トークの中に 湊: のセリフがあれば、それがそのまま出力されます。
  • トーク名() は、直前の行がセリフのときに call として動きません。セリフの続き行として扱われてしまいます(10. 改行のルール、14. FAQ)。迷ったら、call トーク名 と書くのが安全です。

引数を渡す関数は func で書き、関数名(引数) で呼びます。func はトークとは別の仕組みで、戻り値を返せます。

func 二倍(x) {
    return x * 2
}

OnBoot => {
    湊: ${二倍(21)}
}
\042\e

トークと func に同じ名前を付けると、func が優先されます。名前は分けてください。

名前が変数に入っているとき

里々で ((変数)) のように入れ子で呼んでいたものは、call 変数名 で書けます。変数の中身がトーク名(または関数名)として使われます。

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

OnBoot => {
    let n = "挨拶"
    call n
}
\0こんにちは。\e

選択肢の reference["0"] に入ったトーク名で呼び出す使い方は、7. 選択肢を参照してください。

トークの途中で終わる

return だけを書くと、そのトークを終了します(セリフはそこまでの分が出力されます)。

OnBoot => {
    湊: A
    return
    湊: B
}
\0A\e

* と @ の区別はない

里々では、*(トーク)は改行やスコープの自動挿入が入り、@(単語群)は入りませんでした。湊は区別せず、**どちらも「トーク」**です。

  • 文字列だけを返したいときは return "…" と書きます(6. 単語群)。
  • セリフを出力したいときは 湊: … と書きます。

次は5. 変数に進んでください。