Questsmith でスクリプトを使う方法
シナリオスクリプトを使って、入力・文脈・出力の動作をエディター画面の設定以上に細かく制御できます。
スクリプトを使うと、シナリオエディターだけでは難しいプレイヤー体験の調整ができます。
Questsmith ではスクリプトはシナリオに紐づき、そのシナリオから始めた冒険で共有されます。一方で、各冒険のゲーム状態はそれぞれ独立して保持されます。
対応シナリオと公開範囲
- スクリプトはシンプル開始シナリオとキャラクター作成シナリオで利用できます。
- 複数選択の親シナリオにはスクリプトを置けませんが、各選択肢側には設定できます。
- スクリプトを閲覧・編集できるのはシナリオ作成者のみです。
- 公開済みシナリオのスクリプトは、ガイドライン準拠の確認のために審査対象になる場合があります。
スクリプト画面の概要
対応シナリオの編集中に、詳細タブ下部からスクリプトを開きます。
- ライブラリ: 他のスクリプトから使える共通ヘルパーや定数を置く場所です。
- 入力: onInput ライフサイクルフック中に実行されます。
- 文脈: onModelContext ライフサイクルフック中に実行されます。
- 出力: onOutput ライフサイクルフック中に実行されます。
ライブラリ以外のスクリプトでは、最終行で modifier(text) を呼び出す必要があります。
スクリプトテストパネル
- 入力: スクリプトの挙動を試すための、編集可能なテスト用データです。
- 送信: スクリプト + ライブラリ + 入力をサーバーへ送り、実行します。
- 出力: 返却テキスト、stop、ログ、state、storyCards を表示します。
コンソールログパネル
- そのシナリオから開始した自分のプレイテスト冒険の最新ログを表示します。
- リアルタイムで流れるため、分割タブ(エディター + プレイテスト)運用に向いています。
- ログの保持期間は 15 分です。
ライフサイクルフック
スクリプト API には 3 つのフックがあり、それぞれ隔離されたサンドボックスで動作します。
- onInput
- onModelContext
- onOutput
実行制限は、各フックごとにメモリ 16 MB とタイムアウト 2 秒です。
利用できる引数
以下はスクリプトスコープで直接参照できます。
- text: フックに応じて、プレイヤー入力・モデル文脈テキスト・出力テキストが入ります。
- history: 直近アクションの配列で、text・rawText・type を含みます。
- storyCards: 冒険カード配列です(旧エイリアス worldInfo も引き続き利用可能)。
- state: ターンをまたいで保持される、カスタムスクリプト用の永続オブジェクトです。
- info: actionCount、characterNames、maxChars、memoryLength などの補助メタ情報です。
state オブジェクトの注意点
- state はヘルパー不要で直接変更できます。
- state.memory では context、authorsNote、frontMemory の上書きが可能です。
- state.placeholders にはシナリオのプレースホルダー質問/回答値が保存され、ターンをまたいで維持されます。
- state.message はクライアント対応状況に応じてプレイヤーへ表示される場合があります。
利用できる関数
- log
- addStoryCard
- removeStoryCard
- updateStoryCard
戻り値の契約
スクリプトは通常、次のようなオブジェクトを返します。
return { text: '新しいテキスト' }
return { stop: true }- text: フックのテキスト列(入力、モデル文脈、出力)を置き換えます。
- stop: 処理ループの進行を止めます。意図を持って慎重に使ってください。
重要なエラー挙動
- onInput で空テキストを返すと、プレイヤーにスクリプトエラーが表示されます。
- onModelContext で空テキストを返すと、スクリプト未実行と同じ扱いになります。
- onOutput で空テキストを返すと、プレイヤーに独自スクリプト失敗として表示されます。
- onOutput で stop を返すことは推奨されません。
最小構成の入力スクリプト例
const modifier = (text) => {
let modifiedText = text
if (text.includes('剣をつかむ')) {
state.items = ['sword']
state.memory = { context: 'あなたは剣を持っている。' }
state.message = '剣を手に入れた!'
log('プレイヤーに剣を追加')
modifiedText = text + '\nあなたは今、剣も持っている!'
}
return { text: modifiedText }
}
modifier(text)実用的な利用例
- コマンド解析(プレイヤー独自コマンド)。
- state を使った所持品や状態の追跡。
- memory、authorsNote、frontMemory の動的調整。
- 文脈の後処理や安全ガード。
- イベントに応じた Story Card の自動追加・削除。
ベストプラクティス
- まずは小さなスクリプトから始め、各フックを個別に検証します。
- スクリプトは決定的に保ち、重い計算を避けます。
- 再利用するロジックや定数はライブラリにまとめます。
- history、placeholders、info の値など未定義項目に備えます。
- 可能なら全文書き換えより加算的な変更を優先します。
- ライブのプレイテストではコンソールログを活用し、最小再現で問題を切り分けます。
トラブル対処のコツ: スクリプトが不規則に失敗する場合は、最小再現シナリオを公開し、そのリンクを不具合報告に添えてください。調査が大幅に速くなります。
スクリプトの不具合や機能要望は、Discord の不具合/機能要望チャンネルに、可能なら再現手順付きで投稿してください。