dndwright 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dndwright/__init__.py ADDED
@@ -0,0 +1,69 @@
1
+ """dndwright — a domain-neutral D&D 5e (2024) rules & character-computation engine.
2
+
3
+ A character sheet is modelled as a **directed acyclic computation graph**: nodes
4
+ are values, edges are dependencies, and formulas are *data* (a JSON-serialisable
5
+ DSL), not code. The engine is pure (pydantic + stdlib) — no application or
6
+ framework coupling — so any tool can map its own character data in and read
7
+ computed stats out.
8
+
9
+ Quickstart (one call — dict in, computed sheet out):
10
+
11
+ from dndwright import evaluate_character
12
+ sheet = evaluate_character({
13
+ "ability_scores": {"strength": 8, "dexterity": 14, "constitution": 14,
14
+ "intelligence": 18, "wisdom": 12, "charisma": 10},
15
+ "class_data": {"class_name": "wizard"},
16
+ "species_data": {"name": "Human", "speed": 30},
17
+ "level": 5,
18
+ })
19
+ sheet["proficiency_bonus"] # 3
20
+ sheet["ability_modifiers"] # {"intelligence": 4, ...}
21
+
22
+ Lower level (assemble typed inputs, evaluate against the ruleset):
23
+
24
+ from dndwright import (DND_5E_2024_RULESET, assemble_character_inputs,
25
+ evaluate, apply_modifiers)
26
+ from dndwright.rules.components import ClassMechanics
27
+ inputs = assemble_character_inputs(class_mechanics=..., ability_scores={...}, level=5)
28
+ computed = apply_modifiers(evaluate(DND_5E_2024_RULESET, inputs), inputs)
29
+
30
+ The rules tables (hit dice, spell slots, armour AC, save proficiencies) encode
31
+ game mechanics derived from the **D&D SRD 5.2 (CC-BY-4.0)** — see NOTICE.
32
+ """
33
+
34
+ from .content import categories, generate_library, load_content
35
+ from .ontology import Ontology, load_ontology
36
+ from .rules.adapters import character_data_to_inputs, computed_values_to_sheet
37
+ from .rules.assembler import apply_modifiers, assemble_character_inputs
38
+ from .rules.character_evaluator import compute_key_stats, evaluate_character
39
+ from .rules.dnd_5e_2024 import DND_5E_2024_RULESET
40
+ from .rules.evaluator import evaluate
41
+ from .rules.schema import ComputationNode, FormulaSpec, NodeType, Ruleset
42
+
43
+ __version__ = "0.3.0"
44
+
45
+ __all__ = [
46
+ # high-level (dict in -> computed sheet out)
47
+ "evaluate_character",
48
+ "compute_key_stats",
49
+ # ruleset + low-level evaluation
50
+ "DND_5E_2024_RULESET",
51
+ "evaluate",
52
+ "assemble_character_inputs",
53
+ "apply_modifiers",
54
+ # neutral adapters
55
+ "character_data_to_inputs",
56
+ "computed_values_to_sheet",
57
+ # schema types
58
+ "Ruleset",
59
+ "ComputationNode",
60
+ "FormulaSpec",
61
+ "NodeType",
62
+ # component ontology (graph schema)
63
+ "load_ontology",
64
+ "Ontology",
65
+ # content (bundled starter + generator)
66
+ "load_content",
67
+ "categories",
68
+ "generate_library",
69
+ ]
@@ -0,0 +1,56 @@
1
+ """Bundled starter content + a generator for original homebrew.
2
+
3
+ from dndwright.content import load_content, categories
4
+ load_content("creatures") # list of creature dicts (bundled samples)
5
+ categories() # ["classes", "creatures", "magic_items", "species"]
6
+
7
+ The bundled ``classes`` / ``species`` / ``creatures`` are original homebrew (no
8
+ official content); ``magic_items`` are SRD 5.2 (CC-BY) — see NOTICE. Grow the
9
+ library with :func:`generate_library` (you supply the LLM).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import importlib.resources
15
+ import json
16
+
17
+ from .generate import (
18
+ JsonLLM,
19
+ generate_classes,
20
+ generate_creatures,
21
+ generate_library,
22
+ generate_species,
23
+ )
24
+
25
+ # category -> (filename, top-level array key)
26
+ _CONTENT = {
27
+ "classes": ("classes.json", "classes"),
28
+ "species": ("species.json", "species"),
29
+ "creatures": ("creatures.json", "creatures"),
30
+ "magic_items": ("magic_items.json", "magic_items"),
31
+ }
32
+
33
+
34
+ def categories() -> list[str]:
35
+ """The bundled content categories."""
36
+ return sorted(_CONTENT)
37
+
38
+
39
+ def load_content(category: str) -> list[dict]:
40
+ """Load the bundled starter content for ``category`` as a list of dicts."""
41
+ if category not in _CONTENT:
42
+ raise ValueError(f"unknown category {category!r}; choose from {categories()}")
43
+ filename, key = _CONTENT[category]
44
+ text = (importlib.resources.files("dndwright.content") / filename).read_text(encoding="utf-8")
45
+ return json.loads(text).get(key, [])
46
+
47
+
48
+ __all__ = [
49
+ "load_content",
50
+ "categories",
51
+ "generate_library",
52
+ "generate_classes",
53
+ "generate_species",
54
+ "generate_creatures",
55
+ "JsonLLM",
56
+ ]
@@ -0,0 +1,147 @@
1
+ {
2
+ "metadata": {
3
+ "source": "dndwright original homebrew",
4
+ "license": "Original content — not derived from any copyrighted RPG product.",
5
+ "note": "Sample starter content; generate more with dndwright.content.generate."
6
+ },
7
+ "classes": [
8
+ {
9
+ "name": "Echo-Binder",
10
+ "mechanics": {
11
+ "hit_die": "d8",
12
+ "primary_ability": "CHA",
13
+ "saving_throws": [
14
+ "CHA",
15
+ "INT"
16
+ ],
17
+ "spellcasting_type": "full",
18
+ "key_features": [
19
+ "Resonant Tether",
20
+ "Harmonic Mimicry",
21
+ "Sonic Feedback",
22
+ "Shatter-Point Focus"
23
+ ]
24
+ },
25
+ "narrative": {
26
+ "description": "Echo-Binders capture the lingering vibrations of historical events and reality itself to weave them into offensive spells. They manipulate the soundscapes of combat to disrupt enemies and amplify their own presence.",
27
+ "role": "Controller/Support",
28
+ "flavor": "Every silence has a story, and I am the one who makes it scream."
29
+ }
30
+ },
31
+ {
32
+ "name": "Kinetics-Smith",
33
+ "mechanics": {
34
+ "hit_die": "d10",
35
+ "primary_ability": "STR",
36
+ "saving_throws": [
37
+ "STR",
38
+ "CON"
39
+ ],
40
+ "spellcasting_type": "none",
41
+ "key_features": [
42
+ "Momentum Storage",
43
+ "Inertia Plating",
44
+ "Impact Discharge",
45
+ "Velocity Strike"
46
+ ]
47
+ },
48
+ "narrative": {
49
+ "description": "These warriors wear heavy, specialized armor designed to absorb and store the kinetic energy of incoming blows. They release this stored force in devastating, explosive counter-attacks that can shatter stone.",
50
+ "role": "Frontline Tank",
51
+ "flavor": "Hit me harder; you are only fueling my next strike."
52
+ }
53
+ },
54
+ {
55
+ "name": "Vellum-Weaver",
56
+ "mechanics": {
57
+ "hit_die": "d6",
58
+ "primary_ability": "INT",
59
+ "saving_throws": [
60
+ "INT",
61
+ "WIS"
62
+ ],
63
+ "spellcasting_type": "full",
64
+ "key_features": [
65
+ "Ink-Skin Calligraphy",
66
+ "Living Manuscript",
67
+ "Paper-Slide Mobility",
68
+ "Scripted Reality"
69
+ ]
70
+ },
71
+ "narrative": {
72
+ "description": "Vellum-Weavers treat the fabric of the world as a blank page, using enchanted inks to inscribe reality-altering runes directly onto the air or their own skin. They command shifting geometries and constructs birthed from written logic.",
73
+ "role": "Utility/Blaster",
74
+ "flavor": "History is not written by the victors, it is written by those who know how to edit."
75
+ }
76
+ },
77
+ {
78
+ "name": "Soul-Sifter",
79
+ "mechanics": {
80
+ "hit_die": "d8",
81
+ "primary_ability": "WIS",
82
+ "saving_throws": [
83
+ "WIS",
84
+ "CHA"
85
+ ],
86
+ "spellcasting_type": "half",
87
+ "key_features": [
88
+ "Ethereal Sieve",
89
+ "Spirit-Dust Extraction",
90
+ "Vestige Manifestation",
91
+ "Ancestral Tether"
92
+ ]
93
+ },
94
+ "narrative": {
95
+ "description": "Soul-Sifters act as conduits for the residual spiritual energy left behind by the departed. By filtering this energy through a spectral tool, they can briefly manifest the skills or memories of those long gone.",
96
+ "role": "Utility/Support",
97
+ "flavor": "The dead have so much to say if you simply know how to filter the noise."
98
+ }
99
+ },
100
+ {
101
+ "name": "Cinder-Gardener",
102
+ "mechanics": {
103
+ "hit_die": "d10",
104
+ "primary_ability": "CON",
105
+ "saving_throws": [
106
+ "CON",
107
+ "DEX"
108
+ ],
109
+ "spellcasting_type": "none",
110
+ "key_features": [
111
+ "Ash-Bloom Cultivation",
112
+ "Emberskin Growth",
113
+ "Root-Fire Entanglement",
114
+ "Coal-Heart Resilience"
115
+ ]
116
+ },
117
+ "narrative": {
118
+ "description": "These survivalists cultivate symbiotic relationships with magical, fire-consuming flora that thrives in arid or destroyed landscapes. They heal themselves and trap foes using blackened thorns and smoldering pollen.",
119
+ "role": "Defender/Controller",
120
+ "flavor": "From the ashes of the world, I grow the beauty that will consume you."
121
+ }
122
+ },
123
+ {
124
+ "name": "Void-Strider",
125
+ "mechanics": {
126
+ "hit_die": "d8",
127
+ "primary_ability": "DEX",
128
+ "saving_throws": [
129
+ "DEX",
130
+ "CHA"
131
+ ],
132
+ "spellcasting_type": "pact",
133
+ "key_features": [
134
+ "Phase-Shift Step",
135
+ "Vacuum Edge",
136
+ "Null-Space Pocket",
137
+ "Shadow-Stutter"
138
+ ]
139
+ },
140
+ "narrative": {
141
+ "description": "Void-Striders navigate the thin, freezing gaps between dimensions, using these shortcuts to teleport and reposition instantly. They wield weapons forged from the absolute cold and silence of the void.",
142
+ "role": "Striker/Skirmisher",
143
+ "flavor": "I am not moving; I am simply deciding where the world should keep me."
144
+ }
145
+ }
146
+ ]
147
+ }
@@ -0,0 +1,334 @@
1
+ {
2
+ "metadata": {
3
+ "source": "dndwright original homebrew",
4
+ "license": "Original content — not derived from any copyrighted RPG product.",
5
+ "note": "Sample starter content; generate more with dndwright.content.generate."
6
+ },
7
+ "creatures": [
8
+ {
9
+ "name": "Gliss-Tick",
10
+ "size": "Tiny",
11
+ "creature_type": "beast",
12
+ "alignment": "unaligned",
13
+ "cr": "1/8",
14
+ "hp": 4,
15
+ "ac": 13,
16
+ "speed": "10 ft., climb 20 ft.",
17
+ "stat_block": {
18
+ "abilities": {
19
+ "str": 2,
20
+ "dex": 17,
21
+ "con": 10,
22
+ "int": 2,
23
+ "wis": 12,
24
+ "cha": 4
25
+ },
26
+ "actions": [
27
+ "Bite: +5 to hit, 1 piercing damage",
28
+ "Adhesive Secretion: Target must succeed on a DC 10 Strength save or have speed reduced by 10 feet"
29
+ ],
30
+ "traits": [
31
+ "Spider Climb: The creature can climb difficult surfaces"
32
+ ]
33
+ }
34
+ },
35
+ {
36
+ "name": "Vellocite Swarmer",
37
+ "size": "Small",
38
+ "creature_type": "monstrosity",
39
+ "alignment": "neutral evil",
40
+ "cr": "1/2",
41
+ "hp": 22,
42
+ "ac": 14,
43
+ "speed": "30 ft.",
44
+ "stat_block": {
45
+ "abilities": {
46
+ "str": 10,
47
+ "dex": 16,
48
+ "con": 12,
49
+ "int": 6,
50
+ "wis": 11,
51
+ "cha": 8
52
+ },
53
+ "actions": [
54
+ "Razor Claw: +5 to hit, 6 slashing damage",
55
+ "Pack Tactics: Advantage on attack rolls if an ally is within 5 feet"
56
+ ],
57
+ "traits": [
58
+ "Frenzy Reflexes: Can take the Disengage action as a bonus action"
59
+ ]
60
+ }
61
+ },
62
+ {
63
+ "name": "Amber-Wisp",
64
+ "size": "Medium",
65
+ "creature_type": "elemental",
66
+ "alignment": "neutral",
67
+ "cr": "1",
68
+ "hp": 30,
69
+ "ac": 15,
70
+ "speed": "0 ft., fly 40 ft. (hover)",
71
+ "stat_block": {
72
+ "abilities": {
73
+ "str": 6,
74
+ "dex": 18,
75
+ "con": 12,
76
+ "int": 10,
77
+ "wis": 14,
78
+ "cha": 12
79
+ },
80
+ "actions": [
81
+ "Sear: +6 to hit, 9 fire damage",
82
+ "Flashblind: Creatures within 10 feet must succeed on a DC 12 Constitution save or be blinded until the end of their next turn"
83
+ ],
84
+ "traits": [
85
+ "Illumination: Sheds bright light in a 20-foot radius"
86
+ ]
87
+ }
88
+ },
89
+ {
90
+ "name": "Thrum-Carapace",
91
+ "size": "Large",
92
+ "creature_type": "construct",
93
+ "alignment": "lawful neutral",
94
+ "cr": "3",
95
+ "hp": 65,
96
+ "ac": 17,
97
+ "speed": "20 ft.",
98
+ "stat_block": {
99
+ "abilities": {
100
+ "str": 18,
101
+ "dex": 8,
102
+ "con": 16,
103
+ "int": 5,
104
+ "wis": 10,
105
+ "cha": 6
106
+ },
107
+ "actions": [
108
+ "Slam: +6 to hit, 13 bludgeoning damage",
109
+ "Resonating Pulse: Creatures within 15 feet must succeed on a DC 13 Constitution save or take 7 thunder damage"
110
+ ],
111
+ "traits": [
112
+ "Immutable Form: Immune to any spell or effect that would alter its form"
113
+ ]
114
+ }
115
+ },
116
+ {
117
+ "name": "Mycelian Weaver",
118
+ "size": "Large",
119
+ "creature_type": "plant",
120
+ "alignment": "chaotic neutral",
121
+ "cr": "5",
122
+ "hp": 90,
123
+ "ac": 14,
124
+ "speed": "30 ft.",
125
+ "stat_block": {
126
+ "abilities": {
127
+ "str": 16,
128
+ "dex": 14,
129
+ "con": 18,
130
+ "int": 12,
131
+ "wis": 15,
132
+ "cha": 10
133
+ },
134
+ "actions": [
135
+ "Spore Lash: +6 to hit, 14 slashing damage plus 7 poison damage",
136
+ "Entangling Growth: Targets within 20 feet must succeed on a DC 14 Strength save or be restrained"
137
+ ],
138
+ "traits": [
139
+ "Regeneration: Regains 5 hit points at the start of its turn if it is in contact with soil"
140
+ ]
141
+ }
142
+ },
143
+ {
144
+ "name": "Void-Stalker Maw",
145
+ "size": "Huge",
146
+ "creature_type": "aberration",
147
+ "alignment": "chaotic evil",
148
+ "cr": "8",
149
+ "hp": 125,
150
+ "ac": 16,
151
+ "speed": "40 ft.",
152
+ "stat_block": {
153
+ "abilities": {
154
+ "str": 20,
155
+ "dex": 12,
156
+ "con": 18,
157
+ "int": 8,
158
+ "wis": 14,
159
+ "cha": 16
160
+ },
161
+ "actions": [
162
+ "Bite: +8 to hit, 18 piercing damage",
163
+ "Gravity Well: Targeted creature must succeed on a DC 15 Strength save or be pulled 30 feet toward the Maw"
164
+ ],
165
+ "traits": [
166
+ "Magic Resistance: Advantage on saving throws against spells and other magical effects"
167
+ ]
168
+ }
169
+ },
170
+ {
171
+ "name": "Kril-Sliver",
172
+ "size": "Tiny",
173
+ "creature_type": "monstrosity",
174
+ "alignment": "unaligned",
175
+ "cr": "1/8",
176
+ "hp": 7,
177
+ "ac": 14,
178
+ "speed": "20 ft., climb 20 ft.",
179
+ "stat_block": {
180
+ "abilities": {
181
+ "str": 4,
182
+ "dex": 18,
183
+ "con": 10,
184
+ "int": 3,
185
+ "wis": 12,
186
+ "cha": 6
187
+ },
188
+ "actions": [
189
+ "Bite: +6 to hit, reach 5 ft., 1 piercing damage.",
190
+ "Phase Shift: The creature turns invisible until the end of its next turn."
191
+ ],
192
+ "traits": [
193
+ "Evasion: Takes no damage on successful Dexterity saves."
194
+ ]
195
+ }
196
+ },
197
+ {
198
+ "name": "Vex-Bloom",
199
+ "size": "Small",
200
+ "creature_type": "plant",
201
+ "alignment": "neutral",
202
+ "cr": "1/2",
203
+ "hp": 22,
204
+ "ac": 12,
205
+ "speed": "5 ft.",
206
+ "stat_block": {
207
+ "abilities": {
208
+ "str": 10,
209
+ "dex": 14,
210
+ "con": 14,
211
+ "int": 6,
212
+ "wis": 15,
213
+ "cha": 10
214
+ },
215
+ "actions": [
216
+ "Pollen Burst: Each creature within 10 ft. must succeed on a DC 12 Constitution saving throw or be poisoned for 1 minute.",
217
+ "Root Lash: +4 to hit, reach 10 ft., 5 bludgeoning damage."
218
+ ],
219
+ "traits": [
220
+ "False Appearance: While motionless, it looks like a normal flowering shrub."
221
+ ]
222
+ }
223
+ },
224
+ {
225
+ "name": "Cinder-Husk",
226
+ "size": "Medium",
227
+ "creature_type": "elemental",
228
+ "alignment": "chaotic neutral",
229
+ "cr": "1",
230
+ "hp": 30,
231
+ "ac": 13,
232
+ "speed": "30 ft.",
233
+ "stat_block": {
234
+ "abilities": {
235
+ "str": 14,
236
+ "dex": 16,
237
+ "con": 12,
238
+ "int": 8,
239
+ "wis": 10,
240
+ "cha": 10
241
+ },
242
+ "actions": [
243
+ "Searing Touch: +5 to hit, reach 5 ft., 7 fire damage.",
244
+ "Ignite: The Cinder-Husk targets one flammable object and sets it on fire."
245
+ ],
246
+ "traits": [
247
+ "Death Burst: When the husk dies, it explodes in a 5 ft. radius for 2d6 fire damage."
248
+ ]
249
+ }
250
+ },
251
+ {
252
+ "name": "Gloom-Strider",
253
+ "size": "Large",
254
+ "creature_type": "aberration",
255
+ "alignment": "neutral evil",
256
+ "cr": "3",
257
+ "hp": 45,
258
+ "ac": 15,
259
+ "speed": "40 ft.",
260
+ "stat_block": {
261
+ "abilities": {
262
+ "str": 16,
263
+ "dex": 14,
264
+ "con": 15,
265
+ "int": 10,
266
+ "wis": 12,
267
+ "cha": 8
268
+ },
269
+ "actions": [
270
+ "Shadow Claw: +5 to hit, reach 10 ft., 12 slashing damage.",
271
+ "Terrifying Gaze: Target must succeed on a DC 13 Wisdom saving throw or be frightened for 1 minute."
272
+ ],
273
+ "traits": [
274
+ "Shadow Stealth: Can hide as a bonus action in dim light or darkness."
275
+ ]
276
+ }
277
+ },
278
+ {
279
+ "name": "Ion-Shell Sentinel",
280
+ "size": "Large",
281
+ "creature_type": "construct",
282
+ "alignment": "lawful neutral",
283
+ "cr": "5",
284
+ "hp": 68,
285
+ "ac": 18,
286
+ "speed": "20 ft.",
287
+ "stat_block": {
288
+ "abilities": {
289
+ "str": 20,
290
+ "dex": 8,
291
+ "con": 18,
292
+ "int": 4,
293
+ "wis": 10,
294
+ "cha": 5
295
+ },
296
+ "actions": [
297
+ "Slam: +8 to hit, reach 5 ft., 18 bludgeoning damage.",
298
+ "Lightning Discharge: Recharge 5-6, 30 ft. line, 24 lightning damage (DC 15 Dex save for half)."
299
+ ],
300
+ "traits": [
301
+ "Magic Resistance: Advantage on saving throws against spells."
302
+ ]
303
+ }
304
+ },
305
+ {
306
+ "name": "Skyshard Weaver",
307
+ "size": "Huge",
308
+ "creature_type": "fey",
309
+ "alignment": "chaotic good",
310
+ "cr": "8",
311
+ "hp": 110,
312
+ "ac": 16,
313
+ "speed": "10 ft., fly 50 ft.",
314
+ "stat_block": {
315
+ "abilities": {
316
+ "str": 18,
317
+ "dex": 20,
318
+ "con": 16,
319
+ "int": 14,
320
+ "wis": 16,
321
+ "cha": 18
322
+ },
323
+ "actions": [
324
+ "Multiattack: Makes two crystalline claw attacks.",
325
+ "Crystalline Claw: +8 to hit, reach 10 ft., 16 slashing damage.",
326
+ "Prism Pulse: Each creature in 20 ft. radius must succeed on DC 15 Con save or be blinded until end of next turn."
327
+ ],
328
+ "traits": [
329
+ "Reflective Carapace: Any spell targeting the weaver has a 25% chance to reflect back at the caster."
330
+ ]
331
+ }
332
+ }
333
+ ]
334
+ }