Frameworki kodowe
Pule i modyfikatory
Dziel budżet punktów między dane wejściowe i pozwól treściom zmieniać liczby na postaci.
Pule
Pula ogranicza grupę liczbowych danych wejściowych, które gracz wypełnia razem, na przykład trzy cechy dzielące budżet punktów. Serwer sprawdza każdą pulę, gdy postać jest tworzona lub edytowana.
"pools": {
"traits": {
"label": "Traits",
"inputs": ["might", "wit", "grace"],
"methods": {
"pointBuy": {
"budget": 6,
"min": 1,
"max": 5,
"costs": { "1": 0, "2": 1, "3": 2, "4": 4, "5": 6 }
}
}
}
}- Wiersz 23 Liczbowe dane wejściowe puli. Każde potrzebuje wpisu w inputs.
- Wiersz 24 Metody, których może użyć gracz.
- Wiersz 26 Łączny koszt wyników nie może przekroczyć budżetu.
- Wiersz 27 Każdy wynik jest co najmniej tyle.
- Wiersz 28 Każdy wynik jest co najwyżej tyle.
- Wiersz 29 Koszt każdego wyniku. Każdy wynik od min do max potrzebuje kosztu.
| Metoda | Co sprawdza |
|---|---|
| standardArray | Wyniki to wymienione wartości, w dowolnej kolejności. |
| pointBuy | Każdy wynik mieści się między min a max, a koszty sumują się do najwyżej budżetu. |
| manual | Każdy wynik mieści się między min a max. |
| roll | Serwer rzuca count wartości kością dice, dodaje opcjonalny bonus, mnoży przez opcjonalny multiplier, a gracz przypisuje sumy do pól. |
| budget | Każdy wynik mieści się między min a max, a wyniki sumują się do najwyżej total. |
Pula musi deklarować co najmniej jedną metodę. Pula z więcej niż jedną metodą wskazuje w methodInput dane wejściowe, które wybierają metodę. Presety i scenariusze muszą spełniać pulę, a scenariusz to pokazuje:
{
"id": "new-keeper",
"framework": "keeper",
"parameters": {
"name": "Mira",
"max_hp": 10,
"might": 3,
"wit": 2,
"grace": 1
},
"expectedValues": {
"name": "Mira",
"max_hp": 10,
"hp": 10,
"might": 3,
"wit": 2,
"grace": 1
}
}- Wiersze 7-9 Te wyniki kosztują 2, 1 i 0, więc suma to 3, a budżet to 6.
is not satisfied: pointBuy.budgetpointBuy costs has no entry for 5A pool declares at least one method.| Limit | Wartość |
|---|---|
| Pule na framework | 4 |
| Dane wejściowe na pulę | 64 |
| Wartości między min a max | 64 |
| Budżet | 1000 |
Metoda budget przyjmuje total, min i max. Każdy wynik jest liczbą całkowitą od min do max, a wyniki sumują się do najwyżej total. Wyniki nie mają ceny, więc metoda pasuje do budżetu punktów umiejętności i nie potrzebuje kosztów.
Rzucane wyniki
Metoda roll sprawia, że wartości rzuca serwer, więc gracz nie może wpisać własnych. Przyjmuje dice i count oraz dwa opcjonalne klucze, bonus i multiplier. dice to jedna grupa kości, na przykład "3d6" lub "4d6dl1". count to liczba wartości rzucanych przez serwer i równa się liczbie pól w puli. bonus (od -20 do 100) jest dodawany do każdej sumy kości, a potem multiplier (od 1 do 10) ją mnoży, więc każda wartość to (suma kości + bonus) × multiplier. Cecha 3d6 × 5, jak w Zewie Cthulhu, to dice "3d6" z multiplier 5.
"pools": {
"traits": {
"label": "Traits",
"inputs": ["might", "wit", "grace"],
"methodInput": "method",
"methods": {
"manual": { "min": 15, "max": 90 },
"roll": { "dice": "3d6", "count": 3, "multiplier": 5 }
}
}
}- Wiersz 29 Pula z więcej niż jedną metodą wskazuje dane wejściowe, które wybierają metodę.
- Wiersz 31 Gracz może wpisać wyniki.
- Wiersz 32 Albo serwer rzuca 3 wyniki z 3d6, po jednym na dane wejściowe.
methodInput wskazuje pole tekstowe, które wybiera metodę puli. Wybór gracza w tym polu decyduje, którą metodę sprawdza serwer, więc te same wartości można zmierzyć standardową tablicą, zakupem punktów albo rzutem. Pula z jedną metodą nie potrzebuje methodInput i zawsze używa tej metody. Przy więcej niż jednej metodzie jest wymagane, a options pola muszą być dokładnie nazwami metod puli. Scenariusz lub preset ustawia to pole na jedną z tych nazw. Brakująca wartość lub wartość niebędąca nazwą metody kończy się błędem method.missing lub method.unknown.
"method": {
"label": "Scores by",
"options": ["manual", "roll"],
"defaultValue": "manual"
},- Wiersz 11 Dokładnie metody puli i nic więcej.
Każda suma, jaką może dać rzut, po uwzględnieniu bonus i multiplier, musi mieścić się w min i max każdego pola. 3d6 × 5 daje od 15 do 90, więc każda cecha dopuszcza od 15 do 90. Kości to jedna grupa: do 10 kości o co najwyżej 100 ściankach, a dl, dh, kl lub kh odrzuca albo zachowuje od 1 do 9 z nich, przy czym zostaje co najmniej jedna kość. Mnożnik zapisz kluczem multiplier, nigdy w kościach: 3d6x5 jest odrzucane.
The roll dice must be one group such asoutside the min/max of inputgive exactly one roll per input.Brakujący klucz pojawia się jako lista JSON. Ścieżka na liście wskazuje klucz, tutaj pools, traits, methods, roll, dice, a komunikat brzmi Required.
RequiredW formularzu tworzenia postaci pula z roll pokazuje zamiast danych wejściowych przycisk Rzuć wartości, a po pierwszym rzucie Przerzuć wszystko. Serwer rzuca i zapisuje wynik, więc przeglądarka nigdy nie rzuca. Gracz przypisuje potem sumy do danych wejściowych w dowolnej kolejności. Rzucanie jest dostępne tylko w formularzu tworzenia.
Scenariusz wybierający metodę roll sam podaje rzuty w poolRolls, bo prawdziwe rzuty istnieją tylko na serwerze. poolRolls przypisuje identyfikatorowi puli po jednym slocie na każdą rzuconą wartość. Slot ma total, czyli końcową liczbę po bonus i multiplier, oraz opcjonalnie dice i dropped, które służą tylko do odczytu. Sprawdzanie puli traktuje wtedy sloty jak zapis serwera, więc wartości scenariusza muszą być tymi sumami, w dowolnej kolejności. Każda suma musi być taka, jaką rzut może dać. Bez poolRolls scenariusz wybierający roll kończy się błędem roll.missing. Preset nie może używać metody roll. Formularz tworzenia testuje prawdziwy rzut.
{
"id": "new-keeper",
"framework": "keeper",
"parameters": {
"name": "Mira",
"max_hp": 10,
"method": "roll",
"might": 60,
"wit": 45,
"grace": 75
},
"expectedValues": {
"name": "Mira",
"max_hp": 10,
"hp": 10,
"might": 60,
"wit": 45,
"grace": 75,
"method": "roll"
},
"poolRolls": {
"traits": [
{ "total": 45, "dice": [3, 4, 2] },
{ "total": 60, "dice": [5, 4, 3] },
{ "total": 75, "dice": [6, 5, 4] }
]
}
}- Wiersz 7 Scenariusz wybiera metodę roll.
- Wiersze 21-27 Zapisane rzuty. Każdy total to suma kości razy multiplier, tutaj 9 × 5 = 45.
is not satisfied: roll.missingModyfikatory i efekty
Modyfikator to liczba, którą platforma wylicza z treści, jakie ma postać. Zasila go lista, która stosuje efekty. Twoje reguły czytają go jak pole. Ten przykład pozwala noszonym amuletom podnosić Guard.
Framework postaci deklaruje modyfikator.
"modifiers": {
"mod_guard": {
"label": "Guard",
"stack": "sum",
"each": { "min": -3, "max": 3 },
"total": { "min": -5, "max": 5 },
"appliesTo": ["guard"]
}
},- Wiersz 25 Nazwa, którą widzą gracze.
- Wiersz 26 sum dodaje każdy wkład. max bierze największy.
- Wiersz 27 Zakres jednego wkładu.
- Wiersz 28 Zakres sumy.
- Wiersz 29 Pole ledgera, które zasila modyfikator. To etykieta dla ludzi. Matematykę robią Twoje reguły.
Lista mówi, że jej wpisy stosują efekty, i może je ograniczać.
"lists": {
"worn": {
"label": "Worn",
"of": "charm",
"max": 3,
"effects": true,
"distinctBy": "name",
"caps": [
{ "label": "Rings", "where": { "slot": { "eq": "Ring" } }, "max": 1 }
]
}
},- Wiersz 37 Wpisy tej listy zmieniają modyfikatory.
- Wiersz 38 Wpis o tej samej nazwie co wpis na liście zostaje odrzucony z SAME_NAME.
- Wiersze 39-41 Najwyżej 1 wpis ze slotem Ring. Kolejny zostaje odrzucony z LIST_CAP.
Framework treści nazywa swoje dane wejściowe efektów. Pomiń ich wybory i zakresy, bo kompilator uzupełnia je z modyfikatorów postaci.
{
"id": "charm",
"name": "Charm",
"elementType": "item",
"constructor": "rules/charm.ts",
"inputs": {
"name": { "label": "Name" },
"slot": {
"label": "Slot",
"options": ["Ring", "Cloak"],
"defaultValue": "Ring"
},
"effect_1": { "label": "Effect" },
"amount_1": { "label": "Amount" }
},
"effects": [{ "target": "effect_1", "amount": "amount_1" }],
"frames": [
{ "id": "charm-card", "source": "layouts/charm.json", "default": true }
],
"content": [
{
"id": "ring-of-guard",
"name": "Ring of Guard",
"parameters": {
"name": "Ring of Guard",
"slot": "Ring",
"effect_1": "Guard",
"amount_1": 2
}
},
{
"id": "ring-of-calm",
"name": "Ring of Calm",
"parameters": {
"name": "Ring of Calm",
"slot": "Ring",
"effect_1": "None",
"amount_1": 0
}
},
{
"id": "cloak-of-guard",
"name": "Cloak of Guard",
"parameters": {
"name": "Cloak of Guard",
"slot": "Cloak",
"effect_1": "Guard",
"amount_1": 1
}
},
{
"id": "cloak-spare",
"name": "Cloak of Guard",
"parameters": {
"name": "Cloak of Guard",
"slot": "Cloak",
"effect_1": "Guard",
"amount_1": 1
}
}
]
}- Wiersze 13-14 Efekt i jego wartość nie mają opcji ani zakresu.
- Wiersz 16 Jeden efekt: które dane wejściowe nazywają modyfikator, a które przechowują wartość.
- Wiersz 27 Preset podaje etykietę modyfikatora i wartość.
Funkcja ledgera czyta modyfikator jak każde inne pole.
export function guard(currentValue: number, self: ElementRef): number {
return 10 + (element.var(self, "mod_guard") as number);
}- Wiersz 2 mod_guard jest zadeklarowany we frameworku, a nie zwracany przez konstruktor.
Scenariusz potwierdza każdy przypadek. expectedValuesAfter sprawdza wartość pochodną po kroku, a expectedModifiers sprawdza modyfikatory na końcu.
{
"id": "wear-charms",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "guard": 10 },
"actions": [
{
"action": "wear",
"parameters": {},
"choose": { "charm": "ring-of-guard" },
"expectedWrites": [
{ "op": "list.add", "key": "worn", "value": "ring-of-guard" }
],
"expectedValuesAfter": { "guard": 12 }
},
{
"action": "wear",
"parameters": {},
"choose": { "charm": "ring-of-calm" },
"expectedRefusal": "LIST_CAP",
"expectedWrites": []
},
{
"action": "wear",
"parameters": {},
"choose": { "charm": "cloak-of-guard" },
"expectedWrites": [
{ "op": "list.add", "key": "worn", "value": "cloak-of-guard" }
],
"expectedValuesAfter": { "guard": 13 }
},
{
"action": "wear",
"parameters": {},
"choose": { "charm": "cloak-spare" },
"expectedRefusal": "SAME_NAME",
"expectedWrites": []
},
{
"action": "remove_charm",
"parameters": {},
"choose": { "charm": "ring-of-guard" },
"expectedWrites": [
{ "op": "list.remove", "key": "worn", "value": "ring-of-guard" }
],
"expectedValuesAfter": { "guard": 11 }
}
],
"expectedLists": { "worn": ["cloak-of-guard"] },
"expectedModifiers": { "mod_guard": 1 }
}- Wiersz 14 Guard 12: 10 plus 2 od pierścienia.
- Wiersz 20 Drugi pierścień zostaje odrzucony: limit pozwala na 1.
- Wiersz 30 Guard 13 z 1 od płaszcza.
- Wiersz 36 Drugi płaszcz o tej samej nazwie zostaje odrzucony.
- Wiersz 46 Guard 11 po zdjęciu pierścienia.
- Wiersz 50 Pozostała suma to 1 od płaszcza.
| Pole modyfikatora | Znaczenie |
|---|---|
| label | Nazwa widoczna w wyborach efektów treści. |
| stack | sum lub max. |
| each, total | Zakres jednego wkładu i sumy. |
| appliesTo | Do 8 nazw pól, które zasila modyfikator. |
| appliesWhen | Warunek, jako etykieta. Egzekwują go Twoje reguły. |
Jeszcze nieopisane
Istnieją też inne zaawansowane części, które nie są tu opisane: listy wierszy, wybory treści i sloty, awansowanie i przebudowy, role bojowe oraz katalogi rekordów. Każda potrzebuje własnej strony.

