{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://marcallabs.co.uk/job-schema.json",
  "title": "Dungeon Quest job",
  "description": "One job for the notice boards of Grimhold, the castle town in Dungeon Quest (Marcal Labs). The player takes it from a board, does the steps in order, then goes back to the giver to be paid. Upload as jobs/<id>.json with the puzzle checker. Rules this schema cannot express: (1) the characters < and > may not appear anywhere in the file; (2) in a carry step, from and to must be different people; (3) the file must be no bigger than 64 KB. Check files at https://marcallabs.co.uk/puzzle-checker.html.",
  "type": "object",
  "required": [
    "id",
    "title",
    "text",
    "boards",
    "giver",
    "steps",
    "reward"
  ],
  "additionalProperties": false,
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9-]{1,40}$",
      "description": "Short name in small letters, numbers and dashes; also the file name."
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 60,
      "description": "The heading of the notice."
    },
    "text": {
      "type": "string",
      "minLength": 1,
      "maxLength": 400,
      "description": "What the notice on the board says."
    },
    "boards": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "enum": [
          "square",
          "inn",
          "tavern",
          "guardhouse",
          "drowned-rat",
          "keep"
        ]
      },
      "description": "Where the job is posted."
    },
    "giver": {
      "enum": [
        "watch",
        "inn",
        "tavern",
        "temple",
        "store",
        "armourer",
        "weaponsmith",
        "alchemist",
        "wizard",
        "jeweller",
        "treasury",
        "stables",
        "gaol",
        "baker",
        "chandler",
        "ropes",
        "fortune",
        "lostprop",
        "forger",
        "locksmith",
        "luckyfind",
        "complaints",
        "drownedrat",
        "diceden",
        "ratcatcher",
        "auction",
        "fence",
        "porter",
        "steward",
        "cook",
        "chaplain",
        "captain"
      ],
      "description": "Who posted the job and pays for it."
    },
    "minLevel": {
      "type": "integer",
      "minimum": 1,
      "maximum": 20,
      "description": "Players below this level are warned. Default 1."
    },
    "repeat": {
      "type": "boolean",
      "description": "true: the job can be done again the next day."
    },
    "steps": {
      "type": "array",
      "minItems": 1,
      "maxItems": 6,
      "description": "Done in order.",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "description": "Beat a number of foes.",
            "additionalProperties": false,
            "required": [
              "type",
              "foe",
              "count",
              "text"
            ],
            "properties": {
              "type": {
                "const": "beat"
              },
              "foe": {
                "enum": [
                  "cutpurse",
                  "thug",
                  "bruiser",
                  "rat",
                  "spider",
                  "goblin",
                  "gang",
                  "any"
                ],
                "description": "gang: any cutpurse, thug or bruiser; any: anything."
              },
              "count": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10
              },
              "where": {
                "enum": [
                  "anywhere",
                  "square",
                  "lanes",
                  "cellar"
                ]
              },
              "night": {
                "type": "boolean",
                "description": "true: only fights after dark count."
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "Go to a place.",
            "additionalProperties": false,
            "required": [
              "type",
              "place",
              "text"
            ],
            "properties": {
              "type": {
                "const": "visit"
              },
              "place": {
                "enum": [
                  "watch",
                  "inn",
                  "tavern",
                  "temple",
                  "store",
                  "armourer",
                  "weaponsmith",
                  "alchemist",
                  "wizard",
                  "jeweller",
                  "treasury",
                  "stables",
                  "gaol",
                  "lostprop",
                  "forger",
                  "locksmith",
                  "luckyfind",
                  "complaints",
                  "drownedrat",
                  "diceden",
                  "ratcatcher",
                  "auction",
                  "fence",
                  "fountain",
                  "gate",
                  "noticeboard",
                  "keep",
                  "cellar",
                  "upstairs",
                  "greathall"
                ]
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "Talk to someone.",
            "additionalProperties": false,
            "required": [
              "type",
              "to",
              "say",
              "text"
            ],
            "properties": {
              "type": {
                "const": "talk"
              },
              "to": {
                "enum": [
                  "watch",
                  "inn",
                  "tavern",
                  "temple",
                  "store",
                  "armourer",
                  "weaponsmith",
                  "alchemist",
                  "wizard",
                  "jeweller",
                  "treasury",
                  "stables",
                  "gaol",
                  "baker",
                  "chandler",
                  "ropes",
                  "fortune",
                  "lostprop",
                  "forger",
                  "locksmith",
                  "luckyfind",
                  "complaints",
                  "drownedrat",
                  "diceden",
                  "ratcatcher",
                  "auction",
                  "fence",
                  "porter",
                  "steward",
                  "cook",
                  "chaplain",
                  "captain"
                ]
              },
              "say": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What they tell you."
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "Bring someone a number of things.",
            "additionalProperties": false,
            "required": [
              "type",
              "item",
              "count",
              "to",
              "text"
            ],
            "properties": {
              "type": {
                "const": "bring"
              },
              "item": {
                "enum": [
                  "rations",
                  "torches",
                  "oil",
                  "rope",
                  "sack",
                  "potion",
                  "antidote",
                  "hay",
                  "scroll",
                  "arrows",
                  "tails",
                  "lockbox",
                  "pitmap",
                  "letter"
                ]
              },
              "count": {
                "type": "integer",
                "minimum": 1,
                "maximum": 20
              },
              "to": {
                "enum": [
                  "watch",
                  "inn",
                  "tavern",
                  "temple",
                  "store",
                  "armourer",
                  "weaponsmith",
                  "alchemist",
                  "wizard",
                  "jeweller",
                  "treasury",
                  "stables",
                  "gaol",
                  "baker",
                  "chandler",
                  "ropes",
                  "fortune",
                  "lostprop",
                  "forger",
                  "locksmith",
                  "luckyfind",
                  "complaints",
                  "drownedrat",
                  "diceden",
                  "ratcatcher",
                  "auction",
                  "fence",
                  "porter",
                  "steward",
                  "cook",
                  "chaplain",
                  "captain"
                ]
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "Take something to someone.",
            "additionalProperties": false,
            "required": [
              "type",
              "item",
              "to",
              "text"
            ],
            "properties": {
              "type": {
                "const": "carry"
              },
              "item": {
                "type": "string",
                "minLength": 1,
                "maxLength": 40,
                "description": "What is carried, like 'a sealed letter'."
              },
              "from": {
                "enum": [
                  "watch",
                  "inn",
                  "tavern",
                  "temple",
                  "store",
                  "armourer",
                  "weaponsmith",
                  "alchemist",
                  "wizard",
                  "jeweller",
                  "treasury",
                  "stables",
                  "gaol",
                  "baker",
                  "chandler",
                  "ropes",
                  "fortune",
                  "lostprop",
                  "forger",
                  "locksmith",
                  "luckyfind",
                  "complaints",
                  "drownedrat",
                  "diceden",
                  "ratcatcher",
                  "auction",
                  "fence",
                  "porter",
                  "steward",
                  "cook",
                  "chaplain",
                  "captain"
                ],
                "description": "Collect it from them first. Without it, the player is given it when taking the job."
              },
              "to": {
                "enum": [
                  "watch",
                  "inn",
                  "tavern",
                  "temple",
                  "store",
                  "armourer",
                  "weaponsmith",
                  "alchemist",
                  "wizard",
                  "jeweller",
                  "treasury",
                  "stables",
                  "gaol",
                  "baker",
                  "chandler",
                  "ropes",
                  "fortune",
                  "lostprop",
                  "forger",
                  "locksmith",
                  "luckyfind",
                  "complaints",
                  "drownedrat",
                  "diceden",
                  "ratcatcher",
                  "auction",
                  "fence",
                  "porter",
                  "steward",
                  "cook",
                  "chaplain",
                  "captain"
                ]
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "Find something lying in the square, the lanes or the inn cellar.",
            "additionalProperties": false,
            "required": [
              "type",
              "item",
              "at",
              "text"
            ],
            "properties": {
              "type": {
                "const": "find"
              },
              "item": {
                "type": "string",
                "minLength": 1,
                "maxLength": 40,
                "description": "What is found."
              },
              "at": {
                "enum": [
                  "square",
                  "lanes",
                  "cellar"
                ]
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          },
          {
            "type": "object",
            "description": "A named villain to beat.",
            "additionalProperties": false,
            "required": [
              "type",
              "foe",
              "name",
              "at",
              "text"
            ],
            "properties": {
              "type": {
                "const": "fight"
              },
              "foe": {
                "enum": [
                  "cutpurse",
                  "thug",
                  "bruiser",
                  "rat",
                  "spider",
                  "goblin"
                ]
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 40,
                "description": "The villain's name."
              },
              "at": {
                "enum": [
                  "square",
                  "lanes",
                  "cellar"
                ]
              },
              "night": {
                "type": "boolean",
                "description": "true: the villain only comes out after dark."
              },
              "text": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300,
                "description": "What the player reads when this step is done."
              }
            }
          }
        ]
      }
    },
    "reward": {
      "type": "object",
      "additionalProperties": false,
      "description": "Paid by the giver when the steps are done.",
      "properties": {
        "gold": {
          "type": "integer",
          "minimum": 0,
          "maximum": 500
        },
        "xp": {
          "type": "integer",
          "minimum": 0,
          "maximum": 300
        },
        "item": {
          "enum": [
            "rations",
            "torches",
            "oil",
            "rope",
            "sack",
            "potion",
            "antidote",
            "hay",
            "scroll",
            "arrows",
            "tails",
            "lockbox",
            "pitmap",
            "letter"
          ]
        },
        "count": {
          "type": "integer",
          "minimum": 1,
          "maximum": 20,
          "description": "How many of the item; needs item."
        },
        "text": {
          "type": "string",
          "minLength": 1,
          "maxLength": 300,
          "description": "What the giver says."
        }
      }
    }
  }
}
