コードフレームワーク
フレームワークスキーマ
1 種類のエレメントについて、入力、アクション、派生値、フレーム、コンテンツ、子フレームワークを宣言します。
フレームワークファイル
schemas/ の各ファイルは、1 つのフレームワークを宣言します。リファレンスのページでは、クイックスタートの Keeper を育てていきます。ここでは Calling の選択肢、派生値の Guard、用意済みのプリセット、セクション、子の Lamp を持っています。
manifest/project.json
schemas/keeper.json
schemas/lamp.json
rules/keeper.ts
rules/lamp.ts
rules/hurt.ts
rules/heal.ts
rules/guard.ts
layouts/keeper.json
layouts/lamp.json
scenarios/new-keeper.json
scenarios/heal.json
scenarios/new-lamp.json基本フィールド
| フィールド | 必須 | 意味 |
|---|---|---|
| id | はい | フレームワークの一意な ID です。マニフェストとシナリオがこれを使います。 |
| name | はい | 表示名です。 |
| elementType | はい | 作るものの種類です。プレイアブルキャラクターは character、物は item、呪文は spell です。独自の種類も使えます。 |
| constructor | はい | 新しいエレメントを作るルールファイルのパスです。 |
| inputs | いいえ | エレメントを作るときにプレイヤーが入力する内容です。各キーはコンストラクタのパラメータに対応します。 |
| actions | いいえ | エレメントができることです。それぞれ id、name、ルールファイルを持ちます。 |
| ledgerFunctions | いいえ | 派生値です。それぞれ保存されたフィールドを対象にし、ルールファイルを持ちます。 |
| frames | はい | 1 つから 16 のフレームです。default が true のものがちょうど 1 つ必要です。 |
| sections | いいえ | 入力を作成ウィザードのステップにまとめます。 |
| content | いいえ | 用意済みのプリセットです。それぞれ id、name、入力値を持ちます。 |
| childFrameworks | いいえ | 子スロット名を、同じゲームの別のフレームワークに対応付けます。 |
ゲームでは、マニフェストのエントリーフレームワークはプレイアブルキャラクターである必要があります。
The entry framework must be a character constructor.入力
入力は、コンストラクタの 1 つのパラメータをカスタマイズします。キーはパラメータ名と一致する必要があります。ほとんどの入力は label だけで足ります。ほかのキーで、プレイヤーが入力できる内容を絞り込みます。
"inputs": {
"name": { "label": "Name" },
"max_hp": {
"label": "Maximum HP",
"description": "How much damage a Keeper can take.",
"defaultValue": 10,
"min": 1,
"max": 40
},
"calling": {
"label": "Calling",
"options": ["Guard", "Scout"],
"defaultValue": "Guard"
},
"lamp": { "label": "Lamp", "defaultValue": "lamp", "hidden": true }
},- 8-14 行目 min と max は数値の範囲を決めます。範囲外のシナリオやプリセットは失敗します。
- 15-19 行目 options は選択肢の固定リストです。既定値はその中の 1 つでなければなりません。
- 20 行目 hidden の入力は、プレイヤーに見えない値を持ちます。ここでは子の Lamp をつなぎます。
schemas/keeper.json
{
"id": "keeper",
"name": "Keeper",
"elementType": "character",
"constructor": "rules/keeper.ts",
"inputs": {
"name": { "label": "Name" },
"max_hp": {
"label": "Maximum HP",
"description": "How much damage a Keeper can take.",
"defaultValue": 10,
"min": 1,
"max": 40
},
"calling": {
"label": "Calling",
"options": ["Guard", "Scout"],
"defaultValue": "Guard"
},
"lamp": { "label": "Lamp", "defaultValue": "lamp", "hidden": true }
},
"childFrameworks": { "lamp": "lamp" },
"sections": [
{
"id": "basics",
"title": "Basics",
"inputs": ["name", "max_hp", "calling", "lamp"]
}
],
"actions": [
{ "id": "hurt", "name": "Take damage", "source": "rules/hurt.ts" },
{ "id": "heal", "name": "Heal", "source": "rules/heal.ts" }
],
"ledgerFunctions": [
{
"id": "guard",
"name": "Guard",
"field": "guard",
"source": "rules/guard.ts"
}
],
"frames": [
{ "id": "sheet", "source": "layouts/keeper.json", "default": true }
],
"content": [
{
"id": "mira-scout",
"name": "Mira the Scout",
"parameters": {
"name": "Mira",
"max_hp": 8,
"calling": "Scout",
"lamp": "lamp"
}
}
]
}| キー | 意味 |
|---|---|
| label | プレイヤーに表示するテキストです。 |
| description | ヘルプテキストです。最大 1024 文字です。 |
| defaultValue | プレイヤーが入力に触れなかったときに使う値です。 |
| options | 2 個から 64 個の固定のテキスト選択肢で、それぞれ最大 128 文字です。デフォルトはそのいずれかである必要があります。 |
| optionLabels | 選択肢のプレイヤー向けラベルです。保存される値は選択肢のままです。 |
| min, max | 数値の範囲です。min は max を超えてはいけません。 |
| minLength, maxLength | テキストの長さの範囲です。 |
| required | false にすると、プレイヤーは入力を空のままにできます。 |
| hidden | 入力をウィザードに表示しません。hidden の入力には defaultValue が必要です。 |
| visibleWhen | ほかの入力に対する条件が成り立つ間だけ、入力を表示します。 |
選択肢にないデフォルトは拒否されます。
{
"calling": {
"label": "Calling",
"options": ["Guard", "Scout"],
"defaultValue": "Mage"
}
}Default for calling must be one of its options ("Guard", "Scout").シナリオとプリセットも範囲内に収まる必要があります。
Parameter max_hp 99 is not between 1 and 40.デフォルトのない hidden の入力は、次のエラーになります。
Input name is hidden, so it must declare a defaultValue.アクションとレジャー関数
各アクションは id、name、ソースファイルを持ちます。各レジャー関数も同じで、さらに field を持ちます。field は関数が導く保存値で、コンストラクタが返すスカラーのフィールドである必要があります。レジャー関数は値を読み取り、派生した値を返します。書き込みはしません。
"ledgerFunctions": [
{
"id": "guard",
"name": "Guard",
"field": "guard",
"source": "rules/guard.ts"
}
],- 36-39 行目 id と name は関数を識別し、field は導き出される保存値、source はそのルールファイルです。
function base_guard(calling: string): number {
return calling === "Guard" ? 3 : 1;
}
export function guard(currentValue: number, self: ElementRef): number {
const calling: string = element.var(self, "calling") as string;
return base_guard(calling);
}- 1-3 行目 ヘルパー関数です。export はなく、レジャー関数が名前で呼び出します。
- 5 行目 レジャー関数は、現在の値とエレメントを受け取ります。
- 6 行目 保存された値は element.var で読み取ります。
- 7 行目 導き出した値を返します。
Ledger function must target an existing scalar field.ID は Framework の中で一意にします。アクションとレジャー関数は、1 つの ID の集まりを共有します。
Duplicate semantic identity or source path.2 つのレジャー関数は、1 つのソースファイルを共有できます。アクションとレジャー関数は共有できません。
action source does not match its owner contractアクションの入力
アクションの入力は、その関数のパラメーターです。シグネチャが入力を宣言し、スキーマでは入力ごとに項目を追加できます。各入力は、数値、テキスト、または真偽値です。
プレイヤーがボタンを使うと、各入力がダイアログで求められます。項目にラベルがなければ、ダイアログはパラメーター名で入力を示します。項目には説明と既定値も指定できます。数値の入力には最小値と最大値を設定できます。テキストの入力には、選択肢の一覧、または表からの選択肢を設定できます。ダイアログはこれらをすべて表示し、サーバーは範囲や選択肢の外の値を拒否します。ボタンから値を渡すことはできません。 プレイヤーが読めるように、パラメータには roll のような名前を付けます。r は避けます。
{
"id": "check_lore",
"name": "Lore check",
"source": "rules/check-lore.ts",
"inputs": { "roll": { "label": "Roll", "min": 1, "max": 100 } }
}- 24 行目 ロール入力の項目です。ダイアログがラベルを表示し、サーバーが最小値と最大値を強制します。
最小値と最大値では、小数を含む数値は防げません。ルールが整数を必要とする場合は、ルール自身で確認し、シナリオのステップで証明します。範囲外のシナリオのステップは拒否されます。
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 行目 目標値とロールを書き込みます。
テキスト入力では、ルールブックの表から選択肢の一覧を出すこともできます。方法は「ルールブックの表」のページで説明します。
テキスト入力は、options の代わりに fields の一覧を使って、フレームワークの保存フィールドの 1 つを名前で選ぶこともできます。使い方は「ルールの書き方」のページのアクションで確認できます。
数値の入力は、サーバーにロールを頼むことができます。"roll": "1d100" や "roll": "2d6+1" のように、ダイス式を 1 つ指定した roll キーを追加します。するとダイアログには、プレイヤーが入力するフィールドの代わりに「ロール」ボタンが表示されます。サーバーがロールし、ダイアログは合計を表示します。プレイヤーはこの合計を変更できません。ロールできるのは数値のパラメーターだけです。コンパイラーは、roll と defaultValue の併用と、サーバーが受け付けないダイス式を拒否します。
ロールされる入力は一度だけ消費されます。アクションは実行時にそのロールを使い、新しいロールはその入力の未消費の以前のロールを無効にします。ロールはそのキャンペーンに紐づき、15 分で期限切れになります。テーブルに何が見えるかは、レイアウトとシートのページで確認できます。
アクションのログ行
アクションは結果の1行をテーブルのログに投稿できます。スキーマのアクションのエントリーにログテンプレートを追加します。例: "log": "{name} takes {amount} damage, defense {defense}"。アクションが保存された後、サーバーが各 {name} プレースホルダーをプレーンテキストとして埋めます。ブラウザーがこの行を送ることはありません。
プレースホルダーには、アクションの入力、または同じ Framework の数値・テキスト・真偽値のフィールドを指定できます。コンパイラーは、非表示の入力、体力フィールド(hp、current_hp、hit_points、temp_hp、current_health、max_health、hitPoints、および戦闘ブロックの体力と状態のフィールド)、存在しない名前、200文字を超えるテンプレート、16個を超えるプレースホルダー、単独の波括弧、制御文字を拒否します。入力とフィールドが同じ名前の場合は入力が優先されます。値はアクション実行後のものなので、アクションが書き込んだフィールドは新しい値を表示します。計算フィールドは再計算されないため、アクション前の値が表示されます。
自分のキャラクターで行動したプレイヤーには、ダイスロールと同じ公開範囲(全員、本人のみ、本人とGM)でこの行が表示されます。それ以外の場合は、GM が任意のキャラクターで行動した場合も含め、そのキャラクターを閲覧できるキャンペーンメンバーにだけ届きます。公開範囲が全員でも、キャラクターを閲覧できないメンバーがいる場合は、閲覧できるメンバーへのプライベートメッセージとして送られます。テーブルでは「ゲーム」ラベルの下に表示されるため、プレイヤーのメッセージと間違えることはありません。
コンテンツのプリセット
プリセットは、用意済みのキャラクターのような、名前付きの入力値のセットです。Fabled は各プリセットをシナリオと同じように検証するため、すべての値が入力に合っている必要があります。ゲームには、フレームワークごとに最大 512 個のプリセットを含められます。
"content": [
{
"id": "mira-scout",
"name": "Mira the Scout",
"parameters": {
"name": "Mira",
"max_hp": 8,
"calling": "Scout",
"lamp": "lamp"
}
}
]- 47-48 行目 プリセットには id と name があります。
- 49-54 行目 プリセットが入力する値です。入力の範囲に収まっている必要があります。
セクション
セクションは、入力を作成ウィザードのステップにまとめます。フレームワークがセクションを宣言する場合、hidden の入力も含めて、すべての入力をいずれかのセクションに載せる必要があります。
"sections": [
{
"id": "basics",
"title": "Basics",
"inputs": ["name", "max_hp", "calling", "lamp"]
}
],- 25-27 行目 セクションには id、title、表示する入力があります。すべての入力がいずれかのセクションに入っている必要があります。
Input lamp is not assigned to any section.子フレームワーク
子フレームワークは、Keeper が持つ Lamp のように、より大きなエレメントの一部です。子は独自のスキーマ、コンストラクタ、フレーム、シナリオを持ちます。
"childFrameworks": { "lamp": "lamp" },- 22 行目 子スロット lamp を、id が lamp のフレームワークに対応付けます。
{
"id": "lamp",
"name": "Lamp",
"elementType": "item",
"constructor": "rules/lamp.ts",
"inputs": {
"name": { "label": "Name" },
"oil": { "label": "Oil", "defaultValue": 5 }
},
"frames": [{ "id": "card", "source": "layouts/lamp.json", "default": true }]
}- 6-9 行目 子の入力です。子にも name が必要です。
- 10 行目 子には専用のフレームがあります。
親は childFrameworks で、スロット名をフレームワークの ID に対応付けます。参照は hidden の入力が保持します。コンストラクタは、自身の値と並べて子の入力を返します。
export function construct(
name: string,
max_hp: number,
calling: string,
lamp: FrameworkRef,
): {
values: { name: string; max_hp: number; hp: number; calling: string; guard: number };
children: { lamp: { framework: FrameworkRef; params: { name: string; oil: number } } };
} {
return {
values: { name: name, max_hp: max_hp, hp: max_hp, calling: calling, guard: 0 },
children: { lamp: { framework: lamp, params: { name: "Lantern", oil: 5 } } },
};
}- 5 行目 lamp は FrameworkRef です。プラットフォームが、入力のフレームワーク id をこれに変換します。
- 6-9 行目 戻り値の型には、保存される値と子スロットが並びます。
- 11 行目 Keeper の初期値です。
- 12 行目 子スロットです。どのフレームワークを作るか、どの入力を渡すかを指定します。
子を含むすべてのフレームワークは、name を返す必要があります。
must define the required 'name' value, normally as a string constructor field.ゲームの外のフレームワークを指すスロットは、次のエラーになります。
Invalid child Framework constraint: lamp.高度なフィールド
| フィールド | 用途 |
|---|---|
| lists | キャラクターがプレイ中に得るコンテンツです。 |
| contentChoices | プレイヤーがコンテンツのフレームワークからエントリを 1 つ選ぶ選択ポイントです。 |
| slots | 繰り返せる選択のためのピッカーです。 |
| pools | 数値入力の取得元になる共有プールです。 |
| modifiers | プラットフォームがコンテンツの効果から導き出す数値です。 |
| effects | コンテンツのフレームワークが、修正値とその量を指定する方法です。 |
| levelling | 作成後に、キャラクターのレベルを 1 つ上げ下げします。 |
| rebuild | レベル変更など、再構築がプレイ状態に与える影響です。 |
| combat | テーブルの戦闘ツールが読む役割です。 |
| catalogue | ソースの外に置き、チャンクに分けて追加するコンテンツの記録です。 |
| tables | 共有のデータ表です。 |
| playReads | テーブルが保存済みの属性から読み取る派生値です。 |
| rulesAttacks | すべてのキャラクターが持つ攻撃です。 |
| optionsFrom | 入力の選択肢を別のソースから取得します。 |
| rich, richText | テキスト入力をリッチテキストにします。 |

