コンテンツにスキップ

コミュニケートコマンドの改善

華和梨Phase 8のコミュニケートコマンド群は、原始的コマンドばかりで、Phase 7.3.1より使いにくい部分があります。キーワードを動的に拡張できる反面、エントリ名を大量に消費します。そこで、あえてキーワードを従来同様に固定にすることで、記述を容易にする方法を考えました。

=kis
# 第1引数: 登録する対象のエントリ
# 第2引数: 登録するデータを記録したエントリ
function regist_communicate $(
    # 引数が2以外の場合終了
    if $[ $(size @arg) != 3 ] $(return);
    # 登録すべきデータがなければ終了
    if $[ $(size $@arg[2]) == 0 ] $(return);
    # 登録対象にデータ登録数を設定
    if $[ $(size $@arg[1]) == 0 ] $(setstr $@arg[1].size 0);

    setstr @pos 0;
    setstr @segment 0;
    # メインルーチン
    while $[ ${@segment} < $(size $@arg[2]) ] $(
        # キーワード、応答分部分の特定
        setstr @segment $(find $@arg[2] "//" ${@pos});
        if $[ ${@segment} == -1 ] $(return);
        setstr @keypos $(find $@arg[2] "-" ${@pos});
        if $[ ${@keypos} == -1 ] $(return);
        if $[ ${@keypos} > ${@segment} ] $(return);
        if $[ ${@keypos}+1 >= ${@segment} ] $(return);

        # communicate用エントリに登録
        # キーワード
        setstr @i ${@pos};
        while $[ ${@i} < ${@keypos} ] $(
            push $@arg[1].${$@arg[1].size}.keyword $(getcode $@arg[2][${@i}]);
            inc @i;
        );
        # 応答文
        setstr @i $[ ${@keypos}+1 ];
        while $[ ${@i} < ${@segment} ] $(
            push $@arg[1].${$@arg[1].size}.answer $(getcode $@arg[2][${@i}]);
            inc @i;
        );

        # communicateエントリに登録
        push $@arg[1] (
            "$(if $(xargs "
            $@arg[1]
            "."
            ${$@arg[1].size}
            ".keyword matchall ${System.Request.Reference1}) "
            $@arg[1]
            "."
            ${$@arg[1].size}".answer)"
        );

        # インクリメント
        inc $@arg[1].size;
        setstr @pos $[ ${@segment}+1 ];
    );
);


# 第1引数: 登録する対象のエントリ
# 第2引数: 登録するデータを記録したエントリ
function regist_communicate_to $(
    # 引数が2以外の場合終了
    if $[ $(size @arg) != 3 ] $(return);
    # 登録すべきデータがなければ終了
    if $[ $(size $@arg[2]) == 0 ] $(return);
    # 登録対象にデータ登録数を設定
    if $[ $(size $@arg[1]) == 0 ] $(setstr $@arg[1].size 0);

    setstr @pos 0;
    setstr @segment 0;
    # メインルーチン
    while $[ ${@segment} < $(size $@arg[2]) ] $(
        # ゴースト名部分の特定
        setstr @segment $(find $@arg[2] "//" ${@pos});
        if $[ ${@segment} == -1 ] $(return);
        setstr @ghostpos $(find $@arg[2] "-" ${@pos});
        if $[ ${@ghostpos} == -1 ] $(return);
        if $[ ${@ghostpos} > ${@segment} ] $(return);
        if $[ ${@ghostpos}+1 >= ${@segment} ] $(return);

        # communicate用エントリに登録
        # ゴースト名
        setstr @i ${@pos};
        while $[ ${@i} < ${@ghostpos} ] $(
            push $@arg[1].${$@arg[1].size}.ghost $(getcode $@arg[2][${@i}]);
            inc @i;
        );

        # キーワード、応答分部分の特定
        setstr @pos $[ ${@ghostpos}+1 ];
        setstr @keypos $(find $@arg[2] "-" ${@pos});
        if $[ ${@keypos} == -1 ] $(return);
        if $[ ${@keypos} > ${@segment} ] $(return);
        if $[ ${@keypos}+1 >= ${@segment} ] $(return);

        # communicate用エントリに登録
        # キーワード
        setstr @i ${@pos};
        while $[ ${@i} < ${@keypos} ] $(
            push $@arg[1].${$@arg[1].size}.keyword $(getcode $@arg[2][${@i}]);
            inc @i;
        );
        # 応答文
        setstr @i $[ ${@keypos}+1 ];
        while $[ ${@i} < ${@segment} ] $(
            push $@arg[1].${$@arg[1].size}.answer $(getcode $@arg[2][${@i}]);
            inc @i;
        );

        # communicateエントリに登録
        push $@arg[1] (
            "$(if $[ $(find "
            $@arg[1]
            "."
            ${$@arg[1].size}
            ".ghost ${System.Request.Reference0}) >= 0 && $(xargs "
            $@arg[1]
            "."
            ${$@arg[1].size}
            ".keyword matchall ${System.Request.Reference1}) ] "
            $@arg[1]
            "."
            ${$@arg[1].size}".answer)"
        );

        # インクリメント
        inc $@arg[1].size;
        setstr @pos $[ ${@segment}+1 ];
    );
);
=end

以上で定義したregist_communicateは、次のように使います。まず、あるエントリ(仮にdata1とする)に、次のような単語を登録します。

data1 (
    今日, 天気, 良い,
    -,
    \0\s[5]そうだね。どこかにお出かけしたいね。\e,
    \0\s[0]こんな日は、外に遊びに行きたいな。\e,
    \0\s[4]こんな日に限って、仕事が一杯なの…\e,
    //
  )

その後、実際にcommunicateコマンドに登録するエントリを、仮にcomとすると、

=kis
regist_communicate com data1;
=end

このように記述します。すると、com以下の次のようなエントリ群に、data1エントリの内容が展開されます。

com : $(if $(xargs com.0.keyword matchall ${System.Request.Reference1}) com.0.answer)
com.0.keyword : 今日 , 天気 , 良い
com.0.answer : \0\s[5]そうだね。どこかにお出かけしたいね。\e
com.0.answer : \0\s[0]こんな日は、外に遊びに行きたいな。\e
com.0.answer : \0\s[4]こんな日に限って、仕事が一杯なの…\e
com.size : 1

なお、上記の展開結果を確認したい場合、regist_communicateを実行後、次のようなスクリプトを実行してください。saved.txtに展開結果が記録されています。

=kis
clear temp;
listtree temp com;
xargs temp save saved.txt;
=end

regist_communicateで読み込むエントリの形式ですが、最初の「-」までの単語は、「キーワード」になります。Reference1の文章に上記キーワードがすべて存在すると、「-」以降の文章のうち、一つが応答文として選ばれます。一つの応答の組み合わせの最後には、「//」を置いて区切りとして下さい。「//」以降は、また別の応答を書くことが出来ます。

data2 (
    キーワード1,
    -,
    応答文1,
    //,
    キーワード2,
    -,
    応答文2,
    //
  )

これらの応答は、comエントリをcommunicateコマンドを通じて、OnCommunicateイベントに登録登録することで機能します。

reply.OnCommunicate : $(communicate com)

一方、regist_communicate_toコマンドは、さらに反応するゴースト名も指定できるよう、機能拡張したものです。最初の「-」までの単語が反応するゴースト名で、ここに列挙したゴーストのうち、いずれかが呼びかけた場合に反応します。最初の「-」から次の「-」までがキーワード、2番目の「-」以降は返す文章です。regist_communicateコマンドと同様、キーワード・応答文の組み合わせの最後に、「//」を置いて下さい。

data3 (
    毒子,サンバーレイン,
    -,
    メタル,
    -,
    \0\s[5]今度、いいアルバム紹介してね。\e,
    \0\s[0]デスとゴアってどう違うの?\e,
    //
  )

=kis
regist_communicate_to com data3;
=end

ゴーストの判定はcommunicateを2段重ねにして、regist_communicateのみを使う方法もあります。使い勝手の良い方を選んで使ってください。

# com.毒子エントリには、対毒子用文章をregist_communicateで登録
# com.陽子エントリには、対陽子用文章をregist_communicateで登録
com : $(
    if $[ ${System.Request.Reference0} == "毒子" ]
        com.毒子
    );
  )

com : $(
    if $[ ${System.Request.Reference0} == "陽子" ]
        com.陽子
    );
  )

reply.OnCommunicate : $(communicate com ${com.unknown})

なお、このスクリプトはゴーストに組み込んで使っても構いませんし、幸水を使って事前に変換する為に利用しても大丈夫です。