Liminalia

Ink と Yarn Spinner のインポート

Ink(inkle の .ink)と Yarn Spinner 2(.yarn)で書いたシナリオを .lim に変換して取り込む。 変換は packages/story-import にあり、lim import-ink / lim import-yarn と、Studio の「テキストをインポート」が同じものを使う。 扱えない書き方があっても止めずに、コメントにして残し、報告に出す。

使い方

lim import-ink  [プロジェクト] story.ink                 # INCLUDE のファイルも読み込む
lim import-yarn [プロジェクト] dialogue/                 # フォルダの中の .yarn をすべて(ファイルを並べてもよい)
lim import-yarn [プロジェクト] intro.yarn --name opening # 書き出す .lim の名前(Ink と、Yarn のファイルが一つのとき)
lim import-ink  [プロジェクト] story.ink --end stop      # 話の終わりの扱い(下)
  • .lim はシナリオのフォルダ(paths.scenario)に、元のファイル名(英数字、_、- 以外は _ に)で書く。 Ink は INCLUDE を含めて一つの .lim に、Yarn Spinner は .yarn ごとに一つの .lim にする(ノードの名前はファイルをまたいで共通。 別のファイルのノードへの <<jump>> は ファイル#ラベル になる)
  • 同じ名前の .lim があるときは、前に lim import-ink / lim import-yarn で作ったもの(先頭の行がその印のコメント)だけを上書きする。 ほかは上書きせずに報告に出す(--force で上書き)
  • 台詞の話者は cast.json の speakers に、変数の初期値は liminalia.json の variables に足す(すでにある変数は変えない)
  • 報告はプロジェクトの ink-import-report.md / yarn-import-report.md(TyranoScript の import-report.md と同じ形。 mapped は変換したもの、dropped は書き出さないと決めたもの、generic は対応表に無くコメントにしたタグとコマンド、 manual は変換しない構文)。変換した .lim を読み直した構文エラーと検査エラーも出す
  • 終了コードは、generic、manual、エラー、上書きしなかったファイルがすべて 0 のとき 0、それ以外は 1
  • --end は話の終わり(Ink の END、DONE、Yarn のノードの終わりと <<stop>>)を何にするか。 title(既定。@title-screen でタイトル画面へ戻る)、stop(@stop)、return(@return。@call で呼ぶ話にするとき)

Studio では、「テキストをインポート」の形式で Ink か Yarn Spinner を選ぶ(.ink、.yarn のファイルを落とすか、自動で見分ける)。 一つのファイルとして変換し、変数の初期値は先頭の @set の行に書く。変換できない箇所の数と理由を変換結果の横に出す。

変換するもの

Ink

Ink.lim
=== ノット ===、= ステッチ# ノット、# ノット-ステッチ(ステッチがあって中身の無いノットは最初のステッチへ)
本文、名前: 台詞、#speaker: 名前 のタグ地の文、名前「台詞」
<>(グルー)前後の行を一行に
-> 先、-> END、-> DONE@jump #先、終わり
-> 先 ->、->->(トンネル)@call #先、@return
* + の選択肢、[ ]、{条件}、(ラベル)、入れ子、ギャザー -(ラベル付きも)@choice と、選んだ後の中身と続きのラベル
*(一度だけ)同じ選択肢に戻ってくる作りのときだけ、選んだかどうかの変数(game.once_…)で隠す
文の無い選択肢 * -> 先ほかの選択肢がすべて出ないときに 先 へ
VAR、CONST、~ tempgame. の変数(初期値は liminalia.json)、値そのもの、@let
~ x = …、+=、-=、++、--@set / @let
{x}、{条件: A|B}、{A|B}、{&A|B}、{~A|B}、{!A|B}{= …} の式(順番は game.ink_seq… で数える)
{条件: -> a | -> b}行ごとの @if
複数行の {条件: … - else: …}、{ - 条件: … }、{ x: - 1: … }@if / @elif / @else(選択肢やラベルを中に持つときは枝ごとのラベルへのジャンプ)
複数行の {stopping: …}、{cycle: …}、{once: …}、{shuffle: …}回数の変数か乱数での @if
ノット、ステッチの名前を式で使う(訪れた回数)、READ_COUNT(-> x)そのラベルで増やす game.seen_…
RANDOM、INT、FLOOR、CEILING、MIN、MAX、FLOATrandom、floor、ceil、min、max
and or not mod&& || ! %
#タグ(行末、行だけ)対応表のコマンド(その行の前に置く)
INCLUDE始まりのファイルのフォルダの中のファイルだけを、後ろにつないで読む
TODO:コメント

変換しないもの(コメントにして報告に出す): 関数(=== function)、ノットとステッチの引数、スレッド <-、LIST、EXTERNAL、 ジャンプ先を値にする式と変数へのダイバート、TURNS などの関数、選択肢の文の中の順番(いつも同じ回の文を出す)。 shuffle once などは shuffle として変換する。整数どうしの割り算は小数になる(Ink は切り捨て)。

Yarn Spinner

Yarn Spinner.lim
ノード(title: 〜 --- 〜 ===)# タイトル(Start という名前のノードをファイルの先頭に置く)
本文、名前: 台詞地の文、名前「台詞」
-> 選択肢(字下げした中身)、-> 選択肢 <<if 条件>>@choice と、選んだ後の中身と続きのラベル
<<jump ノード>>、<<detour ノード>>、<<return>>、<<stop>>@jump、@call、@return、終わり
<<declare $x = 値>>、<<set $x to …>>(= += -= *= /=)game.x の初期値(liminalia.json)、@set
宣言の無い変数game.x(初期値は <<set>> の値の種類から 0、""、false。報告の情報に出す)
<<if>> <<elseif>> <<else>> <<endif>>@if / @elif / @else / @end
{$x}、{式}{= …}
visited("ノード")、visited_count("ノード")そのノードで増やす game.seen_…
random()、random_range(a, b)、dice(n)、round、floor、ceil、int同じ働きの式
and or not xor is eq neq gt lt gte lte&& || ! != == == != > < >= <=
[b] [i] [wave] [shake]、[pause=500 /]、[nomarkup]{b …} {i …} {fx wave …} {fx shake …}、{@wait 500ms}、そのままの文字
#line:…(行の ID)書き出さない
ほかの <<コマンド>> と #タグ対応表のコマンド

変換しないもの(コメントにして報告に出す): 行のグループ =>、<<once>>、式のジャンプ <<jump {$x}>>、[select] などの置き換えのマークアップ (中の文字だけを残す)、ほかの関数。

タグとコマンドの対応表

Ink のタグ(# bg: forest.png も # bg forest.png も同じ)と Yarn Spinner のコマンド(<<bg forest.png>>)は、名前で対応表を引く。 組み込みの表:

名前.lim
bg、background@bg {1}
bgm、music@bgm {1}
stop-bgm、stop_bgm、stopmusic、stop_music@stop-bgm
se、sfx、sound@se {1}
voice@voice {1}
wait@wait {1:s}(秒)
chara、show@chara {1} {2?}
hide@chara-hide {1}
hide-all、hide_all@chara-hide-all
quake、shake@quake

プロジェクトで足したり上書きしたりするときは、liminalia.json に書く(名前の大文字と小文字は区別しない)。

"import": {
  "ink": { "commands": { "flash": "@quake time=200ms", "mood": null } },
  "yarn": { "commands": { "fade_out": "@mask fade={1:s}", "camera": "@camera zoom={1}" } }
}
  • 型の中の {1} {2} は何番目の値(無ければ変換せずにコメントにする)、{2?} は無ければ空、{1:s} は秒の数を時間に(2 → 2s)、 {1:ms} はミリ秒、{*} はすべての値。空白を含む値は "…" で囲む。\n で区切れば複数の行にできる
  • null はそのタグ、コマンドを書き出さない(dropped として数える)
  • 対応表に無いものは // #タグ か // <<コマンド>> のコメントにし、報告の「対応表に無いタグとコマンド」に件数を出す