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

コードフレームワーク

レシピ:スキルに対してロールする

スキルの値に対してパーセンタイルロールを判定し、成功ランクを表示します。

目標

プレイヤーが Lore スキルに対して d100 を振り、Flawless、Strong、Pass、Miss のランクを見られるようにします。ロールが低いほど良い結果です。

ロールの入り方

ルールはダイスを振れません。プレイヤーがシートで振り、出た数値をアクションに入力します。ルールがその数値を確認して書き込みます。プレイの流れは 4 つのステップです。

  1. ダイスのバッジをクリックします

    シートに Roll: [[1d100]] と表示されます。クリックすると d100 を振ります。

  2. ログでロールを読みます

    結果は、テーブルのダイスログとチャットに表示されます。この時点では、キャラクターには何も書き込まれません。

  3. アクションを実行してロールを入力します

    「Lore check」ボタンを押します。Fabled がダイアログでロールを尋ねます。ログにある数値を入力します。

  4. バンドが更新されます

    ルールがロールと目標値を書き込みます。レジャー関数がバンドを導き出し、シートに表示されます。

変更内容

スキーマに Lore の入力、アクション、レジャー関数を追加します。コンストラクタの入力には範囲を付けられます。

schemas/keeper.json
    "lore": {
      "label": "Lore",
      "description": "The percentile a Lore check must roll under.",
      "defaultValue": 40,
      "min": 1,
      "max": 99
    }
  1. 13-14 行目 この範囲が適用されるのは、キャラクターを作るときです。ロールには適用されません。
schemas/keeper.json
    {
      "id": "check_lore",
      "name": "Lore check",
      "source": "rules/check-lore.ts",
      "inputs": { "roll": { "label": "Roll", "min": 1, "max": 100 } }
    }
  1. 21-23 行目 Lore check アクションと、そのルールファイルです。
  2. 24 行目 Roll 入力: ラベルと範囲です。ダイアログがそれらを表示し、サーバーが強制します。
schemas/keeper.json
  "ledgerFunctions": [
    {
      "id": "last_band",
      "name": "Last band",
      "field": "last_band",
      "source": "rules/band.ts"
    }
  ]
  1. 32-35 行目 レジャー関数は、アクションが書き込む 2 つのフィールドから last_band を導き出します。

コンストラクタは、新しいフィールドをプレースホルダーとともに返します。レジャー関数は、エレメントが作られるときに last_band を置き換えます。

rules/keeper.ts
export function construct(
  name: string,
  max_hp: number,
  lore: number,
): {
  name: string;
  max_hp: number;
  hp: number;
  lore: number;
  last_roll: number;
  last_target: number;
  last_band: string;
} {
  return {
    name: name,
    max_hp: max_hp,
    hp: max_hp,
    lore: lore,
    last_roll: 0,
    last_target: 0,
    last_band: "",
  };
}
  1. 10-12 行目 アクションが書き込み、レジャー関数が読むフィールドです。
  2. 19-21 行目 初期値です。まだロールはありません。

入力の範囲により、ロールは 1 から 100 に保たれます。アクションは小数を含む数値を無視し、それ以外はロールとターゲットを書き込みます。

rules/check-lore.ts
export function check_lore(self: ElementRef, roll: number): void {
  if (math.floor(roll) === roll) {
    const lore: number = element.var(self, "lore") as number;
    ledger.set(self, "last_target", lore);
    ledger.set(self, "last_roll", roll);
  }
}
  1. 1 行目 ロールは、プレイヤーが入力する値です。
  2. 2 行目 小数を含む数値は無視します。入力の範囲により、すでに 1 から 100 に保たれています。
  3. 4-5 行目 目標値とロールを書き込みます。ランクはそこから決まります。

1 つのレジャー関数が、それらをランクに変えます。どのスキルのアクションも同じ 2 つのフィールドを書き込むので、すべてのスキルで使えます。

rules/band.ts
export function last_band(currentValue: string, self: ElementRef): string {
  const roll: number = element.var(self, "last_roll") as number;
  const target: number = element.var(self, "last_target") as number;
  if (roll === 0) {
    return "No roll yet";
  }
  if (roll <= math.floor(target / 5)) {
    return "Flawless";
  }
  if (roll <= math.floor(target / 2)) {
    return "Strong";
  }
  if (roll <= target) {
    return "Pass";
  }
  return "Miss";
}
  1. 2-3 行目 アクションが書き込んだ 2 つのフィールドを読みます。
  2. 4-6 行目 ロール前なら、そのことを返します。
  3. 7-15 行目 ロールは低いほど良い結果です。各ランクは、目標値の一定の割合です。
  4. 16 行目 目標値を超えると失敗です。

別のスキルには、check-lore.ts をコピーし、関数名と element.var 呼び出しのフィールドを変えます。フィールド名はコードに直接書くので、スキルごとに専用のアクションが必要です。

シートに、ダイス、ランク、ボタンを表示します。ランクを requiredBindings に、アクションをエイリアスに追加します。

layouts/keeper.json
      { "binding": "element.attributes.last_band", "expectedType": "string" }
  1. 15 行目 ランクはテキストです。
layouts/keeper.json
      { "name": "check_lore", "functionRef": "check_lore" }
  1. 21 行目 ボタンが使うエイリアスです。
layouts/keeper.json
      { "kind": "text", "text": "Roll: [[1d100]]" },
      {
        "kind": "text",
        "text": "Last check: {{element.attributes.last_band}}"
      },
      { "kind": "button", "label": "Lore check", "actionRef": "check_lore" }
  1. 35 行目 ダイスのバッジです。クリックするとロールし、結果がダイスログに表示されます。
  2. 36-39 行目 レジャー関数が導き出したランクです。
  3. 40 行目 ロール用のダイアログを開くボタンです。

テストする

各ランクと、範囲外のロールをテストします。各ステップは 2 つの書き込みを列挙します。expectedValuesAfter は、アクションの後のランクを確認します。

scenarios/lore.json
    {
      "action": "check_lore",
      "parameters": { "roll": 6 },
      "expectedWrites": [
        { "op": "ledger.set", "key": "last_target", "value": 40 },
        { "op": "ledger.set", "key": "last_roll", "value": 6 }
      ],
      "expectedValuesAfter": { "last_band": "Flawless" }
    },
  1. 17 行目 プレイヤーが入力した数値です。
  2. 18-21 行目 2 つの書き込みを順に示します。
  3. 22 行目 アクションの後に導き出されるランクです。

最後のステップは、ロール 40.5 です。何も書き込まないので、小数のガードが証明されます。ロール 500 はステップにできません。入力の範囲外であり、シナリオが拒否されます。

scenarios/lore.json
    {
      "action": "check_lore",
      "parameters": { "roll": 40.5 },
      "expectedWrites": [],
      "expectedValuesAfter": { "last_band": "Miss" }
    }
  1. 53 行目 小数を含む数値。
  2. 54 行目 書き込みなし。
  3. 55 行目 ランクは、前のステップの結果のままです。

シナリオファイルをマニフェストに列挙します。ほかのシナリオの期待値に、新しいフィールドを追加します。

manifest/project.json
{
  "formatVersion": "fabled.game-project/v1",
  "projectId": "game-your-game-id",
  "projectKind": "GAME",
  "compilerProfile": "native-game-v1",
  "name": "Lantern Keepers",
  "entryFramework": "keeper",
  "frameworks": ["schemas/keeper.json"],
  "scenarios": [
    "scenarios/new-keeper.json",
    "scenarios/heal.json",
    "scenarios/lore.json"
  ]
}
  1. 12 行目 新しいシナリオファイルです。

次へ