mkworks

シムトラ関係のエントリーまとめ群

Simutrans Advent Calender 2022 21日目 ~The Programable Dat~

Simutrans Advent Calender 2022 8日目に続いて21日目も担当させて頂くことになりました、当日ギリギリに書いているのでかなり乱雑な内容ですがご容赦
記事の一覧については以下のリンクからどうぞ

adventar.org

「pakに必要なものを3つあげよ」

この質問をされた時に何を3つ挙げるでしょうか? 今日の記事における模範解答としては以下の3つです

  • dat(pakの性能定義)
  • png(pakの外観)
  • makeobj(pak化)

どれもpakには必要な物です、諸元を定めるdat・外観を定めるpng・この2つをまとめてpakとして構成するmakeobj、最悪pngがなくてもアドオンとして定義出来るケース*1もありますがdatがないことには始まらないと思います。
これらを効率的に作るテクニックが今回のアドカレの17日目にM_Kasumiさんが公開した記事においてdat・png共に効率化するツールと手法として紹介されていますが、あえて別アプローチと言う形で今回は書いてみたいと思います。

前提条件

  • Ruby使います
  • Linux環境使います(開発の都合)
  • ドキュメントなくてもコードからドキュメントを拾う気合

なぜRuby(とLinuxやら)を使うのか

 理由は至極明快です、開発環境としてある程度整っているのがLinux環境上だっただけです。Windows環境でもそれなりに整えることは出来ると思いますが、既に開発関係はLinux上にある程度構築しており、どのマシンからでもSSH経由で作業が出来る強みがあります。
既にアドオンの構成ファイル(datもしくはpng)が更新された場合に自動でmakeobjを走らせるスクリプトがあるなど、切っても切り離せなくなりました。
そんなLinux環境*2で部分的に動くdatを書くための言語として開発中である「Radgrid(仮称)」について少しお話させていただきます。
Radgridについては以下のリポジトリからソースコード等をダウンロードなりすることが出来ますので、気が向いたら覗いてみてください。処理がガサツなコードまみれですが。
github.com

datの言語化とは?

 端的には「一定の言語規則に基づいて書いたらdatが出力される」という風にだけ覚えていてください、実際はフォーマットがガチガチだったりするので自由度的にはKasumiさんのよりはあるかないか位だと思います。内部でガチガチなRubyの処理コードを書けるので記法やテクニックをわかっていたら効率よく書けるかもしれない、そんなレベルです。

サンプルコード

# coding: utf-8
#common
obj "builDing"
name "YIC-Mk_EX-/platform-1f_1"
copyright "wa / M.Kousaka"
#DratBuilding.group "station"
#group "station"
dims 1,1,16
type "stop"
enables "pax"
level 3
waytype "track"
_image "platform-f_fence"
cursor 5
icon 4
offset 2,0
_snow 1
#infos(['info','construction','ground'])
infos(['ground'])
frontImage{
  siz = 0..@dim_t.to_i - 1
  y_pos = 0
  y_pos.to_i

  siz.each do |pos|
    line = "FrontImage[#{pos}][0][0][0][0][0]=#{@image}"
    if pos.to_i < 8
      if pos.to_i == 0 || (pos.to_i % 2) == 0
        puts line.to_s + ".#{y_pos}.#{@offset_x}"
      else
        puts line.to_s + ".#{y_pos}.#{@offset_x + 1}"
        y_pos += 1
      end
    else
      if pos.to_i == 0 || (pos.to_i % 2) == 0
        puts line.to_s + ".#{y_pos}.#{@offset_x - 2}"
      else
        puts line.to_s + ".#{y_pos}.#{(@offset_x - 2)+ 1}"
        y_pos += 1
      end
    end
    if pos.to_i == 7
      puts "\n"
      y_pos = 0
    end
  end
  puts "\n"
  if @snow == 1 # 降雪画像がある場合のみ追加処理
    siz.each do |pos|
      line = "FrontImage[#{pos}][0][0][0][0][1]=#{@image}"
      if pos.to_i < 8
        if pos.to_i == 0 || (pos.to_i % 2) == 0
          puts line.to_s + ".#{y_pos}.#{@offset_x}"
        else
          puts line.to_s + ".#{y_pos}.#{@offset_x + 1}"
          y_pos += 1
        end
      else
        if pos.to_i == 0 || (pos.to_i % 2) == 0
          puts line.to_s + ".#{y_pos}.#{@offset_x - 2}"
        else
          puts line.to_s + ".#{y_pos}.#{(@offset_x - 2)+ 1}"
          y_pos += 1
        end
      end
      if pos.to_i == 7
        puts "\n"
        y_pos = 4
      end
    end
  end
}

backImage{
  siz = 0..@dim_t.to_i - 1
  y_pos = 0
  y_pos.to_i

  siz.each do |pos|
    line = "BackImage[#{pos}][0][0][0][0][0]=#{@image}"
    if pos.to_i < 8
      if pos.to_i == 0 || (pos.to_i % 2) == 0
        puts line.to_s + ".#{y_pos}.#{@offset_x}"
      else
        puts line.to_s + ".#{y_pos}.#{@offset_x + 1}"
        y_pos += 1
      end
    else
      if pos.to_i == 0 || (pos.to_i % 2) == 0
        puts line.to_s + ".#{y_pos}.#{@offset_x - 2}"
      else
        puts line.to_s + ".#{y_pos}.#{(@offset_x - 2)+ 1}"
        y_pos += 1
      end
    end
    if pos.to_i == 7
      puts "\n"
      y_pos = 4
    end
  end
  puts "\n"

  if @snow == 1 # 降雪画像がある場合のみ追加処理
    y_pos = 4 
    siz.each do |pos|
      line = "BackImage[#{pos}][0][0][0][0][1]=#{@image}"
      if pos.to_i < 8
        if pos.to_i == 0 || (pos.to_i % 2) == 0
          puts line.to_s + ".#{y_pos}.#{@offset_x}"
        else
          puts line.to_s + ".#{y_pos}.#{@offset_x + 1}"
          y_pos += 1
        end
      else
        if pos.to_i == 0 || (pos.to_i % 2) == 0
          puts line.to_s + ".#{y_pos}.#{@offset_x - 2}"
        else
          puts line.to_s + ".#{y_pos}.#{(@offset_x - 2)+ 1}"
          y_pos += 1
        end
      end
      if pos.to_i == 7
        puts "\n"
        y_pos = 4
      end
    end
  end
}

ソース: radgrid/sample_plathome.rdg at master · Myagami/radgrid · GitHub

言わなくてもわかります、明らかに汚いコードというのは自他ともに認めざるを得ません。
これはpak.nippon向けに制作している「YIC_Platform_Extends」というプラットホームのニッチな拡張アドオンの1ファイルをradgird向けに書き直したものになります

github.com

ぱっと見で「これはdatの劣化コピーじゃないか?」と思われるかもしれませんが、それがおそらく正解です。
思想としては「既存のdatを一部手直しすればRadgrid側で読み込める」という所があります、それだけでなく同一画像を使用する前提として設計しているので画像指定を1箇所でして、内部的にはそこから参照したり、今のところ画像指定部分では生のRubyソースコードを書けるようにして柔軟性(要検証)をもたせたりしています。
建物についてはかなり複雑なコードになりつつありますが、車両についてはかなりシンプルな構成になっている…とは思います

obj "vehicle"
name "JRH DC_Kiha_130"
copyright "555"
waytype "track"
_group "diesel"
#engine_type "diesel"
#smoke "Diesel"
engine_smoke
freight "Passagiere"
speed "110"
gear "140"
payload "100"
cost "1800000"
weight "28"
power "186"
length "6"
RunningCost "110"
sound "2"
year_month([1988,10],[2003,3])

車両アドオンのソースについては都合により日本語化Wikiに投稿されている555さんの「[Emu][Dmu]JR北海道車両セット」よりキハ130系のdatをサンプルコードに変換して作成しております、こっちのほうが結構シンプルに書ける要素が多いとは思います。
intro_year/monthとretire_year/monthを1つの行でまとめて書いて「これは1988年10月から登場して、2003年の3月には引退するな」という直感的なメソッドになっていたり、車両のタイプを指定したら付随する要素を自動的に指定したりと細かいところは手が入っていても、車両アドオン(特に電車や特急等)で必要な「連結設定が破綻していないか*3」といった重要な要素がまだ実装しきれていません。とりあえず気動車1両ならシンプルなテストが出来るので…*4

まだまだ荒削りな言語について雑な紹介という形で21日目の記事とさせていただきました、今後なにか更新したりしていたらシムトランス交流会議なる所にこっそり書いているかもしれません。
参加についてはこの記事をご参照ください
シムトランス交流会議 参加者募集! - Simutrans Addon Portal

最後に

余談①

8日目の記事のタイトルは「そのマップを離さない」、今日の記事のタイトルは「The Programable Dat」、そして記事で出した言語名は「Radgrid」
仕込んできた答え合わせと行きましょう

  • そのマップを離さない

bushiroad-music.com
楽曲:君の手を離さない、厳密には「君の手を離さない ~BOUQUET Ver.~」が正解です

  • The Programable Dat

assaultlily-pj.com
舞台名: The Fateful Gift

  • Radgrid

dic.pixiv.net

ヴァルキリーの一柱

『アサルトリリィ』に登場する「一柳隊」の正式名。

余談②

言語名としてRadgridを付けた話とその由来については先に上げましたが、最初はdratという明らかに適当につけた名前でしたが英和翻訳を掛けたら明らかに和訳結果が色々と申し訳なくなったので仮案として「Radgrid」か「Eir(エイル)」で悩んだ末に「Radgridのほうがかっこいいじゃん」ということで決定、なおEirについてもまぁ…そういうことです。

youtu.be

詳しい話はこの動画に一切を丸投げします

*1:知っている限りでは貨物の定義

*2:ほとんど拡張なしのRubyではありますが、Windowsでは動作確認していません

*3:連結する側とされる側でそれぞれ設定されてないと、組成出来ても走れないため

*4:なお、キハ183でテストしようとしたらN183やらNN183等細かい要素が多いので頭痛の種になりそうです、先に挙げたセットに同梱されているキハ183は設定無し