playlist-data-engine 1.7.3 → 1.8.0
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.
- package/README.md +14 -0
- package/bin/cli.cjs +85 -0
- package/dist/gateway-CDMPqFEH.js +1320 -0
- package/dist/gateway-DKa45Uz6.cjs +6 -0
- package/dist/gateway.d.ts +1 -0
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +1 -1
- package/dist/gateway.mjs +22 -19
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/playlist-data-engine.js +4 -4
- package/dist/playlist-data-engine.mjs +30 -27
- package/dist/utils/engineDocs.d.ts +33 -0
- package/dist/utils/engineDocs.d.ts.map +1 -0
- package/docs/DATA_ENGINE_REFERENCE.md +6660 -0
- package/docs/USAGE_IN_OTHER_PROJECTS.md +587 -0
- package/docs/features/AUDIO_ANALYSIS.md +610 -0
- package/docs/features/BEAT_DETECTION.md +5250 -0
- package/docs/features/COMBAT_SYSTEM.md +1632 -0
- package/docs/features/CONTENT_PACKS.md +464 -0
- package/docs/features/CUSTOM_CONTENT.md +603 -0
- package/docs/features/ENEMY_GENERATION.md +1711 -0
- package/docs/features/EQUIPMENT_SYSTEM.md +2279 -0
- package/docs/features/EXTENSIBILITY_GUIDE.md +1106 -0
- package/docs/features/GATEWAY_RESOLUTION.md +725 -0
- package/docs/features/IRL_SENSORS.md +360 -0
- package/docs/features/PLAYLIST_PARSING.md +446 -0
- package/docs/features/PREREQUISITES.md +571 -0
- package/docs/features/ROLLS_AND_SEEDS.md +687 -0
- package/docs/features/XP_AND_STATS.md +1221 -0
- package/llms.txt +33 -0
- package/package.json +9 -2
- package/skills/playlist-data-engine/SKILL.md +69 -0
- package/dist/gateway-C_p9Ku3O.js +0 -1211
- package/dist/gateway-Ceg-5xug.cjs +0 -1
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
# Prerequisites Reference
|
|
2
|
+
|
|
3
|
+
Complete guide to the prerequisite system for skills, spells, and features in the Playlist Data Engine.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Overview](#overview)
|
|
10
|
+
2. [Skill Prerequisites](#skill-prerequisites)
|
|
11
|
+
3. [Spell Prerequisites](#spell-prerequisites)
|
|
12
|
+
4. [Feature Prerequisites](#feature-prerequisites)
|
|
13
|
+
5. [Validation System](#validation-system)
|
|
14
|
+
6. [Examples](#examples)
|
|
15
|
+
7. [API Reference](#api-reference)
|
|
16
|
+
8. [Best Practices](#best-practices)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
The Playlist Data Engine supports a comprehensive prerequisite system that allows skills, spells, and features to require specific conditions before they can be learned or used.
|
|
23
|
+
|
|
24
|
+
### Key Features
|
|
25
|
+
|
|
26
|
+
- **Skill Prerequisites**: Skills can require levels, abilities, other skills, features, or spells
|
|
27
|
+
- **Spell Prerequisites**: Spells can require levels, abilities, features, other spells, or skills
|
|
28
|
+
- **Feature Prerequisites**: Features can require levels, abilities, skills, spells, or subraces
|
|
29
|
+
|
|
30
|
+
### Design Principles
|
|
31
|
+
|
|
32
|
+
- **Backward Compatible**: Existing skills, spells, races, and characters continue to work
|
|
33
|
+
- **Consistent Pattern**: All prerequisite types follow the same `FeaturePrerequisite` pattern
|
|
34
|
+
- **Validation First**: All prerequisites validated before assignment
|
|
35
|
+
- **Type Safe**: Full TypeScript type safety maintained
|
|
36
|
+
- **Extensible**: Custom content registered same as default content
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Skill Prerequisites
|
|
41
|
+
|
|
42
|
+
Skills can have prerequisites that must be met before a character can gain proficiency in them.
|
|
43
|
+
|
|
44
|
+
### SkillPrerequisite
|
|
45
|
+
|
|
46
|
+
*Also known as: skill requirements, skill conditions*
|
|
47
|
+
|
|
48
|
+
Defines conditions that must be met before a character can gain proficiency in a skill.
|
|
49
|
+
|
|
50
|
+
**Location:** [`src/core/skills/SkillTypes.ts`](src/core/skills/SkillTypes.ts#L23-L47)
|
|
51
|
+
|
|
52
|
+
| Property | Type | Description |
|
|
53
|
+
|----------|------|-------------|
|
|
54
|
+
| `level` | `number?` | Minimum character level required |
|
|
55
|
+
| `abilities` | `Partial<Record<Ability, number>>?` | Minimum ability scores (STR/DEX/CON/INT/WIS/CHA) |
|
|
56
|
+
| `class` | `Class?` | Specific class required |
|
|
57
|
+
| `race` | `Race?` | Specific race required |
|
|
58
|
+
| `skills` | `string[]?` | Skills that must be proficient first (by skill ID) |
|
|
59
|
+
| `features` | `string[]?` | Features that must be learned first (by feature ID) |
|
|
60
|
+
| `spells` | `string[]?` | Spells that must be known first (by spell name) |
|
|
61
|
+
| `custom` | `string?` | Custom condition description (display only) |
|
|
62
|
+
|
|
63
|
+
### CustomSkill.prerequisites
|
|
64
|
+
|
|
65
|
+
**Location:** [`src/core/skills/SkillTypes.ts`](src/core/skills/SkillTypes.ts#L128)
|
|
66
|
+
|
|
67
|
+
The `CustomSkill` interface includes an optional `prerequisites?: SkillPrerequisite` property. When specified, the skill is filtered out during character generation if prerequisites are unmet.
|
|
68
|
+
|
|
69
|
+
### Validation
|
|
70
|
+
|
|
71
|
+
Skill prerequisites are validated automatically during:
|
|
72
|
+
|
|
73
|
+
1. **Skill Registration**: Schema validation ensures prerequisite structure is valid
|
|
74
|
+
2. **Skill Assignment**: During character generation, skills with unmet prerequisites are filtered out
|
|
75
|
+
3. **Manual Validation**: Use `SkillValidator.validateSkillPrerequisites()` or `SkillQuery.validatePrerequisites()`
|
|
76
|
+
|
|
77
|
+
### Example Skills with Prerequisites
|
|
78
|
+
|
|
79
|
+
| Skill | Prerequisites Used |
|
|
80
|
+
|-------|-------------------|
|
|
81
|
+
| Dragon Smithing | `features`, `level`, `class` |
|
|
82
|
+
| Advanced Arcana | `abilities`, `skills`, `level` |
|
|
83
|
+
| Spell Mastery | `spells`, `class`, `level` |
|
|
84
|
+
| Dwarven Warfare | `race` |
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { ExtensionManager } from 'playlist-data-engine';
|
|
88
|
+
|
|
89
|
+
const skills = [
|
|
90
|
+
{
|
|
91
|
+
id: 'dragon_smithing',
|
|
92
|
+
name: 'Dragon Smithing',
|
|
93
|
+
description: 'Craft weapons from dragon scales',
|
|
94
|
+
ability: 'INT' as const,
|
|
95
|
+
prerequisites: {
|
|
96
|
+
features: ['draconic_bloodline'],
|
|
97
|
+
level: 5,
|
|
98
|
+
class: 'Sorcerer' as const
|
|
99
|
+
},
|
|
100
|
+
source: 'custom' as const
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'advanced_arcana',
|
|
104
|
+
name: 'Advanced Arcana',
|
|
105
|
+
description: 'Cast complex spells and understand magical theory',
|
|
106
|
+
ability: 'INT' as const,
|
|
107
|
+
prerequisites: {
|
|
108
|
+
abilities: { INT: 16 },
|
|
109
|
+
skills: ['arcana'],
|
|
110
|
+
level: 7
|
|
111
|
+
},
|
|
112
|
+
source: 'custom' as const
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'spell_mastery',
|
|
116
|
+
name: 'Spell Mastery',
|
|
117
|
+
description: 'Improved control over known spells',
|
|
118
|
+
ability: 'INT' as const,
|
|
119
|
+
prerequisites: {
|
|
120
|
+
spells: ['Fireball', 'Lightning Bolt'],
|
|
121
|
+
class: 'Wizard' as const,
|
|
122
|
+
level: 10
|
|
123
|
+
},
|
|
124
|
+
source: 'custom' as const
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'dwarven_warfare',
|
|
128
|
+
name: 'Dwarven Warfare',
|
|
129
|
+
description: 'Advanced dwarven combat techniques',
|
|
130
|
+
ability: 'STR' as const,
|
|
131
|
+
prerequisites: {
|
|
132
|
+
race: 'Dwarf' as const
|
|
133
|
+
},
|
|
134
|
+
source: 'custom' as const
|
|
135
|
+
}
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
ExtensionManager.getInstance().register('skills', skills);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Spell Prerequisites
|
|
142
|
+
|
|
143
|
+
Spells can have prerequisites that must be met before they can be learned.
|
|
144
|
+
|
|
145
|
+
### SpellPrerequisite
|
|
146
|
+
|
|
147
|
+
*Also known as: spell requirements, spell conditions*
|
|
148
|
+
|
|
149
|
+
Defines conditions that must be met before a spellcaster can learn a spell.
|
|
150
|
+
|
|
151
|
+
**Location:** [`src/core/spells/SpellTypes.ts`](src/core/spells/SpellTypes.ts#L32-L59)
|
|
152
|
+
|
|
153
|
+
| Property | Type | Description |
|
|
154
|
+
|----------|------|-------------|
|
|
155
|
+
| `level` | `number?` | Minimum character level |
|
|
156
|
+
| `casterLevel` | `number?` | Minimum spellcaster level (if different from character level) |
|
|
157
|
+
| `abilities` | `Partial<Record<Ability, number>>?` | Minimum ability scores |
|
|
158
|
+
| `class` | `Class?` | Specific class required |
|
|
159
|
+
| `race` | `Race?` | Specific race required |
|
|
160
|
+
| `features` | `string[]?` | Features that must be learned first (by feature ID) |
|
|
161
|
+
| `spells` | `string[]?` | Spells that must be known first (by spell name) |
|
|
162
|
+
| `skills` | `string[]?` | Skills that must be proficient first (by skill ID) |
|
|
163
|
+
| `custom` | `string?` | Custom condition description (display only) |
|
|
164
|
+
|
|
165
|
+
### Spell.prerequisites
|
|
166
|
+
|
|
167
|
+
**Location:** [`src/core/spells/SpellTypes.ts`](src/core/spells/SpellTypes.ts#L80)
|
|
168
|
+
|
|
169
|
+
The `Spell` interface includes an optional `prerequisites?: SpellPrerequisite` property. `SpellManager` automatically filters spells by prerequisites during character generation.
|
|
170
|
+
|
|
171
|
+
### Validation
|
|
172
|
+
|
|
173
|
+
Spell prerequisites are validated automatically during:
|
|
174
|
+
|
|
175
|
+
1. **Spell Registration**: Schema validation via `SpellValidator.validateSpell()`
|
|
176
|
+
2. **Spell Assignment**: During character generation, `SpellManager` filters spells by prerequisites
|
|
177
|
+
3. **Manual Validation**: Use `SpellValidator.validateSpellPrerequisites()`
|
|
178
|
+
|
|
179
|
+
### Example Spells with Prerequisites
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { ExtensionManager, SpellManager, CharacterGenerator } from 'playlist-data-engine';
|
|
183
|
+
|
|
184
|
+
// Spell with feature + ability prerequisites
|
|
185
|
+
const dragonBreath = {
|
|
186
|
+
id: 'dragon_breath',
|
|
187
|
+
name: 'Dragon Breath',
|
|
188
|
+
level: 3,
|
|
189
|
+
school: 'Evocation',
|
|
190
|
+
casting_time: '1 action',
|
|
191
|
+
range: '60 ft cone',
|
|
192
|
+
components: ['V', 'S', 'M'],
|
|
193
|
+
duration: 'Instantaneous',
|
|
194
|
+
description: 'Exhale destructive energy',
|
|
195
|
+
prerequisites: {
|
|
196
|
+
features: ['dragon_bloodline'],
|
|
197
|
+
abilities: { CHA: 16 }
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Spell with level + class + spell prerequisites
|
|
202
|
+
const limitedMeteorSwarm = {
|
|
203
|
+
id: 'limited_meteor_swarm',
|
|
204
|
+
name: 'Meteor Swarm',
|
|
205
|
+
level: 9,
|
|
206
|
+
school: 'Evocation',
|
|
207
|
+
casting_time: '1 action',
|
|
208
|
+
range: '1 mile',
|
|
209
|
+
components: ['V', 'S'],
|
|
210
|
+
duration: 'Instantaneous',
|
|
211
|
+
description: 'Blazing orbs rain down',
|
|
212
|
+
prerequisites: {
|
|
213
|
+
level: 17,
|
|
214
|
+
class: 'Wizard',
|
|
215
|
+
spells: ['Fireball']
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Spell with skill prerequisites
|
|
220
|
+
const arcaneSwordSpell = {
|
|
221
|
+
id: 'arcane_sword',
|
|
222
|
+
name: 'Arcane Sword',
|
|
223
|
+
level: 5,
|
|
224
|
+
school: 'Evocation',
|
|
225
|
+
casting_time: '1 bonus action',
|
|
226
|
+
range: '60 ft',
|
|
227
|
+
components: ['V', 'S', 'M'],
|
|
228
|
+
duration: 'Concentration, 1 minute',
|
|
229
|
+
description: 'Summon a sword of pure magic',
|
|
230
|
+
prerequisites: {
|
|
231
|
+
skills: ['arcana']
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const manager = ExtensionManager.getInstance();
|
|
236
|
+
manager.register('spells', [dragonBreath, limitedMeteorSwarm, arcaneSwordSpell]);
|
|
237
|
+
|
|
238
|
+
// SpellManager automatically filters spells by prerequisites during character generation
|
|
239
|
+
const character = CharacterGenerator.generate(seed, audioProfile, track);
|
|
240
|
+
const knownSpells = SpellManager.getKnownSpells(character.class, character.level, character);
|
|
241
|
+
// Only includes spells whose prerequisites are met
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Feature Prerequisites
|
|
247
|
+
|
|
248
|
+
Features (class features and racial traits) can have prerequisites that must be met.
|
|
249
|
+
|
|
250
|
+
### FeaturePrerequisite
|
|
251
|
+
|
|
252
|
+
*Also known as: feature requirements, trait conditions*
|
|
253
|
+
|
|
254
|
+
Defines conditions for class features and racial traits. Note: `SkillPrerequisite` and `SpellPrerequisite` follow the same pattern for consistency.
|
|
255
|
+
|
|
256
|
+
**Location:** [`src/core/features/FeatureTypes.ts`](src/core/features/FeatureTypes.ts#L67-L94)
|
|
257
|
+
|
|
258
|
+
| Property | Type | Description |
|
|
259
|
+
|----------|------|-------------|
|
|
260
|
+
| `level` | `number?` | Minimum level required |
|
|
261
|
+
| `features` | `string[]?` | Features that must be learned first (by ID) |
|
|
262
|
+
| `abilities` | `Partial<Record<Ability, number>>?` | Minimum ability scores required |
|
|
263
|
+
| `class` | `Class?` | Specific class required |
|
|
264
|
+
| `race` | `Race?` | Specific race required |
|
|
265
|
+
| `subrace` | `string?` | Specific subrace required (e.g., 'High Elf', 'Hill Dwarf') |
|
|
266
|
+
| `skills` | `string[]?` | Skills that must be proficient first (by skill ID) |
|
|
267
|
+
| `spells` | `string[]?` | Spells that must be known first (by spell name) |
|
|
268
|
+
| `custom` | `string?` | Custom condition description (display only) |
|
|
269
|
+
|
|
270
|
+
### Validation
|
|
271
|
+
|
|
272
|
+
Feature prerequisites are validated via `FeatureQuery.validatePrerequisites()` which checks level, abilities, class, race, subrace, skills, spells, features, and custom conditions.
|
|
273
|
+
|
|
274
|
+
### Example Features with Prerequisites
|
|
275
|
+
|
|
276
|
+
| Feature | Type | Prerequisites Used |
|
|
277
|
+
|---------|------|-------------------|
|
|
278
|
+
| Arcane Mastery | Class feature | `skills`, `level` |
|
|
279
|
+
| Spellblade | Class feature | `spells`, `features` |
|
|
280
|
+
| Elven Battle Training | Racial trait | `skills`, `level` |
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { ExtensionManager } from 'playlist-data-engine';
|
|
284
|
+
|
|
285
|
+
// Class features
|
|
286
|
+
ExtensionManager.getInstance().register('classFeatures', [
|
|
287
|
+
{
|
|
288
|
+
id: 'arcane_mastery',
|
|
289
|
+
name: 'Arcane Mastery',
|
|
290
|
+
description: 'Bonus to spellcasting based on Arcana skill',
|
|
291
|
+
type: 'passive' as const,
|
|
292
|
+
level: 10,
|
|
293
|
+
class: 'Wizard' as const,
|
|
294
|
+
prerequisites: {
|
|
295
|
+
skills: ['arcana'],
|
|
296
|
+
level: 10
|
|
297
|
+
},
|
|
298
|
+
effects: [
|
|
299
|
+
{ type: 'passive_modifier' as const, target: 'spell_save_dc', value: 1 }
|
|
300
|
+
],
|
|
301
|
+
source: 'custom' as const
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: 'spellblade',
|
|
305
|
+
name: 'Spellblade',
|
|
306
|
+
description: 'Channel spells through your weapon',
|
|
307
|
+
type: 'active' as const,
|
|
308
|
+
level: 10,
|
|
309
|
+
class: 'Eldritch Knight' as const,
|
|
310
|
+
prerequisites: {
|
|
311
|
+
spells: ['Green-Flame Blade', 'Booming Blade'],
|
|
312
|
+
features: ['weapon_bond']
|
|
313
|
+
},
|
|
314
|
+
effects: [
|
|
315
|
+
{ type: 'passive_modifier' as const, target: 'spell_strike_damage', value: 4 }
|
|
316
|
+
],
|
|
317
|
+
source: 'custom' as const
|
|
318
|
+
}
|
|
319
|
+
]);
|
|
320
|
+
|
|
321
|
+
// Racial traits
|
|
322
|
+
ExtensionManager.getInstance().register('racialTraits', [{
|
|
323
|
+
id: 'elven_battle_training',
|
|
324
|
+
name: 'Elven Battle Training',
|
|
325
|
+
description: 'Advanced elven combat techniques',
|
|
326
|
+
type: 'active' as const,
|
|
327
|
+
race: 'Elf' as const,
|
|
328
|
+
prerequisites: {
|
|
329
|
+
skills: ['athletics', 'perception'],
|
|
330
|
+
level: 3
|
|
331
|
+
},
|
|
332
|
+
effects: [
|
|
333
|
+
{ type: 'passive_modifier' as const, target: 'initiative', value: 2 }
|
|
334
|
+
],
|
|
335
|
+
source: 'custom' as const
|
|
336
|
+
}]);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Validation System
|
|
340
|
+
|
|
341
|
+
### ValidationResult Interfaces
|
|
342
|
+
|
|
343
|
+
| Type | Location | Properties |
|
|
344
|
+
|------|----------|------------|
|
|
345
|
+
| `ValidationResult` | [`src/core/features/FeatureTypes.ts`](src/core/features/FeatureTypes.ts#L238-L247) | `valid: boolean`, `unmet?: string[]`, `errors?: string[]` |
|
|
346
|
+
| `SkillValidationResult` | [`src/core/skills/SkillTypes.ts`](src/core/skills/SkillTypes.ts#L239-L244) | `valid: boolean`, `errors: string[]` (required) |
|
|
347
|
+
| `SpellValidationResult` | Inferred from `SpellValidator` | `valid: boolean`, `errors: string[]` (required) |
|
|
348
|
+
|
|
349
|
+
### Skill Validation
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { SkillValidator, SkillQuery } from 'playlist-data-engine';
|
|
353
|
+
|
|
354
|
+
// Direct validation
|
|
355
|
+
const result = SkillValidator.validateSkillPrerequisites(
|
|
356
|
+
skill.prerequisites,
|
|
357
|
+
character
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
// Via registry
|
|
361
|
+
const result2 = SkillQuery.getInstance().validatePrerequisites(skill, character);
|
|
362
|
+
|
|
363
|
+
if (!result.valid) {
|
|
364
|
+
console.log('Unmet prerequisites:', result.errors);
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Spell Validation
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { SpellValidator, validateSpellPrerequisites } from 'playlist-data-engine';
|
|
372
|
+
|
|
373
|
+
// Direct validation
|
|
374
|
+
const result = SpellValidator.validateSpellPrerequisites(
|
|
375
|
+
spell.prerequisites,
|
|
376
|
+
character
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
// Helper function
|
|
380
|
+
const result2 = validateSpellPrerequisites(spell.prerequisites, character);
|
|
381
|
+
|
|
382
|
+
if (!result.valid) {
|
|
383
|
+
console.log('Unmet prerequisites:', result.errors);
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Feature Validation
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { FeatureQuery } from 'playlist-data-engine';
|
|
391
|
+
|
|
392
|
+
const registry = FeatureQuery.getInstance();
|
|
393
|
+
|
|
394
|
+
const result = registry.validatePrerequisites(feature, character);
|
|
395
|
+
|
|
396
|
+
// Access unmet prerequisites (FeatureQuery-specific)
|
|
397
|
+
if (!result.valid) {
|
|
398
|
+
console.log('Unmet prerequisites:', result.unmet || result.errors);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Or check boolean directly
|
|
402
|
+
const canLearn = registry.meetsPrerequisites(feature, character);
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
### Prerequisite Validation Rules
|
|
408
|
+
|
|
409
|
+
| Field | Schema Validation | Runtime Check |
|
|
410
|
+
|-------|------------------|---------------|
|
|
411
|
+
| `level` | Number between 1-20 | Compares character level against required |
|
|
412
|
+
| `abilities` | Valid ability keys, scores 1-20 | Checks ability scores meet minimum |
|
|
413
|
+
| `class` | Valid D&D 5e class or registered custom class | Matches character's class |
|
|
414
|
+
| `race` | Valid default race or registered custom race | Matches character's race |
|
|
415
|
+
| `subrace` | Non-empty string | Matches character's subrace |
|
|
416
|
+
| `features` | Array of feature ID strings | IDs in `class_features` array |
|
|
417
|
+
| `skills` | Valid skill IDs (lowercase_with_underscores) | Skills proficient or expertise |
|
|
418
|
+
| `spells` | Array of spell name strings | In `known_spells` or `cantrips` |
|
|
419
|
+
| `custom` | String | Displayed only, not validated |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Examples
|
|
424
|
+
|
|
425
|
+
### Subrace-Specific Prerequisites
|
|
426
|
+
|
|
427
|
+
Races with subraces can have traits that only apply to specific subraces using the `subrace` prerequisite field:
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { ExtensionManager } from 'playlist-data-engine';
|
|
431
|
+
|
|
432
|
+
// Register a custom race with subraces
|
|
433
|
+
const manager = ExtensionManager.getInstance();
|
|
434
|
+
manager.register('races.data', [{
|
|
435
|
+
race: 'Dragonkin',
|
|
436
|
+
ability_bonuses: { STR: 2, CON: 1, CHA: 1 },
|
|
437
|
+
speed: 30,
|
|
438
|
+
traits: ['Draconic Ancestry', 'Darkvision'],
|
|
439
|
+
subraces: ['Fire Dragonkin', 'Ice Dragonkin', 'Lightning Dragonkin']
|
|
440
|
+
}]);
|
|
441
|
+
manager.register('races', ['Dragonkin']);
|
|
442
|
+
|
|
443
|
+
// Register a subrace-specific trait
|
|
444
|
+
manager.register('racialTraits', [{
|
|
445
|
+
id: 'fire_dragonkin_fire_resistance',
|
|
446
|
+
name: 'Fire Resistance',
|
|
447
|
+
description: 'You have resistance to fire damage.',
|
|
448
|
+
race: 'Dragonkin',
|
|
449
|
+
subrace: 'Fire Dragonkin',
|
|
450
|
+
prerequisites: { subrace: 'Fire Dragonkin' }, // Only Fire Dragonkin get this
|
|
451
|
+
effects: [
|
|
452
|
+
{ type: 'ability_unlock', target: 'fire_resistance', value: true }
|
|
453
|
+
],
|
|
454
|
+
source: 'custom'
|
|
455
|
+
}]);
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Example: Prerequisite Chains
|
|
459
|
+
|
|
460
|
+
Skills and spells can form chains by requiring each other:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
// Basic skill
|
|
464
|
+
const herbLore = {
|
|
465
|
+
id: 'herb_lore',
|
|
466
|
+
name: 'Herb Lore',
|
|
467
|
+
ability: 'WIS',
|
|
468
|
+
source: 'custom'
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// Advanced skill requiring the basic one
|
|
472
|
+
const advancedHerbalism = {
|
|
473
|
+
id: 'advanced_herbalism',
|
|
474
|
+
name: 'Advanced Herbalism',
|
|
475
|
+
ability: 'INT',
|
|
476
|
+
prerequisites: {
|
|
477
|
+
skills: ['herb_lore'], // Must know Herb Lore first
|
|
478
|
+
level: 5
|
|
479
|
+
},
|
|
480
|
+
source: 'custom'
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// Master skill requiring both
|
|
484
|
+
const masterHerbalist = {
|
|
485
|
+
id: 'master_herbalist',
|
|
486
|
+
name: 'Master Herbalist',
|
|
487
|
+
ability: 'INT',
|
|
488
|
+
prerequisites: {
|
|
489
|
+
skills: ['herb_lore', 'advanced_herbalism'],
|
|
490
|
+
features: [' Herbalist_certification'],
|
|
491
|
+
level: 10
|
|
492
|
+
},
|
|
493
|
+
source: 'custom'
|
|
494
|
+
};
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## API Reference
|
|
500
|
+
|
|
501
|
+
### SkillValidator
|
|
502
|
+
|
|
503
|
+
**Location:** [`src/core/skills/SkillValidator.ts`](src/core/skills/SkillValidator.ts)
|
|
504
|
+
|
|
505
|
+
| Method | Returns | Description |
|
|
506
|
+
|--------|---------|-------------|
|
|
507
|
+
| `validateSkillPrerequisites(prerequisites, character)` | `SkillValidationResult` | Validate skill prerequisites against a character |
|
|
508
|
+
| `validateSkill(skill)` | `SkillValidationResult` | Validate skill schema including prerequisites |
|
|
509
|
+
|
|
510
|
+
### SpellValidator
|
|
511
|
+
|
|
512
|
+
**Location:** [`src/core/spells/SpellValidator.ts`](src/core/spells/SpellValidator.ts)
|
|
513
|
+
|
|
514
|
+
| Method | Returns | Description |
|
|
515
|
+
|--------|---------|-------------|
|
|
516
|
+
| `validateSpellPrerequisites(prerequisites, character)` | `SpellValidationResult` | Validate spell prerequisites against a character |
|
|
517
|
+
| `validateSpell(spell)` | `boolean` | Validate spell schema including prerequisites |
|
|
518
|
+
|
|
519
|
+
### FeatureQuery
|
|
520
|
+
|
|
521
|
+
**Location:** [`src/core/features/FeatureQuery.ts`](src/core/features/FeatureQuery.ts)
|
|
522
|
+
|
|
523
|
+
| Method | Returns | Description |
|
|
524
|
+
|--------|---------|-------------|
|
|
525
|
+
| `validatePrerequisites(feature, character)` | `ValidationResult` | Validate feature prerequisites against a character |
|
|
526
|
+
| `meetsPrerequisites(feature, character)` | `boolean` | Boolean check if prerequisites are met |
|
|
527
|
+
| `getRacialTraitsForSubrace(race, subrace)` | `RacialTrait[]` | Get traits for a specific subrace |
|
|
528
|
+
|
|
529
|
+
### SkillQuery
|
|
530
|
+
|
|
531
|
+
**Location:** [`src/core/skills/SkillQuery.ts`](src/core/skills/SkillQuery.ts)
|
|
532
|
+
|
|
533
|
+
| Method | Returns | Description |
|
|
534
|
+
|--------|---------|-------------|
|
|
535
|
+
| `validatePrerequisites(skill, character)` | `SkillValidationResult` | Validate skill prerequisites via SkillQuery |
|
|
536
|
+
|
|
537
|
+
### ExtensionManager
|
|
538
|
+
|
|
539
|
+
**Location:** [`src/core/extensions/ExtensionManager.ts`](src/core/extensions/ExtensionManager.ts)
|
|
540
|
+
|
|
541
|
+
| Method | Returns | Description |
|
|
542
|
+
|--------|---------|-------------|
|
|
543
|
+
| `register(category, items, options?)` | `void` | Register custom races, spells, skills, features, or other content |
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Best Practices
|
|
548
|
+
|
|
549
|
+
1. **Use Prerequisites Judiciously**: Not every skill/spell needs prerequisites. Use them for:
|
|
550
|
+
- Advanced/specialized content
|
|
551
|
+
- Class or race-specific abilities
|
|
552
|
+
- Progression chains (basic → advanced → master)
|
|
553
|
+
|
|
554
|
+
2. **Provide Clear Descriptions**: When a prerequisite isn't met, the error message should clearly explain why
|
|
555
|
+
|
|
556
|
+
3. **Test Prerequisite Chains**: If skills/spells require each other, ensure there are no circular dependencies
|
|
557
|
+
|
|
558
|
+
4. **Consider Custom Conditions**: Use the `custom` field for prerequisites that don't fit the standard types
|
|
559
|
+
|
|
560
|
+
5. **Document Custom Content**: When creating custom content with prerequisites, document the requirements clearly
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## See Also
|
|
565
|
+
|
|
566
|
+
- [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md) - Complete API reference
|
|
567
|
+
- [CUSTOM_CONTENT.md](CUSTOM_CONTENT.md) - Custom races and classes guide
|
|
568
|
+
- [USAGE_IN_OTHER_PROJECTS.md](../USAGE_IN_OTHER_PROJECTS.md) - Usage examples
|
|
569
|
+
- [EXTENSIBILITY_GUIDE.md](EXTENSIBILITY_GUIDE.md) - Custom content registration
|
|
570
|
+
- [XP_AND_STATS.md](XP_AND_STATS.md) - Progression and level requirements
|
|
571
|
+
- [EQUIPMENT_SYSTEM.md](EQUIPMENT_SYSTEM.md) - Equipment with prerequisites
|