Ruleset Checks

Use this page to set how your ruleset rolls a check or a save: the five resolution kinds, outcome bands, checks that roll their own way, and spending or charms that change a roll. It is for ruleset authors. Before you start, read Writing Game Mode Rulesets.

Resolution kinds

resolution.kind picks how a check is rolled. Every kind reads the same character sheet and shares three keys, so the parts of the file below resolution do not change when you switch:

What the resulting number means is the kind's business: dice-sum adds it to the roll, dice-pool and dice-highest throw that many dice. symbol-pool keeps ability and training separate to build and upgrade narrative dice.

dice-sum: add the dice up

"resolution": {
  "kind": "dice-sum",
  "dice": { "count": 2, "sides": 6 },
  "abilityModifier": { "op": "identity" },
  "proficiencyTiers": [
    { "id": "untrained", "label": "Untrained" },
    { "id": "trained", "label": "Trained", "flat": 1 }
  ],
  "advantage": false,
  "difficultyLadder": [
    { "label": "Easy", "dc": 6 },
    { "label": "Hard", "dc": 10 }
  ]
}

dice-pool: throw the dice and count them

The sheet's number is the size of the pool, not a bonus on top of it. A rating of 3 and a trade worth 2 throw five dice. That is the whole trick: no new sheet vocabulary, no new editor, and a system whose ratings are handfuls of dice is written with the same abilities, skills and proficiencyTiers as any other.

"resolution": {
  "kind": "dice-pool",
  "die": { "sides": 10 },
  "abilityModifier": { "op": "identity" },
  "proficiencyTiers": [
    { "id": "rating_0", "label": "Untried" },
    { "id": "rating_1", "label": "Shown once", "flat": 1 }
  ],
  "pool": { "min": 1, "max": 15, "abilityPlusAbility": true },
  "target": { "default": 7, "min": 5, "max": 9 },
  "explode": { "from": 10, "min": 8 },
  "cancel": { "upTo": 1 },
  "botch": { "upTo": 1 },
  "exceptional": { "successes": 5 },
  "situationalDice": { "min": -3, "max": 3 },
  "reroll": [{ "id": "careful", "upTo": 6, "mode": "once" }],
  "difficultyLadder": [
    { "label": "Plain work", "successes": 1, "target": 6 },
    { "label": "Grim", "successes": 3, "target": 8 }
  ]
}

cancel and botch faces must be below the lowest target, and every face any of these rules names has to be a face the die has. A rule that could never fire is refused at import rather than found in play.

A pool ruleset is Capability API 1.24 for a packaged ruleset; a min on explode or double, pool.abilityPlusAbility and botch.rule are 1.37; reroll is 1.38; target.from, stances and exact are 1.137. A community ruleset you import is validated by the Engine that reads it, so it needs nothing.

What the Game Master may write on a pool check

[skill_check: skill="Ward" dc="2" who="Bram the Quiet" threshold="8" bonus="-2" with="Sinew"]
[skill_check: skill="Ward" difficulty="Grim" explode="9"]
[skill_check: skill="Nerve" dc="1" with="Warmth"]
[skill_check: skill="Ward" dc="2" reroll="careful"]

Each one is held to what your file declares: a value outside the range is pulled back to the nearest end, and an attribute your ruleset does not offer is ignored rather than refusing the check. The saved record then shows what the roll used: the difficulty and the threshold as numbers, the bonus dice after your limits, with= only when that ability was swapped in or added, a face only when the check moved it, reroll= only when the re-throw it names was the one thrown and threw something, and complication="true" when a halfOrMore botch went wrong alongside a result. The Engine always throws the dice itself. A pool result the model wrote is replaced, mode="advantage" is ignored because the kind has no advantage, and a die the player rolled before the turn does not apply.

dice-highest: throw the dice and read the highest

Blades in the Dark and Trophy Dark throw a handful of d6 and read only the highest one. Capability API 1.138.

"resolution": {
  "kind": "dice-highest",
  "die": { "sides": 6 },
  "abilityModifier": { "op": "identity" },
  "proficiencyTiers": [{ "id": "rating_0", "label": "0" }, { "id": "rating_1", "label": "1", "flat": 1 }],
  "pool": { "min": 0, "max": 6 },
  "zeroDice": "lowest-of-two",
  "critical": { "count": 2 },
  "situationalDice": { "min": -1, "max": 2 },
  "difficultyLadder": [{ "label": "Partial", "dc": 4 }, { "label": "Full", "dc": 6 }],
  "outcomes": {
    "by": "total",
    "tiers": [
      { "id": "critical", "label": "Critical", "on": "critical-success", "success": true },
      { "id": "full", "label": "Full success", "atLeast": 6, "success": true },
      { "id": "partial", "label": "Partial success", "atLeast": 4, "success": true, "text": "You do it, with a consequence." },
      { "id": "bad", "label": "Bad outcome" }
    ]
  }
}

The record keeps the summed shape (resolution="sum", modifier="0", the kept dice as the total) and adds highest="1", with zeroDice="true" and dark="N" where they apply; the dark dice are the last ones in rolls. A light-only outcome also records darkOutcome="light", so the card highlights only kept light dice, including after reload. A ruleset of this kind has no fight of its own, so combat is refused beside it.

roll-against: roll at most (or at least) the sheet's number

Call of Cthulhu, GURPS and an old-school thief's percentages roll against a number on the sheet instead of adding to the dice. Capability API 1.139.

"resolution": {
  "kind": "roll-against",
  "dice": { "count": 1, "sides": 100 },
  "abilityModifier": { "op": "identity" },
  "proficiencyTiers": [{ "id": "base", "label": "Base" }],
  "against": "at-most",
  "criticalSuccess": [{ "from": 1, "to": 1 }],
  "criticalFailure": [{ "from": 100, "to": 100 }, { "from": 96, "whenTarget": { "below": 50 } }],
  "tens": { "max": 2 },
  "difficultyLadder": [
    { "label": "Regular", "dc": 0 },
    { "label": "Hard", "dc": 0, "divide": 2 },
    { "label": "Extreme", "dc": 0, "divide": 5 }
  ],
  "outcomes": {
    "by": "fraction",
    "tiers": [
      { "id": "critical", "label": "Critical", "on": "critical-success", "success": true },
      { "id": "extreme", "label": "Extreme success", "atLeast": 5, "success": true },
      { "id": "hard", "label": "Hard success", "atLeast": 2, "success": true },
      { "id": "regular", "label": "Regular success", "atLeast": 1, "success": true },
      { "id": "fail", "label": "Failure" },
      { "id": "fumble", "label": "Fumble", "on": "critical-failure" }
    ]
  }
}

symbol-pool: throw narrative dice and read the symbols

Genesys builds a pool from a characteristic and a skill rank, then adds opposing dice. Faces carry success, advantage, triumph, failure, threat and despair instead of numbers. Capability API 1.141.

"resolution": {
  "kind": "symbol-pool",
  "abilityModifier": { "op": "identity" },
  "proficiencyTiers": [
    { "id": "untrained", "label": "Untrained", "flat": 0 },
    { "id": "rank_one", "label": "Rank 1", "flat": 1 }
  ],
  "symbols": [
    { "id": "s", "label": "Success" },
    { "id": "f", "label": "Failure", "cancels": "s" },
    { "id": "a", "label": "Advantage" },
    { "id": "h", "label": "Threat", "cancels": "a" },
    { "id": "t", "label": "Triumph", "counts": "s" },
    { "id": "d", "label": "Despair", "counts": "f" }
  ],
  "dice": [
    { "id": "ability", "label": "Ability", "faces": [[], ["s"], ["s"], ["s", "s"], ["a"], ["a"], ["s", "a"], ["a", "a"]] },
    { "id": "proficiency", "label": "Proficiency", "faces": [[], ["s"], ["s"], ["s", "s"], ["s", "s"], ["a"], ["s", "a"], ["s", "a"], ["s", "a"], ["a", "a"], ["a", "a"], ["t"]] },
    { "id": "difficulty", "label": "Difficulty", "faces": [[], ["f"], ["f", "f"], ["h"], ["h"], ["h"], ["h", "h"], ["f", "h"]] },
    { "id": "challenge", "label": "Challenge", "faces": [[], ["f"], ["f"], ["f", "f"], ["f", "f"], ["h"], ["h"], ["f", "h"], ["f", "h"], ["h", "h"], ["h", "h"], ["d"]] },
    { "id": "boost", "label": "Boost", "faces": [[], [], ["s"], ["s", "a"], ["a", "a"], ["a"]] },
    { "id": "setback", "label": "Setback", "faces": [[], [], ["f"], ["f"], ["h"], ["h"]] }
  ],
  "success": { "symbol": "s", "needed": 1 },
  "pool": { "die": "ability", "upgrade": "proficiency", "max": 6 },
  "difficulty": { "die": "difficulty", "upgrade": "challenge", "max": 5 },
  "boost": { "die": "boost", "max": 3 },
  "setback": { "die": "setback", "max": 3 },
  "criticalSuccess": "t",
  "criticalFailure": "d",
  "difficultyLadder": [{ "label": "Easy", "dc": 1 }, { "label": "Average", "dc": 2 }, { "label": "Hard", "dc": 3 }]
}

What is out of scope, and why

These mechanics still need their own resolution kind:

Both of the things this kind used to leave out are modelled now, and Spending to change a roll below says how. A rule of the system itself, "spend a point for a success" or "spend a point to throw the failures again", is resolution.spend. A re-throw the system grants for free when the situation calls for it is resolution.reroll, above. One that belongs to something a character picked is mechanics.check on a catalog entry, bought with that entry's own cost.

Outcome bands: more than success or failure

Many systems read a check as one of several results rather than a bare pass or fail: Pathfinder's four degrees of success, a "barely" that succeeds at a cost, Call of Cthulhu's hard and extreme successes, Fate's "success with style". resolution.outcomes names those bands, and the Engine says on every check which one it landed in (Capability API 1.135). It works with every resolution kind.

"outcomes": {
  "by": "margin",
  "naturals": "shift",
  "tiers": [
    { "id": "critical_success", "label": "Critical success", "atLeast": 10, "success": true, "critical": true },
    { "id": "success", "label": "Success", "atLeast": 0, "success": true },
    { "id": "failure", "label": "Failure", "atLeast": -9 },
    { "id": "critical_failure", "label": "Critical failure", "critical": true }
  ]
}

The band decides the outcome: success and the two criticals come from it, never from the bare comparison. Where a summed ruleset's naturals make a face an automatic success or failure, that face lands in the band on that critical, or else in the best or the worst band, and stays a critical. A pool's botch does the same at the bottom, and a pool with bands leaves exceptional out, because the bands already say what a critical success is.

A pool read by: "total" is how a system whose difficulty is fixed says its results: Lasers & Feelings' "1 success: you barely manage it, 2: you do it well, 3: critical success" is three bands at 3, 2 and 1 successes and a miss below.

The record names the band with outcome="Critical success", the dice card shows it in place of the plain word, and the Game Master is taught the bands and their text and told to narrate the band. A packaged ruleset that declares bands needs Capability API 1.135.

Checks that roll their own way

Some games roll most checks one way and a few another: an old-school game rolls a d20 under an ability score, but a thief's skills on a d100 and Open Doors on a d6. resolution.overrides names those checks and the resolution keys they roll with instead. Capability API 1.140.

"overrides": [
  { "id": "thief", "label": "Thief skills", "skills": ["open_locks", "pick_pockets"], "set": { "dice": { "count": 1, "sides": 100 } } },
  { "id": "x_in_6", "label": "X-in-6", "skills": ["open_doors", "listen"], "set": { "dice": { "count": 1, "sides": 6 } } },
  { "id": "favored", "label": "Favored", "skills": ["athletics"], "when": { "field": "favored_athletics" }, "set": { "cancel": null } }
]

Spending to change a roll

Some systems let a player pay for a roll they are about to make: a point of will for an automatic success. resolution.spend says so, as a standing rule of the system rather than as something a character went and bought:

"spend": [{ "pool": "resolve", "amount": 1, "successes": 1, "perCheck": 2 }]

It goes on the check itself. The Game Master writes [skill_check: skill="Nerve" dc="2" spend="resolve:1"], not a separate [sheet:] command, because the dice are thrown before sheet commands are applied and there would be nothing left to change. One resolution rolls the dice and pays for what changed them.

A charm that changes a roll

resolution.spend is a rule of the system. An entry a character PICKED can change a check too, with mechanics.check on the catalog entry:

"mechanics": {
  "kind": "utility",
  "cost": [{ "pool": "blood", "amount": 1 }],
  "perCostStep": { "flat": 1 },
  "check": { "reroll": { "upTo": 1, "mode": "once" }, "successes": 1 }
}

What it costs is the entry's own cost, paid through exactly the machinery that pays for using anything else: the pool, and one use of every counter the same entry wrote. perCostStep is what says the entry SCALES; an entry that declares one is bought as many times over as the price was paid, and one that does not is bought once however much was offered.

The Game Master names it on the check: [skill_check: skill="Brawl" dc="3" use="Potence" spend="blood:3"]. Not a separate sheet command, for the same reason as above: the dice are thrown before any bookkeeping runs.

All or nothing. If the pool cannot cover it, the purchase does not happen and nothing is deducted: the roll is exactly the one it would have been. Points that are not a whole number of purchases buy nothing either. Asking for more than perCheck is clamped rather than refused, and only the cap is paid for. The Engine works all of this out; the Game Master names what the player said they were spending and never touches the dice. The record says what was paid, which entry was applied, how many successes nobody rolled and how many dice were thrown again. A charm the character has not picked, or one the Engine cannot read the catalog for, does nothing at all rather than being applied on trust.