マップファイルのinclude構文

:::note
これはBve Trainsimのマップファイルに関する記事です。
https://bvets.net/jp/edit/
:::

# 1. includeディレクティブとは
他のマップファイルの内容をその位置に挿入する構文です。
## 仕様
<details><summary>サンプル</summary>

~~~ mainmap.txt
BveTs Map 2.00

0;
  Track[0].Position(3.80, 0.00);

　include 'submap.txt';

1200;
  Track[0].Position(7.60, 0.00);
~~~
~~~ submap.txt
BveTs Map 2.00

980;
  Beacon.Put(0, 1, 0);
1000;
  Section.BeginNew(0, 4);
~~~

読み込み後
~~~
BveTs Map 2.00

0;
  Track[0].Position(3.80, 0.00);


980;
  Beacon.Put(0, 1, 0);
1000;
  Section.BeginNew(0, 4);

1200;
  Track[0].Position(7.60, 0.00);
~~~
</details>

includeされたファイルのマップファイルヘッダー以外の行が呼び出し元のファイルに展開されます。

公式ドキュメントにあるとおり、includeされるファイルにもマップファイルヘッダーが必要です。
なお、マップファイルヘッダー以外にBVEの動作に有効な行がない場合、「オブジェクト参照がオブジェクトインスタンスに設定されていません」のエラーが出ます。

includeで指定するファイルのパスは、シナリオファイルで指定されたマップファイルに対する相対パスになります。

:::note warn
後述しますが、includeの展開が完了した後に計算が行われるため、includeで指定するファイルパスに変数や計算式は使用できません。この場合も「オブジェクト参照がオブジェクトインスタンスに設定されていません」のエラーが出ます。
:::

## 利点
- シナリオの分岐分割が楽
  例えば、A駅～D駅の路線で列車1はB駅1番線、列車2はB駅2番線、列車3はC～D駅のみとする場合、
　ファイルVはA駅～B駅分岐、ファイルWはB駅分岐～B駅1番線～B駅合流、ファイルXはB駅分岐～B駅2番線～B駅合流、ファイルYはB駅合流～C駅手前、ファイルZはC駅手前～D駅として、
　列車1はファイルVとファイルWとファイルYとファイルZ、列車2はファイルVとファイルXとファイルYとファイルZ、列車3はファイルZをincludeします。
　ファイルの数は増えますが、ファイルサイズの合計は小さくなります。また、AB駅間を修正したい場合はファイルVだけ修正すれば良くなるので保守も楽になります。

- 同じ動作の繰り返しをまとめる
  たとえば、いつもSection.Beginの20m前と600m前にBeacon.Putを9種類置かないといけない場合に、Beacon.Putを9種類置く構文だけのファイルを作って、Section.Beginの際に一緒にincludeを書けば、行数はかなり抑えられます。

# 2. 多重include
includeされるファイルの中にincludeを設置することも可能です。
<details><summary>サンプル</summary>

~~~mainmap.txt
BveTs Map 2.00

0;
  Track[0].Position(3.80, 0.00);

　include 'submap1.txt';

1200;
  Track[0].Position(7.60, 0.00);
~~~

~~~submap1.txt
BveTs Map 2.00

980;
  Beacon.Put(0, 1, 0);

include 'submap2.txt';
~~~

~~~submap2.txt
BveTs Map 2.00

1000;
  Section.BeginNew(0, 4);
~~~
</details>

まずmainmap.txtにsummap1.txtが展開されます。
<details><summary>展開後1</summary>


~~~ mainmap.txt
BveTs Map 2.00

0;
  Track[0].Position(3.80, 0.00);

980;
  Beacon.Put(0, 1, 0);

include 'submap2.txt';

1200;
  Track[0].Position(7.60, 0.00);
~~~
</details>
新たなincludeが見つかったのでそれが展開されます。

<details><summary>展開後2</summary>

~~~ mainmap.txt
BveTs Map 2.00

0;
  Track[0].Position(3.80, 0.00);

980;
  Beacon.Put(0, 1, 0);

1000;
  Section.BeginNew(0, 4);

1200;
  Track[0].Position(7.60, 0.00);
~~~
</details>

この順序で展開されていると思われます。
そのため、submap1.txtで指定するsubmap2.txtのパスは、submap1.txtからの相対パスではなくmainmap.txtからの相対パスである必要があります。

# 3. 変数
include先のファイルも普通のマップファイルと同じで変数や計算式が使用できます。

## distance
注意が必要なのが、現在の距離程が格納されている変数distanceです。これはファイルごとに管理されているような挙動をします。
すなわち、マップファイルヘッダーの次の行に見えない距離程0mの指定構文があると思ってください。
~~~mainmap.txt
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

　include 'submap1.txt';

  Track[0].Position(7.60, 0.00);
~~~

~~~ submap1.txt
BveTs Map 2.00

  Beacon.Put(0, 1, 0);
200;
  Beacon.Put(0, 1, 0);
~~~

~~~ mainmap.txt(顧客が欲しかったもの)
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

  Beacon.Put(0, 1, 0);
200;
  Beacon.Put(0, 1, 0);

  Track[0].Position(7.60, 0.00);
~~~
~~~ mainmap.txt(実際に得られたもの)
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

0; // <- 見えない0m指定
  Beacon.Put(0, 1, 0);
200;
  Beacon.Put(0, 1, 0);

100; // <- include前の距離程が再指定される。
  Track[0].Position(7.60, 0.00);
~~~
includeが絡む形で変数distanceを使用したい場合は注意が必要です。

## 関数もどき
変数distance以外は展開後に計算・代入が行われます。
したがって、変数を使用してinclude先に値を渡すことができますし、include先での計算結果をinclude元で使用することもできます。

例1:
~~~mainmap.txt
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

$distance = distance;
　include 'submap1.txt';

200;
$distance = distance;
　include 'submap1.txt';
~~~

~~~ submap1.txt
BveTs Map 2.00

$distance;
  Beacon.Put(0, 1, 0);
$distance+20;
  Beacon.Put(0, 1, 0);
~~~
~~~ mainmap.txt(展開後)
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

$distance = distance;
100; // $distance;
  Beacon.Put(0, 1, 0);
120; //$distance+20;
  Beacon.Put(0, 1, 0);

200;
$distance = distance;
200; //$distance;
  Beacon.Put(0, 1, 0);
220; //$distance+20;
  Beacon.Put(0, 1, 0);
~~~

例2:
~~~mainmap.txt
BveTs Map 2.00

100;
  Track[0].Position(3.80, 0.00);

200;
$radius = 500;
$length = 100;
  Track[0].X.Interpolate(3.80, $radius);
　include 'curve1.txt';

distance + $length;
  Track[0].X.Interpolate(3.80+$deltaX, 0);
~~~

~~~ curve1.txt
BveTs Map 2.00
// $radius:半径(m) (右カーブが正)
// $length:直進距離(m) ($radius > $length)
// 変位(m)
$deltaX = $radius - sqrt($radius * $radius - $length * $length);
// 角度(deg)
$deg = asin($length / $radius) * 180 / 3.14;
~~~