メインコンテンツへスキップ

コードフレームワーク

コンテンツのリスト

キャラクターがプレイ中にコンテンツを得られるようにします。リストを宣言し、アクションで変更し、シートに表示します。

リストとは

リストは、小物のパックのように、キャラクターがプレイ中に得るコンテンツを保持します。コンテンツは別のフレームワークで、そのプリセットがエントリです。リストはレジャーにあり、コンストラクタのフィールドではありません。変更できるのはアクションだけです。

オプション意味
labelリストの名前です。
ofコンテンツのフレームワークの ID です。
maxリストが持てるエントリ数です。1 から 128 までです。
cardエントリをカードとして描くフレームです。コンテンツのフレームワークのフレームにします。
summaryエントリの行に表示するフィールドです。最大 4 つです。
effects, caps, distinctBy修正値を変えるエントリと、その上限です。「プールと修正値」を参照してください。

各行にセルを加える行リストもありますが、まだ説明していません。

リストを宣言する

リストを、それを持つフレームワークに追加します。コンテンツのフレームワークは、エントリをプリセットとして持ちます。「Lantern を育てる」のチュートリアルでは、Trinket フレームワークを順に作ります。

schemas/keeper.json
  "lists": {
    "pack": {
      "label": "Pack",
      "of": "trinket",
      "max": 2,
      "card": "trinket-card",
      "summary": ["weight"]
    }
  }
  1. 45 行目 プリセットがエントリになるコンテンツのフレームワークです。
  2. 46 行目 リストが持てるエントリは、最大でこの数です。
  3. 47 行目 エントリを描くフレームです。
  4. 48 行目 エントリの行に表示するフィールドです。summary のフィールドには、閉じた範囲が必要です。選択肢、最小値と最大値、または真偽値です。

追加と削除

リストはアクションでしか変わりません。エントリを ContentRef の入力として受け取り、オファーを付けて list.add を呼び出します。

rules/pack-trinket.ts
export function pack_trinket(self: ElementRef, trinket: ContentRef): void {
  list.add(self, "pack", trinket, offer.where({ weight: { lte: 3 } }));
}
  1. 1 行目 プレイヤーが選ぶエントリです。
  2. 2 行目 list.add は最初にオファーを確認します。このオファーが許可するのは、weight が 3 以下のエントリです。

エントリは list.remove で削除します。

rules/unpack-trinket.ts
export function unpack_trinket(self: ElementRef, trinket: ContentRef): void {
  list.remove(self, "pack", trinket);
}
  1. 2 行目 選ばれたエントリを削除します。リストにそのエントリがなければ拒否されます。

プレイヤーがボタンを使うと、Fabled はオファーが許可するエントリから 1 つ選ぶよう求めます。独自のルールで追加を止めるには、「ルールの書き方」のページにあるように list.count を使います。

オファー

offer.where は、エントリのフィールドに対する条件を取ります。条件はリテラルで書くので、オファーはキャラクターを読めません。キャラクターに応じて変えたいときは、list.add の前に if で確認します。

演算子意味例
eqフィールドが値と等しい。{"slot":{"eq":"Ring"}}
neフィールドが値と等しくない。{"slot":{"ne":"Ring"}}
gte数値が値以上。{"weight":{"gte":2}}
lte数値が値以下。{"weight":{"lte":3}}
inフィールドが値のどれかと等しい。値は最大 64 個です。{"slot":{"in":["Ring","Cloak"]}}
hasフィールドがカンマ区切りのテキストで、値のどれかを含む。{"tags":{"has":["fire"]}}

オファーのすべての条件が成り立つ必要があり、オファーが指定できるフィールドは最大 6 つです。エントリにないフィールドは、決して一致しません。

シートに表示する

リストを表示するフレームはバージョン 2.0 を使います。dataContract でリージョンを宣言してから、描きます。リージョンは、各エントリに最大 4 つのボタンを付けることもでき、各ボタンはそのエントリに対してアクションを実行します。

layouts/keeper.json
      {
        "kind": "region",
        "id": "pack_list",
        "listBinding": "{{element.lists.pack}}",
        "emptyText": "Your pack is empty.",
        "itemActions": [{ "actionRef": "unpack_trinket", "label": "Unpack" }]
      }
  1. 46 行目 リストが空の間に表示されます。
  2. 47 行目 各エントリのボタンです。アクションが受け取る入力は、エントリだけにします。

テストする

オファーとサイズが返すすべての拒否をテストします。次のステップは、追加、3 通りの拒否、削除、削除の拒否を行います。

scenarios/pack.json
{
  "id": "pack-trinkets",
  "framework": "keeper",
  "parameters": {
    "name": "Mira",
    "max_hp": 10,
    "calling": "Guard",
    "lamp": "lamp"
  },
  "expectedValues": {
    "name": "Mira",
    "max_hp": 10,
    "hp": 10,
    "calling": "Guard",
    "guard": 3
  },
  "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } },
  "actions": [
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedWrites": [{ "op": "list.add", "key": "pack", "value": "rope" }]
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedRefusal": "ALREADY_IN_LIST",
      "expectedWrites": []
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "anvil" },
      "expectedRefusal": "NOT_OFFERED",
      "expectedWrites": []
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "candle" },
      "expectedWrites": [
        { "op": "list.add", "key": "pack", "value": "candle" }
      ]
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "bell" },
      "expectedRefusal": "LIST_FULL",
      "expectedWrites": []
    },
    {
      "action": "unpack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedWrites": [
        { "op": "list.remove", "key": "pack", "value": "rope" }
      ]
    },
    {
      "action": "unpack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedRefusal": "NOT_IN_LIST",
      "expectedWrites": []
    }
  ],
  "expectedLists": { "pack": ["candle"] }
}
  1. 19-24 行目 受け入れ: rope が追加されます。
  2. 25-31 行目 拒否: パックにはすでに rope があります。
  3. 32-38 行目 拒否: オファーは anvil を許可しません。
  4. 47-53 行目 拒否: パックは 2 つのエントリを持っていて、これが最大です。
  5. 54-61 行目 削除: rope がパックから出ます。
  6. 62-68 行目 拒否: rope はもうパックにありません。
  7. 70 行目 パックに残るのは candle だけです。

シナリオは、すでにエントリを持つリストから始めることもできます。lists にプリセット ID で指定し、expectedLists で確認します。

scenarios/seeded.json
{
  "id": "seeded-pack",
  "framework": "keeper",
  "parameters": {
    "name": "Mira",
    "max_hp": 10,
    "calling": "Guard",
    "lamp": "lamp"
  },
  "expectedValues": {
    "name": "Mira",
    "max_hp": 10,
    "hp": 10,
    "calling": "Guard",
    "guard": 3
  },
  "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } },
  "lists": { "pack": ["rope"] },
  "expectedLists": { "pack": ["rope"] }
}
  1. 18 行目 エレメントが最初に持つリストです。
  2. 19 行目 シナリオ後のリストです。

SAME_NAME と LIST_CAP は、効果を適用するリストの上限から出ます。「プールと修正値」のページで確認します。