ゾーンシート (Zone)
ソーステーブルを作成するときは、必ず公式ソーステーブルの最初の3行をそのままコピーし、4行目以降にデータを入力してください。
列、空行、空セルについて
足りない列は空の値で埋められます。その際ゲームはログ(Player.log)に #source ill-format 警告を出力し、読み込みは続行されます。列の順序が入れ替わっている場合もヘッダー名で自動的に再マッピングされます。とはいえ、公式テーブルのヘッダー行をまるごとコピーしておけば、どちらのケースも最初から避けられます。
id が空の行があると、そこでシートの読み込みが打ち切られます。 それ以降の行はすべて読み込まれず、警告も出ません。意図的でない限り、データの区切りに空行を使わないでください。
空セルは空の値ではありません——ゲームは3行目のデフォルト値にフォールバックします。このシートの既定値は type=Zone、LV=1、chance=100、idBiome=Plain、dev=0、image=default です。
3行目のデフォルト値を書き換えれば、それを他のすべての行に適用できます。データは4行目から入力してください。
シートの列
| 列 | タイプ | 説明 |
|---|---|---|
| id | テキスト | ゾーンの一意の識別子。バニラのエントリまたは他のModのエントリIDと一致する場合、最後にロードされたシートが他を上書きします。この値にスペースを含めることはできません — 必要に応じて snake_case スタイルを使用してください(例:mymod_zone_funk_house)。 |
| parent | テキスト | 親ノードのID。ニューゲーム時、ゲームは world から再帰的にツリーを構築し、parent が現在のノードと一致するすべての行を子として生成します。ノースティリス大陸にぶら下げたい場合は ntyris を指定します。ゾーンをワールドマップに配置するを参照。 |
| name_JP | テキスト | 日本語の表示名。 |
| name | テキスト | 英語の表示名。その他の言語については SourceLocalization を使用してください。 |
| type | テキスト | ゾーンのC#型名。既存のZone型またはDLLのZoneサブクラスを使用できます。コードでカスタマイズする場合は、以下のカスタムゾーンタイプを参照してください。 |
| LV | 整数 | 危険度レベル。ゾーンの基本危険度として書き込まれます。子フロアの危険度は トップゾーンの危険度 + abs(lv) - 1 で算出されます。 |
| chance | 整数 | ランダムサイトを抽選する際の重み。random タグと併用した場合のみ意味を持ちます。 |
| faction | テキスト | このゾーンが属する派閥のID。 |
| value | 整数 | ホームランキングリストで使用されるゾーンの価値。lv == 0 かつ value > 0 のゾーンのみがランキング対象になります。 |
| idProfile | テキスト | ゾーンプロファイルID。ランダム生成されるマップの作られ方を決めます。マップファイルを読み込むゾーンでは無視されます。ゾーンプロファイルを参照。 |
| idFile | テキスト[] | マップファイルのベース名。実際に使われるのは最初の要素だけです — ゲームがマップファイルを探す順序を参照。ファイルが見つからない場合はランダムマップが生成されます。 |
| idBiome | テキスト | バイオームタイプ。既存の BiomeProfile のIDである必要があり、不明な値は例外になります。マップ設定にバイオーム上書きを持つマップファイルは、この列より優先されます。 |
| idGen | テキスト | 未使用。この列を読むコードはゲーム内に存在しません——ダンジョンジェネレーターはC#型の IDGenerator プロパティから決まります。 |
| idPlaylist | テキスト | プレイリスト。lv != 0 のゾーンで空欄の場合は Underground にフォールバックします。現在、カスタムプレイリストにはCWLが必要です。 |
| tag | テキスト[] | このゾーンに適用されるタグのカンマ区切りリスト。下記の タグリファレンス を参照してください。 |
| costSkyTravel | 整数 | スカイトラベル(ムーンゲート)の費用。サバイバルモードでは目的地の条件としても使われます。 |
| cost | 整数 | 未使用。 |
| dev | 整数 | デフォルトのゾーン開発レベル。 |
| image | テキスト | ゾーン選択画面に表示される画像名。ゲーム内蔵の Media/Graphics/Image/Zone/ リソースから読み込まれます。空欄なら default。カスタム画像には対応していません。 |
| pos | 整数[] | ワールドマップ上のゾーン位置。x,y,iconID の形式で指定します。3つの値すべてが必須です——セルが空でない限り、ゲームは3番目の値を無条件に読み取ります。空欄にするとゾーンは -1000,-1000、つまりワールドマップ外に置かれます。iconID の調べ方は下記の ワールドアイコンID を参照してください。 |
| questTag | テキスト[] | このゾーンで発生可能なクエストタイプ。各項目は タグ/重み の形式です(例:deliver/7,food/8)。プレイヤーの派閥ゾーンの場合は無視されます(固定リストが使われます)。 |
| textFlavor_JP | テキスト | ゾーン進入時に表示されるフレーバーテキスト(日本語)。 |
| textFlavor | テキスト | ゾーン進入時に表示されるフレーバーテキスト(英語)。その他の言語については SourceLocalization を使用してください。 |
| detail_JP | テキスト | ゾーンの説明(日本語)。 |
| detail | テキスト | ゾーンの説明(英語)。その他の言語については SourceLocalization を使用してください。 |
タグリファレンス
tag 列で認識されるタグ:
| タグ | 説明 |
|---|---|
addMap | 効果は2つあります。idFile が空でもModパッケージ内のマップファイルを探せるようにすること、そしてロードのたびにゾーンをワールドへ生成すること——つまり既存のセーブデータにも反映されます。親を指定できます:addMap(ntyris)(旧CWL形式 addMap_ntyris も可)。ゾーンをワールドマップに配置するを参照。 |
random | このゾーンをワールドマップ上のランダムサイトとして出現させます。重みは chance です。 |
debug | 開発モードが有効なときのみ生成/抽選されます。出荷したくないテスト用ゾーンに便利です。 |
closed | 閉鎖状態としてマークします。ワールドマップからの進入は zoneClosed で拒否され、ファストトラベル不可、配達先の候補からも除外され、ワールドマップのタイルには閉鎖表示が重ねられます。 |
return | プレイヤーのホームゾーンでなくても、帰還先として使用できます。 |
light | プレイヤーの派閥ゾーンでなくても、照明を有効にします。 |
tech | 商人のインベントリ背景にテックボックスを使用します。 |
iconFlag | ワールドマップのアイコンを旗タイルに強制し、pos のアイコンIDを上書きします。 |
ワールドアイコンID
pos 列は x,y,iconID 形式です。3番目の値 iconID は、ゲーム内蔵タイルセットのワールドマップアイコンの数値IDです。下のタイルセットにカーソルを合わせて各アイコンのIDを確認し、pos 列で使用してください。
外部スプライトによるカスタムゾーンアイコンは現在サポートされていません。
タイルセットビューアー
さらに、ゾーンの x,y 座標を決定する際に、コンソールコマンド mod.pos を使用して、現在のプレイヤーキャラクターがいるワールドマップの座標を取得することができます。
カスタムゾーンタイプ
C# DLLで定義されたカスタムゾーンタイプを使用できます。
public class Zone_MyFunkHouse : Zone_Civilized
{
// overrides
}基本クラスは Zone から派生している必要があり、どの Zone タイプを使用するかは自由に選択できます。
type 列はリフレクションで解決されます。まず本体アセンブリを探し、続いてMod側で登録済みのすべてのアセンブリを型名で走査します(アセンブリが登録されていれば名前空間付きの完全名も使えます)。解決に失敗してもエラーは出ません——ゲームは黙って素の Zone にフォールバックします。カスタム処理がまったく動かない場合は、まず綴りを確認してください。
サブクラス化する際によく使うフック:
| メンバー | 用途 |
|---|---|
OnVisitNewMapOrRegenerate() | マップが初めて生成された、またはインポートされたときに実行されます。手作りマップの後処理に最適です。 |
OnActivate() | プレイヤーがゾーンに入るたびに実行されます。 |
GetNewZoneID(int level) | 新しいフロアを作るときにどのゾーン行を使うか。複数階層のゾーンを参照。 |
StartLV | 新規生成されるゾーンの初期 lv(既定は 0)。 |
IDGenerator | non-null を返すとDunGenのダンジョンジェネレーターに切り替わります。 |
IdProfile / IdBiome / IDPlayList | 対応するシート列を実行時に上書きします。 |
マップの作成!
noa氏の引用:
マップ作成(NPCの配置、家具の設置、ブロックのレイアウトなど)は、すべてゲーム内のビルドモード(開発モード)で行います。マップが完成したら、F1キーの「Export Map」機能でエクスポートします。その後、SourceGame.xlsxのZoneシートで既存のゾーンエントリをコピーし、id、name、type、posなどのフィールドを変更し、idFileをエクスポートしたマップのファイル名に設定します。基本的に、ゲームに新しいマップを追加するために必要なのはこれだけです。
以下では、現行ビルドの実際の挙動に沿ってこの流れを掘り下げます。
開発モードに入る
コンソールコマンド mod.elin_dev を使うか、-dev 引数付きでゲームを起動します。mod.elin_dev false で再起動せずに解除できます。
マップを編集する
編集はすべて通常のビルドモードで行います。ビルドモード中に使える開発者用ショートカット:
| キー | 動作 |
|---|---|
F1 | デバッグコマンドのレイヤーを開きます(エクスポートコマンドはここにあります)。 |
F2 | ゾーンの再生成を強制します——つまりマップファイルを読み込み直します。.z が実際に拾われているかの確認に便利です。 |
コピーツール中の K / L | マップピース(.mp)のエクスポート/インポート。他のマップに貼り付けられる矩形の区画です。マップピースは Map Piece/ に置かれ、ゾーンのマップとは別物です。 |
マップをエクスポートする
F1 を開いて、次のいずれかを使います:
| コマンド | 結果 |
|---|---|
Export Zone | <ゲームフォルダ>/Package/_Elona/Map/<idFile>.z に書き出します。書き出す前に同名の旧ファイルを Map/Backup/ にコピーします。ゾーンの idFile が空の場合ファイル名は _new.z になりますが、ゲームは意図的にこの名前を読み込みません——エクスポート前に idFile を設定してください。 |
Export Zone(Dialog) | 同じエクスポートですが、保存先を自分で選べます。 |
Import Zone(Dialog) | 任意の .z を選ぶと、ゲームがそれ用の Zone_User と、そこへ通じるテレポーターを足元に作ります。シートを触らずに他人のマップを覗くのに便利です。 |
エクスポートされるのはプレイヤー作成物だけ
地形(ブロック、床、オブジェクト、橋、屋根、高さ、デカール、装飾……)は常に完全に書き出されます。一方、物とキャラクターは isPlayerCreation フラグが立っているものだけが書き出されます。 マップジェネレーターやデバッグ生成コマンドが置いたものは、エクスポート時に捨てられます。
ビルドモードで自分が設置した物はプレイヤー作成物なので、家具はたいてい残ります。キャラクターは通常残りません。noa氏自身のツールはエクスポート前にマップ上のすべてにフラグを立てており、スクリプトModでも同じことができます:
foreach (var t in EClass._map.things) t.isPlayerCreation = true;
foreach (var c in EClass._map.charas) c.isPlayerCreation = true;.z ファイルの中身
.z は以下を含むzipアーカイブです:
- セル単位の地形バイト配列(
blocks、floors、objs、heights、bridges、roofBlocksなど) map—— シリアライズされたMapオブジェクト。MapConfig(バイオーム上書き、屋内フラグ、シーンプロファイル、LUT、霧、天候……)を含みますが、物のリストは取り除かれていますexport—— シリアライズされたカード(プレイヤー作成物の物とキャラクター)meta—— 名前、id、tag、そしてエクスポート時のゲームバージョン。古すぎるバージョンは検証に失敗しますTexture Replace/—— そのゾーンのローカルテクスチャ置き換えフォルダ(あれば)
ゲームがマップファイルを探す順序
ゾーンが初めてアクティブ化されるとき、探索順は次のとおりです:
<ゲームフォルダ>/Package/_Elona/Map/<idExport>.z——idExportはidFile[0]に、0以外のフロアなら_F<lv>サフィックスを付けたもの。_new.zは明示的に除外されます。- そのファイルが存在せず、かつその行の
idFileが空でないかaddMapタグを持つ場合、有効化されているすべてのModパッケージについて、次の相対パスを順に探します:Maps/<idExport>.zMaps/Zone_<id>@<lv>.zMap/<idExport>.zMap/Zone_<id>@<lv>.z
- どれも見つからなければ、
idProfileに従ってランダム生成されます。
覚えておく価値のある点が2つあります:
Zone_<id>@<lv>という形式(ゾーンのフルネーム)を使えば、行にaddMapタグさえあればidFileを一切書かずにマップを配布できます。- 複数のパッケージが同じ相対パスを提供している場合、最後に読み込まれたものが勝ちます。また手順1が最優先なので、
Package/_Elona/Map/に残ったエクスポートファイルはMod内のコピーを覆い隠します——テスト中は削除するかリネームしてください。
Modに同梱する
エクスポートした .z を、Modパッケージのルート直下の Maps フォルダに、ソースシートと並べて置きます:
MyMod/
├─ package.xml
├─ SourceGame.xlsx (あなたのZone行)
└─ Maps/
├─ mymod_funk_house.z
└─ mymod_funk_house_F-1.z訪問済みのゾーンは自前のコピーを保持します
プレイヤーが一度ゾーンに入ると、そのマップはセーブデータ内に保存され、以後 .z は参照されません。マップファイルを更新しても、再生成されるまで訪問済みゾーンは変わりません。反復作業中は、新しいセーブで始めるか、ビルドモードで F2 を使ってください。
ゾーンをワールドマップに配置する
仕組みは2つあり、挙動が異なります。
parent —— ニューゲームのみ。 ワールド生成時、ゲームは world の行から再帰し、構築中のノードを parent に指すすべての行を実体化します。したがって parent に ntyris のような大陸IDを設定すると、それ以降に作成したキャラクターにのみ反映されます。debug タグの行は開発モード以外ではスキップされます。既存のセーブデータには影響しません。
addMap —— 既存セーブを含む、ロードのたび。 Modパッケージ由来のゾーン行では、このタグがカスタムコンテンツのエントリを登録します。ロードごとにそのゾーンが既に存在するかを確認し、なければ生成して、その行の pos に従って大陸のワールドマップへ刻み込みます。親は次の順で解決されます:
- タグ内の値、例:
addMap(ntyris)—— 旧CWL構文addMap_ntyrisも受け付けます parent列ntyris
親はゾーンフルネームで検索されるため、Zone_<id>@<lv> でも素の <id> でも動作し、対象フロアが未生成なら必要に応じて作られます。
WARNING
pos は3つの値を含み、空いているワールドマップのタイルを指している必要があります。pos のないゾーンは -1000,-1000 に置かれ、どのタグを使っても永久に見えず、到達もできません。
複数階層のゾーン
階層モデル
ゾーンは浅いツリーを構成します:world → 大陸 → トップゾーン → その各フロア。lv は地上が 0、地下が負、天空が正です。GetTopZone() は1段しか遡らないため、フロアはトップゾーンの直接の子である必要があります——フロアの中にフロアを入れ子にはできません。
既定では、ダンジョンの各フロアは同じシート行を再利用します。フロアの区別はマップファイル名の _F<lv> サフィックスで行われます:
Maps/mymod_dungeon.z → lv 0
Maps/mymod_dungeon_F-1.z → lv -1
Maps/mymod_dungeon_F-2.z → lv -2
Maps/mymod_dungeon_F1.z → lv 1 (天空階層)フルネーム形式でも同様です:Maps/Zone_mymod_dungeon@-1.z。
マップファイルのないフロアはランダム生成にフォールバックするので、入口だけ手作りして深層は自動生成に任せることもできます。
階段
TraitStairsDown と TraitStairsUp(およびそのサブクラス TraitMineEntrance、TraitManhole)は、使用時に行き先を解決します:
- 目標階層 = 現在の
lv∓ 1 GetTopZone().FindZone(目標階層)—— 既に存在すればそのフロアを再利用- なければ生成:
SpatialGen.Create(GetTopZone().GetNewZoneID(目標階層), トップゾーン, …)としてlvを目標階層に設定
既定の GetNewZoneID はゾーン自身のIDを返すため、手順3はすべてのフロアを1行のシートデータにまとめます。特定の深さだけ別のデータ(名前、タイプ、派閥、ボスなど)が必要な場合は、Zone サブクラスでオーバーライドします:
public override string GetNewZoneID(int level)
{
if (level == -5) return "mymod_dungeon_boss";
return base.GetNewZoneID(level);
}戻りの階段は普通は置かなくてよい
両側ともDunGenジェネレーターを使わない場合、階段を使うと進入前イベントがキューされ、行き先フロアの同じ座標にバイオームのスタイルで逆向きの階段が生成されます。そのタイルに既に適切な向きの階段(または TraitStairsLocked)があればスキップされるため、手置きの階段は尊重されます。
同一トップゾーン内を移動する手段は他にも2つあります:
TraitElevator—— トップゾーンと既存の全フロアを一覧から選べます。TraitTeleporter—— 同じ刻印IDを持つ他のテレポーターとペアになります。まずマップ内、次にゾーンをまたいで探します。
別のゾーンへ繋ぐ
現在のゾーンのフロアではない場所へ送るには、traitにパラメーターが必要です。Trait.Params は物の trait 列、またはインスタンス単位では c_editorTraitVal から取られます。後者は先頭にカンマが付与されるため、あなたが書く最初の値が GetParam(1) になります:
| パラメーター | 意味 |
|---|---|
GetParam(1) | 行き先のゾーンID。テレポート系でないtraitでは、この値が空でなければ外部ゾーンリンクになり、行き先が現在のゾーンの子として生成され isExternalZone が立ちます。 |
GetParam(2) | 行き先の階層(lv)。既定は 0。 |
GetParam(3) | 到着地点の決定に使うテレポートマーカーID。 |
したがって TraitStairsDown,mymod_funk_house,0 のような専用のThing行を作れば、常にあなたのゾーンへ通じる階段になります。
インスタンスのパラメーターにゲーム内エディタはありません
c_editorTraitVal と c_idTrait はUnityのInspectorからしか公開されておらず、製品版ではその画面は無効です。公開ビルドでは、パラメーターを trait 列に焼き込んだ専用のThing行を定義するか、スクリプトModからフィールドを直接設定してください。
また TraitNewZone.OnImportMap() はインポート時に c_uidZone をクリアします:マップファイルは、その階段がどの具体的なゾーンインスタンスを指していたかを決して覚えていません。 リンクはtraitパラメーターか階層計算から再導出できる必要があります。
ゾーンプロファイル
idProfile は World/Zone/Profile/ 配下の ZoneProfile アセットを指し、マップをランダム生成するゾーンでのみ意味を持ちます。空欄の場合はゲームが自動で選びます:lv < 0 なら Underground、lv > 0 なら Sky、大陸の直下にある地上ゾーンならそのワールドマップタイルに割り当てられたプロファイルです。
組み込みプロファイルには Default、Dungeon、DungeonForest、DungeonWater、DungeonFactory、DungeonDead、DungeonCursedManor、Lesimas、Mine、Sky、Underground、U_Hill、U_Plain、U_PlainSmall、U_Seaside、U_Snow、U_Valley、および Random/ 系(Random/R_Plain、Random/R_Forest、Random/R_Mountain、Random/R_Shore、Random/R_Snow、Random/R_Water、Random/R_Undersea など)があります。これらはUnityリソースなので、Modがシートから追加することはできません。
トラブルシューティング
| 症状 | 考えられる原因 |
|---|---|
| 自作マップではなくランダムマップが読み込まれる | idFile がファイル名と一致していない、ファイルが Maps/ 配下にない、またはこのセーブで既にゾーンを訪問済み。 |
カスタム Zone サブクラスが動かない | type の解決に失敗し、黙って素の Zone にフォールバックしている。綴りと、アセンブリが登録されているかを確認。 |
| ワールドマップに何も出ない | pos が空か3値未満、あるいは world から辿れる parent も addMap タグも無い。 |
| ゾーンはあるのに入れない | closed タグが付いている。 |
| インポートしたマップからNPCと家具が消えている | エクスポート時に isPlayerCreation が立っていなかった。 |
| ある行以降がまったく読み込まれない | 途中に id が空の行があり、そこで読み込みが打ち切られた。 |
| 階段がどこにも繋がらない | 行き先を解決できないと「何も起こらない」と表示されます。多くは外部ゾーンリンクの GetParam(1) 欠落です。 |