Salta al contenuto principale

Framework in codice

Riserve e modificatori

Condividi un budget di punti tra gli input, e lascia che i contenuti cambino i numeri del personaggio.

Riserve

Una riserva limita un gruppo di input numerici che un giocatore compila insieme, come tre tratti che condividono un budget di punti. Il server controlla ogni riserva quando un personaggio viene creato o modificato.

schemas/keeper.json
  "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 }
        }
      }
    }
  }
  1. Riga 23 Gli input numerici della riserva. Ognuno ha bisogno di una voce sotto inputs.
  2. Riga 24 I metodi che il giocatore può usare.
  3. Riga 26 Il costo totale dei punteggi non può superare il budget.
  4. Riga 27 Ogni punteggio è almeno questo.
  5. Riga 28 Ogni punteggio è al massimo questo.
  6. Riga 29 Il costo di ogni punteggio. Ogni punteggio da min a max ne ha bisogno.
MetodoCosa controlla
standardArrayI punteggi sono i valori elencati, in qualsiasi ordine.
pointBuyOgni punteggio è tra min e max, e i costi sommati arrivano al massimo al budget.
manualOgni punteggio è tra min e max.
rollIl server tira count punteggi con dice, aggiunge il bonus facoltativo, moltiplica per il multiplier facoltativo, e il giocatore assegna i totali agli input.
budgetOgni punteggio è tra min e max, e i punteggi sommati arrivano al massimo a total.

Una riserva deve dichiarare almeno un metodo. Una riserva con più di un metodo indica in methodInput l'input che sceglie il metodo. I preset e gli scenari devono rispettare la riserva, e uno scenario lo mostra:

scenarios/new-keeper.json
{
  "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
  }
}
  1. Righe 7-9 Questi punteggi costano 2, 1 e 0, quindi il totale è 3 e il budget è 6.
is not satisfied: pointBuy.budget
pointBuy costs has no entry for 5
A pool declares at least one method.
LimiteValore
Riserve per Framework4
Input per riserva64
Valori tra min e max64
Budget1000

Il metodo budget accetta total, min e max. Ogni punteggio è un numero intero da min a max, e i punteggi sommati arrivano al massimo a total. I punteggi non hanno un prezzo, quindi è adatto a un budget di punti abilità e non richiede costi.

Punteggi tirati

Il metodo roll fa tirare i punteggi al server, quindi un giocatore non può digitare i propri. Accetta dice e count, e due chiavi facoltative, bonus e multiplier. dice è un gruppo di dadi, come "3d6" o "4d6dl1". count è quanti punteggi tira il server ed è uguale al numero di input del pool. bonus (da -20 a 100) si somma a ogni totale dei dadi, poi multiplier (da 1 a 10) lo moltiplica, quindi ogni punteggio è (totale dei dadi + bonus) × multiplier. Una caratteristica 3d6 × 5, come in Il richiamo di Cthulhu, è dice "3d6" con multiplier 5.

schemas/keeper.json
  "pools": {
    "traits": {
      "label": "Traits",
      "inputs": ["might", "wit", "grace"],
      "methodInput": "method",
      "methods": {
        "manual": { "min": 15, "max": 90 },
        "roll": { "dice": "3d6", "count": 3, "multiplier": 5 }
      }
    }
  }
  1. Riga 29 Una riserva con più di un metodo indica l'input che sceglie il metodo.
  2. Riga 31 Il giocatore può scrivere i punteggi.
  3. Riga 32 Oppure il server tira 3 punteggi di 3d6, uno per ogni input.

methodInput indica l'input di testo che sceglie il metodo di un pool. La scelta del giocatore in quell'input decide quale metodo controlla il server, quindi gli stessi punteggi possono essere verificati con la serie standard, con l'acquisto a punti o con un tiro. Un pool con un solo metodo non ha bisogno di methodInput e usa sempre quel metodo. Con più metodi è obbligatorio, e le options dell'input devono essere esattamente i nomi dei metodi del pool. Uno scenario o un preset imposta l'input su uno di questi nomi. Un valore mancante o che non è un nome di metodo fallisce con method.missing o method.unknown.

schemas/keeper.json
    "method": {
      "label": "Scores by",
      "options": ["manual", "roll"],
      "defaultValue": "manual"
    },
  1. Riga 11 Esattamente i metodi della riserva, nient'altro.

Ogni totale che il tiro può dare, dopo il bonus e il multiplier, deve rientrare in min e max di ogni input. 3d6 × 5 dà da 15 a 90, quindi ogni tratto consente da 15 a 90. I dadi sono un solo gruppo: fino a 10 dadi con fino a 100 facce, e dl, dh, kl o kh scarta o tiene da 1 a 9 di essi, tenendo almeno un dado. Scrivi un moltiplicatore con la chiave multiplier, mai dentro i dadi: 3d6x5 viene rifiutato.

The roll dice must be one group such as
outside the min/max of input
give exactly one roll per input.

Una chiave mancante appare come elenco JSON. Il percorso nell'elenco indica la chiave, qui pools, traits, methods, roll, dice, e il messaggio dice Required.

Required

Nel modulo di creazione del personaggio, una riserva con roll mostra un pulsante Tira i punteggi al posto dei suoi input, e Ritira tutto dopo il primo tiro. Il server tira e conserva un registro, quindi il browser non tira mai. Il giocatore poi assegna i totali agli input in qualsiasi ordine. Il tiro è offerto solo nel modulo di creazione.

Uno scenario che sceglie il metodo roll fornisce da sé i tiri in poolRolls, perché i tiri veri esistono solo sul server. poolRolls associa l'id di un pool a uno slot per ogni punteggio tirato. Uno slot ha un total, il numero finale dopo il bonus e il multiplier, e facoltativamente dice e dropped, che servono solo per la lettura. Il controllo del pool tratta allora gli slot come la registrazione del server, quindi i punteggi dello scenario devono essere quei totali, in qualsiasi ordine. Ogni totale deve essere uno che il tiro può produrre. Senza poolRolls, uno scenario che sceglie roll fallisce con roll.missing. Un preset non può usare il metodo roll. Il modulo di creazione prova il tiro vero.

scenarios/new-keeper.json
{
  "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] }
    ]
  }
}
  1. Riga 7 Lo scenario sceglie il metodo roll.
  2. Righe 21-27 I tiri registrati. Ogni total è la somma dei dadi per il multiplier, qui 9 × 5 = 45.
is not satisfied: roll.missing

Modificatori ed effetti

Un modificatore è un numero che la piattaforma ricava dai contenuti che un personaggio possiede. Un elenco che applica effetti lo alimenta. Le tue regole lo leggono come un campo. In questo esempio i talismani indossati alzano Guard.

Il Framework del personaggio dichiara il modificatore.

schemas/keeper.json
  "modifiers": {
    "mod_guard": {
      "label": "Guard",
      "stack": "sum",
      "each": { "min": -3, "max": 3 },
      "total": { "min": -5, "max": 5 },
      "appliesTo": ["guard"]
    }
  },
  1. Riga 25 Il nome che i giocatori vedono.
  2. Riga 26 sum somma ogni contributo. max prende il più grande.
  3. Riga 27 L'intervallo di un singolo contributo.
  4. Riga 28 L'intervallo del totale.
  5. Riga 29 Il campo del registro che il modificatore alimenta. È un'etichetta per le persone. Il calcolo lo fanno le tue regole.

L'elenco dichiara che le sue voci applicano effetti, e può limitarli.

schemas/keeper.json
  "lists": {
    "worn": {
      "label": "Worn",
      "of": "charm",
      "max": 3,
      "effects": true,
      "distinctBy": "name",
      "caps": [
        { "label": "Rings", "where": { "slot": { "eq": "Ring" } }, "max": 1 }
      ]
    }
  },
  1. Riga 37 Le voci di questo elenco cambiano i modificatori.
  2. Riga 38 Una voce con lo stesso nome di una già nell'elenco viene rifiutata con SAME_NAME.
  3. Righe 39-41 Al massimo 1 voce con lo slot Ring. Un'altra viene rifiutata con LIST_CAP.

Il Framework di contenuti indica i suoi input degli effetti. Lascia fuori le loro scelte e i loro intervalli, perché il compilatore li riempie dai modificatori del personaggio.

schemas/charm.json
{
  "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
      }
    }
  ]
}
  1. Righe 13-14 L'effetto e la sua quantità non hanno opzioni né intervallo.
  2. Riga 16 Un effetto: quale input indica il modificatore, e quale contiene la quantità.
  3. Riga 27 Il preset dà l'etichetta del modificatore e la quantità.

Una funzione del registro legge il modificatore come ogni altro campo.

rules/guard.ts
export function guard(currentValue: number, self: ElementRef): number {
  return 10 + (element.var(self, "mod_guard") as number);
}
  1. Riga 2 mod_guard è dichiarato sul Framework, non restituito dal costruttore.

Lo scenario dimostra ogni caso. expectedValuesAfter controlla il valore derivato dopo un passo, e expectedModifiers controlla i modificatori alla fine.

scenarios/wear.json
{
  "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 }
}
  1. Riga 14 Guard 12: 10 più il 2 dell'anello.
  2. Riga 20 Un secondo anello viene rifiutato: il limite ne ammette 1.
  3. Riga 30 Guard 13 con l'1 del mantello.
  4. Riga 36 Un secondo mantello con lo stesso nome viene rifiutato.
  5. Riga 46 Guard 11 dopo che l'anello viene tolto.
  6. Riga 50 Il totale che resta è l'1 del mantello.
Campo del modificatoreSignificato
labelIl nome che compare nelle scelte di effetto del contenuto.
stacksum oppure max.
each, totalL'intervallo di un singolo contributo e del totale.
appliesToFino a 8 nomi dei campi che il modificatore alimenta.
appliesWhenUna condizione, come etichetta. Le tue regole la fanno rispettare.

Non ancora trattato

Esistono altre parti avanzate che non sono trattate qui: elenchi a righe, scelte e slot di contenuti, avanzamento di livello e ricostruzioni, ruoli di combattimento e cataloghi di record. Ognuna ha bisogno di una pagina propria.

Avanti