Fiches des ensembles de règles

Utilise cette page pour concevoir la fiche de personnage d'un ensemble de règles : attributs, compétences, champs et listes, états vivants, pistes de blessures, pénalités, repos et texte du GM (maître du jeu), ainsi que la fiche d'équipe et les décomptes de progression. Elle s'adresse aux auteurs d'ensembles de règles. Avant de commencer, lis Écrire des ensembles de règles Game Mode.

La fiche

Tout ce qui lit un nombre le nomme par une référence de valeur : un objet avec exactement une clé parmi const, field, derived, abilityScore, abilityMod, abilityModFromField, skillMod, saveMod, listSum, livePool, liveTrack et itemStat. Par exemple, une réserve au maximum dérivé : "max": { "derived": "grit_max" }.

Ce que fait un test sans entraînement. Une compétence ou sauvegarde dans laquelle le personnage n'a aucun entraînement (son niveau est le premier) se lance normalement, sauf si l'ensemble en décide autrement avec untrained sur la compétence, sur la sauvegarde ou sur la section où elle se trouve (la règle propre à la compétence ou à la sauvegarde l'emporte) :

"sections": [{ "id": "labour", "label": "Labour", "untrained": { "by": -1 } }],
"skills": [
  { "id": "dig", "label": "Dig", "ability": "sinew", "section": "labour", "untrained": "refuse" },
  { "id": "listen", "label": "Listen", "ability": "nerve", "untrained": "harder" }
]

Les sections sur les attributs, compétences et sauvegardes, et untrained où qu'il soit, relèvent de Capability API 1.41 pour un ensemble en package.

Une compétence ou sauvegarde peut porter un cap, une référence de valeur qui fixe le maximum que son test puisse jamais atteindre : une valeur qu'elle ne peut dépasser, ou une piste qui la retient. Gravewatch plafonne Soothe à la Resolve qui reste à un gardien, "cap": { "livePool": "resolve" }. Le nombre plafonné est celui que montre la fiche et que lance chaque test, et un échange with= est calculé sur le nombre avant le plafond, puis plafonné à nouveau. Un plafond ne peut pas lire un modificateur de compétence ou de sauvegarde, pas plus que la valeur dérivée qu'il lit ni aucune valeur dérivée déclarée au-dessus de celle-ci : la fiche est toujours calculée une seule fois, de haut en bas. Capability API 1.39.

hideWhen cache un champ, une valeur dérivée, une liste, une réserve ou une piste ordinaire selon la valeur d'un autre champ, d'exactement une façon parmi trois : equals une valeur, notEquals une valeur (caché dès que le champ contient autre chose : c'est ainsi qu'on dit "seulement pour ce type de personnage"), ou in une liste de valeurs. Chaque valeur nommée doit pouvoir figurer dans le champ, sinon la règle ne correspondrait jamais, et elle est vérifiée valeur par valeur ; pour notEquals et in, cela inclut la plage d'un champ numérique et la longueur d'un champ texte. La règle lit la valeur que montre l'éditeur de fiche : un champ non défini a la valeur de départ d'une fiche vierge, et une valeur enum que l'ensemble ne propose plus vaut la valeur par défaut du champ. Le fichier 5e utilise equals pour cacher les emplacements de sorts aux personnages qui n'en lancent pas ; Gravewatch retire l'huile de lanterne de la fiche de chaque gardien qui n'est pas de la garde de nuit avec "hideWhen": { "field": "watch", "notEquals": "night" }. Une couche ne peut pas retirer une valeur avec laquelle l'une de ces règles compare. Une piste de blessures ne peut pas être cachée, car les jets et les combats la lisent quoi que montre la fiche. notEquals et in relèvent de Capability API 1.39.

Le max d'une piste ordinaire peut être une référence de valeur plutôt qu'un nombre, pour qu'une valeur du personnage fixe sa longueur : "max": { "field": "willpower_rating" }. Son min et son default restent des nombres. Une piste de blessures à niveaux nommés a un max égal à son nombre de niveaux ; une piste à cases numérotées est aussi longue que son propre max (voir Cases numérotées ci-dessous). alwaysShow: true affiche une piste dans le bloc de fiche du Game Master même à sa valeur par défaut, pour une valeur qui compte à chaque tour ; sans lui, une piste à sa valeur par défaut est omise, car trois sauvegardes contre la mort à zéro ne disent rien. Ces trois éléments relèvent de Capability API 1.37 pour un ensemble en package.

États vivants : une forme, une posture, une lumière

Un champ enum est choisi à la création du personnage et le reste, et un état (condition) est seulement actif ou inactif. Un état vivant (live state) est une valeur parmi un ensemble fermé qui change en jeu : la forme d'un métamorphe, une posture de combat, la clarté d'une lanterne.

"live": {
  "states": [
    {
      "id": "stance",
      "label": "Stance",
      "values": ["guarded", "steady", "reckless"],
      "valueLabels": { "guarded": "Guarded", "steady": "Steady", "reckless": "Reckless" },
      "default": "steady"
    }
  ]
}

Des nombres qui suivent. Une valeur dérivée avec "op": "enumTable" donne un nombre pour chaque valeur d'un champ enum ou d'un état vivant :

{
  "id": "stance_brawn",
  "label": "Stance on Brawn",
  "op": "enumTable",
  "from": { "liveState": "stance" },
  "table": { "guarded": -1, "reckless": 2 },
  "default": 0
}

Les états vivants, enumTable et une étape de repos qui nomme un state relèvent de Capability API 1.42 pour un ensemble en package.

Pistes de blessures : une santé marquée sur une piste

Beaucoup de systèmes ne comptent pas de points de vie. Ils utilisent une colonne de cases, chacune pire que la précédente, dont on coche une lorsqu'on est blessé. Donne à une entrée live.tracks des kinds et soit des levels nommés, soit des boxes numérotées (ci-dessous), pour remplacer un nombre sur une échelle par une telle piste :

Quelle forme convient à ton système ? Une réserve enregistre COMBIEN de dégâts sont passés ; une piste enregistre combien ET le type de chaque part. Si une blessure est contondante, létale ou aggravée et que ce type importe après le coup (parce que l'aggravé guérit moins vite, ne peut pas être absorbé ou finit par tuer), il doit être conservé après le jet. Seule une marque le porte. Une réserve ne le peut pas : après soustraction des dégâts, il ne reste qu'un plus petit nombre, sans souvenir de la nature des points. Voilà pourquoi combat.damageKinds est refusé lorsque la santé est une réserve, plutôt qu'ignoré. Une réserve peut toujours avoir damageTypes et un adversaire peut y résister ou en être immunisé : cela concerne la quantité qui passe, pas la nature de la blessure après le coup.

{
  "id": "harm",
  "label": "Harm",
  "min": 0,
  "max": 4,
  "levels": [
    { "label": "Scuffed", "penalty": 0 },
    { "label": "Winded", "penalty": -1 },
    { "label": "Bleeding", "penalty": -3 },
    { "label": "Down", "penalty": -99 }
  ],
  "kinds": [
    { "id": "knock", "label": "K", "severity": 0 },
    { "id": "tear", "label": "T", "severity": 1 }
  ]
}

Les règles exactes, car une lecture vague produit la mauvaise piste :

Marquer en jeu. Le GM écrit [sheet: op="damage" track="harm" kind="knock" amount="1"] et soigne avec un amount négatif. Sur une piste qui se remplit par case, il ajoute box="3" pour la case que le coup atteint. La forme de damage pour réserves, qui nomme pool=, ne change pas. La commande ordinaire track est refusée sur une piste de blessures : un nombre ne précise pas le type des nouvelles marques. Le joueur peut aussi marquer et effacer les cases à la main, comme ces systèmes le prévoient.

Un combat peut aussi la marquer. Fais pointer combat.health vers la piste plutôt qu'une réserve : un coup réussi marque les cases indiquées par combat.damageKinds.marks, du type auquel ce bloc associe ses dégâts. Un personnage à la piste pleine est à terre, ce que lit la règle de mort. Sur une piste qui se remplit par case, des dégâts per-point nomment la case qu'ils atteignent et per-blow vise la première ; un coup qu'aucune case ne peut recevoir met le personnage à terre, ce que signifie être mis hors de combat dans les systèmes qui tiennent une telle piste. Guérir efface une marque, la plus légère, quel que soit son type. Les points temporaires sont refusés faute de tampon où les placer. Le moteur lit la piste comme les niveaux RESTANTS ; tout le reste du combat, tomber, être ranimé, le journal et le récapitulatif, reste inchangé.

Un repos peut guérir une piste de blessures. Une étape de restauration qui la nomme avec "to" la ramène à ce nombre de marques, débordement compris ; avec un "by" NÉGATIF, elle en efface ce nombre, débordement d'abord : "by": { "const": -2 } en efface donc deux. Une étape qui nomme aussi un kind n'efface que les marques de ce type : le "Catch your breath" de Gravewatch s'écrit { "track": "harm", "kind": "knock", "to": "min" }, qui soigne les coups et laisse les déchirures. Une étape qui AJOUTERAIT des marques ne fait rien, car un repos ne marque aucune blessure, et cela inclut un "by" positif : il est ignoré sans un mot, alors écris le signe moins.

Cases numérotées au lieu de niveaux nommés

Quand une piste est aussi longue que le personnage est robuste, donne-lui boxes au lieu de levels. Elle a autant de cases que son propre max, qui peut être une valeur calculée par la fiche (jamais une valeur qui lit l'état courant), jusqu'à 64 :

{
  "id": "strain",
  "label": "Strain",
  "min": 0,
  "max": { "derived": "strain_boxes" },
  "boxes": {
    "penalty": {
      "by": "remaining",
      "table": [
        [0, -1],
        [1, 0]
      ]
    }
  },
  "kinds": [{ "id": "strain", "label": "S", "severity": 0 }],
  "fill": "indexed",
  "onFull": "refuse"
}

Remplir par case, et pistes qui refusent

Niveaux ajoutés par une liste

"extra": { "list": "scars", "countColumn": "levels", "penaltyColumn": "penalty" } sur une piste à niveaux nommés permet à une liste de la fiche de l'allonger pour chaque personnage. Chaque ligne, dans l'ordre, ajoute son nombre de niveaux (16 au plus) avec sa pénalité, après le dernier niveau dont la pénalité est au moins aussi bonne ; ces niveaux prennent le nom de ce niveau quand les pénalités correspondent, et celui de la pénalité sinon. Les cicatrices de Gravewatch fonctionnent ainsi. Une liste cachée par la fiche n'ajoute rien, et si une ligne est supprimée alors que ses niveaux sont marqués, les marques qui ne tiennent plus sont conservées comme débordement : modifier la fiche n'annule pas une blessure.

boxes, fill, onFull, extra et le kind d'une étape de repos relèvent de Capability API 1.40 pour un ensemble en package.

La pénalité sur tes jets

resolution.penaltyFrom nomme la piste de blessures dont la pénalité touche chaque test de l'ensemble. Elle est déclarée, pas supposée : un ensemble qui l'omet lance exactement comme avant l'existence des pistes.

L'EFFET de la pénalité dépend du type de résolution, comme celui du nombre de la fiche :

Elle doit nommer une piste de blessures. Une piste ordinaire n'a pas de pénalité et est refusée à l'importation. Le résultat indique celle qui s'applique pour expliquer au joueur ses dés en moins ; le bloc de fiche du GM montre aussi le degré et son coût.

Modificateurs de la fiche

Certains nombres d'une fiche accompagnent chaque jet qu'ils concernent : un sac lourd à chaque escalade, une pénalité d'armure à chaque déplacement discret, une bénédiction sur tout. resolution.adjust l'exprime, pour les deux types :

"adjust": [{ "value": { "derived": "burdened" }, "abilities": ["brawn"] }]

Le résultat indique ce que la fiche a ajouté (adjust="-2" dans le registre, et une ligne sur la carte des dés), pour que le joueur voie pourquoi un jet a donné ce résultat. Cela relève de Capability API 1.38 pour un ensemble en package.

Repos

Un repos liste des restaurations et des éléments à effacer. Chaque étape nomme une cible (pool, poolGroup, listPools, track ou state) et la fixe ("to": "max", "to": "min" ou un nombre) ou la modifie ("by": { "const": 1 } ou "by": { "fractionOfMax": 0.5 }). Une étape visant une piste de blessures peut seulement la soigner : son by est donc négatif ; voir plus haut. Une étape visant un état vivant le fixe seulement, à "default" ou à l'une de ses valeurs. Une étape poolGroup avec un fractionOfMax modifie chaque réserve du groupe de sa propre fraction ; ajoute "shared": true (Capability API 1.77) pour calculer plutôt la fraction sur le maximum de tout le groupe et la répartir entre les réserves du groupe dans l'ordre où la fiche les liste, chacune jusqu'à ce qui lui manque. Le repos long de 5e, "half of the character's total number of" dés de vie gardés dans une réserve par dé, s'écrit { "poolGroup": "hit_dice", "by": { "fractionOfMax": 0.5, "round": "down", "min": 1 }, "shared": true }.

Texte du Game Master

Référence complète des règles pour le GM

Le gmReference facultatif de premier niveau contient la référence complète des règles de l'ensemble pour le Game Master, jusqu'à 16 000 caractères. Places-y les règles d'arbitrage détaillées et garde les courtes consignes sur les tests et les ressources dans gm.checkGuidance et gm.sheetGuidance. Ces champs, et gm.worldGuidance, gardent leur limite de 1 500 caractères ; les consignes des couches gardent aussi leurs limites actuelles.

"gmReference": "When a journey crosses hostile country, judge supplies, shelter and exposure before the next leg. A failed navigation check costs time rather than silently moving the party to its destination."

La référence apparaît sous Game Master rules reference (référence des règles du Game Master) dans le prompt système stable, une fois par requête. Elle n'est jamais recopiée dans le rappel de chaque tour. Comme tout texte destiné au prompt, elle doit tenir sur une ligne, sans caractères de contrôle, crochets ni accolades de macro ({{ et }}). Si la requête dépasse encore la limite de contexte après les ajustements habituels de l'historique et du budget de réponse, la référence est raccourcie, avec une coupe signalée, avant que les instructions principales ne soient coupées. Ne la définis pas pour garder les prompts actuels. Un package qui l'utilise doit déclarer schemaVersion: 2 dans son manifeste et capabilityApi: { "major": 1, "minor": 145 } ou plus récent.

Horloges de progression de l'équipe et de la scène (clocks)

Capability API 1.143 ajoute un objet clocks facultatif de premier niveau. Omets-le pour laisser les commandes d'horloge désactivées. L'objet est strict : seules ces trois clés sont acceptées.

"clocks": {
  "sizes": [4, 6, 8],
  "max": 8,
  "text": "Create clocks for looming threats and long projects. Tick them when the fiction advances."
}

sizes accepte de un à six nombres de segments entiers et distincts, chacun de 2 à 12 ; sa valeur par défaut est [4, 6, 8]. max est le nombre maximal d'horloges gardées en même temps, de 1 à 12, 8 par défaut. Le text facultatif est une ligne destinée au prompt, jusqu'à 400 caractères, qui explique quand le GM doit créer et faire avancer des horloges. Un objet vide active les valeurs par défaut.

Les horloges appartiennent à l'équipe ou à la scène, pas à un personnage. Le rappel du GM liste leur nom et leur remplissage à chaque tour et enseigne ces commandes :

Les noms tiennent sur une ligne de 1 à 100 caractères, sans guillemets doubles, crochets, caractères de contrôle ni accolades de macro. Chaque balise demande exactement une action. Les commandes s'appliquent dans l'ordre de la réponse : une horloge peut donc être créée et avancée dans la même réponse. Le moteur réécrit chaque balise avec result="ok" now="4/6" (ou now="cleared"), ou avec result="refused" reason="...". Les attributs de résultat fournis par le modèle sont ignorés. Les horloges inconnues et les demandes mal formées sont refusées ; au plus 40 commandes s'appliquent par réponse.

Game Mode affiche un cercle segmenté, le nom et le remplissage à côté de l'état de l'équipe. Les balises restent dans la réponse enregistrée comme reçus et sont masquées de la narration. Les horloges sont stockées dans chaque instantané d'état de la partie sous rulesetClocks ; en l'absence de données, il n'y a pas d'horloge. Régénérer part de l'instantané précédent, continuer part de l'instantané actuel, et sélectionner ou supprimer des swipes ou des messages restaure les horloges avec le reste de cet instantané.

Fiche d'équipe : une bande, un vaisseau ou des Story Points partagés

Capability API 1.144 ajoute un party facultatif de premier niveau, à côté de sheet. Il contient une fiche partagée par partie, comme la bande de Blades, le vaisseau de Lasers & Feelings ou les Story Points de Genesys :

"party": {
  "label": "Crew",
  "fields": [
    { "id": "heat", "label": "Heat", "type": "number", "min": 0, "max": 9, "default": 0 },
    { "id": "vault", "label": "Vault capacity", "type": "number", "min": 0, "max": 16, "default": 8 },
    { "id": "upgrades", "label": "Upgrades", "type": "text", "maxLength": 400 }
  ],
  "pools": [{ "id": "coin", "label": "Coin", "max": { "field": "vault" }, "start": "empty" }],
  "advancement": { "fields": ["heat", "vault", "upgrades"], "text": "Record heat after a score." },
  "text": "Coin belongs to the crew."
}

fields utilise le même schéma de champ que sheet.fields ; pools utilise sheet.live.pools, y compris start, group, hideWhen et allowTemp. Il faut au moins un champ ou une réserve, et leurs identifiants doivent être uniques dans la fiche d'équipe. Les identifiants de personnage et d'équipe peuvent coïncider. Dans cette version mineure, les fiches d'équipe n'ont ni sections, ni listes, ni attributs, ni valeurs dérivées, ni migrations de fiche de personnage. Le max d'une réserve lit une constante ou un champ numérique de l'équipe. Les formules de personnage ne peuvent pas lire les valeurs de l'équipe, et les formules d'équipe ne peuvent pas lire les valeurs des personnages. hideWhen ne nomme lui aussi que des champs de l'équipe.

advancement.fields nomme les champs number, text ou longtext que le GM peut modifier de façon permanente. advancement.text et text prennent chacun une ligne destinée au prompt d'au plus 400 caractères. Le summary facultatif reprend gm.sheetSummary : ses fields choisissent des champs de l'équipe ; derived et lists doivent être vides. Sans résumé, tous les champs visibles de l'équipe sont affichés. Les réserves apparaissent toujours.

[sheet: sheet="party" op="restore" pool="coin" amount="3"]
[sheet: sheet="party" op="spend" pool="coin" amount="2"]
[sheet: sheet="party" op="advance" field="heat" by="2"]
[sheet: sheet="party" op="advance" field="upgrades" to="Hidden vault"]

sheet="party" choisit la fiche partagée ; laisse who de côté. Le who="party" existant s'applique toujours à chaque personnage et ne modifie jamais la fiche partagée. Cette version mineure permet spend, restore et l'advance d'un champ sur la fiche d'équipe. Les fiches inconnues, les opérations non prises en charge, les réserves insuffisantes, la progression non déclarée et les valeurs invalides sont refusées et réécrites avec le résultat du moteur. Les réserves d'équipe suivent la même arithmétique valeur actuelle/maximum et les mêmes valeurs par défaut que celles des personnages.

Le GM reçoit à chaque tour le libellé, les champs et les réserves de l'équipe à côté des blocs de fiche des personnages. Game Mode propose une fiche d'équipe repliable, en lecture seule, à côté des portraits des personnages, avec la même présentation de fiche. Les valeurs permanentes sont stockées une seule fois dans les métadonnées du chat (gamePartySheet), à côté de gameCharacterCards, et partagent les reçus de progression. Les réserves vivantes utilisent l'entrée réservée $party de rulesetLive ; les noms de personnages normalisés ne peuvent pas entrer en collision avec elle. Régénérer repart d'avant la réponse, et sélectionner ou supprimer un swipe restaure les valeurs permanentes et vivantes par l'historique existant. Les ensembles sans party gardent leur comportement actuel.

Création d'équipe partagée (Capability API 1.163). Une fiche d'équipe peut porter des lists (jusqu'à 12, écrites comme les listes de la fiche de personnage), son propre builder guidé et fromMembers : jusqu'à 8 champs numériques d'équipe lus sur les personnages de l'équipe, chacun { "field", "count": true } (combien de personnages il y a) ou { "field", "sum": "<character number field>" } (la somme des leurs, comme les points de Totem). Les champs de membres sont calculés à partir des personnages tels qu'ils sont chaque fois que la fiche partagée est lue : un personnage qui rejoint ou quitte l'équipe les modifie aussitôt. Avec des listes, le summary.lists de l'équipe peut les nommer.

L'assistant de création s'écrit exactement comme celui d'un personnage (réserves, étapes, lignes à prix, offres de dépense, profils) et respecte les mêmes règles vis-à-vis des champs et des listes de l'équipe. Ses étapes de catalogue et de copie de ligne peuvent lire les catalogues de l'ensemble qui alimentent les listes d'équipe. En Game Mode, n'importe quel joueur ouvre l'Edit de la fiche partagée, qui propose la création guidée, et l'enregistre pour toute l'équipe. Chaque enregistrement nomme la révision sur laquelle il a été ouvert (gamePartySheetRevision dans les métadonnées du chat, augmenté par chaque enregistrement et par les propres modifications de l'histoire) : un enregistrement ouvert avant que celui d'une autre personne n'aboutisse est refusé, la fiche plus récente s'affiche et le brouillon du joueur reste ouvert ; enregistrer à nouveau est alors son choix de la remplacer.

"party": {
  "label": "The Crew",
  "fields": [
    { "id": "tier", "label": "Tier", "type": "number", "min": 0, "max": 4, "default": 0 },
    { "id": "size", "label": "Crew size", "type": "number", "min": 0, "max": 12, "default": 0 }
  ],
  "lists": [{ "id": "upgrades", "label": "Upgrades", "columns": [{ "id": "name", "label": "Name", "type": "text" }] }],
  "builder": { "steps": [{ "id": "upgrades", "label": "Upgrades", "kind": "rows", "list": "upgrades" }] },
  "fromMembers": [{ "field": "size", "count": true }]
}