Back to Black Site
SOURCE / PINNED RELEASE

Made of little things.

Black Site

Release
666bc7c74ebd…
Author-recorded commit
05e95af79676…
License
LICENSE
Author’s source reference
nostr://npub12lm3rxsva8kfempyjkxupt09e02n3fezurkyadyqfejdc5e0r2kscqty6r/wss%3A%2F%2Fgit.napplet.soy%2F/n-d2225ddc391

Archive hash verified: 1544e072e245c4a8…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

spec/schemas/black-site-campaign.schema.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://black-site.napplet/spec/schemas/black-site-campaign.v1.json",
  "title": "Black Site campaign",
  "description": "A Black Site campaign, version 1: an ordered list of maps played back to back, with optional rules. It is published as the content of a kind 35859 event, and the event's d tag is its id. See spec/campaign-format.md.",
  "type": "object",
  "additionalProperties": false,
  "required": ["version", "name", "stages"],
  "properties": {
    "version": { "const": 1 },
    "name": { "description": "Display name.", "type": "string", "minLength": 1, "maxLength": 32 },
    "desc": { "description": "One-line description shown in the campaign list.", "type": "string", "maxLength": 200 },
    "rules": { "$ref": "#/$defs/rules" },
    "stages": {
      "description": "Maps in play order.",
      "type": "array",
      "minItems": 1,
      "maxItems": 50,
      "items": { "$ref": "#/$defs/stage" }
    }
  },
  "$defs": {
    "hex64": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
    "rules": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "completionBonus": { "description": "Paid on top of the funds hold when the last map is cleared, before the difficulty money multiplier.", "type": "integer", "minimum": 0, "maximum": 1000000, "default": 3000 },
        "quitPenalty": { "description": "Taken from the hold when a player quits a map partway through.", "type": "integer", "minimum": 0, "maximum": 100000, "default": 400 },
        "difficulty": { "description": "Lock the campaign to one difficulty. Without it, the player picks the difficulty when starting.", "enum": ["easy", "normal", "hard"] },
        "carryInventory": { "description": "Weapons and items carry over from one map to the next. When false, every map starts with the player's loadout.", "type": "boolean", "default": true },
        "restoreHealth": { "description": "Health and armour are restored between maps.", "type": "boolean", "default": true }
      }
    },
    "stage": {
      "description": "One map in the campaign: either a built-in map, or a published map pinned to an exact version.",
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["builtin"],
          "properties": {
            "builtin": { "description": "Id of a map that ships with the game.", "enum": ["town", "docks", "desert", "snow", "refinery"] },
            "briefing": { "$ref": "#/$defs/briefing" }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["address", "x"],
          "properties": {
            "address": { "description": "Map event address: 35858:<author pubkey hex>:<map id>.", "type": "string", "pattern": "^35858:[0-9a-f]{64}:[a-z0-9][a-z0-9-]{0,31}$" },
            "x": { "description": "SHA-256 of the map JSON this campaign was built with (the map event's x tag at the time). It pins the stage to that exact version.", "$ref": "#/$defs/hex64" },
            "relays": { "description": "Relays where the map event can be found.", "type": "array", "maxItems": 5, "items": { "type": "string", "pattern": "^wss://" } },
            "briefing": { "$ref": "#/$defs/briefing" }
          }
        }
      ]
    },
    "briefing": { "description": "Shown before the map starts, as plain text.", "type": "string", "maxLength": 500 }
  }
}