論理と、幻想と。

ゲームやガジェットが好きなITスペシャリストが作ったものや考えたことについてダラダラ書きます

タイムライン定義におけるテーブルソートの実装例

スペスペたいむ用タイムライン定義ファイルにおけるテーブルソート機能の仕組みについて、実例を交えて簡単に解説します。

スペスペたいむは補助輪に含まれるプラグイン、SpecialSpellTimer(通称スペスペ)の機能の一つです。補助輪はanoyetta氏によって開発されているACT用プラグインの詰め合わせです。

github.com

テーブルソート機能は、絶アレキサンダー討滅戦における未来観測ギミックに対応する機能として開発して頂いたものですが、他にもランダムに出現する要素を一定機序で並び替えて評価するなど汎用的に使える機能です。

本記事で例として用いるタイムライン定義ファイルはこちらです。

blog.sheeva.me

蛇足ですが、未来観測ギミックでテーブル機能が役に立った理由はこちらです。

blog.sheeva.me

値の格納

テーブルへの値の格納は変数のsetと同様に作用します。トリガーがマッチし、expressionタグ内のpre条件を満たしていた場合、テーブルに1行のレコードを代入します。行内の列名および格納する値はtableタグ内にJSON形式で指定します。後方参照によって、マッチングさせた文字列をそのまま値として代入することができます。

<t name="Alpha-Tableset" sync="03:([0-9A-F]{8}):Added new combatant .  Job: (\w{3}) Level: 80 Max HP: 148000 Max MP: 0 Pos:" >
  <expressions>
    <pre name="current" value="alpha" />
    <table>
      {
      "method" : "Insert",
      "table" : "alpha",
      "cols" : [
          {
              "name" : "id",
              "val" : "$1",
              "key" : "true"
          },
          {
              "name" : "job",
              "val" : "$2",
          }
        ]
      }
    </table>
  </expressions>
</t>

Sync句"03:([0-9A-F]{8}):Added new combatant . Job: (\w{3}) Level: 80 Max HP: 148000 Max MP: 0 Pos:" と、tableタグ内の後方参照に注目します。後方参照とは、正規表現によってマッチングした文字列グループの値を後に評価するための手法です。カッコで括ったグループが有効なキャプチャグループになります。正規表現パターン内で1つ目に登場したグループから順に $1$2$3……のようにして参照します。ログ解析では頻出です。

最初の正規表現グループである ([0-9A-F]{8}) を table タグ内で $1 として参照し、id 列に格納しています。これはギミックで登場するクローンが持つIDです。クローンが持つID順にソートする必要があるため、id 列の key 属性にtrue を指定することでこの列をテーブルのソートキーに設定しています。

2つ目の正規表現グループは (\w{3}) です。これは正規表現で任意のアルファベット3文字にマッチングします。未来観測ギミックの例ではここにジョブ名称が入ります。2つめに登場する正規表現グループなので$2 として参照し、値を job 列に格納します。

値の評価

ログに8体のクローンが出現し、このトリガーの評価が8回分完了すると、テーブル内のデータは以下の例のようになります。

要素番号 id (key) job
0 4000A4B6 Mnk
1 4000A4B7 Pld
2 4000A4B8 Whm
3 4000A4B9 Drg
4 4000A4BA Brd
5 4000A4BB Smn
6 4000A4BC Drk
7 4000A4BD Sch

要素番号の考え方はプログラミングにおける一般的な配列と同じです。key属性を持つ id 列の値により昇順にソートされ、若い順から要素番号が割り当てられます。

この要素番号を指定することで任意の値の呼び出しが可能です。実際の記述方法としては TABLE['alpha'][0]['job']のようにテーブル名と要素番号と列名を指定してテーブル内の値を呼び出します。変数として通知文(text)の一部に組み込むことも可能ですし、後述しますが pre タグによる前提条件の評価にも用いることができます。

<a time="100" text="1番目の値を表示" >
  <v-notice
    text="1番目は TABLE['hoge'][0]['job']"
    duration="10"
    duration-visible="false" />
</a>

値(レコード)はトリガーによって動的に格納されていきますが、正確な評価のためには、期待するレコードがすべてテーブル内に格納されたタイミングで評価する必要があります。テーブル内のデータの評価にはタイムラインのアクティビティやトリガーなど任意の方法を用いることができますが、そのタイミングには注意が必要です。

テーブル内の値の判定タイミングとテーブルへ値を格納するタイミングが同時だと期待した通りの動作をしない可能性があります。

私の作成したタイムライン定義では以下のようにトリガー発動タイミングをずらしています。


1. 未来観測αまたはβの詠唱開始で初期化

未来観測は2回あり、クローン出現ログパターンも同じであるため、現在詠唱開始しているのがαかβのどちらであるかを変数 currentに格納します。

<t name="Alpha-init" sync="00:282b:パーフェクト・アレキサンダーは「未来観測α」の構え。" >
  <expressions>
    <set name="current" value="alpha" />
  </expressions>
</t>

2. クローン出現をキャプチャしてテーブルにレコードをセット(2つ目のトリガー)

値の格納の項目に例示したトリガーを用いて、currentalpha ならテーブル alphaにレコードを格納していきます。


3. 未来確定の詠唱開始時にテーブル内のレコードを評価(3つ目のトリガー群)

直前の未来観測の完了から少し時間をあけることで、8体すべてのクローンが出現し、テーブル内に8個のレコードが格納されていることが確実に期待できます。要素番号を用いて上から順番にレコードを評価していき、「job列が自分のジョブと一致するレコード」が要素番号のいくつめであるかを判定します。

<t name="α:加重罰1" sync="00:282b:パーフェクト・アレキサンダーは「未来確定α」の構え。" >
  <expressions>
    <pre name="TABLE['alpha'][3]['job']" value="@Model.Player.Job" />
  </expressions>
  <v-notice
    text="加重:右"
    icon="PunishmentHevy.png"
    duration="30"
    duration-visible="false" />
</t>

preタグ内では変数の評価が行えますが、テーブル内の値を比較することが可能です。 TABLE['alpha'][0]['job']のように要素番号と列名を指定してテーブル内の値を呼び出します。上記例ではテーブルalpha の要素番号3のレコードのjobから値を取り出しています。この値が @Model.Player.Job と一致していれば、このトリガーが発動し notice および v-notice で指定した通知が行われます。

@Model.Player.Job はタイムラインのロード時にRazor構文がコンパイルされる際の自分のジョブ名(英字3文字)で置き換えられます。私はジョブによる分岐を組み込む際によく使います。