diff --git a/Taskfile.yml b/Taskfile.yml index 2a7949e..b32e9e6 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -32,7 +32,11 @@ tasks: --data \ -c ajv-keywords \ -c ./src/sumOf.cjs \ + -c ./src/maxSpells.cjs \ -r schemas-json/classes.json \ + -r schemas-json/languages.json \ + -r schemas-json/races.json \ + -r schemas-json/spells.json \ -s schemas-json/character.json \ -d {{.CLI_ARGS}} test: diff --git a/samples/verg.yml b/samples/verg.yml index 2277afd..16e2e0b 100644 --- a/samples/verg.yml +++ b/samples/verg.yml @@ -14,3 +14,76 @@ statistics: intelligence: 18 wisdom: 15 charisma: 11 +gender: male +age: 18 +height: 6'2" +appearance: | + Tall, skinny bloke clad in a white cloak. + Looks like he could use some hot cocoa. +alignment: Neutral +experience: + total: 17660 + log: + - date: '2020-11-05' + amount: 2500 + - date: '2020-12-10' + amount: 500 + - date: '2021-01-21' + amount: 1500 + - date: '2021-03-18' + amount: 600 + - date: '2021-04-29' + amount: 1000 + - date: '2021-05-13' + amount: 400 + - date: '2021-06-10' + amount: 2600 + - date: '2021-08-05' + amount: 1000 + - date: '2021-08-26' + amount: 560 + - date: '2021-09-02' + amount: 700 + - date: '2021-09-30' + amount: 1000 + - date: '2021-11-04' + amount: 3300 + - date: '2022-02-10' + amount: 1000 + - date: '2022-03-31' + amount: 1000 + +spells: + - Magic Ice Dart + - Freezing Hands + - Detect Magic + - Identify + - Ray of Enfeeblement + +gear: + - hand axe x2 + - silver dagger + - short spear + - backpack + - bandages + - blanket + - beeswax candles x3 + - chalk + - crampons + - small hammer + - ink and quill + - bull's eye lantern + - desc: lamp oil + qty: 2 + - parchment x3 + - hard leather pouch + - soft leather pouch + - silk rope + - large sack + - iron spikes x12 + - tinderbox + - wineskin (full) + - writing stick + - iron rations + - spell book + diff --git a/schemas-json/character.json b/schemas-json/character.json index f5ddad2..a0397ac 100644 --- a/schemas-json/character.json +++ b/schemas-json/character.json @@ -1,5 +1,36 @@ { "$defs" : { + "experience" : { + "properties" : { + "items" : { + "properties" : { + "amount" : { + "type" : "number" + }, + "date" : { + "type" : "string" + }, + "notes" : { + "type" : "string" + } + }, + "type" : "object" + }, + "log" : { + "type" : "array" + }, + "total" : { + "sumOf" : { + "list" : { + "$data" : "1/log" + }, + "map" : "amount" + }, + "type" : "number" + } + }, + "type" : "object" + }, "health" : { "properties" : { "current" : { @@ -41,12 +72,37 @@ "$id" : "https://hyperboria.babyl.ca/character.json", "additionalProperties" : false, "properties" : { + "age" : { + "type" : "number" + }, + "alignment" : { + "type" : "string" + }, + "appearance" : { + "type" : "string" + }, "class" : { "$ref" : "/classes.json" }, + "experience" : { + "$ref" : "#/$defs/experience" + }, + "gender" : { + "type" : "string" + }, "health" : { "$ref" : "#/$defs/health" }, + "height" : { + "type" : "string" + }, + "languages" : { + "items" : { + "$ref" : "/languages.json" + }, + "minItems" : 1, + "type" : "array" + }, "level" : { "minimum" : 1, "type" : "number" @@ -57,6 +113,23 @@ "player" : { "type" : "string" }, + "race" : { + "$ref" : "/races.json" + }, + "spells" : { + "items" : { + "$ref" : "/spells.json" + }, + "maxSpells" : { + "class" : { + "$data" : "/class" + }, + "level" : { + "$data" : "/level" + } + }, + "type" : "array" + }, "statistics" : { "allRequired" : true, "properties" : { @@ -88,7 +161,12 @@ "statistics", "class", "level", - "health" + "health", + "experience", + "age", + "height", + "appearance", + "alignment" ], "title" : "Hyperboria character sheet", "type" : "object" diff --git a/schemas-json/languages.json b/schemas-json/languages.json new file mode 100644 index 0000000..c7bbb2c --- /dev/null +++ b/schemas-json/languages.json @@ -0,0 +1,8 @@ +{ + "$id" : "https://hyperboria.babyl.ca/languages.json", + "enum" : [ + "Common", + "Thracian" + ], + "title" : "Languages spoken in Hyperboria" +} diff --git a/schemas-json/races.json b/schemas-json/races.json new file mode 100644 index 0000000..489c30f --- /dev/null +++ b/schemas-json/races.json @@ -0,0 +1,7 @@ +{ + "$id" : "https://hyperboria.babyl.ca/races.json", + "enum" : [ + "Viking" + ], + "title" : "Character races" +} diff --git a/schemas-json/spells.json b/schemas-json/spells.json new file mode 100644 index 0000000..2f57e31 --- /dev/null +++ b/schemas-json/spells.json @@ -0,0 +1,11 @@ +{ + "$id" : "https://hyperboria.babyl.ca/spells.json", + "enum" : [ + "Magic Ice Dart", + "Freezing Hands", + "Detect Magic", + "Identify", + "Ray of Enfeeblement" + ], + "title" : "List of known spells" +} diff --git a/schemas-yaml/character.yml b/schemas-yaml/character.yml index 92e268e..242c98a 100644 --- a/schemas-yaml/character.yml +++ b/schemas-yaml/character.yml @@ -1,33 +1,76 @@ $id: https://hyperboria.babyl.ca/character.json title: Hyperboria character sheet -type: object additionalProperties: false +type: object required: - - name - - player - - statistics - - class - - level - - health + - name + - player + - statistics + - class + - level + - health + - experience + - age + - height + - appearance + - alignment properties: - name: &string - type: string - player: *string - class: { $ref: "/classes.json" } - statistics: - type: object - allRequired: true - properties: - strength: &stat - $ref: "#/$defs/statistic" - dexterity: *stat - constitution: *stat - intelligence: *stat - wisdom: *stat - charisma: *stat - level: { type: number, minimum: 1 } - health: { $ref: "#/$defs/health" } + name: &string + type: string + player: *string + class: { $ref: "/classes.json" } + statistics: + type: object + allRequired: true + properties: + strength: &stat + $ref: "#/$defs/statistic" + dexterity: *stat + constitution: *stat + intelligence: *stat + wisdom: *stat + charisma: *stat + level: { type: number, minimum: 1 } + health: { $ref: "#/$defs/health" } + experience: { $ref: '#/$defs/experience' } + gender: *string + age: &number + type: number + height: *string + appearance: *string + alignment: *string + race: { $ref: /races.json } + languages: + type: array + minItems: 1 + items: + $ref: /languages.json + spells: + type: array + items: { $ref: /spells.json } + maxSpells: + class: { $data: /class } + level: { $data: /level } + gear: { $ref: '#/$defs/gear' } + $defs: + gear: + type: array + items: + oneOf: + - *string + - type: object + properties: + desc: + type: string + description: description of the equipment + qty: + type: number + description: quantity of the item in the character's possession + required: [ desc ] + additionalProperties: false + examples: + - { desc: 'lamp oil', qty: 2 } statistic: type: number minimum: 1 @@ -43,6 +86,22 @@ $defs: log: type: array description: history of health rolls - items: { type: number } + items: &number { type: number } minItems: { $data: /level } maxItems: { $data: /level } + experience: + type: object + properties: + total: + type: number + sumOf: + list: { $data: '1/log' } + map: amount + log: + type: array + items: + type: object + properties: + date: *string + amount: *number + notes: *string diff --git a/schemas-yaml/languages.yml b/schemas-yaml/languages.yml new file mode 100644 index 0000000..75c0c39 --- /dev/null +++ b/schemas-yaml/languages.yml @@ -0,0 +1,6 @@ +--- +$id: https://hyperboria.babyl.ca/languages.json +title: Languages spoken in Hyperboria +enum: + - Common + - Thracian diff --git a/schemas-yaml/races.yml b/schemas-yaml/races.yml new file mode 100644 index 0000000..59ed374 --- /dev/null +++ b/schemas-yaml/races.yml @@ -0,0 +1,5 @@ +--- +$id: https://hyperboria.babyl.ca/races.json +title: Character races +enum: + - Viking diff --git a/schemas-yaml/spells.yml b/schemas-yaml/spells.yml new file mode 100644 index 0000000..5d82713 --- /dev/null +++ b/schemas-yaml/spells.yml @@ -0,0 +1,9 @@ +--- +$id: https://hyperboria.babyl.ca/spells.json +title: List of known spells +enum: + - Magic Ice Dart + - Freezing Hands + - Detect Magic + - Identify + - Ray of Enfeeblement diff --git a/src/maxSpells.cjs b/src/maxSpells.cjs new file mode 100644 index 0000000..819b998 --- /dev/null +++ b/src/maxSpells.cjs @@ -0,0 +1,30 @@ +const _ = require("lodash"); +const resolvePointer = require('./resolvePointer.cjs'); + +module.exports = (ajv) => + ajv.addKeyword({ + keyword: "maxSpells", + validate: function validate( + schema, + data, + _parent, + { rootData, instancePath } + ) { + if (schema.class.$data) { + schema.class = resolvePointer(rootData, instancePath, schema.class.$data); + } + + if( schema.class !== 'magician' && schema.class?.generic !== 'magician' && data.length ) { + validate.errors = [ + { + message: "non-magician can't have spells", + }, + ]; + return false; + } + + return true; + }, + $data: true, + errors: true, + }); diff --git a/src/resolvePointer.cjs b/src/resolvePointer.cjs new file mode 100644 index 0000000..84e263f --- /dev/null +++ b/src/resolvePointer.cjs @@ -0,0 +1,13 @@ +const ptr = require("json-pointer"); + +module.exports = function resolvePointer(data, rootPath, relativePath) { + if (relativePath[0] === "/") return ptr.get(data, relativePath); + + const m = relativePath.match(/^(\d+)(.*)/); + relativePath = m[2]; + for (let i = 0; i < parseInt(m[1]); i++) { + rootPath = rootPath.replace(/\/[^\/]+$/, ""); + } + + return ptr.get(data, rootPath + relativePath); +} diff --git a/src/sumOf.cjs b/src/sumOf.cjs index 2605de0..1b0a706 100644 --- a/src/sumOf.cjs +++ b/src/sumOf.cjs @@ -1,17 +1,6 @@ const _ = require("lodash"); -const ptr = require("json-pointer"); -function resolvePointer(data, rootPath, relativePath) { - if (relativePath[0] === "/") return ptr.get(data, relativePath); - - const m = relativePath.match(/^(\d+)(.*)/); - relativePath = m[2]; - for (let i = 0; i < parseInt(m[1]); i++) { - rootPath = rootPath.replace(/\/[^\/]+$/, ""); - } - - return ptr.get(data, rootPath + relativePath); -} +const resolvePointer = require('./resolvePointer.cjs'); module.exports = (ajv) => ajv.addKeyword({ @@ -26,7 +15,7 @@ module.exports = (ajv) => list = resolvePointer(rootData, instancePath, list.$data); } - if (map) data = _.map(data, map); + if (map) list = _.map(list, map); if (_.sum(list) === total) return true;