里々の内部処理について

ここでは、里々がdll内部で行っている処理のうち、注意を要する場合があるものを取り上げています。
こうした処理は本来里々利用者の便宜を計るために行われているものですが、状況によっては思わぬ弊害となります。
また他のSHIORIの経験があるとかえってつまずきやすい部分でもあります。
里々を使っていて奇妙な不具合に遭遇した場合には、思い出してみてください。




里々の選択肢処理

本題の前に、里々利用者が見落としがちな基本的な原理について強調しておきます。 里々ではさくらスクリプトも使用できますが、捉え方としては「里々で作成したトークは自動的にさくらスクリプト主体の(ベースウェアが使用できる形式の)トークへと変換される」とした方が正確です。 以降、辞書のトークは自動的にさくらスクリプトに変換される事を念頭に置いてお読みください。


下例は、あるトークと、それを里々が自動的に変換した結果のさくらスクリプトです*1

*
:(7)じゃんけんするよー!
:いくでー。(11)最初は……
_グー
_パー【タブ】アンブッシュ
\1\n[half]\0\_w[6]\s[7]じゃんけんするよー!\n\n[half]\1\_w[66]いくでー。\_w[30]\s[11]最初は
……\n\q[グー,グーグー1]\n\q[パー,アンブッシュパー2]\e

選択肢である \q[グー,グーグー1] と、 \q[パー,アンブッシュパー2] に注目して下さい。
明らかに記述した覚えの無い単語が、\qタグ内に勝手に記述されています。


実は、里々は選択肢に関連した情報取得変数を実装するために、選択肢について他の栞にはない独特な処理を行っています。
まず、里々の選択肢の記法は、以下のようなさくらスクリプトで変換・実現しています。

_選択ラベル【タブ】選択ID
\q[選択ラベル,選択ID]

ここまでは基本的なさくらスクリプトですが、里々はさらに続く処理で、その\q[選択ラベル,選択ID]を含めた、トーク中の全ての\q[ラベル,ID]を、次のような独特な形式へと置換します(ベースウェア側でスクリプトログを確認してみて下さい*2)。

\q[選択ラベル,選択ID(バイト値、1)選択ラベル(バイト値、1)選択番号]

結果、選択肢が選ばれ、OnChoiceSelectイベントがベースウェアから通知されると、このreference0には
選択ID 選択ラベル 選択番号
が返却される事になります(半角スペースは1バイト文字)。
里々はこれをユーザーの目に触れる前に内部で分割し、それぞれの部分を選択肢に関連した情報取得変数にセットしてから、(R0)に改めてIDのみセットし直すといった手順を取ります。こうして里々の情報取得変数の(選択ID)(選択ラベル)(選択番号)が利用可能になっているというわけです。
従って、選択肢のID部分が通知されるOnChoiceEnterも同様に、バイト値1区切りの「選択ID 選択ラベル 選択番号」が通知されます。

(↓ Mc159-3 で「script:」を使用した時に記述通りの動作をするよう修正されています。)
上記の仕様のため、\q[タイトル,script:実行内容]は独特な形式へ置換されるため、実質使えないことになります。
例えば、以下を実行してクリックするとします。

\q[テスト,"script:\0\s[0]"]

これは、クリック時に「\0\s[0]」が実行されるさくらスクリプトです。
しかし、里々でこれを書いた場合、実際には以下に変形されています。

\q[テスト,"script:\0\s[0]"(バイト値、1)テスト(バイト値、1)1]

従って、バルーンには記述した覚えのない「テスト 1」という文字列が出力されてしまいます。

留意すべき点

しかしながら、上記の選択肢の仕様はさくらスクリプト構成のトークとしては特殊な使い方です。選択肢が記述者の思いがけない変形を受けていることが、思わぬトラブルの種になる場合もあるのです。

例えば、スクリプトログで確認できるように、MAKOTOやreplace_after.txtOnTranslateで処理するトークの状態は
上記の変形を受けた段階のものという事になります。
OnTranslateを活用するケースでは、このイベントの性質からトーク全文を引数とする事が大半ですから、この時、関数の引数の区切り字に「バイト値1」を使用していた場合、引数の指定位置が狂ってしまい、思わぬ引数エラーが発生する可能性があるという事です。

SSPがいくつか独自に実装している、選択肢関係のSHIORI Eventにも注意が必要です。

例えば、SSPはOnChoiceSelectと同時にOnChoiceSelectExというイベントも通知します。

(↓ Mc159-3でOnChoiceSelectEx の不具合は修正済みで、正しく処理が行われます。)
しかし、里々の上記処理はこれらSSP独自のイベントには対応していません。
従って、上記の戻し処理が行われないので、ID部分には上記のバイト値1区切りの文字列がそのまま入ってしまいます。

結論として、里々では\q選択肢タグでOnChoiceSelectExイベントを利用しない方が無難です。
この動作仕様が把握できれば、以下のように処理を組んで稼動させる事はもちろん可能です。

*OnChoiceSelectEx
$引数区切り追加【タブ】(バイト値、2)
$ダミー【タブ】(nop、(split(バイト値、2)(R1)(バイト値、2)(バイト値、1)))
$引数区切り削除【タブ】(バイト値、2)
>(S0)
:選択肢のジャンプ先「(S0)」は存在しません。

ちなみに、SSPでは選択肢系のさくらスクリプトとして、\__q[選択ID]選択ラベル\__qも用意されていますが、こちらは選択IDが未加工である代わりに選択肢関係の情報取得変数も更新されません。

先ほど例にあげた「\q[テスト,"script:\0\s[0]"]」は「\__q["script:\0\s[0]"]テスト\__q」とすることで、さくらスクリプトとして正常な動作をします。

一部SHIORIイベントの自動化

里々には、簡単にゴーストを作れるよう、基本的な処理を里々自身に内蔵しています。
これにより、ややこしい処理は省いて、トークだけを書けば良いようになっています。

OnSecondChange

里々には一定時間ごとにランダムトークする機能がついていますが、これはOnSecondChangeを里々が勝手に使用しています。
$喋り間隔$タイマはこの里々が使っているOnSecondChange内で使われる値です。
そのため、OnSecondChangeを辞書に書くと、ランダムトークをしなくなる上、タイマーが使えなくなります。

#ただし、こんな感じで改行以外に何もトークがない場合は大丈夫
*OnSecondChange
$変数=(変数)+1
(nop,(split,123_12_1,_))

上記のようにトークがない場合は問題ありません。

再現

$○○タイマ」や「$次から○回目のトーク」という、名前が固定されていない変数を扱うので、里々スクリプトでは再現出来ません。
また、(R0)と(R1)を書き換えるため、これも里々スクリプトでは再現出来ません。

OnMouseMove

「*0Headなでられ」など○○なでられに使用されてます。
OnMouseMoveを記述すると、$なでられ反応回数など、なでに関する変数が全て使えなくなります。
OnSecondChangeと違い、「*OnMouseMove」が辞書にあるだけでなでられ反応が使えなくなるので注意が必要です。
しかし、部位ごとになで時間を調整したい場合など、より凝った処理が必要な場合は、自分でOnMouseMove通知時の処理を作る必要があるでしょう。

再現

辞書にOnMouseMoveが未記述の場合に行われる処理を、里々スクリプトで再現したものです。
里々のOnMouseMoveの動作に加えて何かしたい、という場合は以下を改造すると良いでしょう。

*OnMouseMove
$計算用なでられ回数=(計算用なでられ回数)+1
$なでられ回数初期化タイマ=(なでられ持続秒数)
>なにもしない【タブ】(count、(Status)、talking)>0&&(トーク中のなでられ反応)==無効
>なにもしない【タブ】(計算用なでられ回数)<(なでられ反応回数)
$計算用なでられ回数=0
>(R3)(R4)なでられ

*なにもしない

*なでられ回数初期化
$計算用なでられ回数=0

部位ごとになでられ時間を調整するサンプルが以下です。

*OnMouseMove
$なでられ回数初期化タイマ=(なでられ持続秒数)
>なにもしない【タブ】(count、(Status)、talking)>0&&(トーク中のなでられ反応)==無効
$計算用Headなでられ回数=(計算用Headなでられ回数)(when、(R4)==Head、+1)
>なにもしない【タブ】(計算用Headなでられ回数)<50&&(R4)==Head
$計算用Mouseなでられ回数=(計算用Mouseなでられ回数)(when、(R4)==Mouse、+1)
>なにもしない【タブ】(計算用Mouseなでられ回数)<20&&(R4)==Mouse
$計算用なでられ回数=(計算用なでられ回数)(when、(R4)!=Head&&(R4)!=Mouse、+1)
>なにもしない【タブ】(計算用なでられ回数)<60&&(R4)!=Head&&(R4)!=Mouse
$ダミー【タブ】(なでられ回数初期化)
>(R3)(R4)なでられ

*なにもしない

*なでられ回数初期化
$計算用なでられ回数=0
$計算用Headなでられ回数=0
$計算用Mouseなでられ回数=0

OnMouseDoubleClick

「*0Headつつかれ」など○○つつかれに使用されてます。
OnSecondChangeと違い、「*OnMouseDoubleClick」が辞書にあるだけでつつかれ反応が使えなくなるので注意が必要です。

再現

辞書にOnMouseDoubleClickが未記述の場合に行われる処理を、里々スクリプトで再現したものです。
里々のOnMouseDoubleClickの動作に加えて何かしたい、という場合は以下を改造すると良いでしょう。
テンプレートゴースト「Rポストと狛犬」には記述済みです。

*OnMouseDoubleClick
>(R3)(R4)つつかれ
()

OnMouseWheel

「*0Headころころ」など○○ころころに使用されてます。
OnSecondChangeと違い、「*OnMouseWheel」が辞書にあるだけでころころ反応が使えなくなるので注意が必要です。

再現

辞書にOnMouseWheelが未記述の場合に行われる処理を、里々スクリプトで再現したものです。
里々のOnMouseWheelの動作に加えて何かしたい、という場合は以下を改造すると良いでしょう。

*OnMouseWheel
$計算用マウスホイール=(when、(計算用マウスホイール)>=2、1、(計算用マウスホイール)+1)
$計算用マウスホイール初期化タイマ=2
>(R3)(R4)ころころ【タブ】(計算用マウスホイール)>=2

*計算用マウスホイール初期化
$計算用マウスホイール=0

ホイールを回転させた時、連続で反応してしまうため、トーク中はホイール反応しないようにした記述が以下です。

*OnMouseWheel
$計算用マウスホイール=(when、(計算用マウスホイール)>=2、1、(計算用マウスホイール)+1)
$計算用マウスホイール初期化タイマ=2
>(R3)(R4)ころころ【タブ】(計算用マウスホイール)>=2&&(count、(Status)、talking)==0

*計算用マウスホイール初期化
$計算用マウスホイール=0

OnMouseDown、OnSecondChange、OnMouseUp

「*0Headホールド」など○○ホールドの実装に使用されています。
マウス左クリックを押したのをOnMouseDownで検知してホールドをカウントし、OnMouseUpで終了します。
ホールドが続いている場合、OnSecondChangeのイベントでトークを発生させます。
OnMouseDownとOnMouseUpにトークを記述していても動作します。

再現

辞書に*○○ホールド呼び出し時に行われる処理を、里々スクリプトで再現したものです。
*○○ホールドに限り、OnMouseDownとOnMouseUpの記述があっても動作するので、以下を書く必要はありません。
ただ、OnMouseDownの最初の行の条件、「(when、(R5)==1、2、0)」を「(when、(R5)==2、2、0)」とすれば、マウスホイールのホールド反応にできます。
呼び出しイベント名は、実際に里々が使うイベント名の頭に、「代用」をつけたものを使っています。
「*○○ホールド」だと里々本来のホールド処理が優先され、上記の「マウスホイールのホールド反応」などが作れないためです。

*OnMouseDown
$計算用ホールドタイマ【タブ】(when、(R5)==1、2、0)
$計算用ホールド終了【タブ】初期化
$計算用ホールド箇所【タブ】(R3)(when、(is_empty、(R4))==0、(R4))

*OnMouseDragStart
$計算用ホールドタイマ【タブ】0
$計算用ホールド終了【タブ】初期化

*計算用ホールド
$計算用ホールド終了【タブ】ホールド済み
>代用(計算用ホールド箇所)ホールド

*OnMouseUp
$計算用ホールドタイマ【タブ】0
$計算用ホールド終了【タブ】(when、(計算用ホールド終了)==ホールド済み、ホールド終了、初期化)
>代用(計算用ホールド箇所)ホールド終了【タブ】(計算用ホールド終了)==ホールド終了
*代用0Headホールド
:痛い痛い!
*代用0Headホールド終了
:ふう、痛かった……。

OnCommunicate

コミュニケートの実装に使われています。
ユーザからのコミュニケートは\![open,communicatebox]で開いたコミュニケートボックスに入力されたもので判断されます。 OnSecondChangeと違い、「*OnCommunicate」が辞書にあるだけでコミュニケートが使えなくなるので注意が必要です。

再現

辞書にOnCommunicateが未記述の場合に行われる処理を、里々スクリプトで再現したものです。
里々のOnCommunicateの動作に加えて何かしたい、という場合は以下を改造すると良いでしょう。

*OnCommunicate
≫ユーザ「 (R1)【タブ】(R0)==user
≫(R0)「 (R1)
≫「 (R1)
>COMMUNICATE該当なし

OnSurfaceRestore

なにかしらのトーク後、一定時間経過時のサーフェス戻しに使用されてます。
$会話時サーフェス戻しに値をセットすることで、このイベントの自動化をするかしないかを決定できます。
OnSecondChangeと違い、「*OnSurfaceRestore」が辞書にあるだけでサーフェス戻しが効かなくなるので注意が必要です。

再現

辞書にOnSurfaceRestoreが未記述の場合に行われる処理を、里々スクリプトで再現したものです。
里々のOnSurfaceRestoreの動作に加えて何かしたい、という場合は以下を改造すると良いでしょう。

*OnSurfaceRestore
:((デフォルトサーフェス0))
:((デフォルトサーフェス1))

より正確には以下ですが、@のため$などが使えないので、上記で書いた方が改造は楽です。

@OnSurfaceRestore
\0((デフォルトサーフェス0))\1((デフォルトサーフェス1))\e

一部のリソース

sakura.recommendsitesなどのリンク設定(他に、sakura.portalsites、kero.recommendsites、char*.recommendsites)は、ukadoc仕様ではなく、里々独自の形式で書かないと動作しません

予約トーク

$次のトークで予約したトークは、「OnTalkの発生時」と「()の展開時」(←中身が空っぽの括弧)に処理されます。
従って、トークをジャンルわけして全てのランダムトークに名前をつけている場合、$次のトークが機能しなくなってしまいます。
解決方法として、以下のように1つだけ()の展開先を用意し、ランダムトークの制御用イベントとする方法があります。

*メニュー
_何か話して
*何か話して
()
*
$トーク乱数【タブ】(乱数0~9)
>良い雰囲気トーク【タブ】(calc,(起動回数)>9||(累計時)>2)&&(トーク乱数)==0
>変なトーク【タブ】(トーク乱数)==1
>普通トーク
*良い雰囲気トーク
:~
*変なトーク
:~
*普通トーク
:~

replace.txtとreplace_after.txt

それぞれ、一部の記述を置換出来る便利な機能ですが、タイミングが違います。

replace.txt

replace.txtは、ゴーストのロード時に実行されます。
辞書ファイルをロードする時に、replace.txtの記述に従って内容を読み替えてロードします。
例えば、replace.txtに以下が書いてあったとします。

(箱の数、【タブ】(call、箱の数、

辞書ファイルに、以下のような対応する記述があれば、ロード時に全部読み換えます。

(箱の数、部屋、箱、16)
(call、箱の数、部屋、箱、16)

置換前は、ただの括弧なので、同じ名前のトークや変数がないかぎり、そのままバルーンに表示されてしまうでしょう。
しかし、置換後は自作関数として動作するようになります。

ファイル読み込み時に辞書の記述全てに対して処理をするため、以下の場合、ゴーストの読み込みに時間がかかるようになります。

辞書ファイルのみの合計サイズがメガバイトを超えるような場合、replace.txtの中を空にすると起動が劇的に早くなることがあります。

replace_after.txt

replace_after.txtは、SSPに完成したトークを渡す時に実行されます。
例えば、replace_after.txtに以下がかいてあったとします。

ちゃんさん【タブ】ちゃん

辞書の中ではまだ置換がされません。

*
$ユーザ名【タブ】ユーザちゃん
:(ユーザ名)さん。

これが出力される時、里々があれこれ処理して、ベースウェアが実行できるよう、さくらスクリプト入りの内容にします。
その結果、出力されるのが以下の内容です。

\1\s[10]\0\s[0]ユーザちゃんさん。\e

里々が処理済みで、もうベースウェアに渡すだけ、というタイミングで、replace_after.txtの置換は実行されます。

#里々が出力しようとしたトーク
\1\s[10]\0\s[0]ユーザちゃんさん。\e
#replace_after.txt実行後
\1\s[10]\0\s[0]ユーザちゃん。\e

まとめ

replace.txtの置換が行われるタイミングは、括弧展開の
replace.txtで置換された後に、括弧が展開される。
さくらスクリプトへの変換は行われていない。

replace_after.txtの置換が行われるタイミングは、括弧展開の
ベースウェアに送る直前に行われるため、ここで()が出現しても展開されない。
さくらスクリプトへ変換済み。

dicAnchor○○.txt

dicAnchor○○.txtというファイルを用意し、その中にトークを書くと、アンカーが設定されるようになります。 名称は「dicAnchor」で始まるテキストファイルならなんでも構いません。

dicAnchor.txtに以下が書かれているとします。

*犬
:ワンワンなく。

すると、別のトークに「犬」という単語が出るたびにアンカーがはられ、クリックすると「ワンワンなく。」とトークするようになります。
dicAnchor.txtに名前付きのトークを書いておくだけでよいため、専門的な話をするゴーストや、独自の世界を持つゴーストの用語説明などに向いています。

アンカー化で行われている処理

\_a[ID]表示ラベル\_aに置換が行われています。 処理自体はreplace_after.txtと似ています。
上記をdicAnchor.txtを使わず、あえてreplace_after.txtで書くと以下となります。

犬【タブ】\_a[犬]犬\_a

OnUpdateReadyのファイル数

SHIORI Event(参照:構造とイベントの流れ)のReference(イベントの関連情報)は、里々では情報取得変数の(R*)で取得出来ます。

どのイベントでどのようなReferenceが取得できるかは、通常SSPの公式リファレンスでもあるUKADOCなどで確認する事ができます。

ただしネットワーク更新において更新すべきファイルが見つかった場合に発生するイベント「OnUpdateReady」で(R0)を使う場合には少し注意が必要です。

UKADOCにもあるように、OnUpdateReadyのReference0には本来「更新を行うファイルの総数から1引かれたもの」が入っています。つまりreference0が「0」のとき、更新のあったファイル数は1個である事を意味します。

しかし里々の(R0)ではこの値は補正され、更新を行うファイル数が1個の場合には(R0)にも1が入っています。

これは例えば

*OnUpdateReady
:ネットワーク更新を開始するよ。
:ファイルは全部で(R0)個あるみたいや。

といったトークを書く場合に(R0)を素直な序数として扱うのに役立ちます。

しかし一方で、同様に更新ファイル総数や現在更新中のファイルの番号をReferenceにもつOnUpdate.OnDownloadBeginなどでは、この補正がされない事に注意する必要があります。
もし

#思ったように動かない例
*OnUpdate.OnDownloadBegin
:今(R1)個目のファイルをダウンロード中だよ~。

などといったトークを実現したい場合は、calc関数などを用いて

#思ったように動く例
*OnUpdate.OnDownloadBegin
:今(calc,(R1)+1)個目のファイルをダウンロード中だよ~。

のようにする必要があります。


*1 この例では見やすいように改行していますが、実際には変換後は一行です。また、里々の特殊変数等の設定で、ウェイトコマンドや改行コマンドが変化します。
*2 SSPではCtrl+Lで開けます。ただし開発者機能ONの場合のみ

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2022-05-01 (日) 23:27:16