(訳注: 原文では 各レコードを tuple と呼んでいますが、コード例にもあるように、実際の dialogs モジュール内のレコードは(scripts モジュールなどと違って)[] でくくっているので、ここではリストやレコードなどと訳します。)
会話文が表示されるたびに、行が上から下へスキャンされる。
プレイヤーが発話する場面では、一致する全てのセリフが選択肢として表示され、プレイヤーはそこから選ぶ。
プレイヤー以外の人物が発話する場面では、最初に一致する(つまり一番上の)行が使われる。
各レコード(リスト)には次のような項目がある。
(1) 会話相手: プレイヤーが話しかける相手(であるはず)。
通常、これは兵種 ID(troop id)。
この要素に「|party_tpl」を追加することで、集団テンプレート ID(party template id)の指定も可。
特に指定したくない(任意の相手を会話相手としたい)場合は、定数「anyone」を指定。
この要素に「|」を使って plyr を追加すると、プレイヤーが実際のセリフを話すことを意味する。
other(兵種ID) という関数を追加すると、そこにいる第三者によって発話されることを意味する。
(この第三者が確かにその場にいる必要がある)
(2) 開始時会話状態:
会話中は、いずれか一つの「会話状態」が常にアクティブ。
会話行が候補となるためには、開始時会話状態が現在の(アクティブな)会話状態と同じである必要がある。
マップ上で何らかの隊に会うことで会話が始まった場合、現在の開始時会話状態は start(開始)。
街にいる NPC に話しかけることで会話が始まった場合、現在の開始時会話状態は start(開始)。
ある隊が別の隊を倒すのを手伝うことによって会話が始まった場合、現在の開始時会話状態は party_relieved(隊を救援完了)。
囚人を解放することで会話が始まった場合、現在の開始時会話状態は prisoner_liberated (囚人を解放完了)。
候伯が率いる隊を倒すことによって会話が始まった場合、現在の開始時会話状態は enemy_defeated(敵に勝利)。
トリガー発動によって会話が始まった場合、現在の開始時会話状態は event_triggered(イベント発動)
(3) 条件ブロック(リスト): 正しい「命令」の羅列でなければならない。header_operations.py が参考になる。
(4) 会話文テキスト(文字列):
(5) 終了時の会話状態:
会話行が選択されると、現在の会話状態が その行の「終了時の会話状態」で指定した状態になる。
(6) 後処理ブロック(リスト): 正しい「命令」の羅列でなければならない。header_operations.py が参考になる。 (訳注: 訳者が試した限りでは、plyr 付きの場合はプレイヤーが選択後に実行され、plyr 無しの場合は相手の会話文が表示される前に実行される。)
(7) 音声名(文字列): 発声を再生する音声ファイルの名前。不用の場合は空のままにする。
ここでは、module_dialogs.py について調べます。このファイルは、モジュール・システム内で突出してサイズが大きく、Mount&Blade のほとんどの会話文が含まれる、最も大事なファイルの 1 つです。新しい会話文を加える場合にも このファイルに入れます。会話の機会が発生するたびに、ゲーム・エンジンは(ここで定義した dialogs というリストから疑似コンパイルしてでき上がった conversation.txt をゲーム起動時にメモリ上に読み込んでおいて)その情報を上から下まで読み、実行条件が成立するレコードを見つけると、そのレコードを処理します。
module_dialogs.py ファイルは、以前より少し複雑になっています。最初の 3 つほどのレコードを見ると、第 1 項目「会話相手」はどれも「anyone」で、第 2 項目「開始時会話状態」(後述)が異なります。条件がチェックされ、数値レジスタ、文字列レジスタ、グローバル変数が設定されます。それらの各会話テキストに「{!}Warning: This line is never displayed. ...」つまり この行は表示されない、と書かれていて、奇妙に思えるかもしれません。これらのレコードは、ファイルのもっと下のほうで使われる共通的な情報を設定します。そうすることで、これらのコード・ブロックは会話ごとに手で打ち込む必要が無く、一度だけで済むのです。
会話の相手が あるレコードの条件に一致しなければ、そのレコードはスキップされます。だから、会話の設定を気にすることなく、新しい NPC や村長などを後付けで簡単に追加できます。冒頭付近のコードで その 1 つをざっと見てみましょう。
dialogs = [
[anyone ,"start",
[(store_conversation_troop, "$g_talk_troop"),
(store_conversation_agent, "$g_talk_agent"),
(store_troop_faction, "$g_talk_troop_faction", "$g_talk_troop"),
(troop_get_slot, "$g_talk_troop_relation", "$g_talk_troop", slot_troop_player_relation),
(call_script, "script_troop_get_player_relation", "$g_talk_troop"),
(assign, "$g_talk_troop_relation", reg0),
...
(try_begin),
(this_or_next|is_between, "$g_talk_troop", village_elders_begin, village_elders_end),
(is_between, "$g_talk_troop", mayors_begin, mayors_end),
(party_get_slot, "$g_talk_troop_relation", "$current_town", slot_center_player_relation),
(try_end),
(訳注: 上記のうち、troop_get_slot の行は、Module system 1.171 ではコメント化され、次行で呼んでいるスクリプトがパラメータを使って同スロット値を取得しています。)
上記はコードの一部ですが、これだけでもヒントがあるでしょう。この最初のレコードでは任意の誰か(anyone)と会話を開始(start)するときにチェックされます。try ブロックを見ると、定数 village_elders_begin と village_elders_end の間に "$g_talk_troop" が登録されているかどうか調べています。this_or_next という命令を使って、その行の条件と次行の条件が論理 OR で結ばれます。つまり、最初の条件が不成立でも 2 番目の条件 (is_between, "$g_talk_troop", mayors_begin, mayors_end) が成立なら、コード・ブロックの後続区間が実行されます。
使用される定数は module_constants.py で定義されます。だから、あなたが村長を追加したくて、既存の村長たちのために事前定義された設定を利用したいなら、そのファイル内で定義済みの「trp_village_1_elder」と「trp_merchants_end」の間に 新しい村長を置けば済みます。
もう少しスクロールして、下のほうにある もっと具体的な会話、奴隷商 Ramun との会話の出だしを見つけてみましょう。
[trp_ramun_the_slave_trader, "start",
[
(troop_slot_eq, "$g_talk_troop", slot_troop_met_previously, 0),
],
"Good day to you, {young man/lassie}.", "ramun_introduce_1",[]],
このレコードの各項目を細かく見てみましょう。
(1) 会話相手 : trp_ramun_the_slave_trader
(2) 開始時会話状態: "start"
(3) 条件ブロック : (troop_slot_eq, "$g_talk_troop", slot_troop_met_previously, 0),
(4) 会話文テキスト : "Good day to you, {young man/lassie}."
(5) 終了時会話状態 : "ramun_introduce_1"
(6) 後処理ブロック : []
このレコードで一番大事な点は、会話状態(開始時と終了時の両方)です。それらについて掘り下げていきましょう。
終了時会話状態 "ramun_introduce_1" は、そのレコードを別の(複数かもしれない)レコードにつなぎます。この終了時会話状態の指定は任意ですが、指定するなら それと同じ開始時会話状態を持つ別のレコードが必要です。例えば、終了時会話状態に "blue_oyster" と指定すると、開始時会話状態 "blue_oyster" を持つレコードにつながります。両者は完全に一致する必要があります。ビルド時に一致するものが見つからないと、build_module.bat はエラーを throw します。
開始側が "blue_oyster" であるようなレコードが複数ある場合、少し変わったことが起きます。その複数レコードがプレイヤーの発言なら、対応するレコード群の中からプレイヤーの選べる選択肢が表示されます。バニラ(つまりWarband でない)M&B では、ゲームには一度に 5 つまでしか発言の選択肢がありませんが、Warband エンジンでは制限が 1024 もあります。行の文字数が長すぎてもいけません。長すぎると、行が縮んだり枠からはみ出してしまいます。それがプレイヤーの答えなら、可能な限り縮んで表示されます。他の人物の発言行なら、たちまち溢れます [1]。NPC が話すレコードなら、モジュール・システムは、たとえ条件を満たす行が複数あっても、全ての条件が満たされるような module_dialogs.py 内の最初のレコードを使います。
会話を終了するには、終了時会話状態「close_window」を使う必要があります。一方で、会話を開始するには 開始時会話状態のうち「初期会話状態」と呼ばれる 下記のようないくつかの特別なものを使います。
- start はシーン内の NPC と話す時、またはシーン内で会話が発動される時に、対象かどうか調べられます。
- party_encounter はワールド・マップやシーン内で別の部隊(や個人)に遭遇時に、対象かどうか調べられます。
- party_relieved はワールド・マップ上で戦闘中の部隊の一方をプレイヤーが支援し、その戦闘に勝った時、対象かどうか調べられます。
- prisoner_liberated は、1 人以上の候伯の捕虜を含む敵部隊をプレイヤーが倒した時、対象かどうか調べられます。
- enemy_defeated は候伯の率いる敵部隊をプレイヤーが倒した時、対象かどうか調べられます。
- event_triggered はシーン内にいない時に(スクリプトなどでコードされた)命令によって会話が発動された場合、対象かどうか調べられます。
ご覧の通り、各 初期会話状態は特定の状況に合わせて設計されていて、その状況以外では発動しません。
要件と条件ブロック
(訳注: 「要件」(requirements)と「条件」(condition)の違いが不明瞭ですが、「要件」のほうが きつく、下記 2 段落目の第一~第三の同時成立を指す、ということのようです。)
会話のインタフェースはとても柔軟で、種々の使い方ができます。ワールド・マップ上のイベントとシーン内のイベント、どちらも処理します。だから、必要な時にいつでも会話を発動できます。下記では、会話インタフェースを最大限に活用する方法について検討してみます。
上で概説したように、会話行は、要件が全て満たされている場合にのみ考慮されます(対象かどうか調べられます)。まず第一に、プレイヤーが話しかける部隊と要件が一致している必要があります。例えば、プレイヤーについて trp_constable_hareck を指定している場合、trp_ramun_the_slave_trader を含む行は考慮されません。定数 anyone は、その時点でプレイヤーが話しかけている誰かがセリフを話す場合なら、相手が誰でも使えます。
第二に、開始時会話状態は状況に合ったものでなければなりません。つまり、会話行が初期会話状態によって開始されるか、別行の一致する終了時会話状態から継続しているかのどちらかです。開始時会話状態が仕様を満たさない場合、使用対象かどうか考慮されません。
第三に、前の 2 点と同じ考え方が条件ブロックに適用されます。行の全条件が満たされない限り、その行は考慮されません。この条件か開始時会話状態のいずれかが間違っていると、問題が発生します。build_module.bat がエラーを出すか、さもなくば有効化すべき別のタプルを、終了時会話状態が見つけられずに、誤った会話行が単にゲームをフリーズさせます。これが、条件ブロックに注意を要する理由です。条件を不適切に作り込んでしまうことが無いよう注意して下さい。
とは言え、条件ブロックには try ブロックを含めることができるので、全てが調和して機能しているなら、非常に強力です。条件ブロック内からスロットを呼び出し、その結果を同ブロック内の条件命令で使えます。数値レジスタや文字列レジスタの値を設定すれば、実際の会話テキスト内で使えます。
例として、もう一度 奴隷商 Ramun との会話のレコードで条件ブロックを見てみましょう。
(訳注: 原文では条件ブロックの後ろを省略していて、後ろの説明と結びつきにくいので、当該レコードを全文抜粋し、字下げと改行位置を少し変えてあります。)[trp_ramun_the_slave_trader, "start",
[
(troop_slot_eq, "$g_talk_troop", slot_troop_met_previously, 0),
],
"Good day to you, {young man/lassie}.", "ramun_introduce_1",[] ],
条件ブロックには条件判定命令 troop_slot_eq が 1 つだけ含まれています。グローバル変数 "$g_talk_troop" が示す「兵種 ID」について、スロット slot_troop_met_previously が 0 に等しいかどうかを判定しています。新規ゲーム開始時に全てのレジスタと変数が 0 に初期設定されていることが前提にあります (訳注: つまり、この人物に初めて会った時だけ条件が成立し、このレコードの考慮が続行される、ということ)。後ろに会話文が続き、更にその次の次のパラメータが [] なので、後処理ブロックは空です。
では、その次のレコードを見てみましょう。下記のように条件ブロックが空で、後処理ブロックには内容があります。
(訳注: 字下げと改行位置を少し変えてあります。)[trp_ramun_the_slave_trader|plyr, "ramun_introduce_1", [],
"Forgive me, you look like a trader, but I see none of your merchandise.",
"ramun_introduce_2",
[
(troop_set_slot, "$g_talk_troop", slot_troop_met_previously, 1),
]
],
これはプレイヤー選択肢なので、選択されると、後処理ブロックの troop_set_slot 命令が実行され、前の "start" のレコードと同じグローバル変数 "$g_talk_troop" が示す「兵種 ID」(会話相手)の同じスロット slot_troop_met_previously を 1 に設定します。つまり、この会話行が一度選択されると、再度表示されることはありません。なぜなら、次に条件ブロックを通った時にスロット slot_troop_met_previously が 0 でなくなっているからです。結果的にこれ以降、ゲーム・エンジンの会話処理は上の "start" のレコードの会話文が何であるかを考慮することがなくなります。
(訳注: なお、上の "start" のレコードの「終了時の会話状態」"ramun_introduce_1" に対応するレコード、つまり「開始時の会話状態」がそれと同じであるレコードは上記の他に もう一つあり、その会話文が "Never mind." です。だから、Ramun と初めて会うと上記 "Forgive me, you look..." という文と "Never mind." という文がプレイヤーの選択肢として表示され、前者を一度選択すると、それ以降は 2 つとも表示されなくなり、別の文の選択肢に変わります。"Never mind." のほうを選択している限りは、彼と何度会っても "Forgive me, you look..." と "Never mind." が表示されます。以下 2 つの画像は訳者が追加。)
プレイヤーが一度 上記 "Forgive me, you look..." を選択した後、次に Ramun と会って話すと、ゲーム・エンジンはファイル内で次に要件を満たすようなレコードを探し、下記を見つけます。その結果、Ramun は今度は下記のようにプレイヤー名で呼びかけてきます。
[trp_ramun_the_slave_trader,"start", [], "Hello, {playername}.", "ramun_talk",[]],
この行における唯一の要件は、会話相手が Ramun だということです。Ramun が発話後、プレイヤーが彼に話しかける場面で必ずこの行が選択されます。(訳注: 原文では「あるシーン内で会話相手が...」ですが、シーンうんぬんに特段の意味は無いはずなので省略。)
このファイルの冒頭付近(下記)にあるいくつかのレコードで いくつか変数に値が設定されることに着目して下さい。これらは誰か(anyone)と話すときに実行されます (訳注: このページの冒頭付近の説明の繰り返し)。各人物ごとに特定の開始時会話状態がありますが、この会話は、プレイヤーと特定の相手との間に限定しています。グローバル変数 "$g_talk_troop" は、この一連の処理のために設定する変数のうちの 1 つにすぎません (訳注: 下記 条件ブロックの最初の命令 store_conversation_troop のパラメータは格納先で、このグローバル変数に値を書き込んでいます。)。最初のリスト(訳注: 条件ブロック)内の最初の何行かのタプル(命令)で、プレイヤーと "$g_talk_troop" が示す会話相手との関係性(良く思っているか悪く思っているかの度合い)を reg0 に設定しています。その処理の本体はスクリプト troop_get_player_relation にあり(詳細は module_scripts.py で確認して下さい)、返ってきた reg0 の値を "$g_talk_troop_relation" に保存しています (訳注: assign 命令は、右辺から左辺へ代入)。
(訳注: 下記コードも、このページの冒頭のコードの前半付近の再掲。troop_get_slot のコメント化も前述通り。)[anyone ,"start",
[(store_conversation_troop, "$g_talk_troop"),
(store_conversation_agent, "$g_talk_agent"),
(store_troop_faction, "$g_talk_troop_faction", "$g_talk_troop"),
(troop_get_slot, "$g_talk_troop_relation", "$g_talk_troop", slot_troop_player_relation),
(call_script, "script_troop_get_player_relation", "$g_talk_troop"),
(assign, "$g_talk_troop_relation", reg0),
(ゲーム中に誰かとの会話が発生すると毎回)この処理が行われるので、新しく会話ブロックを作るたびに同じような処理を書く必要がありません (訳注: つまり会話相手が誰にせよ後続のレコードを処理する時点では "$g_talk_troop_relation" に関係性が既に格納済、ということ)。会話相手との関係性などを考慮する特別な事情がある場合は、これら(または特定の開始時会話状態)をざっと調べて、チェック事項が既存かどうか確認するとよいでしょう。
会話用に宣言済の定数 [2]
次のような定数が会話用に定義されています (訳注: header_dialogs.py 内)。
| anyone | ゲームが会話状態になった時、相手が誰であっても この会話行が考慮されます。つまり、相手を特定の「兵種 ID」に限定しません。 |
| auto_proceed | 通常の会話ではプレイヤーがマウス左ボタンを押して続行しますが、この会話行ではその動作が不要になります。瞬時に移行するので、プレイヤーは文章を読むことさえできません。このフラグは、移行先の会話行で使用されるいくつかの重要な変数に ここで代入する場合を想定しています。 |
| multi_line |
これは plyr を使った回答群(選択肢)でだけで使います(つまり使う場合は必ず plyr を併用します)。通常の選択肢は改行できず、長文だと 1 行に収まるように小さな文字で表示されます。これを指定すると、下図の一番下のようにボタン内で(右上の区画と同様に)改行可能になります。
|
| party_tpl | 指定した集団テンプレートのパーティとワールド・マップ上で出会った場合のみ、この会話行が考慮されます。指定方法については、Native の例を参照して下さい。 |
| plyr | プレイヤー・キャラクタ(主人公)からの回答群(選択肢)として使われます。 |
| repeat_for_factions | プレイヤーの回答群として全「勢力」(factions)のリストを作成します。でき上がる選択肢の数は module_factions.py ファイルで定義された勢力の数に依ります。 |
| repeat_for_parties | プレイヤーの回答群として全「部隊」(parties)のリストを作成します。でき上がる選択肢の数は module_parties.py ファイルで定義された部隊の数に依ります。 |
| repeat_for_troops | プレイヤーの回答群として全「兵種」(troops)のリストを作成します。でき上がる選択肢の数は module_troops.py ファイルで定義された兵種の数に依ります。 |
| repeat_for_100 | 回答群の上限数を 100 件に制限します。 |
| repeat_for_1000 | 回答群の上限数を 1,000 件に制限します。 |
repeat_for_x という形のものは どれもプレイヤー選択肢のリストを作成します(だからOR 演算子「|」を使って plyr を必ず併用する必要があります)。各選択肢は個別のオブジェクトです。選択肢の数は、各 ID_xxx.py ファイル内の最終番号によって異なります(最大 1024)。この指定は、(会話の回答の両方の角括弧内、つまり条件ブロックと後処理ブロック それぞれの中で)store_repeat_object 命令と組み合わせて使う必要があります。実例は こちら。
会話に関する注意点 [3]
各会話文は 1 つのブロックです。 (訳注: 原文の "The first section" を「コードの最初の部分」とか「『(プレイヤー選択肢などの)従属する分岐』ではない、先頭の要素」と解釈してしまうと後ろの 2 段落での説明と整合しないので、後続の Secondly に対する First と解釈して意訳しています。次の訳注で説明。またコードの原文にあるダブルクオートは混乱するので ここでは省略。原文は脚注 [3] に。)
[ ... 何らかのコード ... ]
そこで単一または一連の条件が成立するかどうか(ゲーム・エンジンが)調べます。出力は TRUE か FALSE だけです。それを全ての会話行について それぞれ行ない、結果が TRUE になる行だけ使われます。
(訳注: 上の説明が次の段落につながるためには、上記コードは「条件ブロック」を指しているのではなく、どうやら module_dialogs.py の dialogs というリスト内の各要素(各会話行)を指しているらしく、上の説明中の「条件」は その中の anyone や "start" や条件ブロック、つまり この web ページで用いている「要件」を指しているらしい。そうだとすると、この項の冒頭「first」は「あるリスト内の先頭の要素」を指すのではなく、次段落の Secondly に対応しそう。)
更に、"start" の後ろの全ての部分は、事象 "start" が発生し、その分岐(訳注: 恐らく、プレイヤー選択肢のような従属するもの)がアクティブで かつ その条件ブロックが TRUE である場合にのみアクセスされます。だから例えば、Generalissimo EvilGuy という人物が火曜日にプレイヤーに会った時には常に何かが起こるようにしたいが、水曜日には別のことをしてもらいたい、という場合なら彼の "start" 行は次のようになります。
(訳注: 下記コードは リスト dialogs 内の単一要素、つまり 1 つの会話行。下記コードの最初の「[」が上記コードの「[」に対応するらしい。)
#Start of Dialog block
[
#See header_dialogs for what can be here besides "anyone". All Dialogs must have a "start".
anyone, "start",
#Start condition block here
[
(eq, "$g_talk_troop", "trp_generalissimo_evilguy"),#ONLY RUN ME IF EVILGUY
(try_begin),
(eq, "$g_day_of_week", 2),#DO THIS TUESDAYS
(assign, "$g_conversation_temp",1),
str_store_string, s17, "@This is my Tuesday conversation start"),
(else_try),
(eq, "$g_day_of_week", 3),#WEDNESDAYS
(assign, "$g_conversation_temp",2),
(str_store_string, s17, "@This is my Wednesday conversation start"),
(else_try),
(assign, "$g_conversation_temp",3),#IF ALL ELSE FAILS...
(str_store_string, s17, "@This is what I say any other day of the week"),
(try_end),
],
#Condition is TRUE; we're talking to EvilGuy, now we need our custom text:
"s17",
#Now we the Player to be able to say something, even if it's something prosaic like, "leave", to exit this Dialog.
"player_response_or_responses_here",
#Consequences, if any:
[],
#End of dialog block
],
最初のブロックで兵種(troop)を使った会話文を使うのを好まない人もいます。誤って論理不良を埋め込みやすくなる、というのが その理由です。代わりに 条件ブロックでチェックする 下記のようなやり方があります。 (訳注: ここでの原文 first block は上述の first section と異なり、「『(プレイヤー選択肢などの)従属する分岐』ではない、先頭の要素」を指すらしい。)
[anyone,"start", [(eq, "$g_talk_troop", "trp_player_castellan"),], "What can I do for you {playername}", "castellan_talk",[]],
つまり下記のように、TRUE を返す条件ブロックに応じて その兵種(troop)に複数の start を割り当てることができる、ということです。
[anyone,"start",
[
(eq, "$g_talk_troop", "trp_player_castellan"),
(eq, "$g_some_game_global", 1),
], "What can I do for you {playername}", "castellan_talk",[]],
[anyone,"start",
[
(eq, "$g_talk_troop", "trp_player_castellan"),
(eq, "$g_some_game_global", 2),
], "Oh, it's {playername}, that scummy devil, come to bother me again!", "castellan_talk",[]],
ただし例外的に もっと判定が必要な場合はあります。例えば下記 略奪者(looters)の start のように、どこかの隊と遭遇し、その中のランダムな人物と話すような場合です。
[party_tpl|pt_looters|auto_proceed,"start", [(eq,"$talk_context",tc_party_encounter),(encountered_party_is_attacker),], "{!}Warning: This line should never be displayed.", "looters_1",[
(str_store_string, s11, "@It's your money or your life, {mate/girlie}. No sudden moves or we'll run you through."),
(str_store_string, s12, "@Lucky for you, you caught me in a good mood. Give us all your coin and I might just let you live."),
(str_store_string, s13, "@This a robbery, eh? I givin' you one chance to hand over everythin' you got, or me and my mates'll kill you. Understand?"),
(store_random_in_range, ":random", 11, 14),
(str_store_string_reg, s4, ":random"),
(play_sound, "snd_encounter_looters"),
]],
この場合、2 つでなく 4 つの条件成立が必要であることに注意して下さい。
- ワールド・マップでの party_encounter(他部隊との遭遇)であること。
- 集団テンプレート(Party Template)が pt_looters (略奪者)であること。
- $talk_context(会話の経緯を示す変数)の値が tc_party_encounter(他部隊との出会いを示す定数)に等しいこと。
- encountered_party_is_attacker が TRUE(つまり出会った相手が敵)であること。
(訳注: 上のコードの手前の文にある「ランダムな人物」とコード中で文をランダムに選択していることは直接は結びつきません。このコードなら いつも同じ「盗賊のお頭」が出てきても、乱数で発言が変わります。だから本文の説明は、正確には「ランダムな人物たちが同じセリフを言う違和感を低減するために、発言内容をランダムに変えている」ということ。なお、このコードを条件ブロックに書いた場合、s4 に発言内容が入いるので、テキスト文を "{s4}" とします。MOD システム v.1.171 で "bandit_attack" を探すと付近に似たコードが見つかります。また、原文は "The only major exception to this is ..." 「一つだけ大きな例外がある」という表現ですが、コード下の本文にある 4 条件は単にコードを説明しているだけで、「例外を一つだけ」をもたらす条件ではなく、他にも例外がありそうなので、only major の訳を省略しました。)
複数名との会話
Yoshiboy, Modding Q&A
その他の注意事項
会話の状態, cwr (credit), Modding Q&A
稀な会話の設定, jacobhinds, Modding Q&A, と Somebody, Modding Q&A
集団テンプレート(party_tpl) を使った会話, cwr (credit), Modding Q&A
- 脚注と出典:
- [1] Dalion, Mount & Blade Modding Discord.
- [2] Dalion 氏からの情報。
- [3] xenoargh 氏の An Introduction to Module Syntax and Usage より。 (訳注: 先頭の投稿内の「Other Topics」の「Spoiler: Dialogs (by xenoargh)」というボタンを展開した中。)