Saltar al contenido principal

Code frameworks

Esquemas de Framework

Declara entradas, acciones, valores derivados, Frames, contenido y Frameworks hijos para un tipo de Elemento.

Un archivo de Framework

Cada archivo de schemas/ declara un Framework. Las páginas de referencia hacen crecer al Keeper del inicio rápido. Ahora tiene una elección de Calling, un valor derivado Guard, un preajuste listo, una sección y un Lamp hijo.

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

Campos principales

CampoObligatorioSignificado
idSíEl id único del Framework. Lo usan el manifiesto y los escenarios.
nameSíEl nombre visible.
elementTypeSíLo que crea: character para personajes jugables, item para objetos, spell para conjuros. Se permiten tipos personalizados.
constructorSíLa ruta del archivo de reglas que crea un Elemento nuevo.
inputsNoLo que introduce el jugador al crear un Elemento. Cada clave coincide con un parámetro del constructor.
actionsNoCosas que un Elemento puede hacer. Cada una tiene un id, un nombre y un archivo de reglas.
ledgerFunctionsNoValores derivados. Cada uno apunta a un campo guardado y tiene un archivo de reglas.
framesSíDe uno a dieciséis Frames. Exactamente uno tiene default en true.
sectionsNoAgrupa las entradas en pasos del asistente de creación.
contentNoPreajustes listos. Cada uno tiene un id, un nombre y valores de entrada.
childFrameworksNoAsocia el nombre de una ranura hija con otro Framework del mismo juego.

En un GAME, el Framework de entrada del manifiesto debe ser un personaje jugable.

The entry framework must be a character constructor.

Entradas

Una entrada personaliza un parámetro del constructor, y su clave debe coincidir con el nombre del parámetro. La mayoría de las entradas solo necesitan una label. Las otras claves limitan lo que puede introducir un jugador.

schemas/keeper.json
  "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 }
  },
  1. Líneas 8-14 min y max limitan un número. Un escenario o un preajuste fuera de los límites falla.
  2. Líneas 15-19 options da una lista fija de opciones. El valor predeterminado debe ser una de ellas.
  3. Línea 20 Una entrada hidden guarda un valor que el jugador nunca ve. Aquí conecta al hijo Lamp.
schemas/keeper.json
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"
      }
    }
  ]
}
ClaveSignificado
labelEl texto que ve el jugador.
descriptionTexto de ayuda, de hasta 1024 caracteres.
defaultValueEl valor que se usa cuando el jugador no toca la entrada.
optionsUna lista fija de 2 a 128 opciones de texto, cada una de hasta 128 caracteres. El valor por defecto debe ser una de ellas.
optionLabelsEtiquetas que ve el jugador para las opciones. El valor guardado sigue siendo la opción.
min, maxLímites de un número. min no puede ser mayor que max.
minLength, maxLengthLímites de la longitud de un texto.
requiredPonlo en false para que el jugador pueda dejar la entrada vacía.
hiddenDeja la entrada fuera del asistente. Una entrada oculta necesita un defaultValue.
visibleWhenMuestra la entrada solo mientras se cumpla una condición sobre otras entradas.

Se rechaza un valor por defecto que no sea una de las opciones.

{
  "calling": {
    "label": "Calling",
    "options": ["Guard", "Scout"],
    "defaultValue": "Mage"
  }
}
Default for calling must be one of its options ("Guard", "Scout").

Los escenarios y los preajustes también deben respetar los límites.

Parameter max_hp 99 is not between 1 and 40.

Una entrada oculta sin valor por defecto falla con:

Input name is hidden, so it must declare a defaultValue.

Acciones y funciones de ledger

Cada acción tiene un id, un nombre y un archivo de origen. Cada función de ledger tiene lo mismo, más un campo. El campo es el valor guardado que deriva la función, y debe ser un campo escalar que devuelve el constructor. Una función de ledger lee valores y devuelve el derivado. Nunca escribe.

schemas/keeper.json
  "ledgerFunctions": [
    {
      "id": "guard",
      "name": "Guard",
      "field": "guard",
      "source": "rules/guard.ts"
    }
  ],
  1. Líneas 36-39 id y name identifican la función, field es el valor guardado que deriva y source es su archivo de reglas.
rules/guard.ts
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. Líneas 1-3 Una función auxiliar. No tiene export, y la función del ledger la llama por su nombre.
  2. Línea 5 Una función del ledger recibe su valor actual y el Elemento.
  3. Línea 6 Lee los valores guardados con element.var.
  4. Línea 7 Devuelve el valor derivado.
Ledger function must target an existing scalar field.

Los ids deben ser únicos dentro de un Framework. Las acciones y las funciones del ledger comparten un único conjunto de ids.

Duplicate semantic identity or source path.

Dos funciones del ledger pueden compartir un archivo de origen. Una acción y una función del ledger no pueden:

action source does not match its owner contract

Entradas de una acción

Las entradas de una acción son los parámetros de su función. La firma las declara, y el esquema puede añadir una entrada para cada una. Cada entrada es un número, un texto o un valor verdadero/falso.

Se pide al jugador cada entrada en un diálogo cuando usa el botón. El diálogo nombra una entrada por el nombre de su parámetro, salvo que la entrada defina una etiqueta. Una entrada también puede dar una descripción y un valor predeterminado. Una entrada numérica puede tener un mínimo y un máximo. Una entrada de texto puede tener una lista de opciones u opciones de una tabla. El diálogo lo muestra todo, y el servidor rechaza un valor fuera de los límites o de las opciones. Un botón no puede aportar un valor. Pon a cada parámetro un nombre que el jugador pueda leer: roll, no r.

schemas/keeper.json
    {
      "id": "check_lore",
      "name": "Lore check",
      "source": "rules/check-lore.ts",
      "inputs": { "roll": { "label": "Roll", "min": 1, "max": 100 } }
    }
  1. Línea 24 La entrada del valor de la tirada. El diálogo muestra la etiqueta y el servidor exige el mínimo y el máximo.

Un mínimo y un máximo no impiden un número con decimales. Si la regla necesita un número entero, lo comprueba ella misma, y un paso de escenario lo demuestra. Un paso de escenario fuera de los límites se rechaza.

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. Línea 1 La tirada es una entrada que escribe el jugador.
  2. Línea 2 Ignora un número con decimales. Los límites de la entrada ya lo mantienen entre 1 y 100.
  3. Líneas 4-5 Escribe el objetivo y la tirada.

Una entrada de texto también puede ofrecer una lista de opciones de una tabla del reglamento. La página Tablas del reglamento muestra cómo.

Una entrada de texto puede en cambio elegir por nombre uno de los campos almacenados del Framework, con una lista fields. La página Escribir reglas muestra una acción que lo usa.

Una entrada numérica puede pedir al servidor que la tire. Añade una clave roll con una expresión de dados, como "roll": "1d100" o "roll": "2d6+1". El diálogo muestra entonces un botón Tirar en lugar de un campo donde escribir. El servidor tira y el diálogo muestra el total, que el jugador no puede cambiar. Solo un parámetro numérico puede tirarse. El compilador rechaza un roll junto con un defaultValue y rechaza una expresión de dados que el servidor no acepta.

Una entrada tirada se gasta una sola vez: la acción toma la tirada al ejecutarse, y una tirada nueva anula las anteriores sin gastar de esa entrada. Una tirada queda ligada a su campaña y caduca a los 15 minutos. La página de diseños y hojas muestra lo que ve la mesa.

Línea de registro de una acción

Una acción puede publicar una línea de resultado en el registro de la mesa. Añade una plantilla de registro a la entrada de la acción en el esquema, por ejemplo "log": "{name} takes {amount} damage, defense {defense}". El servidor rellena cada marcador {name} como texto sin formato después de guardar la acción. Un navegador nunca envía la línea.

Un marcador puede nombrar una entrada de la acción, o un campo numérico, de texto o verdadero/falso del mismo Framework. El compilador rechaza una entrada oculta, un campo de salud (hp, current_hp, hit_points, temp_hp, current_health, max_health, hitPoints, y los campos de salud y de estado del bloque de combate), un nombre que no existe, una plantilla de más de 200 caracteres, más de 16 marcadores, una llave suelta y un carácter de control. Cuando una entrada y un campo comparten nombre, gana la entrada. Los valores son los de después de la acción, así que un campo que la acción escribió muestra su valor nuevo. Un campo calculado no se recalcula, así que muestra el valor que tenía antes de la acción.

Un jugador que actúa sobre su propio personaje ve la línea en la misma audiencia que sus tiradas de dados: todos, solo él, o él y los DJ. En cualquier otro caso, incluido un DJ que actúa sobre cualquier personaje, la línea llega solo a los miembros de la campaña que pueden leer ese personaje. Si la audiencia es todos pero un miembro no puede leer el personaje, la línea va como mensaje privado a los miembros que sí pueden. La mesa muestra la línea con la etiqueta Juego, para que nadie la confunda con un mensaje de un jugador.

Preajustes de contenido

Un preajuste es un conjunto con nombre de valores de entrada, como un personaje ya hecho. Fabled comprueba cada preajuste como un escenario, así que cada valor debe encajar en su entrada. Un juego puede tener hasta 512 preajustes por Framework.

schemas/keeper.json
  "content": [
    {
      "id": "mira-scout",
      "name": "Mira the Scout",
      "parameters": {
        "name": "Mira",
        "max_hp": 8,
        "calling": "Scout",
        "lamp": "lamp"
      }
    }
  ]
  1. Líneas 47-48 Un preajuste tiene un id y un name.
  2. Líneas 49-54 Los valores de entrada que rellena el preajuste. Deben respetar los límites de las entradas.

Secciones

Las secciones agrupan las entradas en pasos del asistente de creación. Cuando un Framework declara secciones, cada entrada debe estar en una de ellas, también las ocultas.

schemas/keeper.json
  "sections": [
    {
      "id": "basics",
      "title": "Basics",
      "inputs": ["name", "max_hp", "calling", "lamp"]
    }
  ],
  1. Líneas 25-27 Una sección tiene un id, un title y las entradas que muestra. Cada entrada debe estar en una sección.
Input lamp is not assigned to any section.

Frameworks hijos

Un Framework hijo es una parte de un Elemento más grande, como el Lamp que lleva un Keeper. El hijo tiene su propio esquema, constructor, Frame y escenario.

schemas/keeper.json
  "childFrameworks": { "lamp": "lamp" },
  1. Línea 22 Asigna la ranura hija lamp al Framework con el id lamp.
schemas/lamp.json
{
  "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 }]
}
  1. Líneas 6-9 Las entradas del hijo. Un hijo también necesita un name.
  2. Línea 10 El hijo tiene su propio Frame.

El padre asocia el nombre de una ranura con un id de Framework en childFrameworks. Una entrada oculta guarda la referencia. El constructor devuelve las entradas del hijo junto a sus propios valores.

rules/keeper.ts
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 } } },
  };
}
  1. Línea 5 lamp es un FrameworkRef. La plataforma convierte en uno el id de Framework de la entrada.
  2. Líneas 6-9 El tipo de retorno enumera los valores guardados y las ranuras hijas.
  3. Línea 11 Los valores iniciales del Keeper.
  4. Línea 12 La ranura hija: qué Framework crear y las entradas que se le dan.

Todo Framework, también los hijos, debe devolver un name.

must define the required 'name' value, normally as a string constructor field.

Una ranura que apunta a un Framework fuera del juego falla con:

Invalid child Framework constraint: lamp.

Campos avanzados

CampoPropósito
listsContenido que un personaje gana durante la partida.
contentChoicesPuntos de elección donde el jugador elige una entrada de un Framework de contenido.
slotsSelectores para elecciones repetibles.
poolsReservas compartidas de las que salen las entradas numéricas.
modifiersNúmeros que la plataforma deriva de los efectos del contenido.
effectsCómo un Framework de contenido nombra un modificador y una cantidad.
levellingSubir o bajar un nivel a un personaje después de crearlo.
rebuildQué hace una reconstrucción al estado de la partida, como un cambio de nivel.
combatLos roles que leen las herramientas de combate de la mesa.
catalogueRegistros de contenido guardados fuera del código y añadidos por lotes.
tablesTablas de datos compartidas.
playReadsValores derivados que la mesa lee de atributos guardados.
rulesAttacksAtaques que tiene todo personaje.
optionsFromToma las opciones de una entrada de otra fuente.
rich, richTextMarca una entrada de texto como texto enriquecido.

Siguiente