From 6b85bff94b09e51affe519276e415e9144843333 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 21:30:49 +0000 Subject: [PATCH 1/2] feat: add Shadowdark Quickstart Set data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds full weapon, armor, spell, class, and ancestry data sourced from the Shadowdark RPG Quickstart Set (free content, © 2023 The Arcane Library, LLC). - 14 weapons (club, crossbow, greataxe, greatsword, handaxe, javelin, longbow, longsword, mace, shortbow, shortsword, spear, staff, warhammer) - 4 armor pieces (leather armor, chainmail, plate mail, shield) - 16 spells: 12 wizard tier 1 + 6 priest tier 1 (light and protection from evil shared across both classes) - 4 classes: Fighter, Priest, Thief, Wizard - 4 ancestries: Human, Elf, Dwarf, Halfling - 4 new schemas: armor, spell, class, ancestry - Bumped codex version to 0.1.0 https://claude.ai/code/session_01FzundV4gavWqjzNucHL8cy --- codex.json | 2 +- data/ancestry/dwarf.json | 7 ++++ data/ancestry/elf.json | 7 ++++ data/ancestry/halfling.json | 7 ++++ data/ancestry/human.json | 7 ++++ data/armor/chainmail.json | 12 +++++++ data/armor/leather-armor.json | 10 ++++++ data/armor/plate-mail.json | 12 +++++++ data/armor/shield.json | 10 ++++++ data/class/fighter.json | 11 ++++++ data/class/priest.json | 11 ++++++ data/class/thief.json | 11 ++++++ data/class/wizard.json | 11 ++++++ data/spell/alarm.json | 10 ++++++ data/spell/burning-hands.json | 10 ++++++ data/spell/charm-person.json | 10 ++++++ data/spell/cure-wounds.json | 10 ++++++ data/spell/detect-magic.json | 10 ++++++ data/spell/feather-fall.json | 10 ++++++ data/spell/floating-disk.json | 10 ++++++ data/spell/hold-portal.json | 10 ++++++ data/spell/holy-weapon.json | 10 ++++++ data/spell/light.json | 10 ++++++ data/spell/mage-armor.json | 10 ++++++ data/spell/magic-missile.json | 10 ++++++ data/spell/protection-from-evil.json | 10 ++++++ data/spell/shield-of-faith.json | 10 ++++++ data/spell/sleep.json | 10 ++++++ data/spell/turn-undead.json | 10 ++++++ data/weapon/bastard-sword.json | 3 +- data/weapon/club.json | 14 ++++++++ data/weapon/crossbow.json | 17 +++++++++ data/weapon/dagger.json | 3 +- data/weapon/greataxe.json | 16 +++++++++ data/weapon/greatsword.json | 16 +++++++++ data/weapon/handaxe.json | 14 ++++++++ data/weapon/javelin.json | 17 +++++++++ data/weapon/longbow.json | 16 +++++++++ data/weapon/longsword.json | 14 ++++++++ data/weapon/mace.json | 14 ++++++++ data/weapon/shortbow.json | 16 +++++++++ data/weapon/shortsword.json | 14 ++++++++ data/weapon/spear.json | 17 +++++++++ data/weapon/staff.json | 16 +++++++++ data/weapon/warhammer.json | 16 +++++++++ schema/ancestry.json | 29 ++++++++++++++++ schema/armor.json | 33 ++++++++++++++++++ schema/class.json | 52 ++++++++++++++++++++++++++++ schema/spell.json | 47 +++++++++++++++++++++++++ 49 files changed, 659 insertions(+), 3 deletions(-) create mode 100644 data/ancestry/dwarf.json create mode 100644 data/ancestry/elf.json create mode 100644 data/ancestry/halfling.json create mode 100644 data/ancestry/human.json create mode 100644 data/armor/chainmail.json create mode 100644 data/armor/leather-armor.json create mode 100644 data/armor/plate-mail.json create mode 100644 data/armor/shield.json create mode 100644 data/class/fighter.json create mode 100644 data/class/priest.json create mode 100644 data/class/thief.json create mode 100644 data/class/wizard.json create mode 100644 data/spell/alarm.json create mode 100644 data/spell/burning-hands.json create mode 100644 data/spell/charm-person.json create mode 100644 data/spell/cure-wounds.json create mode 100644 data/spell/detect-magic.json create mode 100644 data/spell/feather-fall.json create mode 100644 data/spell/floating-disk.json create mode 100644 data/spell/hold-portal.json create mode 100644 data/spell/holy-weapon.json create mode 100644 data/spell/light.json create mode 100644 data/spell/mage-armor.json create mode 100644 data/spell/magic-missile.json create mode 100644 data/spell/protection-from-evil.json create mode 100644 data/spell/shield-of-faith.json create mode 100644 data/spell/sleep.json create mode 100644 data/spell/turn-undead.json create mode 100644 data/weapon/club.json create mode 100644 data/weapon/crossbow.json create mode 100644 data/weapon/greataxe.json create mode 100644 data/weapon/greatsword.json create mode 100644 data/weapon/handaxe.json create mode 100644 data/weapon/javelin.json create mode 100644 data/weapon/longbow.json create mode 100644 data/weapon/longsword.json create mode 100644 data/weapon/mace.json create mode 100644 data/weapon/shortbow.json create mode 100644 data/weapon/shortsword.json create mode 100644 data/weapon/spear.json create mode 100644 data/weapon/staff.json create mode 100644 data/weapon/warhammer.json create mode 100644 schema/ancestry.json create mode 100644 schema/armor.json create mode 100644 schema/class.json create mode 100644 schema/spell.json diff --git a/codex.json b/codex.json index adfd97c..ef6c646 100644 --- a/codex.json +++ b/codex.json @@ -3,6 +3,6 @@ "name": "Shadowdark", "icon": "icon.svg", "short_name": "shadowdark", - "version": "0.0.1", + "version": "0.1.0", "description": "Shadowdark RPG is fast, familiar, intuitive, and deadly. It's built for sword-and-sorcery adventures where fell monsters slither in darkness and ancient gems glint upon forgotten thrones, waiting to be discovered. In Shadowdark RPG, real time comes into play." } \ No newline at end of file diff --git a/data/ancestry/dwarf.json b/data/ancestry/dwarf.json new file mode 100644 index 0000000..98d419f --- /dev/null +++ b/data/ancestry/dwarf.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../schema/ancestry.json", + "name": "Dwarf", + "ability": "Stout. Roll your HD with advantage when recovering HP.", + "languages": ["Common", "Dwarvish"], + "source": "data/source/quickstart-set.json" +} diff --git a/data/ancestry/elf.json b/data/ancestry/elf.json new file mode 100644 index 0000000..d62c46f --- /dev/null +++ b/data/ancestry/elf.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../schema/ancestry.json", + "name": "Elf", + "ability": "Farsight. You get a +1 bonus to attack rolls with ranged weapons or a +1 bonus to spellcasting checks.", + "languages": ["Common", "Elvish", "Sylvan"], + "source": "data/source/quickstart-set.json" +} diff --git a/data/ancestry/halfling.json b/data/ancestry/halfling.json new file mode 100644 index 0000000..ea67244 --- /dev/null +++ b/data/ancestry/halfling.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../schema/ancestry.json", + "name": "Halfling", + "ability": "Stealthy. Once per day, you can become invisible for 3 rounds.", + "languages": ["Common"], + "source": "data/source/quickstart-set.json" +} diff --git a/data/ancestry/human.json b/data/ancestry/human.json new file mode 100644 index 0000000..30fe83d --- /dev/null +++ b/data/ancestry/human.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../schema/ancestry.json", + "name": "Human", + "ability": "Ambitious. You gain one additional talent roll at 1st level.", + "languages": ["Common"], + "source": "data/source/quickstart-set.json" +} diff --git a/data/armor/chainmail.json b/data/armor/chainmail.json new file mode 100644 index 0000000..c31d79b --- /dev/null +++ b/data/armor/chainmail.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schema/armor.json", + "name": "Chainmail", + "cost": { + "gp": 60 + }, + "slots": 2, + "ac": "13+DEX", + "stealth_penalty": true, + "swim_penalty": true, + "source": "data/source/quickstart-set.json" +} diff --git a/data/armor/leather-armor.json b/data/armor/leather-armor.json new file mode 100644 index 0000000..8c41e9b --- /dev/null +++ b/data/armor/leather-armor.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/armor.json", + "name": "Leather Armor", + "cost": { + "gp": 10 + }, + "slots": 1, + "ac": "11+DEX", + "source": "data/source/quickstart-set.json" +} diff --git a/data/armor/plate-mail.json b/data/armor/plate-mail.json new file mode 100644 index 0000000..d301881 --- /dev/null +++ b/data/armor/plate-mail.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schema/armor.json", + "name": "Plate Mail", + "cost": { + "gp": 130 + }, + "slots": 3, + "ac": "15", + "stealth_penalty": true, + "swim_penalty": true, + "source": "data/source/quickstart-set.json" +} diff --git a/data/armor/shield.json b/data/armor/shield.json new file mode 100644 index 0000000..46ae25a --- /dev/null +++ b/data/armor/shield.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/armor.json", + "name": "Shield", + "cost": { + "gp": 10 + }, + "slots": 1, + "ac_bonus": 2, + "source": "data/source/quickstart-set.json" +} diff --git a/data/class/fighter.json b/data/class/fighter.json new file mode 100644 index 0000000..9c9cc8f --- /dev/null +++ b/data/class/fighter.json @@ -0,0 +1,11 @@ +{ + "$schema": "../../schema/class.json", + "name": "Fighter", + "hp_die": "1d8", + "weapons": ["All"], + "armor": ["All", "Shields"], + "languages": ["Common"], + "spells": false, + "description": "Fighters are masters of the blade, bow, and shield. They can use all weapons and armor. Once per day, a fighter may reroll one melee or ranged attack. They take the better result.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/class/priest.json b/data/class/priest.json new file mode 100644 index 0000000..794c7cb --- /dev/null +++ b/data/class/priest.json @@ -0,0 +1,11 @@ +{ + "$schema": "../../schema/class.json", + "name": "Priest", + "hp_die": "1d6", + "weapons": ["Club", "Crossbow", "Dagger", "Mace", "Longsword", "Staff", "Warhammer"], + "armor": ["All", "Shields"], + "languages": ["Common"], + "spells": true, + "description": "Priests are holy warriors who can call upon their deity for divine magic. They can cast spells and must make a spellcasting check to do so. On a failure, the spell does not take effect and is not lost. Priests use WIS as their spellcasting ability.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/class/thief.json b/data/class/thief.json new file mode 100644 index 0000000..d8c1b0f --- /dev/null +++ b/data/class/thief.json @@ -0,0 +1,11 @@ +{ + "$schema": "../../schema/class.json", + "name": "Thief", + "hp_die": "1d4", + "weapons": ["Club", "Crossbow", "Dagger", "Shortbow", "Shortsword"], + "armor": ["Leather"], + "languages": ["Common", "Thieves' Cant"], + "spells": false, + "description": "Thieves are nimble rogues who rely on cunning over brawn. They can backstab enemies for extra damage and have several roguish abilities. When a thief hits an enemy who is unaware or flanked, they deal an extra 1d6 damage (increases at higher levels).", + "source": "data/source/quickstart-set.json" +} diff --git a/data/class/wizard.json b/data/class/wizard.json new file mode 100644 index 0000000..57e220c --- /dev/null +++ b/data/class/wizard.json @@ -0,0 +1,11 @@ +{ + "$schema": "../../schema/class.json", + "name": "Wizard", + "hp_die": "1d4", + "weapons": ["Dagger", "Staff"], + "armor": [], + "languages": ["Common"], + "spells": true, + "description": "Wizards are arcane scholars who bend reality through force of intellect. They can cast spells and must make a spellcasting check to do so. On a failure, the spell does not take effect and is not lost. Wizards use INT as their spellcasting ability. They can learn spells from scrolls and spellbooks.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/alarm.json b/data/spell/alarm.json new file mode 100644 index 0000000..163631b --- /dev/null +++ b/data/spell/alarm.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Alarm", + "tier": 1, + "class": ["wizard"], + "duration": "1 day", + "range": "Close", + "description": "You touch one object, such as a door threshold, setting a magical alarm on it. If any creature you do not designate while casting the spell touches or crosses past the object, a magical bell sounds in your head.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/burning-hands.json b/data/spell/burning-hands.json new file mode 100644 index 0000000..e09211e --- /dev/null +++ b/data/spell/burning-hands.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Burning Hands", + "tier": 1, + "class": ["wizard"], + "duration": "Instant", + "range": "Close", + "description": "You spread your fingers with thumbs touching, unleashing a circle of flame that fills a close area around where you stand. Creatures within the area of effect take 1d6 damage. Unattended flammable objects ignite.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/charm-person.json b/data/spell/charm-person.json new file mode 100644 index 0000000..30b4204 --- /dev/null +++ b/data/spell/charm-person.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Charm Person", + "tier": 1, + "class": ["wizard"], + "duration": "1d8 days", + "range": "Near", + "description": "You magically beguile one humanoid of level 2 or less within near range, who regards you as a friend for the duration. The spell ends if you or your allies do anything to hurt it that it notices. The target knows you magically enchanted it after the spell ends.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/cure-wounds.json b/data/spell/cure-wounds.json new file mode 100644 index 0000000..6048db3 --- /dev/null +++ b/data/spell/cure-wounds.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Cure Wounds", + "tier": 1, + "class": ["priest"], + "duration": "Instant", + "range": "Close", + "description": "Your touch restores ebbing life. The target regains 1d6 HP.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/detect-magic.json b/data/spell/detect-magic.json new file mode 100644 index 0000000..59fa237 --- /dev/null +++ b/data/spell/detect-magic.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Detect Magic", + "tier": 1, + "class": ["wizard"], + "duration": "Focus", + "range": "Near", + "description": "You can sense the presence of magic within near range for the spell's duration. If you focus for two rounds, you discern its general properties. Full barriers block this spell.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/feather-fall.json b/data/spell/feather-fall.json new file mode 100644 index 0000000..f67e753 --- /dev/null +++ b/data/spell/feather-fall.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Feather Fall", + "tier": 1, + "class": ["wizard"], + "duration": "Instant", + "range": "Near", + "description": "You may cast this spell when you or a nearby creature starts to fall. The target's rate of descent slows so they land safely on their feet.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/floating-disk.json b/data/spell/floating-disk.json new file mode 100644 index 0000000..9b33f85 --- /dev/null +++ b/data/spell/floating-disk.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Floating Disk", + "tier": 1, + "class": ["wizard"], + "duration": "10 rounds", + "range": "Near", + "description": "You create a floating, circular disk of force with a concave center. It can carry up to 20 gear slots. It hovers at waist level and automatically stays within near of you. It can't cross over drop-offs or pits taller than a human.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/hold-portal.json b/data/spell/hold-portal.json new file mode 100644 index 0000000..13dfb1d --- /dev/null +++ b/data/spell/hold-portal.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Hold Portal", + "tier": 1, + "class": ["wizard"], + "duration": "10 rounds", + "range": "Near", + "description": "You magically hold a portal closed for the duration. A creature must make a successful STR check vs. your spellcasting check to open the portal. The knock spell ends this spell.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/holy-weapon.json b/data/spell/holy-weapon.json new file mode 100644 index 0000000..2c9d1f0 --- /dev/null +++ b/data/spell/holy-weapon.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Holy Weapon", + "tier": 1, + "class": ["priest"], + "duration": "5 rounds", + "range": "Close", + "description": "One weapon you touch is imbued with a sacred blessing. The weapon becomes magical and has +1 to attack and damage rolls for the duration.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/light.json b/data/spell/light.json new file mode 100644 index 0000000..6315bb7 --- /dev/null +++ b/data/spell/light.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Light", + "tier": 1, + "class": ["priest", "wizard"], + "duration": "1 hour", + "range": "Near", + "description": "You touch one object no larger than a human. It sheds light equivalent to a torch for the duration.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/mage-armor.json b/data/spell/mage-armor.json new file mode 100644 index 0000000..5c1e7b8 --- /dev/null +++ b/data/spell/mage-armor.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Mage Armor", + "tier": 1, + "class": ["wizard"], + "duration": "10 rounds", + "range": "Near", + "description": "An invisible layer of magical force protects your vitals. Your armor class becomes 14 (18 on a critical spellcasting check) for the spell's duration.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/magic-missile.json b/data/spell/magic-missile.json new file mode 100644 index 0000000..84f728e --- /dev/null +++ b/data/spell/magic-missile.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Magic Missile", + "tier": 1, + "class": ["wizard"], + "duration": "Instant", + "range": "Far", + "description": "You have advantage on your check to cast this spell. A glowing bolt of force streaks from your open hand, dealing 1d4 damage to one target.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/protection-from-evil.json b/data/spell/protection-from-evil.json new file mode 100644 index 0000000..ca5ca42 --- /dev/null +++ b/data/spell/protection-from-evil.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Protection from Evil", + "tier": 1, + "class": ["priest", "wizard"], + "duration": "Focus", + "range": "Close", + "description": "For the spell's duration, chaotic beings have disadvantage on attack rolls and hostile spellcasting checks against the target. These beings also can't possess, compel, or beguile it. When cast on an already-possessed target, the possessing entity makes a CHA check vs. the last spellcasting check. On a failure, the entity is expelled.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/shield-of-faith.json b/data/spell/shield-of-faith.json new file mode 100644 index 0000000..0acee17 --- /dev/null +++ b/data/spell/shield-of-faith.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Shield of Faith", + "tier": 1, + "class": ["priest"], + "duration": "5 rounds", + "range": "Near", + "description": "A protective force wrought of holy conviction surrounds a creature you designate. The target gains a +2 bonus to their armor class for the duration.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/sleep.json b/data/spell/sleep.json new file mode 100644 index 0000000..e314b8a --- /dev/null +++ b/data/spell/sleep.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Sleep", + "tier": 1, + "class": ["wizard"], + "duration": "Instant", + "range": "Near", + "description": "You weave a lulling spell that fills a near-sized cube extending from you. Living creatures in the area of effect fall into a deep sleep if they are level 2 or less. Vigorous shaking or being injured wakes them.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/spell/turn-undead.json b/data/spell/turn-undead.json new file mode 100644 index 0000000..d84bbc1 --- /dev/null +++ b/data/spell/turn-undead.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../schema/spell.json", + "name": "Turn Undead", + "tier": 1, + "class": ["priest"], + "duration": "Instant", + "range": "Near", + "description": "You rebuke undead creatures, forcing them to flee. You must present a holy symbol to cast this spell. Undead creatures within near of you must make a CHA check opposed by your spellcasting check. If a creature fails by 10+ points and is equal to or less than your level, it is destroyed. Otherwise, on a fail, it flees from you for 5 rounds.", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/bastard-sword.json b/data/weapon/bastard-sword.json index 091556a..d5efc7f 100644 --- a/data/weapon/bastard-sword.json +++ b/data/weapon/bastard-sword.json @@ -12,5 +12,6 @@ "Close" ], "damage": "1d8", - "damage_alt": "1d10" + "damage_alt": "1d10", + "source": "data/source/quickstart-set.json" } \ No newline at end of file diff --git a/data/weapon/club.json b/data/weapon/club.json new file mode 100644 index 0000000..5f92810 --- /dev/null +++ b/data/weapon/club.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Club", + "cost": { + "cp": 5 + }, + "slots": 1, + "attributes": [], + "range": [ + "Close" + ], + "damage": "1d4", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/crossbow.json b/data/weapon/crossbow.json new file mode 100644 index 0000000..ddca3e2 --- /dev/null +++ b/data/weapon/crossbow.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Crossbow", + "cost": { + "gp": 8 + }, + "slots": 2, + "attributes": [ + "TwoHanded", + "Loading" + ], + "range": [ + "Far" + ], + "damage": "1d6", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/dagger.json b/data/weapon/dagger.json index 3e966b5..755b3f7 100644 --- a/data/weapon/dagger.json +++ b/data/weapon/dagger.json @@ -13,5 +13,6 @@ "Close", "Far" ], - "damage": "1d4" + "damage": "1d4", + "source": "data/source/quickstart-set.json" } \ No newline at end of file diff --git a/data/weapon/greataxe.json b/data/weapon/greataxe.json new file mode 100644 index 0000000..b378975 --- /dev/null +++ b/data/weapon/greataxe.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Greataxe", + "cost": { + "gp": 10 + }, + "slots": 2, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Close" + ], + "damage": "1d10", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/greatsword.json b/data/weapon/greatsword.json new file mode 100644 index 0000000..928be9b --- /dev/null +++ b/data/weapon/greatsword.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Greatsword", + "cost": { + "gp": 12 + }, + "slots": 2, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Close" + ], + "damage": "1d12", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/handaxe.json b/data/weapon/handaxe.json new file mode 100644 index 0000000..4997644 --- /dev/null +++ b/data/weapon/handaxe.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Handaxe", + "cost": { + "gp": 4 + }, + "slots": 1, + "attributes": [], + "range": [ + "Close" + ], + "damage": "1d6", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/javelin.json b/data/weapon/javelin.json new file mode 100644 index 0000000..302e216 --- /dev/null +++ b/data/weapon/javelin.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Javelin", + "cost": { + "sp": 5 + }, + "slots": 1, + "attributes": [ + "Thrown" + ], + "range": [ + "Close", + "Far" + ], + "damage": "1d4", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/longbow.json b/data/weapon/longbow.json new file mode 100644 index 0000000..1a35e31 --- /dev/null +++ b/data/weapon/longbow.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Longbow", + "cost": { + "gp": 8 + }, + "slots": 2, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Far" + ], + "damage": "1d8", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/longsword.json b/data/weapon/longsword.json new file mode 100644 index 0000000..463e212 --- /dev/null +++ b/data/weapon/longsword.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Longsword", + "cost": { + "gp": 9 + }, + "slots": 2, + "attributes": [], + "range": [ + "Close" + ], + "damage": "1d8", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/mace.json b/data/weapon/mace.json new file mode 100644 index 0000000..5369947 --- /dev/null +++ b/data/weapon/mace.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Mace", + "cost": { + "gp": 5 + }, + "slots": 2, + "attributes": [], + "range": [ + "Close" + ], + "damage": "1d6", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/shortbow.json b/data/weapon/shortbow.json new file mode 100644 index 0000000..48df301 --- /dev/null +++ b/data/weapon/shortbow.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Shortbow", + "cost": { + "gp": 6 + }, + "slots": 1, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Far" + ], + "damage": "1d4", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/shortsword.json b/data/weapon/shortsword.json new file mode 100644 index 0000000..546f930 --- /dev/null +++ b/data/weapon/shortsword.json @@ -0,0 +1,14 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Shortsword", + "cost": { + "gp": 7 + }, + "slots": 1, + "attributes": [], + "range": [ + "Close" + ], + "damage": "1d6", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/spear.json b/data/weapon/spear.json new file mode 100644 index 0000000..5551376 --- /dev/null +++ b/data/weapon/spear.json @@ -0,0 +1,17 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Spear", + "cost": { + "sp": 5 + }, + "slots": 1, + "attributes": [ + "Thrown" + ], + "range": [ + "Close", + "Near" + ], + "damage": "1d6", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/staff.json b/data/weapon/staff.json new file mode 100644 index 0000000..35d8589 --- /dev/null +++ b/data/weapon/staff.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Staff", + "cost": { + "sp": 5 + }, + "slots": 2, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Close" + ], + "damage": "1d4", + "source": "data/source/quickstart-set.json" +} diff --git a/data/weapon/warhammer.json b/data/weapon/warhammer.json new file mode 100644 index 0000000..eaf199b --- /dev/null +++ b/data/weapon/warhammer.json @@ -0,0 +1,16 @@ +{ + "$schema": "../../schema/weapon.json", + "name": "Warhammer", + "cost": { + "gp": 10 + }, + "slots": 2, + "attributes": [ + "TwoHanded" + ], + "range": [ + "Close" + ], + "damage": "1d10", + "source": "data/source/quickstart-set.json" +} diff --git a/schema/ancestry.json b/schema/ancestry.json new file mode 100644 index 0000000..631aec0 --- /dev/null +++ b/schema/ancestry.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Ancestry", + "type": "object", + "required": [ + "name", + "ability" + ], + "properties": { + "name": { + "type": "string", + "description": "The ancestry name." + }, + "ability": { + "type": "string", + "description": "The ancestry's special ability description." + }, + "languages": { + "type": "array", + "description": "Languages spoken by this ancestry.", + "items": { + "type": "string" + } + }, + "source": { + "type": "string" + } + } +} diff --git a/schema/armor.json b/schema/armor.json new file mode 100644 index 0000000..b388402 --- /dev/null +++ b/schema/armor.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "allOf": [ + { + "$ref": "./item.json" + } + ], + "title": "Armor", + "type": "object", + "required": [ + "ac" + ], + "properties": { + "ac": { + "type": "string", + "description": "The armor class formula (e.g. '11+DEX', '13+DEX', '15')." + }, + "ac_bonus": { + "type": "number", + "description": "A flat AC bonus (for shields)." + }, + "stealth_penalty": { + "type": "boolean", + "description": "Whether the armor imposes a stealth penalty.", + "default": false + }, + "swim_penalty": { + "type": "boolean", + "description": "Whether the armor prevents swimming.", + "default": false + } + } +} diff --git a/schema/class.json b/schema/class.json new file mode 100644 index 0000000..57e67a7 --- /dev/null +++ b/schema/class.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Class", + "type": "object", + "required": [ + "name", + "hp_die" + ], + "properties": { + "name": { + "type": "string", + "description": "The class name." + }, + "hp_die": { + "$ref": "https://ubermanu.github.io/tabletopmancer/schema/dice.json", + "description": "The hit die used for HP." + }, + "weapons": { + "type": "array", + "description": "Weapons this class can use.", + "items": { + "type": "string" + } + }, + "armor": { + "type": "array", + "description": "Armor types this class can wear.", + "items": { + "type": "string" + } + }, + "languages": { + "type": "array", + "description": "Starting languages.", + "items": { + "type": "string" + } + }, + "spells": { + "type": "boolean", + "description": "Whether this class can cast spells.", + "default": false + }, + "description": { + "type": "string", + "description": "A description of the class." + }, + "source": { + "type": "string" + } + } +} diff --git a/schema/spell.json b/schema/spell.json new file mode 100644 index 0000000..427c7de --- /dev/null +++ b/schema/spell.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Spell", + "type": "object", + "required": [ + "name", + "tier", + "class", + "duration", + "range", + "description" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the spell." + }, + "tier": { + "type": "number", + "description": "The spell tier (1–3 in the quickstart).", + "minimum": 1 + }, + "class": { + "type": "array", + "description": "Which classes can cast this spell.", + "items": { + "type": "string", + "enum": ["priest", "wizard"] + } + }, + "duration": { + "type": "string", + "description": "How long the spell lasts (e.g. 'Instant', 'Focus', '5 rounds', '1 hour')." + }, + "range": { + "$ref": "./distance.json", + "description": "The casting range of the spell." + }, + "description": { + "type": "string", + "description": "The full spell description." + }, + "source": { + "type": "string" + } + } +} From adf1c4ff437af4848c0e5d56f091e7966156128c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 6 Jun 2026 21:42:32 +0000 Subject: [PATCH 2/2] ci: add JSON schema validation via ajv-cli - Add .github/workflows/validate.yml running npx -y ajv-cli per data category (weapons, armor, spells, classes, ancestries) on push and PR - Add schema/dice.json locally so validation works offline (was an external URL reference in weapon.json and class.json) - Add $id to coins.json, distance.json, item.json, dice.json so ajv-cli can resolve cross-schema $ref without key collisions - Fix armor.json: replace required ["ac"] with oneOf so shields (which only have ac_bonus) pass validation - Update weapon.json and class.json $ref to use local ./dice.json https://claude.ai/code/session_01FzundV4gavWqjzNucHL8cy --- .github/workflows/validate.yml | 27 +++++++++++++++++++++++++++ schema/armor.json | 5 +++-- schema/class.json | 2 +- schema/coins.json | 1 + schema/dice.json | 8 ++++++++ schema/distance.json | 1 + schema/item.json | 1 + schema/weapon.json | 4 ++-- 8 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/validate.yml create mode 100644 schema/dice.json diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..2ad145a --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,27 @@ +name: Validate JSON Schemas + +on: + push: + pull_request: + +jobs: + validate: + name: Validate JSON against schemas + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate weapons + run: npx -y ajv-cli validate -s schema/weapon.json -r schema/item.json -r schema/coins.json -r schema/distance.json -r schema/dice.json -d "data/weapon/*.json" + + - name: Validate armor + run: npx -y ajv-cli validate -s schema/armor.json -r schema/item.json -r schema/coins.json -d "data/armor/*.json" + + - name: Validate spells + run: npx -y ajv-cli validate -s schema/spell.json -r schema/distance.json -d "data/spell/*.json" + + - name: Validate classes + run: npx -y ajv-cli validate -s schema/class.json -r schema/dice.json -d "data/class/*.json" + + - name: Validate ancestries + run: npx -y ajv-cli validate -s schema/ancestry.json -d "data/ancestry/*.json" diff --git a/schema/armor.json b/schema/armor.json index b388402..7cdc6a3 100644 --- a/schema/armor.json +++ b/schema/armor.json @@ -7,8 +7,9 @@ ], "title": "Armor", "type": "object", - "required": [ - "ac" + "oneOf": [ + { "required": ["ac"] }, + { "required": ["ac_bonus"] } ], "properties": { "ac": { diff --git a/schema/class.json b/schema/class.json index 57e67a7..0bb03f9 100644 --- a/schema/class.json +++ b/schema/class.json @@ -12,7 +12,7 @@ "description": "The class name." }, "hp_die": { - "$ref": "https://ubermanu.github.io/tabletopmancer/schema/dice.json", + "$ref": "./dice.json", "description": "The hit die used for HP." }, "weapons": { diff --git a/schema/coins.json b/schema/coins.json index 82a7981..a07b78b 100644 --- a/schema/coins.json +++ b/schema/coins.json @@ -1,5 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "coins.json", "title": "Cost", "type": "object", "properties": { diff --git a/schema/dice.json b/schema/dice.json new file mode 100644 index 0000000..18003ee --- /dev/null +++ b/schema/dice.json @@ -0,0 +1,8 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "dice.json", + "title": "Dice", + "description": "A dice formula.", + "type": "string", + "pattern": "[\\d]{1,}d[\\d]{1,}" +} diff --git a/schema/distance.json b/schema/distance.json index 4c316bd..69871cb 100644 --- a/schema/distance.json +++ b/schema/distance.json @@ -1,5 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "distance.json", "title": "Distance", "type": "string", "description": "A distance can be close (C), near (N) or far (F).", diff --git a/schema/item.json b/schema/item.json index 8df2898..31887b7 100644 --- a/schema/item.json +++ b/schema/item.json @@ -1,5 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "item.json", "title": "Item", "type": "object", "required": [ diff --git a/schema/weapon.json b/schema/weapon.json index b3ca2bd..a81416f 100644 --- a/schema/weapon.json +++ b/schema/weapon.json @@ -35,11 +35,11 @@ } }, "damage": { - "$ref": "https://ubermanu.github.io/tabletopmancer/schema/dice.json", + "$ref": "./dice.json", "description": "The damage formula of the weapon." }, "damage_alt": { - "$ref": "https://ubermanu.github.io/tabletopmancer/schema/dice.json", + "$ref": "./dice.json", "description": "The alternative damage formula of the weapon." } }