四方山話/セーブ可能なラベルの自動生成

Last-modified: 2016-11-30 (水) 19:06:09

吉里吉里/KAGを使う上で面倒な作業の一つに、セーブ可能なラベルを置く作業がある。どこでもセーブプラグインを組み込んだり、自作変換ツールでセーブ可能なラベルを自動生成している制作者は少なくない。ここではGUIDを使って、セーブ可能なラベルを自動生成するスクリプトを紹介する。*1

以下のスクリプト(AutoLabeling.js;JScriptであってTJSではない)は、KAGシナリオファイル中のcmlマクロをセーブ可能なラベル+cmタグに、ctlマクロをセーブ可能なラベル+ctタグに変換する。この方法だと、KAGシナリオファイルの先頭に、

*chapter_1|第一章
[cm]

といった見出しつきのセーブ可能なラベル(+cm/ctタグ)を1つ置くだけで済む。

//
// 機能概要:
//   マクロcmlをセーブ可能なラベル+cmタグに変換する
//   マクロctlをセーブ可能なラベル+ctタグに変換する
// 使用法:
//   コマンドプロンプトから以下のコマンドラインを実行する
//       cscript //nologo AutoLabeling.js [KAGシナリオファイル1 ...]
// 備考:
//   ‐Windows Script Host 5.6以降がインストールされていること(Internet Explorer 6以降が
//     インストールされていれば一緒にインストールされているはず)
//   ‐セキュリティソフトによっては、当スクリプトの実行を遮断する可能性がある。その場合は、
//     実行の許可を与えること
//   ‐セーブ可能なラベルの書式は以下のようになる(xは0~9A~F)
//     *LB_以降の英数字はGUIDを加工したもので、重複することはまず有り得ない
//       *LB_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx|
//   ‐変換元のKAGシナリオファイルは、.oldという拡張子を付加した上でバックアップされる
//     同名のバックアップファイルが既にある場合は、無条件で上書きするので注意のこと
//
// 例:
//   KAGシナリオ中に以下の行(@cmlでも可)を埋め込んでおけば、
//       [cml]
//   次のように変換される(GUID部分は常に異なる)
//       *LB_428711FF_D971_4D3D_AE2E_CB852F476A77|
//       [cm]
//
// ☆ここから…
  // 変換対象の正規表現
  var objTarget1 = /^\[[cml\]$>^@cml$/;    // [cml]] または @cml だけの行にマッチする
  var objTarget2 = /^\[[ctl\]$>^@ctl$/;    // [ctl]] または @ctl だけの行にマッチする
  // セーブ可能なラベルの前行に置くタグ
  var sPrevTag1 = "";      // cmlマクロ変換時(何も置かない)
  var sPrevTag2 = "";      // ctlマクロ変換時(何も置かない)
  // セーブ可能なラベルのプレフィックス
  var sLBPre = "LB_";      // cml、ctlマクロ共通
  // セーブ可能なラベルの次行に置くタグ
  var sNextTag1 = "[cm]";    // cmlマクロ変換時(cmタグを置く)
  var sNextTag2 = "[ct]";    // ctlマクロ変換時(ctタグを置く)
  // 例えば、objTarget1とsNextTag1を以下のように変更すると *| の行を *LB_~| に変換するようになる
  //  var objTarget1 = /^\*\|$/;    // *| だけの行にマッチする
  //  var sNextTag1 = "";
  // バックアップファイルの拡張子
  var sBakExt = ".old";
// ☆ここまでの設定を変更のこと
// 以下は定数として扱う
var ForReading = 1;
var ForWriting = 2;
// 呼び出すたびに新しいGUIDを返す関数
function GetNewGUID()
{
  var objTypeLib = new ActiveXObject("Scriptlet.TypeLib");
  return objTypeLib.GUID;
}
// コマンドライン引数のチェック
if (WScript.Arguments.length < 1) {
  WScript.Echo("機能概要:マクロcmlをセーブ可能なラベル+cmタグに変換する");
  WScript.Echo("     マクロctlをセーブ可能なラベル+ctタグに変換する");
  WScript.Echo("使用法 :cscript //nologo AutoLabeling.js [KAGシナリオファイル1 ...]");
  WScript.Echo("備考  :セーブ可能なラベルの書式は以下のようになる:xは0~9A~F");
  WScript.Echo("       *LB_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx|");
  WScript.Quit();
}
// ファイルシステムオブジェクトの作成
var objFileSystem = new ActiveXObject("Scripting.FileSystemObject");
// 引数で指定されたKAGシナリオファイルを変換
var i;
for (i = 0; i < WScript.Arguments.length; i++)
{
  // KAGシナリオファイルの有無をチェック
  var sKSFile = WScript.Arguments(i);
  if (!objFileSystem.FileExists(sKSFile)) {
    WScript.Echo(sKSFile+"がありません。スクリプトを中断します");
    WScript.Quit();
  }
  // 変換元KAGシナリオファイルをバックアップする
  var sOldKSFile = sKSFile + sBakExt;
  try {
    objFileSystem.CopyFile(sKSFile, sOldKSFile, true);
  }
  catch (e) {
    WScript.Echo(sKSFile+"のコピーに失敗しました。スクリプトを中断します");
    WScript.Quit();
  }
  // 変換元KAGシナリオファイル(バックアップファイル)をオープン
  try {
    var objRKSFile = objFileSystem.OpenTextFile(sOldKSFile, ForReading, false);
  }
  catch (e) {
    WScript.Echo(sKSFile+"のオープンに失敗しました。スクリプトを中断します");
    WScript.Quit();
  }
  // 出力先KAGシナリオファイルをオープン
  try {
    var objWKSFile = objFileSystem.OpenTextFile(sKSFile, ForWriting, true);
  }
  catch (e) {
    WScript.Echo(sKSFile+"のオープンに失敗しました。スクリプトを中断します");
    WScript.Quit();
  }
  // KAGシナリオファイルを読み込み、変換対象をセーブ可能なラベルに変換(必要なら前後にタグを挿入)
  while (!objRKSFile.AtEndOfStream)
  {
    // 一行読み込み
    var sLine = objRKSFile.ReadLine();
    // cmlマクロか?
    if (objTarget1.test(sLine)) {
      // セーブ可能なラベルの前行に置くタグを挿入
      if (sPrevTag1.length > 0)
        objWKSFile.WriteLine(sPrevTag1);
      // セーブ可能なラベルに変換して出力する
      var sGUID = GetNewGUID().substr(1, 36).replace(/-/g, "_");
      objWKSFile.WriteLine("*" + sLBPre + sGUID + "|");
      // セーブ可能なラベルの次行に置くタグを挿入
      if (sNextTag1.length > 0)
        objWKSFile.WriteLine(sNextTag1);
    }
    // ctlマクロか?
    else if (objTarget2.test(sLine)) {
      // セーブ可能なラベルの前行に置くタグを挿入
      if (sPrevTag2.length > 0)
        objWKSFile.WriteLine(sPrevTag2);
      // セーブ可能なラベルに変換して出力する
      var sGUID = GetNewGUID().substr(1, 36).replace(/-/g, "_");
      objWKSFile.WriteLine("*" + sLBPre + sGUID + "|");
      // セーブ可能なラベルの次行に置くタグを挿入
      if (sNextTag2.length > 0)
        objWKSFile.WriteLine(sNextTag2);
    }
    // それ以外の行か?
    else {
      // 何も加工せずに出力
      objWKSFile.WriteLine(sLine);
    }
  }
  // KAGシナリオファイルをクローズ
  objRKSFile.Close();
  objWKSFile.Close();
  WScript.Echo(sKSFile+"を変換しました");
}

なお、cmlおよびctlマクロ定義は以下の通り。最終的には不要になるので、テキスト検索ツール(JGREPgetiaなど)でcml/ctlマクロが残っていないか確認すること。また、Config.tjsのsaveMacrosはfalseにしておくことが望ましい。
*2

[if exp="kag.debugMenu.visible"]
  [macro name=cml]
    [cm]
  [endmacro]
  [macro name=ctl]
    [ct]
  [endmacro]
[endif]

GUIDを使えば、重複しないラベル名が簡単・確実に得られるため、変換後のKAGシナリオを編集(cml/ctlマクロを置く)→セーブ可能なラベルの自動生成→また変換後のKAGシナリオを編集(cml/ctlマクロを置く)…が繰り返せて便利である。問題は、意味不明な文字の羅列に運用が耐えられるかどうかだろう。

上記スクリプトとその改造版は、以下からダウンロードできる。

  • fileAutoLabeling.lzh…上記スクリプト
  • fileAutoLabeling2.lzh…改造版1。ラベルのプレフィックスに直前のセーブ可能なラベル名を振るようにしたもの。cml/ctlマクロより先にセーブ可能なラベルがないと正しく動作しない
  • fileAutoLabeling3.lzh…改造版2。ラベルのプレフィックスにファイル名を振るようにしたもの

圧縮アーカイブ同梱のバッチファイル(AutoLabeling_drop.batなど)は簡単なフロントエンドで、以下のように使う。このバッチファイルは変換スクリプトと同じフォルダにコピーしておくこと。

  1. エクスプローラから変換対象のKAGシナリオファイルを選択(複数可)
  2. バッチファイル(AutoLabeling_drop.batなど)にドラッグ&ドロップする

類似のスクリプトは、『【雑務担当】冬コミ申し込み&吉里吉里TIPS番外編(ラベル打ち込み効率化) 追記あり』にもまとまっているので参照のこと。


*1 READMEに少し言及されているが、どこでもセーブプラグインは、パッチを適用するとセーブデータの互換性を損なう可能性が高いため、採用には充分な検討を要する。吉里吉里/KAGのメリット(パッチを適用してもセーブデータの互換性が保てる)をスポイルしていることに気付かず、安易に採用している制作者もいるようだ。
*2 この例ではkag.debugMenu.visibleが真、つまり[デバッグ]メニューを表示しているならcml/ctlマクロが使えるようにしている。