コードフレームワーク
レシピ:スキルに対してロールする
スキルの値に対してパーセンタイルロールを判定し、成功ランクを表示します。
目標
プレイヤーが Lore スキルに対して d100 を振り、Flawless、Strong、Pass、Miss のランクを見られるようにします。ロールが低いほど良い結果です。
ロールの入り方
ルールはダイスを振れません。プレイヤーがシートで振り、出た数値をアクションに入力します。ルールがその数値を確認して書き込みます。プレイの流れは 4 つのステップです。
- ダイスのバッジをクリックします
シートに Roll: [[1d100]] と表示されます。クリックすると d100 を振ります。
- ログでロールを読みます
結果は、テーブルのダイスログとチャットに表示されます。この時点では、キャラクターには何も書き込まれません。
- アクションを実行してロールを入力します
「Lore check」ボタンを押します。Fabled がダイアログでロールを尋ねます。ログにある数値を入力します。
- バンドが更新されます
ルールがロールと目標値を書き込みます。レジャー関数がバンドを導き出し、シートに表示されます。
変更内容
スキーマに Lore の入力、アクション、レジャー関数を追加します。コンストラクタの入力には範囲を付けられます。
"lore": {
"label": "Lore",
"description": "The percentile a Lore check must roll under.",
"defaultValue": 40,
"min": 1,
"max": 99
}- 13-14 行目 この範囲が適用されるのは、キャラクターを作るときです。ロールには適用されません。
{
"id": "check_lore",
"name": "Lore check",
"source": "rules/check-lore.ts",
"inputs": { "roll": { "label": "Roll", "min": 1, "max": 100 } }
}- 21-23 行目 Lore check アクションと、そのルールファイルです。
- 24 行目 Roll 入力: ラベルと範囲です。ダイアログがそれらを表示し、サーバーが強制します。
"ledgerFunctions": [
{
"id": "last_band",
"name": "Last band",
"field": "last_band",
"source": "rules/band.ts"
}
]- 32-35 行目 レジャー関数は、アクションが書き込む 2 つのフィールドから last_band を導き出します。
コンストラクタは、新しいフィールドをプレースホルダーとともに返します。レジャー関数は、エレメントが作られるときに last_band を置き換えます。
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: "",
};
}- 10-12 行目 アクションが書き込み、レジャー関数が読むフィールドです。
- 19-21 行目 初期値です。まだロールはありません。
入力の範囲により、ロールは 1 から 100 に保たれます。アクションは小数を含む数値を無視し、それ以外はロールとターゲットを書き込みます。
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 行目 ロールは、プレイヤーが入力する値です。
- 2 行目 小数を含む数値は無視します。入力の範囲により、すでに 1 から 100 に保たれています。
- 4-5 行目 目標値とロールを書き込みます。ランクはそこから決まります。
1 つのレジャー関数が、それらをランクに変えます。どのスキルのアクションも同じ 2 つのフィールドを書き込むので、すべてのスキルで使えます。
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";
}- 2-3 行目 アクションが書き込んだ 2 つのフィールドを読みます。
- 4-6 行目 ロール前なら、そのことを返します。
- 7-15 行目 ロールは低いほど良い結果です。各ランクは、目標値の一定の割合です。
- 16 行目 目標値を超えると失敗です。
別のスキルには、check-lore.ts をコピーし、関数名と element.var 呼び出しのフィールドを変えます。フィールド名はコードに直接書くので、スキルごとに専用のアクションが必要です。
シートに、ダイス、ランク、ボタンを表示します。ランクを requiredBindings に、アクションをエイリアスに追加します。
{ "binding": "element.attributes.last_band", "expectedType": "string" }- 15 行目 ランクはテキストです。
{ "name": "check_lore", "functionRef": "check_lore" }- 21 行目 ボタンが使うエイリアスです。
{ "kind": "text", "text": "Roll: [[1d100]]" },
{
"kind": "text",
"text": "Last check: {{element.attributes.last_band}}"
},
{ "kind": "button", "label": "Lore check", "actionRef": "check_lore" }- 35 行目 ダイスのバッジです。クリックするとロールし、結果がダイスログに表示されます。
- 36-39 行目 レジャー関数が導き出したランクです。
- 40 行目 ロール用のダイアログを開くボタンです。
テストする
各ランクと、範囲外のロールをテストします。各ステップは 2 つの書き込みを列挙します。expectedValuesAfter は、アクションの後のランクを確認します。
{
"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" }
},- 17 行目 プレイヤーが入力した数値です。
- 18-21 行目 2 つの書き込みを順に示します。
- 22 行目 アクションの後に導き出されるランクです。
最後のステップは、ロール 40.5 です。何も書き込まないので、小数のガードが証明されます。ロール 500 はステップにできません。入力の範囲外であり、シナリオが拒否されます。
{
"action": "check_lore",
"parameters": { "roll": 40.5 },
"expectedWrites": [],
"expectedValuesAfter": { "last_band": "Miss" }
}- 53 行目 小数を含む数値。
- 54 行目 書き込みなし。
- 55 行目 ランクは、前のステップの結果のままです。
シナリオファイルをマニフェストに列挙します。ほかのシナリオの期待値に、新しいフィールドを追加します。
{
"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"
]
}- 12 行目 新しいシナリオファイルです。

