ホーム › MOD制作情報 › ミューテータを作る
第03章

ミューテータを作る

ベースゲームやどのMODにも重ねる小さな.oamut。フォルダー、マニフェスト、mutateが返すプラン、オプション、サンドボックス、重ねたときの適用順。

この章はdocs/mutators/authoring.mdとdocs/mutators/oamut-standard.mdの要約です。

ミューテータとは

ミューテータは、ベースゲームやどのMODの上にも重ねる小さな.oamutパッケージで、1回の対戦を変えます。ライブラリはマニフェストのIDでMutatorsフォルダーにインストールしますが、インストールしただけでは有効になりません。有効にするのはプレイヤーで、スカーミッシュ、対戦ルーム、キャンペーンごとに選びます。works-withは合うMODを示し、星印はすべてのMODとベースゲームを意味します。

パッケージ

フォルダーの最上位にはoamut.yamlを置きます。エントリスクリプトはその隣に置き、entryで別のものを指定しない限りmutator.luaです。files/、rules/、lua/の下には置けません。lua/にはそのほかのLuaソースを入れ、requireが読むのはこれらのファイルだけです。files/には、filesレイヤーが追加できるデータを入れます。rules/には、名前が.smで終わるルールファイルを入れます。アイコンは、マニフェストが指定するPNGです。名前が.mdか.txtで終わるメモは人が読むために同梱するもので、ゲームは読み込みません。このリストにないファイルは拒否されます。比較では、ASCII文字の大文字と小文字を区別しません。

my-mutator.oamutプレイヤーが入手するファイル├─ oamut.yaml必須 マニフェスト├─ mutator.luaエントリスクリプト、mutate(ctx)├─ lua/任意。Luaモジュール。requireが読むのはこれらのファイルだけ├─ files/任意。モデル、スクリプトなどのデータ├─ rules/任意。.smルールファイル├─ icon.png任意。iconで指定するPNG└─ README.mdメモ。ゲームは読み込まない

マニフェスト

MODプロファイルと同じルールの厳格なYAMLです。ドキュメントは1つ、最上位は1つのマッピングで、アンカーとブロックスカラーは使えません。ファイルは、整数1を設定したoamutで始まります。規格にないキーは拒否されます。「>」で始まる値と星印は、引用符で囲んでください。囲まないと、読み取り側が別のものとして扱います。requires.engineを引用符で囲むのはこのためです。バージョンも引用符で囲みます。ただの数値は拒否されます。

キー必須内容
oamutはい形式。整数の1。1.0や、引用符で囲んだ1は拒否されます。
idはい小文字のケバブケースで1〜64バイト。先頭や末尾のハイフン、連続したハイフンは使えません。インストール先フォルダーの名前です。
nameはい1〜64バイトで、制御文字は使えません。プレイヤーに表示される名前です。
versionはい引用符で囲み、最大32バイト。1〜3個の部分をドットでつなぎ、各部分は0〜65535の数で、先頭に0は付けません。
authorはいマッピング。nameは必須で1〜128バイト。emailは任意です。
descriptionいいえ任意。1〜2,000バイト。改行を含められます。最初の行を200バイトで切ったものが、カタログに表示される概要です。
homepageいいえ任意。1〜256バイト。httpかhttpsのアドレスです。
iconいいえ任意。正方形のPNGのパッケージ内パスで、.pngで終わります。画像はインストーラーが確認します。
tagsはい1〜4個のIDで、重複は不可。ライブラリが描画する8個は下にあります。
works-withはい1〜32個の条件で、同じIDは2回使えません。星印はすべてのMODとベースゲームを意味し、その場合はそれが唯一の項目になります。ta-3.1cはMODなしのベースゲームです。それ以外のIDはMODで、バージョン範囲を付けることもできます。
requiresいいえ任意。engineとmutatorsだけです。engineはこのビルドに対する範囲で、引用符で囲みます。mutatorsは有効になっている必要があるパッケージを指定し、それらは書かれた順に、このミューテータより先に適用されます。
conflicts-withいいえ任意。このミューテータが一緒に動くことを拒否するミューテータです。ここに書くIDは、requires.mutatorsが指定するものや、このミューテータ自身のIDであってはいけません。
layersはい1〜9個の名前で、重複は不可。files、units、weapons、features、sides、tables、menus、maps、hacksから選びます。プランが書き込めるのは、ここに挙げたレイヤーだけです。
clashesいいえ任意。addかreplace。名前がすでにゲームにあるユニットや武器を、このミューテータがどう扱うかを決めます。プレイヤーの選択が最優先で、次にこのキー、最後に設定mutators.clash-defaultが使われます。未設定ならreplaceです。
optionsいいえ任意。最大16個。対戦の前にプレイヤーが選ぶ設定です。ctx.optionsで読みます。
stringsいいえ任意。最大16個の言語タグ。名前、説明、オプションのラベルの翻訳です。
entryいいえ任意。エントリスクリプト。.luaで終わるパッケージ内パスで、files/、rules/、lua/の下には置けません。省略するとmutator.luaです。
legacyいいえ任意。このパッケージが置き換えるTA: Mutationのミューテータの記録を1〜16個。各記録はname、prefix、compatibility、filesです。リストにせずマッピングだけを書くと拒否されます。

8つのタグ

読み取り側は、1〜32バイトの小文字のケバブケースのタグを最大4個まで受け付けます。ライブラリは次の8つのIDに完全一致したタグにアイコンと翻訳済みのラベルを描画し、それ以外のIDはアイコンなしで書かれたとおりに表示します。マニフェストがアイコンを指定していない場合、最初のタグのIDがこの8つのいずれかなら、バッジにはそのタグのアイコンが使われます。

キー内容
statisticsステータス
economy経済
commandersコマンダー
new-units新ユニット
disable無効化
gameplayゲームプレイ
aiAI
mapsマップ

プラン

エントリはmutateを定義します。エンジンはプランフェーズでmutate(ctx)を1回呼び出しますが、この呼び出しだけでゲームが変わることはありません。mutateはテーブルを1つ返します。空のテーブルは何も変えません。エンジンが知らないキーは拒否されます。

filesはaddとmaskのテーブルです。どちらもテキストのリストで、省略できます。addはパッケージ内のフォルダーを順に指定し、両方にあるパスは後のフォルダーが優先されます。maskはパスを隠します。rulesは、where、all、named、onで作って:changeで仕上げたブロックと、.smファイルを指すsmパスのリストです。変更はset、scale、lock、remove、appendのいずれかです。scaleには下限と上限を付けられ、その上下限はそのひとつの倍率だけを制限します。フックは関数で、units、weapons、features、sides、tables、menusの順に実行されます。mapsはすべてのミューテータの後に、対戦でマップが決まったときだけ実行されます。hacksは、レジストリがミューテータに開放しているパラメーターを、その対戦に限って設定します。書き込みが許されるのは、そのレイヤーを宣言しているからです。

オプションとctx

mutateの実行中、ctxにはMOD(そのID、バージョン、ゲーム)、エンジンのバージョン、オプション、ctx.incompatibleが入っています。MODが有効でないとき、ctx.mod.idはta-3.1cです。理由を付けてctx.incompatibleを呼ぶとこのミューテータは停止し、その理由がプレイヤーに表示されます。コレクションはまだ読み込まれていません。フックは、レイヤーを宣言しなくても、ctxのunits、weapons、features、sides、tables、menusを読めます。書き込むにはレイヤーが必要です。

ctx.optionsには、オプションのIDごとにフィールドが1つあります。トグルはtrueかfalse。数値と、値が数値の選択肢は数値。値が識別子の選択肢はテキストです。プレイヤーが変えなかったオプションは既定値になります。typeはtoggle、choice、numberのいずれかです。選択肢には2〜16個の値を並べ、すべて数値かすべて識別子にします。表示する言葉が値と違うときはlabelsを付けます。数値にはmin、max、step、defaultがあります。プレイヤーが選べるのはminからmaxまでの刻みに乗った値だけなので、スクリプトで範囲を確かめ直す必要はありません。刻みから外れた値は、スクリプトの実行前に拒否されます。オプションのIDはLuaの名前で、Luaの予約語は拒否されます。

サンドボックス

スクリプトは1つのサンドボックス内でLuaとして実行されます。ファイル、ネットワーク、時計、環境変数、プロセスはありません。io、os、debug、package、coroutineは開かれず、プリコンパイル済みのチャンクは拒否されます。チャンクはすべてソースです。2つのミューテータが状態を共有することはありません。

各フェーズは、命令数の上限50,000,000と実時間の上限10秒を、毎回まるごと使える状態から始まります。メモリの上限は64 MiBで、次のフェーズのために改めて割り当てられることはありません。文字列1つは最大65,536バイトです。スクリプトが計算する数値にはfixedを使ってください。65,536分の1単位で数えるので、同じスクリプトはどのマシンでも同じテキストを書きます。pairsは決まった順序でキーをたどります。結果はマシンに左右されません。

重ね掛け

プレイヤーはミューテータを順に並べ、上から下へ適用されます。最初のものが最初に適用され、後のものは、上のミューテータが変えた後のゲームを見ます。requires.mutatorsで指定されたミューテータは、このミューテータと一緒に有効になり、そのリストに書かれた順で先に適用されます。32個を超えるミューテータ、2回並んだID、上にあるどれも満たさない要件、競合する2つのミューテータのいずれかがあると、リスト全体が拒否され、何も実行されません。

まず、すべてのミューテータのファイルがリストの順に重ねられ、同じパスは後のミューテータが優先されます。次に、各ミューテータが同じ順で、自分のユニット、武器、downloadのファイルをレコードとして読み、ルールを適用し、フックを実行します。ルールは決まった順序で1つずつ変更を適用します。倍率は現在の数値に掛けられ、上下限はその倍率だけを制限し、後のものには及びません。代入は現在の値を置き換えます。lockは値を設定し、以降のミューテータがそのフィールドを変えられないようにします。1つのLuaブロックの中では、変更はテーブルに書かれた順ではなく、ASCIIで小文字にしたフィールド名の順に実行されます。ミューテータ間で平均を取ることはありません。すべてのミューテータの適用後、ゲームが保存できる幅を超えたユニットや武器の数値と、ゲームが読む範囲を超えた地形物の数値は、1回だけ、その範囲の端に収められます。