(訳注: 原文に誤りが多く、主旨も不明瞭なので、大幅に編集と意訳をしています。このページを読むにあたり、もし、*.py がソース・コード、それを Python で疑似コンパイルした結果の *.txt をゲーム・エンジンが読む、ということを理解していない場合は、前のほうのページから読み直してみて下さい。)

はじめに

リストとタプル

モジュール・システムでは Python 言語のリスト [] とタプル () を使い、その中にカンマで区切って命令やデータを書きます。モジュール・ファイル module_*.py をテキスト・エディタで開いてみると、それがわかります。習慣的な書き方があって、リスト内にタプル、その中にリスト、その中にタプル、というように。階層毎にタプルとリストを交互に変えます。どのモジュールで何をどのように指定するかについては、各モジュール・ファイルの冒頭コメントに(ゲーム製造元による)説明があります(ただし、module_info.pymodule_info_pages.pymodule_constants.py については構造が少し違います)。

(訳注: Python 言語のリストとタプルには、mutable(プログラムから変更可能)か immutable(変更不可)の違いがあります。しかし、この MOD 開発環境では その変更可否機能を利用しておらず、単に入れ子になった階層を読み易くする目的で使い分けているようです。現に例えば命令のタプルを一ヶ所リストに変えても、疑似コンパイル結果に影響しないように見えます。なお、Python のリストもタプルも、最後の要素の後ろ かつ閉じ括弧の手前に余計なカンマが 1 個だけあっても許され、それは無視されます。最終要素のカンマを残したほうが、コピペや追加の便が良いので、この開発環境でも初期状態から積極的にそうなっています。)

ゲーム・エンジンが理解する数値

(訳注: Python 言語に不慣れなかたへ。プログラミング言語としての Python や機械語のことが出てきますが、MOD を作る上で それらの言語の詳細に(今後も)あまり深入りする必要はありません。疑似コンパイル時に Python のエラーに対処する必要がありますが、大抵はカンマ抜けとか () や [] の不対応によるものです。エラーについては別ページ「MOD 開発で ありがちなエラー」に説明があります。)

まだ この MOD 開発システムのコンパイルを試していないかたは Native のフォルダにある menus.txt を、コンパイル済みのかたは出力された同ファイルを、テキスト・エディタで開いてみて下さい。冒頭の 2 行(バージョンとレコード数)を読み飛ばすと、下記のように書かれているはずです。

menu_start_game_0 18374686479671624192 Welcome,_adventurer,_to_Mount_and_Blade:_Warband._Before_ ...(後略)

この 20 桁もある数字は れっきとした 10 進数で、メモリ上では 8 バイト(64 ビット)の固定小数点数の領域に収まります。

次に、基になっているソース・コードを見てみましょう。MOD 開発システムに(Naitive のソースとして)付いてくる game_manues.py をテキスト・エディタで開き、冒頭の import 群とコメントを読み飛ばすと、下記のように書かれています。

game_menus = [
  ("start_game_0",menu_text_color(0xFF000000)|mnf_disable_all_keys,
    "Welcome, adventurer, to Mount and Blade: Warband. Before ...",

この「menu_text_color(0xFF000000)|mnf_disable_all_keys」という箇所が疑似コンパイルされて、あの 20 桁の数値に変換されています。「|」は Python 言語の「ビット毎 OR」演算子です。 (訳注: 日本語キーボードで入力する時は Shift ¥ キー、英語系キーボードなら Shift バックスラッシュです。)

この「|」の左側の menu_text_color() という関数は、ヘッダ・ファイル header_game_menus.py 内で定義されていて、先ほど読み飛ばした この game_manues.py の冒頭で それを import しているので、game_manues.py 内の全域で この関数を使えます。そのヘッダでは下記のように定義しています。

def menu_text_color(color):
  return color << 32

この「<<」は、Python の左シフト演算子で、ここでは指定された値(色)を 2 進数で表わし、左へ 32 ビット移動したもの、つまり 232 倍したものを(呼び出し元へ)返しています。

つまり、「|」の左側の menu_text_color(0xFF000000) は、0 を 8 個増やした 0xFF00000000000000 と同じです。右側の mnf_disable_all_keys も同じヘッダ・ファイル内で 0x00000200 と定義されています。だから両側を「ビット毎 OR」した結果の 0xFF00000000000200 が「menu_text_color(0xFF000000)|mnf_disable_all_keys」の実体で、それを 10 進数で表記したのが あの 20 桁の数字です。

color とか disable とか keys という語から類推できる通り、この部分で指示しているのは、メニューの表示色(不透明度と色)と、キーボードによる中断や分岐の抑止です。「ソース・コードでは人間が理解し易く、コンパイル結果はマシンが」という構造は、コンパイルを伴うあらゆるプログラミング言語に共通ですが、この MOD 開発言語で際立っている特徴が、上の例のように、一つの指示(フラグや命令やパラメータ)に複数の情報を詰め込んでしまうことです。

例えば MOD のソース・コード内では、様々なもの(オブジェクト)を扱います。ローカル数値変数 ":xxxx"、クイック文字列 "@xxxx"、兵種(troop)、「集落や施設」(Party)、メニュー、シーンなどです。これらを命令(operation)や各レコード中に指定する時、MOD 開発者が意識しなくても、上で見てきたようなビットの詰め込みが行われます。

その詳細はここでは省略しますが、上と同じように上位 32 ビットにオブジェクトの種類を置き、下位 32 ビットにレジスタ番号やシーン ID を置き、1 個の数値にしてゲーム・エンジン(Warband)に見せます。ゲーム・エンジンは、上位と下位を分離してオブジェクトの種類を見分け、reg3 なのか シーン 3 番なのか、クイック文字列の 3 番なのかを知ります。また、命令そのものにも(neg などの修飾子を付加する)同様の機構があります。

注意: この「詰め込み」機構に使うビット位置の いくつかは MOD のソースで定義されていますが、変更してはいけません。

  • 脚注と出典:
  • (訳注: 大幅に編集と意訳をしたので、脚注と本文が対応しません。テーマは変えていないつもりです。リンク先と比較しながらお読み下さい。)
  • [1] cmpxchg8b, Modding Q&A.
  • [2] 古い記述 M&B Modding Wiki から。