Zum Hauptinhalt springen

Code-Frameworks

Rezept: Gegen einen Skill würfeln

Prüfe einen Prozentwurf gegen einen Skill-Wert und melde eine Erfolgsstufe.

Ziel

Lass einen Spieler einen d100 gegen einen Lore-Skill würfeln und eine Stufe sehen: Flawless, Strong, Pass oder Miss. Ein niedrigerer Wurf ist besser.

So kommt der Wurf hinein

Regeln können nicht würfeln. Der Spieler würfelt auf dem Bogen und gibt die Zahl in eine Aktion ein. Die Regel prüft die Zahl und schreibt sie. Der Spielablauf hat vier Schritte.

  1. Klicke auf das Würfelsymbol

    Der Bogen zeigt Roll: [[1d100]]. Ein Klick würfelt einen d100.

  2. Lies den Wurf im Protokoll

    Das Ergebnis erscheint im Würfelprotokoll des Tisches und im Chat. Am Charakter wird noch nichts geschrieben.

  3. Führe die Aktion aus und gib den Wurf ein

    Nutze die Schaltfläche Lore check. Fabled fragt den Wurf in einem Dialog ab. Gib die Zahl aus dem Protokoll ein.

  4. Das Band aktualisiert sich

    Die Regel schreibt den Wurf und das Ziel. Die Ledger-Funktion leitet das Band ab, und der Bogen zeigt es.

Die Änderung

Füge dem Schema eine Lore-Eingabe, die Aktion und die Ledger-Funktion hinzu. Eine Konstruktor-Eingabe kann Grenzen haben.

schemas/keeper.json
    "lore": {
      "label": "Lore",
      "description": "The percentile a Lore check must roll under.",
      "defaultValue": 40,
      "min": 1,
      "max": 99
    }
  1. Zeilen 13-14 Diese Grenzen gelten, wenn ein Charakter erstellt wird. Für den Wurf gelten sie nicht.
schemas/keeper.json
    {
      "id": "check_lore",
      "name": "Lore check",
      "source": "rules/check-lore.ts",
      "inputs": { "roll": { "label": "Roll", "min": 1, "max": 100 } }
    }
  1. Zeilen 21-23 Die Aktion Lore-Probe und ihre Regeldatei.
  2. Zeile 24 Die Eingabe Roll: ein Label und Grenzen. Der Dialog zeigt sie an, und der Server erzwingt sie.
schemas/keeper.json
  "ledgerFunctions": [
    {
      "id": "last_band",
      "name": "Last band",
      "field": "last_band",
      "source": "rules/band.ts"
    }
  ]
  1. Zeilen 32-35 Die Ledger-Funktion leitet last_band aus den zwei Feldern ab, die die Aktion schreibt.

Der Konstruktor gibt die neuen Felder mit Platzhaltern zurück. Die Ledger-Funktion ersetzt last_band, wenn das Element gebaut wird.

rules/keeper.ts
export function construct(
  name: string,
  max_hp: number,
  lore: number,
): {
  name: string;
  max_hp: number;
  hp: number;
  lore: number;
  last_roll: number;
  last_target: number;
  last_band: string;
} {
  return {
    name: name,
    max_hp: max_hp,
    hp: max_hp,
    lore: lore,
    last_roll: 0,
    last_target: 0,
    last_band: "",
  };
}
  1. Zeilen 10-12 Die Felder, die die Aktion schreibt und die Ledger-Funktion liest.
  2. Zeilen 19-21 Startwerte: noch kein Wurf.

Die Grenzen der Eingabe halten den Wurf zwischen 1 und 100. Die Aktion ignoriert eine Zahl mit Dezimalstellen und schreibt sonst den Wurf und das Ziel.

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. Zeile 1 Der Wurf ist eine Eingabe, die der Spieler tippt.
  2. Zeile 2 Ignoriere eine Zahl mit Dezimalstellen. Die Grenzen der Eingabe halten sie bereits zwischen 1 und 100.
  3. Zeilen 4-5 Schreibe das Ziel und den Wurf. Die Stufe ergibt sich daraus.

Eine Ledger-Funktion macht daraus eine Stufe. Jeder Skill kann sie nutzen, denn jede Skill-Aktion schreibt dieselben zwei Felder.

rules/band.ts
export function last_band(currentValue: string, self: ElementRef): string {
  const roll: number = element.var(self, "last_roll") as number;
  const target: number = element.var(self, "last_target") as number;
  if (roll === 0) {
    return "No roll yet";
  }
  if (roll <= math.floor(target / 5)) {
    return "Flawless";
  }
  if (roll <= math.floor(target / 2)) {
    return "Strong";
  }
  if (roll <= target) {
    return "Pass";
  }
  return "Miss";
}
  1. Zeilen 2-3 Lies die zwei Felder, die die Aktion geschrieben hat.
  2. Zeilen 4-6 Sage vor dem ersten Wurf, dass es noch keinen gibt.
  3. Zeilen 7-15 Ein niedrigerer Wurf ist besser. Jede Stufe ist ein Anteil des Ziels.
  4. Zeile 16 Über dem Ziel ist ein Fehlschlag.

Für einen anderen Skill kopiere check-lore.ts und ändere den Funktionsnamen und das Feld im Aufruf element.var. Jeder Skill braucht eine eigene Aktion, weil ein Feldname im Code ausgeschrieben ist.

Zeige die Würfel, die Stufe und eine Schaltfläche auf dem Bogen. Nenne die Stufe in requiredBindings und die Aktion in den Aliasen.

layouts/keeper.json
      { "binding": "element.attributes.last_band", "expectedType": "string" }
  1. Zeile 15 Die Stufe ist Text.
layouts/keeper.json
      { "name": "check_lore", "functionRef": "check_lore" }
  1. Zeile 21 Der Alias, den die Schaltfläche nutzt.
layouts/keeper.json
      { "kind": "text", "text": "Roll: [[1d100]]" },
      {
        "kind": "text",
        "text": "Last check: {{element.attributes.last_band}}"
      },
      { "kind": "button", "label": "Lore check", "actionRef": "check_lore" }
  1. Zeile 35 Das Würfel-Abzeichen. Ein Klick würfelt und zeigt das Ergebnis im Würfelprotokoll.
  2. Zeilen 36-39 Die Stufe, die die Ledger-Funktion abgeleitet hat.
  3. Zeile 40 Die Schaltfläche, die den Dialog für den Wurf öffnet.

Teste es

Teste jede Stufe und einen Wurf außerhalb des Bereichs. Jeder Schritt listet die zwei Schreibvorgänge auf. expectedValuesAfter prüft die Stufe nach der Aktion.

scenarios/lore.json
    {
      "action": "check_lore",
      "parameters": { "roll": 6 },
      "expectedWrites": [
        { "op": "ledger.set", "key": "last_target", "value": 40 },
        { "op": "ledger.set", "key": "last_roll", "value": 6 }
      ],
      "expectedValuesAfter": { "last_band": "Flawless" }
    },
  1. Zeile 17 Die Zahl, die der Spieler eingetippt hat.
  2. Zeilen 18-21 Die zwei Schreibvorgänge, der Reihe nach.
  3. Zeile 22 Die abgeleitete Stufe nach der Aktion.

Der letzte Schritt ist ein Wurf von 40,5. Er schreibt nichts, also ist die Schutzbedingung für Dezimalstellen bewiesen. Ein Wurf von 500 kann kein Schritt sein: Er liegt außerhalb der Grenzen der Eingabe, und das Szenario wird abgelehnt.

scenarios/lore.json
    {
      "action": "check_lore",
      "parameters": { "roll": 40.5 },
      "expectedWrites": [],
      "expectedValuesAfter": { "last_band": "Miss" }
    }
  1. Zeile 53 Eine Zahl mit Dezimalstellen.
  2. Zeile 54 Keine Schreibvorgänge.
  3. Zeile 55 Die Stufe bleibt so, wie der frühere Schritt sie hinterlassen hat.

Liste die Szenario-Datei im Manifest auf. Füge die neuen Felder zu den erwarteten Werten der anderen Szenarien hinzu.

manifest/project.json
{
  "formatVersion": "fabled.game-project/v1",
  "projectId": "game-your-game-id",
  "projectKind": "GAME",
  "compilerProfile": "native-game-v1",
  "name": "Lantern Keepers",
  "entryFramework": "keeper",
  "frameworks": ["schemas/keeper.json"],
  "scenarios": [
    "scenarios/new-keeper.json",
    "scenarios/heal.json",
    "scenarios/lore.json"
  ]
}
  1. Zeile 12 Die neue Szenario-Datei.

Weiter