Couches, traductions et migrations des ensembles de règles

Utilise cette page pour proposer des variantes qu'un joueur active pour une partie, pour traduire le texte d'un ensemble de règles et pour déplacer des valeurs enregistrées vers de nouveaux identifiants quand une fiche change. Elle s'adresse aux auteurs d'ensembles de règles. Avant de commencer, lis Écrire des ensembles de règles Game Mode.

Couches : variantes de ton propre ensemble de règles

Une couche est une variante nommée de ton ensemble de règles, activée par le joueur à la création d'une partie : magie rare, hiver rude, difficulté plus âpre. Les couches résident dans le fichier de l'ensemble de règles, dans un tableau facultatif layers ; elles voyagent donc avec lui et ne peuvent jamais manquer à une partie qui les a utilisées. L'assistant les affiche comme des interrupteurs sous ton ensemble de règles, et le choix reste fixé pour toute la durée de vie de cette partie, exactement comme l'ensemble lui-même.

"layers": [
  {
    "id": "hard_winter",
    "label": "Hard winter",
    "summary": "Cold, hunger and short days. Everything is harder.",
    "conflicts": ["mud_season"],
    "gm": {
      "guidance": "Hard winter is on. Let a failed check cost warmth, food or daylight as well as progress.",
      "worldGuidance": "Hard winter is on. Build a world of closed roads, thin stores and rationed settlements."
    },
    "fields": [{ "id": "calling", "removeValues": ["Sailor"], "default": "Hauler" }],
    "difficultyLadder": [{ "label": "Easy", "dc": 7 }],
    "catalogs": [{ "id": "knacks", "hide": { "filter": "grit", "above": 0 } }]
  },
  {
    "id": "mud_season",
    "label": "Mud season",
    "summary": "Thaw, flooded roads and slow going."
  }
]

Ce qu'une couche peut faire. La liste est fermée, et chaque effet restreint quelque chose ou ajoute du texte :

"items": {
  "market": { "removeSellers": ["magic_dealer", "scribe"], "unsold": [{ "tag": "magical" }] },
  "lootTables": [{ "id": "treasure_low", "label": "Pocket treasure", "entries": [{ "coins": "sp", "weight": 1, "count": "4d6" }] }]
}

Ce qu'une couche ne peut pas faire. Elle ne peut ajouter une valeur énumérée, un champ, une compétence, une réserve ou un repos, ajouter un vendeur ou une table de butin, changer le type de résolution, toucher l'état en cours ou les nombres de combat, ni ajouter un appel de modèle. Une valeur qu'une couche _ajouterait_ serait inconnue de tous les autres lecteurs de la fiche ; les valeurs ne peuvent donc que disparaître. Tout ce qui dépasse cette liste constitue une modification de l'ensemble de règles lui-même ou un second ensemble.

Conflits. conflicts nomme les couches qui ne peuvent être actives ensemble. Nommer un seul côté de la paire suffit. L'assistant désactive l'autre interrupteur, et si un choix sauvegardé contient malgré tout les deux, la couche déclarée plus tard est retirée ; les deux mêmes choix donnent donc toujours les mêmes règles.

Une fiche contenant déjà une valeur retirée la conserve. Rien ne réécrit un personnage. L'éditeur cesse de proposer la valeur, et un personnage qui la possédait déjà l'affiche telle quelle. Désactive la couche dans une nouvelle partie et la valeur sera proposée à nouveau. Il en va de même pour une entrée de catalogue masquée : elle disparaît du sélecteur, et une ligne déjà choisie par le joueur reste sur la fiche. Les pièces qu'une couche retire et que quelqu'un transporte déjà restent dans son sac.

Limites. 12 couches par ensemble de règles et 4000 caractères de consignes par couche, les deux chaînes comptées ensemble. Un ensemble de règles en package qui déclare layers, ou un gm.worldGuidance de base, nécessite Capability API 1.25, un ensemble dont les couches retirent des pièces nécessite 1.64, et un ensemble dont les couches modifient son items nécessite 1.813. Un ensemble que tu importes est validé par Engine à la lecture et n'a donc besoin de rien.

Les couches écrites par quelqu'un d'autre (une couche de magie rare pour un ensemble de règles que tu n'as pas écrit, livrée dans son propre fichier) viendront plus tard. Aujourd'hui, une couche est livrée à l'intérieur de l'ensemble de règles auquel elle appartient.

Traductions

Traductions (Capability API 1.811). Les chaînes affichées d'un ensemble de règles dans une autre langue sont regroupées en une traduction par langue, nommée d'après le code de la langue comme les propres packs de langue du moteur (ru, pt-BR, zh-Hans). Dans le catalogue officiel d'agents, chacune est un pack de langue à côté du fichier de l'ensemble de règles (ci-dessous). Un fichier de package d'ensemble de règles que tu partages peut les contenir à la place, avec un fichier par langue à côté de ruleset.json : locales/<language>.json, listé dans le manifeste comme les autres fichiers. Dans les deux cas, chacun est un catalogue de localisation de package avec une section ruleset : chaque clé est une chaîne affichée de l'ensemble de règles ou de ses catalogues, mot pour mot en anglais, et sa valeur est cette chaîne dans la langue du fichier.

{
  "_meta": { "locale": "ru", "direction": "ltr" },
  "package": { "name": "5e (SRD 5.1)" },
  "ruleset": { "Prone": "Лежащий", "Fire Bolt": "Огненный снаряд", "Goblin": "Гоблин" }
}

_meta.locale doit être la langue d'après laquelle le fichier est nommé, et le fichier contient $schema, _meta, package et ruleset, sans rien d'autre, toutes les valeurs étant du texte. Une chaîne laissée vide n'est pas encore traduite et s'affiche en anglais ; un fichier sans section ruleset (la propre présentation en anglais d'un package, locales/en.json) ne traduit rien. Les traductions ne concernent que l'affichage : les règles, les commandes de fiche et tout ce qui est dit au GM continuent à lire l'anglais. L'écran d'un combat (noms, états, actions, sorts, journal et ordre des tours) affiche chaque chaîne dans la langue du joueur si la traduction de l'ensemble de règles la contient, d'abord depuis le fichier de cette langue, puis depuis celui de la langue dont elle est une variante (pt pour pt-BR), et en anglais sinon ; "Goblin 2" lit la traduction de "Goblin" avec son nombre. Un fichier de package contenant des traductions nécessite Capability API 1.811. Son importation ne conserve que la traduction dans la langue définie pour le moteur (ou dans celle dont elle est une variante) et supprime les autres ; pour lire l'ensemble de règles dans une autre langue, change la langue du moteur et importe de nouveau le fichier, ce qui remplace la traduction conservée. Les traductions ne font pas partie de la version : importer de nouveau la même version avec une traduction corrigée remplace donc aussi celle-ci, et un fichier de cette version sans traduction laisse celle qui était conservée.

Un ensemble de règles du catalogue ne contient jamais locales/<language>.json dans son fichier (s'il en contient un, il est refusé avant son téléchargement). Ses traductions sont des packs de langue (Capability API 1.811) : un fichier JSON par langue, <id>-<version>.<language>.json, publié à côté de <id>-<version>.ruleset.json et contenant exactement ce que contient un locales/<language>.json (_meta.locale indique la langue d'après laquelle il est nommé, et il possède une section ruleset). L'entrée du catalogue les liste à côté de son artifact :

"locales": {
  "ru": {
    "url": "https://raw.githubusercontent.com/Pasta-Devs/Marinara-Agents/main/artifacts/ember-roads-1.0.0.ru.json",
    "sha256": "<64 hex>",
    "bytes": 812345,
    "name": "Угольные дороги",
    "description": "<the store card's description in Russian>"
  }
}

Chaque pack est une URL https de la même forme que celle de l'artefact, nommée d'après sa version et sa langue, avec son sha256 et sa taille (8 MB au plus) ; un ensemble de règles en liste au plus 40, jamais en (l'anglais est l'ensemble de règles lui-même), et son manifeste déclare Capability API 1.811. name et description sont ceux de la fiche de la boutique dans cette langue, de sorte que la fiche se lit dans la langue du moteur sans récupérer le pack. Une installation récupère le fichier de l'ensemble de règles, puis uniquement le pack dans la langue définie pour le moteur (ou dans celle dont elle est une variante), vérifie sa taille, sa somme de contrôle et sa langue, et le conserve avec la version installée. Quand la langue du moteur change (et chaque fois qu'une page s'y ouvre), chaque ensemble de règles installé depuis le catalogue qui liste un pack dans la nouvelle langue le récupère, et le pack de l'ancienne langue est supprimé. Un pack qui ne peut pas être obtenu (hors ligne, aucun pack listé ou fichier différent de celui que liste le catalogue) laisse l'ensemble de règles en anglais ; l'installation ou le changement de langue suivant réessaie. Une mise à jour conserve la version précédente pour permettre un retour arrière, sans son pack : après un retour arrière, le changement de langue suivant récupère de nouveau le pack de cette version, si le catalogue le liste encore.

Déplacer des valeurs vers de nouveaux identifiants : sheet.migrations

Ajouter des éléments ne demande rien de plus. Quand une nouvelle disposition déplace une valeur ailleurs (un champ renommé, un niveau unique qui devient un niveau par classe, une réserve de dés de vie unique qui devient une réserve par dé), indique comment dans sheet.migrations (Capability API 1.77), pour que chaque personnage créé avec l'ancienne disposition garde ses nombres : dans la bibliothèque, dans les parties, dans les anciennes sauvegardes, branches et points de contrôle, et dans les fiches importées.

"migrations": [
  {
    "from": 3,
    "steps": [
      { "rename": "field", "from": "xp", "to": "experience" },
      {
        "route": "level",
        "by": "class",
        "cases": [
          { "words": ["fighter"], "to": "level_fighter" },
          { "words": ["wizard"], "to": "level_wizard" }
        ],
        "else": "level_other",
        "default": 1
      },
      {
        "routeLive": "pool",
        "from": "hit_dice",
        "cases": ["hit_dice_d6", "hit_dice_d8", "hit_dice_d10", "hit_dice_d12"],
        "else": "hit_dice_d8"
      }
    ]
  }
]