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 +69 -0
- dndwright/content/__init__.py +56 -0
- dndwright/content/classes.json +147 -0
- dndwright/content/creatures.json +334 -0
- dndwright/content/generate.py +87 -0
- dndwright/content/magic_items.json +1915 -0
- dndwright/content/species.json +111 -0
- dndwright/ontology/__init__.py +25 -0
- dndwright/ontology/dnd.yaml +141 -0
- dndwright/ontology/loader.py +104 -0
- dndwright/rules/__init__.py +35 -0
- dndwright/rules/adapters.py +691 -0
- dndwright/rules/assembler.py +377 -0
- dndwright/rules/character_evaluator.py +248 -0
- dndwright/rules/components.py +654 -0
- dndwright/rules/dnd_5e_2024.py +606 -0
- dndwright/rules/evaluator.py +217 -0
- dndwright/rules/lookup_tables.py +501 -0
- dndwright/rules/operations.py +412 -0
- dndwright/rules/schema.py +69 -0
- dndwright/rules/theme_scaling.py +207 -0
- dndwright-0.2.0.dist-info/METADATA +101 -0
- dndwright-0.2.0.dist-info/RECORD +26 -0
- dndwright-0.2.0.dist-info/WHEEL +4 -0
- dndwright-0.2.0.dist-info/licenses/LICENSE +21 -0
- dndwright-0.2.0.dist-info/licenses/NOTICE +24 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
"""All D&D 5e 2024 lookup tables extracted from generation.py constants.
|
|
2
|
+
|
|
3
|
+
These tables are pure data — no logic, no code. They become part of the
|
|
4
|
+
Ruleset and are available to any formula operation via the `tables` parameter.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
# =============================================================================
|
|
10
|
+
# Armor
|
|
11
|
+
# =============================================================================
|
|
12
|
+
|
|
13
|
+
ARMOR_BASE_AC: dict[str, int] = {
|
|
14
|
+
"none": 10,
|
|
15
|
+
"unarmored": 10,
|
|
16
|
+
"padded": 11,
|
|
17
|
+
"leather": 11,
|
|
18
|
+
"studded": 12,
|
|
19
|
+
"studded_leather": 12,
|
|
20
|
+
"studded leather": 12,
|
|
21
|
+
"hide": 12,
|
|
22
|
+
"chain_shirt": 13,
|
|
23
|
+
"chain shirt": 13,
|
|
24
|
+
"scale_mail": 14,
|
|
25
|
+
"scale mail": 14,
|
|
26
|
+
"breastplate": 14,
|
|
27
|
+
"half_plate": 15,
|
|
28
|
+
"half plate": 15,
|
|
29
|
+
"ring_mail": 14,
|
|
30
|
+
"ring mail": 14,
|
|
31
|
+
"chain_mail": 16,
|
|
32
|
+
"chain mail": 16,
|
|
33
|
+
"splint": 17,
|
|
34
|
+
"plate": 18,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Maximum DEX bonus allowed by armor type.
|
|
38
|
+
# None = unlimited (light/unarmored), 0 = no DEX bonus (heavy).
|
|
39
|
+
ARMOR_MAX_DEX: dict[str, int | None] = {
|
|
40
|
+
"none": None,
|
|
41
|
+
"unarmored": None,
|
|
42
|
+
"padded": None,
|
|
43
|
+
"leather": None,
|
|
44
|
+
"studded": None,
|
|
45
|
+
"studded_leather": None,
|
|
46
|
+
"studded leather": None,
|
|
47
|
+
"hide": 2,
|
|
48
|
+
"chain_shirt": 2,
|
|
49
|
+
"chain shirt": 2,
|
|
50
|
+
"scale_mail": 2,
|
|
51
|
+
"scale mail": 2,
|
|
52
|
+
"breastplate": 2,
|
|
53
|
+
"half_plate": 2,
|
|
54
|
+
"half plate": 2,
|
|
55
|
+
"ring_mail": 0,
|
|
56
|
+
"ring mail": 0,
|
|
57
|
+
"chain_mail": 0,
|
|
58
|
+
"chain mail": 0,
|
|
59
|
+
"splint": 0,
|
|
60
|
+
"plate": 0,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# =============================================================================
|
|
64
|
+
# Skill → Ability mapping
|
|
65
|
+
# =============================================================================
|
|
66
|
+
|
|
67
|
+
SKILL_ABILITY_MAP: dict[str, str] = {
|
|
68
|
+
"acrobatics": "dexterity",
|
|
69
|
+
"animal_handling": "wisdom",
|
|
70
|
+
"arcana": "intelligence",
|
|
71
|
+
"athletics": "strength",
|
|
72
|
+
"deception": "charisma",
|
|
73
|
+
"history": "intelligence",
|
|
74
|
+
"insight": "wisdom",
|
|
75
|
+
"intimidation": "charisma",
|
|
76
|
+
"investigation": "intelligence",
|
|
77
|
+
"medicine": "wisdom",
|
|
78
|
+
"nature": "intelligence",
|
|
79
|
+
"perception": "wisdom",
|
|
80
|
+
"performance": "charisma",
|
|
81
|
+
"persuasion": "charisma",
|
|
82
|
+
"religion": "intelligence",
|
|
83
|
+
"sleight_of_hand": "dexterity",
|
|
84
|
+
"stealth": "dexterity",
|
|
85
|
+
"survival": "wisdom",
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# =============================================================================
|
|
89
|
+
# Spellcasting ability by class
|
|
90
|
+
# =============================================================================
|
|
91
|
+
|
|
92
|
+
SPELL_ABILITY_BY_CLASS: dict[str, str] = {
|
|
93
|
+
"wizard": "intelligence",
|
|
94
|
+
"artificer": "intelligence",
|
|
95
|
+
"cleric": "wisdom",
|
|
96
|
+
"druid": "wisdom",
|
|
97
|
+
"ranger": "wisdom",
|
|
98
|
+
"monk": "wisdom",
|
|
99
|
+
"bard": "charisma",
|
|
100
|
+
"paladin": "charisma",
|
|
101
|
+
"sorcerer": "charisma",
|
|
102
|
+
"warlock": "charisma",
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# =============================================================================
|
|
106
|
+
# Hit die by class
|
|
107
|
+
# =============================================================================
|
|
108
|
+
|
|
109
|
+
HIT_DIE_BY_CLASS: dict[str, int] = {
|
|
110
|
+
"barbarian": 12,
|
|
111
|
+
"fighter": 10,
|
|
112
|
+
"paladin": 10,
|
|
113
|
+
"ranger": 10,
|
|
114
|
+
"monk": 8,
|
|
115
|
+
"rogue": 8,
|
|
116
|
+
"bard": 8,
|
|
117
|
+
"cleric": 8,
|
|
118
|
+
"druid": 8,
|
|
119
|
+
"warlock": 8,
|
|
120
|
+
"artificer": 8,
|
|
121
|
+
"wizard": 6,
|
|
122
|
+
"sorcerer": 6,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Hit die by archetype (fallback when class name not available)
|
|
126
|
+
HIT_DIE_BY_ARCHETYPE: dict[str, int] = {
|
|
127
|
+
"full_martial": 10,
|
|
128
|
+
"skill_martial": 8,
|
|
129
|
+
"primal_martial": 12,
|
|
130
|
+
"half_caster": 10,
|
|
131
|
+
"full_caster": 6,
|
|
132
|
+
"pact_caster": 8,
|
|
133
|
+
"support_caster": 8,
|
|
134
|
+
"gish": 8,
|
|
135
|
+
"tank": 10,
|
|
136
|
+
"martial": 10,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# =============================================================================
|
|
140
|
+
# Spell slot progression tables
|
|
141
|
+
# =============================================================================
|
|
142
|
+
|
|
143
|
+
# Full casters: Wizard, Cleric, Druid, Sorcerer, Bard
|
|
144
|
+
SPELL_SLOTS_FULL: dict[int, dict[str, int]] = {
|
|
145
|
+
1: {"1st": 2},
|
|
146
|
+
2: {"1st": 3},
|
|
147
|
+
3: {"1st": 4, "2nd": 2},
|
|
148
|
+
4: {"1st": 4, "2nd": 3},
|
|
149
|
+
5: {"1st": 4, "2nd": 3, "3rd": 2},
|
|
150
|
+
6: {"1st": 4, "2nd": 3, "3rd": 3},
|
|
151
|
+
7: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 1},
|
|
152
|
+
8: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 2},
|
|
153
|
+
9: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 1},
|
|
154
|
+
10: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2},
|
|
155
|
+
11: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1},
|
|
156
|
+
12: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1},
|
|
157
|
+
13: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1, "7th": 1},
|
|
158
|
+
14: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1, "7th": 1},
|
|
159
|
+
15: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1, "7th": 1, "8th": 1},
|
|
160
|
+
16: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1, "7th": 1, "8th": 1},
|
|
161
|
+
17: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2, "6th": 1, "7th": 1, "8th": 1, "9th": 1},
|
|
162
|
+
18: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 3, "6th": 1, "7th": 1, "8th": 1, "9th": 1},
|
|
163
|
+
19: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 3, "6th": 2, "7th": 1, "8th": 1, "9th": 1},
|
|
164
|
+
20: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 3, "6th": 2, "7th": 2, "8th": 1, "9th": 1},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# Half casters: Paladin, Ranger — start at level 2
|
|
168
|
+
SPELL_SLOTS_HALF: dict[int, dict[str, int]] = {
|
|
169
|
+
1: {},
|
|
170
|
+
2: {"1st": 2},
|
|
171
|
+
3: {"1st": 3},
|
|
172
|
+
4: {"1st": 3},
|
|
173
|
+
5: {"1st": 4, "2nd": 2},
|
|
174
|
+
6: {"1st": 4, "2nd": 2},
|
|
175
|
+
7: {"1st": 4, "2nd": 3},
|
|
176
|
+
8: {"1st": 4, "2nd": 3},
|
|
177
|
+
9: {"1st": 4, "2nd": 3, "3rd": 2},
|
|
178
|
+
10: {"1st": 4, "2nd": 3, "3rd": 2},
|
|
179
|
+
11: {"1st": 4, "2nd": 3, "3rd": 3},
|
|
180
|
+
12: {"1st": 4, "2nd": 3, "3rd": 3},
|
|
181
|
+
13: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 1},
|
|
182
|
+
14: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 1},
|
|
183
|
+
15: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 2},
|
|
184
|
+
16: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 2},
|
|
185
|
+
17: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 1},
|
|
186
|
+
18: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 1},
|
|
187
|
+
19: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2},
|
|
188
|
+
20: {"1st": 4, "2nd": 3, "3rd": 3, "4th": 3, "5th": 2},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# Warlock pact magic — separate system
|
|
192
|
+
SPELL_SLOTS_WARLOCK: dict[int, dict[str, int]] = {
|
|
193
|
+
1: {"pact": 1, "pact_level": 1},
|
|
194
|
+
2: {"pact": 2, "pact_level": 1},
|
|
195
|
+
3: {"pact": 2, "pact_level": 2},
|
|
196
|
+
4: {"pact": 2, "pact_level": 2},
|
|
197
|
+
5: {"pact": 2, "pact_level": 3},
|
|
198
|
+
6: {"pact": 2, "pact_level": 3},
|
|
199
|
+
7: {"pact": 2, "pact_level": 4},
|
|
200
|
+
8: {"pact": 2, "pact_level": 4},
|
|
201
|
+
9: {"pact": 2, "pact_level": 5},
|
|
202
|
+
10: {"pact": 2, "pact_level": 5},
|
|
203
|
+
11: {"pact": 3, "pact_level": 5},
|
|
204
|
+
12: {"pact": 3, "pact_level": 5},
|
|
205
|
+
13: {"pact": 3, "pact_level": 5},
|
|
206
|
+
14: {"pact": 3, "pact_level": 5},
|
|
207
|
+
15: {"pact": 3, "pact_level": 5},
|
|
208
|
+
16: {"pact": 3, "pact_level": 5},
|
|
209
|
+
17: {"pact": 4, "pact_level": 5},
|
|
210
|
+
18: {"pact": 4, "pact_level": 5},
|
|
211
|
+
19: {"pact": 4, "pact_level": 5},
|
|
212
|
+
20: {"pact": 4, "pact_level": 5},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# =============================================================================
|
|
216
|
+
# Spellcasting type by class
|
|
217
|
+
# =============================================================================
|
|
218
|
+
|
|
219
|
+
SPELLCASTING_TYPE_BY_CLASS: dict[str, str] = {
|
|
220
|
+
"wizard": "full_caster",
|
|
221
|
+
"cleric": "full_caster",
|
|
222
|
+
"druid": "full_caster",
|
|
223
|
+
"sorcerer": "full_caster",
|
|
224
|
+
"bard": "full_caster",
|
|
225
|
+
"paladin": "half_caster",
|
|
226
|
+
"ranger": "half_caster",
|
|
227
|
+
"artificer": "half_caster",
|
|
228
|
+
"warlock": "pact_caster",
|
|
229
|
+
"fighter": "none",
|
|
230
|
+
"barbarian": "none",
|
|
231
|
+
"rogue": "none",
|
|
232
|
+
"monk": "none",
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
# =============================================================================
|
|
236
|
+
# XP thresholds
|
|
237
|
+
# =============================================================================
|
|
238
|
+
|
|
239
|
+
XP_THRESHOLDS: dict[int, int] = {
|
|
240
|
+
1: 0,
|
|
241
|
+
2: 300,
|
|
242
|
+
3: 900,
|
|
243
|
+
4: 2700,
|
|
244
|
+
5: 6500,
|
|
245
|
+
6: 14000,
|
|
246
|
+
7: 23000,
|
|
247
|
+
8: 34000,
|
|
248
|
+
9: 48000,
|
|
249
|
+
10: 64000,
|
|
250
|
+
11: 85000,
|
|
251
|
+
12: 100000,
|
|
252
|
+
13: 120000,
|
|
253
|
+
14: 140000,
|
|
254
|
+
15: 165000,
|
|
255
|
+
16: 195000,
|
|
256
|
+
17: 225000,
|
|
257
|
+
18: 265000,
|
|
258
|
+
19: 305000,
|
|
259
|
+
20: 355000,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# =============================================================================
|
|
263
|
+
# Item rarity unlock requirements
|
|
264
|
+
# =============================================================================
|
|
265
|
+
|
|
266
|
+
RARITY_UNLOCK_REQUIREMENTS: dict[str, dict[str, int]] = {
|
|
267
|
+
"common": {"min_level": 1, "min_xp": 0},
|
|
268
|
+
"uncommon": {"min_level": 1, "min_xp": 0},
|
|
269
|
+
"rare": {"min_level": 5, "min_xp": 6500},
|
|
270
|
+
"very_rare": {"min_level": 11, "min_xp": 85000},
|
|
271
|
+
"legendary": {"min_level": 17, "min_xp": 225000},
|
|
272
|
+
"artifact": {"min_level": 17, "min_xp": 225000},
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Simple level-only lookup (convenience alias)
|
|
276
|
+
RARITY_LEVEL_REQUIREMENTS: dict[str, int] = {
|
|
277
|
+
rarity: req["min_level"] for rarity, req in RARITY_UNLOCK_REQUIREMENTS.items()
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# =============================================================================
|
|
281
|
+
# Weapon mastery (D&D 2024)
|
|
282
|
+
# =============================================================================
|
|
283
|
+
|
|
284
|
+
WEAPON_MASTERY_MAP: dict[str, str] = {
|
|
285
|
+
# Simple melee
|
|
286
|
+
"club": "Slow",
|
|
287
|
+
"dagger": "Nick",
|
|
288
|
+
"greatclub": "Push",
|
|
289
|
+
"handaxe": "Vex",
|
|
290
|
+
"javelin": "Slow",
|
|
291
|
+
"light hammer": "Nick",
|
|
292
|
+
"mace": "Sap",
|
|
293
|
+
"quarterstaff": "Topple",
|
|
294
|
+
"sickle": "Nick",
|
|
295
|
+
"spear": "Sap",
|
|
296
|
+
# Simple ranged
|
|
297
|
+
"dart": "Vex",
|
|
298
|
+
"light crossbow": "Slow",
|
|
299
|
+
"shortbow": "Vex",
|
|
300
|
+
"sling": "Slow",
|
|
301
|
+
# Martial melee
|
|
302
|
+
"battleaxe": "Topple",
|
|
303
|
+
"flail": "Sap",
|
|
304
|
+
"glaive": "Graze",
|
|
305
|
+
"greataxe": "Cleave",
|
|
306
|
+
"greatsword": "Graze",
|
|
307
|
+
"halberd": "Cleave",
|
|
308
|
+
"lance": "Topple",
|
|
309
|
+
"longsword": "Sap",
|
|
310
|
+
"maul": "Topple",
|
|
311
|
+
"morningstar": "Sap",
|
|
312
|
+
"pike": "Push",
|
|
313
|
+
"rapier": "Vex",
|
|
314
|
+
"scimitar": "Nick",
|
|
315
|
+
"shortsword": "Vex",
|
|
316
|
+
"trident": "Topple",
|
|
317
|
+
"war pick": "Sap",
|
|
318
|
+
"warhammer": "Push",
|
|
319
|
+
"whip": "Slow",
|
|
320
|
+
# Martial ranged
|
|
321
|
+
"blowgun": "Vex",
|
|
322
|
+
"hand crossbow": "Vex",
|
|
323
|
+
"heavy crossbow": "Push",
|
|
324
|
+
"longbow": "Slow",
|
|
325
|
+
"musket": "Slow",
|
|
326
|
+
"pistol": "Vex",
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
# D&D 2024 weapon mastery rule text — paraphrased from PHB pp. 213-214,
|
|
330
|
+
# keyed by the canonical mastery label that WEAPON_MASTERY_MAP emits.
|
|
331
|
+
# Used by adapters.py::_build_equipment_info to surface the effect in
|
|
332
|
+
# the character-sheet response. An unknown key MUST
|
|
333
|
+
# surface as `mastery_unknown: true` rather than silently empty
|
|
334
|
+
# description.
|
|
335
|
+
WEAPON_MASTERY_DESCRIPTIONS: dict[str, str] = {
|
|
336
|
+
"Cleave": (
|
|
337
|
+
"After hitting a creature with a melee attack, you can make "
|
|
338
|
+
"a melee attack with the same weapon against a second "
|
|
339
|
+
"creature within 5 feet of the first, using the same attack "
|
|
340
|
+
"roll. The second target must be within the weapon's reach. "
|
|
341
|
+
"You can use this once per turn."
|
|
342
|
+
),
|
|
343
|
+
"Graze": (
|
|
344
|
+
"If your attack roll against a creature misses, you can deal "
|
|
345
|
+
"damage to that creature equal to the ability modifier used "
|
|
346
|
+
"to make the attack roll. The damage is the same type as the "
|
|
347
|
+
"weapon's damage. Doesn't apply on a critical miss."
|
|
348
|
+
),
|
|
349
|
+
"Nick": (
|
|
350
|
+
"When you make the extra attack of the Light property, you "
|
|
351
|
+
"can make it as part of the Attack action instead of as a "
|
|
352
|
+
"Bonus Action. You can make this extra attack only once per "
|
|
353
|
+
"turn."
|
|
354
|
+
),
|
|
355
|
+
"Push": (
|
|
356
|
+
"When you hit a creature with this weapon, you can push the "
|
|
357
|
+
"creature up to 10 feet straight away from you if it's Large "
|
|
358
|
+
"or smaller."
|
|
359
|
+
),
|
|
360
|
+
"Sap": (
|
|
361
|
+
"When you hit a creature with this weapon, that creature has "
|
|
362
|
+
"Disadvantage on its next attack roll before the start of "
|
|
363
|
+
"your next turn."
|
|
364
|
+
),
|
|
365
|
+
"Slow": (
|
|
366
|
+
"When you hit a creature with this weapon and deal damage, "
|
|
367
|
+
"you can reduce that creature's Speed by 10 feet until the "
|
|
368
|
+
"start of your next turn. If the creature is hit more than "
|
|
369
|
+
"once, the speed reduction doesn't stack."
|
|
370
|
+
),
|
|
371
|
+
"Topple": (
|
|
372
|
+
"When you hit a creature with this weapon, you can force the "
|
|
373
|
+
"creature to make a Constitution saving throw (DC 8 + your "
|
|
374
|
+
"proficiency bonus + the ability modifier used to make the "
|
|
375
|
+
"attack roll). On a failed save, the creature has the Prone "
|
|
376
|
+
"condition."
|
|
377
|
+
),
|
|
378
|
+
"Vex": (
|
|
379
|
+
"When you hit a creature with this weapon and deal damage, "
|
|
380
|
+
"you have Advantage on your next attack roll against that "
|
|
381
|
+
"creature before the end of your next turn."
|
|
382
|
+
),
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
# =============================================================================
|
|
386
|
+
# Archetype-based proficiency defaults
|
|
387
|
+
# =============================================================================
|
|
388
|
+
|
|
389
|
+
ARCHETYPE_WEAPON_PROFICIENCIES: dict[str, list[str]] = {
|
|
390
|
+
"full_martial": ["Simple weapons", "Martial weapons"],
|
|
391
|
+
"skill_martial": ["Simple weapons", "Martial weapons"],
|
|
392
|
+
"half_caster": ["Simple weapons", "Martial weapons"],
|
|
393
|
+
"full_caster": ["Daggers", "Darts", "Slings", "Quarterstaffs", "Light crossbows"],
|
|
394
|
+
"support_caster": ["Simple weapons"],
|
|
395
|
+
"gish": ["Simple weapons", "Martial weapons"],
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
ARCHETYPE_ARMOR_PROFICIENCIES: dict[str, list[str]] = {
|
|
399
|
+
"full_martial": ["Light armor", "Medium armor", "Heavy armor", "Shields"],
|
|
400
|
+
"skill_martial": ["Light armor", "Medium armor"],
|
|
401
|
+
"half_caster": ["Light armor", "Medium armor", "Shields"],
|
|
402
|
+
"full_caster": [],
|
|
403
|
+
"support_caster": ["Light armor"],
|
|
404
|
+
"gish": ["Light armor", "Medium armor"],
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
# =============================================================================
|
|
408
|
+
# Saving throw proficiencies by class
|
|
409
|
+
# =============================================================================
|
|
410
|
+
|
|
411
|
+
SAVE_PROFICIENCIES_BY_CLASS: dict[str, list[str]] = {
|
|
412
|
+
"barbarian": ["strength", "constitution"],
|
|
413
|
+
"bard": ["dexterity", "charisma"],
|
|
414
|
+
"cleric": ["wisdom", "charisma"],
|
|
415
|
+
"druid": ["intelligence", "wisdom"],
|
|
416
|
+
"fighter": ["strength", "constitution"],
|
|
417
|
+
"monk": ["strength", "dexterity"],
|
|
418
|
+
"paladin": ["wisdom", "charisma"],
|
|
419
|
+
"ranger": ["strength", "dexterity"],
|
|
420
|
+
"rogue": ["dexterity", "intelligence"],
|
|
421
|
+
"sorcerer": ["constitution", "charisma"],
|
|
422
|
+
"warlock": ["wisdom", "charisma"],
|
|
423
|
+
"wizard": ["intelligence", "wisdom"],
|
|
424
|
+
"artificer": ["constitution", "intelligence"],
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
# =============================================================================
|
|
428
|
+
# Monster/creature stat block tables (for future creature computation graph)
|
|
429
|
+
# =============================================================================
|
|
430
|
+
|
|
431
|
+
# Challenge Rating to Proficiency Bonus
|
|
432
|
+
CR_PROFICIENCY_BONUS: dict[str, int] = {
|
|
433
|
+
"0": 2,
|
|
434
|
+
"1/8": 2,
|
|
435
|
+
"1/4": 2,
|
|
436
|
+
"1/2": 2,
|
|
437
|
+
"1": 2,
|
|
438
|
+
"2": 2,
|
|
439
|
+
"3": 2,
|
|
440
|
+
"4": 2,
|
|
441
|
+
"5": 3,
|
|
442
|
+
"6": 3,
|
|
443
|
+
"7": 3,
|
|
444
|
+
"8": 3,
|
|
445
|
+
"9": 4,
|
|
446
|
+
"10": 4,
|
|
447
|
+
"11": 4,
|
|
448
|
+
"12": 4,
|
|
449
|
+
"13": 5,
|
|
450
|
+
"14": 5,
|
|
451
|
+
"15": 5,
|
|
452
|
+
"16": 5,
|
|
453
|
+
"17": 6,
|
|
454
|
+
"18": 6,
|
|
455
|
+
"19": 6,
|
|
456
|
+
"20": 6,
|
|
457
|
+
"21": 7,
|
|
458
|
+
"22": 7,
|
|
459
|
+
"23": 7,
|
|
460
|
+
"24": 7,
|
|
461
|
+
"25": 8,
|
|
462
|
+
"26": 8,
|
|
463
|
+
"27": 8,
|
|
464
|
+
"28": 8,
|
|
465
|
+
"29": 9,
|
|
466
|
+
"30": 9,
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
# Size categories to hit die size
|
|
470
|
+
CREATURE_SIZE_HIT_DIE: dict[str, int] = {
|
|
471
|
+
"tiny": 4,
|
|
472
|
+
"small": 6,
|
|
473
|
+
"medium": 8,
|
|
474
|
+
"large": 10,
|
|
475
|
+
"huge": 12,
|
|
476
|
+
"gargantuan": 20,
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def get_all_lookup_tables() -> dict:
|
|
481
|
+
"""Return all lookup tables as a flat dict for use in a Ruleset."""
|
|
482
|
+
return {
|
|
483
|
+
"armor_base_ac": ARMOR_BASE_AC,
|
|
484
|
+
"armor_max_dex": ARMOR_MAX_DEX,
|
|
485
|
+
"skill_ability_map": SKILL_ABILITY_MAP,
|
|
486
|
+
"spell_ability_by_class": SPELL_ABILITY_BY_CLASS,
|
|
487
|
+
"hit_die_by_class": HIT_DIE_BY_CLASS,
|
|
488
|
+
"hit_die_by_archetype": HIT_DIE_BY_ARCHETYPE,
|
|
489
|
+
"spell_slots_full": SPELL_SLOTS_FULL,
|
|
490
|
+
"spell_slots_half": SPELL_SLOTS_HALF,
|
|
491
|
+
"spell_slots_warlock": SPELL_SLOTS_WARLOCK,
|
|
492
|
+
"spellcasting_type_by_class": SPELLCASTING_TYPE_BY_CLASS,
|
|
493
|
+
"xp_thresholds": XP_THRESHOLDS,
|
|
494
|
+
"rarity_unlock_requirements": RARITY_UNLOCK_REQUIREMENTS,
|
|
495
|
+
"weapon_mastery_map": WEAPON_MASTERY_MAP,
|
|
496
|
+
"archetype_weapon_proficiencies": ARCHETYPE_WEAPON_PROFICIENCIES,
|
|
497
|
+
"archetype_armor_proficiencies": ARCHETYPE_ARMOR_PROFICIENCIES,
|
|
498
|
+
"save_proficiencies_by_class": SAVE_PROFICIENCIES_BY_CLASS,
|
|
499
|
+
"cr_proficiency_bonus": CR_PROFICIENCY_BONUS,
|
|
500
|
+
"creature_size_hit_die": CREATURE_SIZE_HIT_DIE,
|
|
501
|
+
}
|