@alpaca-software/40kdc-data 0.1.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 +78 -0
- package/dist/bundle-schemas.d.ts +3 -0
- package/dist/bundle-schemas.js +137 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +31 -0
- package/dist/codegen-data.d.ts +1 -0
- package/dist/codegen-data.js +128 -0
- package/dist/commands/translate.d.ts +7 -0
- package/dist/commands/translate.js +238 -0
- package/dist/commands/validate-all.d.ts +3 -0
- package/dist/commands/validate-all.js +20 -0
- package/dist/commands/validate-core.d.ts +3 -0
- package/dist/commands/validate-core.js +12 -0
- package/dist/commands/validate-enrichment.d.ts +3 -0
- package/dist/commands/validate-enrichment.js +12 -0
- package/dist/convert-faction.d.ts +45 -0
- package/dist/convert-faction.js +479 -0
- package/dist/converters/configs/adepta-sororitas.d.ts +3 -0
- package/dist/converters/configs/adepta-sororitas.js +70 -0
- package/dist/converters/configs/adeptus-astartes.d.ts +3 -0
- package/dist/converters/configs/adeptus-astartes.js +74 -0
- package/dist/converters/configs/adeptus-custodes.d.ts +3 -0
- package/dist/converters/configs/adeptus-custodes.js +14 -0
- package/dist/converters/configs/adeptus-mechanicus.d.ts +3 -0
- package/dist/converters/configs/adeptus-mechanicus.js +51 -0
- package/dist/converters/configs/aeldari.d.ts +3 -0
- package/dist/converters/configs/aeldari.js +79 -0
- package/dist/converters/configs/agents-of-the-imperium.d.ts +3 -0
- package/dist/converters/configs/agents-of-the-imperium.js +57 -0
- package/dist/converters/configs/astra-militarum.d.ts +3 -0
- package/dist/converters/configs/astra-militarum.js +80 -0
- package/dist/converters/configs/black-templars.d.ts +3 -0
- package/dist/converters/configs/black-templars.js +16 -0
- package/dist/converters/configs/blood-angels.d.ts +3 -0
- package/dist/converters/configs/blood-angels.js +16 -0
- package/dist/converters/configs/chaos-daemons.d.ts +3 -0
- package/dist/converters/configs/chaos-daemons.js +40 -0
- package/dist/converters/configs/chaos-knights.d.ts +3 -0
- package/dist/converters/configs/chaos-knights.js +14 -0
- package/dist/converters/configs/chaos-space-marines.d.ts +3 -0
- package/dist/converters/configs/chaos-space-marines.js +95 -0
- package/dist/converters/configs/crimson-fists.d.ts +3 -0
- package/dist/converters/configs/crimson-fists.js +16 -0
- package/dist/converters/configs/dark-angels.d.ts +3 -0
- package/dist/converters/configs/dark-angels.js +16 -0
- package/dist/converters/configs/death-guard.d.ts +3 -0
- package/dist/converters/configs/death-guard.js +30 -0
- package/dist/converters/configs/deathwatch.d.ts +3 -0
- package/dist/converters/configs/deathwatch.js +16 -0
- package/dist/converters/configs/drukhari.d.ts +3 -0
- package/dist/converters/configs/drukhari.js +51 -0
- package/dist/converters/configs/emperors-children.d.ts +3 -0
- package/dist/converters/configs/emperors-children.js +38 -0
- package/dist/converters/configs/genestealer-cults.d.ts +3 -0
- package/dist/converters/configs/genestealer-cults.js +36 -0
- package/dist/converters/configs/grey-knights.d.ts +3 -0
- package/dist/converters/configs/grey-knights.js +39 -0
- package/dist/converters/configs/imperial-fists.d.ts +3 -0
- package/dist/converters/configs/imperial-fists.js +16 -0
- package/dist/converters/configs/imperial-knights.d.ts +3 -0
- package/dist/converters/configs/imperial-knights.js +14 -0
- package/dist/converters/configs/iron-hands.d.ts +3 -0
- package/dist/converters/configs/iron-hands.js +16 -0
- package/dist/converters/configs/leagues-of-votann.d.ts +3 -0
- package/dist/converters/configs/leagues-of-votann.js +32 -0
- package/dist/converters/configs/necrons.d.ts +3 -0
- package/dist/converters/configs/necrons.js +19 -0
- package/dist/converters/configs/orks.d.ts +3 -0
- package/dist/converters/configs/orks.js +71 -0
- package/dist/converters/configs/raven-guard.d.ts +3 -0
- package/dist/converters/configs/raven-guard.js +16 -0
- package/dist/converters/configs/salamanders.d.ts +3 -0
- package/dist/converters/configs/salamanders.js +16 -0
- package/dist/converters/configs/space-wolves.d.ts +3 -0
- package/dist/converters/configs/space-wolves.js +16 -0
- package/dist/converters/configs/tau-empire.d.ts +3 -0
- package/dist/converters/configs/tau-empire.js +44 -0
- package/dist/converters/configs/thousand-sons.d.ts +3 -0
- package/dist/converters/configs/thousand-sons.js +30 -0
- package/dist/converters/configs/tyranids.d.ts +3 -0
- package/dist/converters/configs/tyranids.js +27 -0
- package/dist/converters/configs/ultramarines.d.ts +3 -0
- package/dist/converters/configs/ultramarines.js +16 -0
- package/dist/converters/configs/white-scars.d.ts +3 -0
- package/dist/converters/configs/white-scars.js +16 -0
- package/dist/converters/configs/world-eaters.d.ts +3 -0
- package/dist/converters/configs/world-eaters.js +43 -0
- package/dist/converters/faction-config.d.ts +53 -0
- package/dist/converters/faction-config.js +22 -0
- package/dist/converters/id-generator.d.ts +14 -0
- package/dist/converters/id-generator.js +65 -0
- package/dist/converters/keyword-filter.d.ts +26 -0
- package/dist/converters/keyword-filter.js +78 -0
- package/dist/converters/stat-parser.d.ts +22 -0
- package/dist/converters/stat-parser.js +84 -0
- package/dist/converters/view-selector.d.ts +54 -0
- package/dist/converters/view-selector.js +96 -0
- package/dist/converters/weapon-dedup.d.ts +60 -0
- package/dist/converters/weapon-dedup.js +120 -0
- package/dist/data/bundle.generated.d.ts +3 -0
- package/dist/data/bundle.generated.js +3 -0
- package/dist/data/collection.d.ts +64 -0
- package/dist/data/collection.js +118 -0
- package/dist/data/dataset.d.ts +50 -0
- package/dist/data/dataset.js +134 -0
- package/dist/data/entities.d.ts +80 -0
- package/dist/data/entities.js +133 -0
- package/dist/data/index.d.ts +59 -0
- package/dist/data/index.js +57 -0
- package/dist/data/normalize.d.ts +29 -0
- package/dist/data/normalize.js +37 -0
- package/dist/data/types.d.ts +43 -0
- package/dist/data/types.js +25 -0
- package/dist/generated.d.ts +1084 -0
- package/dist/generated.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/known-support-10e.d.ts +31 -0
- package/dist/known-support-10e.js +113 -0
- package/dist/port-10e-faction.d.ts +52 -0
- package/dist/port-10e-faction.js +413 -0
- package/dist/report.d.ts +3 -0
- package/dist/report.js +31 -0
- package/dist/schema-loader.d.ts +15 -0
- package/dist/schema-loader.js +79 -0
- package/dist/validate.d.ts +21 -0
- package/dist/validate.js +124 -0
- package/package.json +77 -0
- package/schemas/$defs/common.schema.json +86 -0
- package/schemas/$defs/game-version-ref.schema.json +11 -0
- package/schemas/core/deployment-pattern.schema.json +102 -0
- package/schemas/core/detachment.schema.json +56 -0
- package/schemas/core/enhancement.schema.json +46 -0
- package/schemas/core/faction.schema.json +29 -0
- package/schemas/core/force-disposition.schema.json +22 -0
- package/schemas/core/game-version.schema.json +20 -0
- package/schemas/core/leader-attachment.schema.json +18 -0
- package/schemas/core/mission-matchup.schema.json +25 -0
- package/schemas/core/mission.schema.json +42 -0
- package/schemas/core/roster.schema.json +203 -0
- package/schemas/core/secondary-card.schema.json +195 -0
- package/schemas/core/stratagem.schema.json +58 -0
- package/schemas/core/terrain-layout.schema.json +135 -0
- package/schemas/core/unit-composition.schema.json +38 -0
- package/schemas/core/unit.schema.json +125 -0
- package/schemas/core/wargear-option.schema.json +47 -0
- package/schemas/core/weapon.schema.json +56 -0
- package/schemas/enrichment/ability-dsl/ability.schema.json +60 -0
- package/schemas/enrichment/ability-dsl/condition.schema.json +48 -0
- package/schemas/enrichment/ability-dsl/effect.schema.json +145 -0
- package/schemas/enrichment/ability-dsl/scope.schema.json +12 -0
- package/schemas/enrichment/interaction-flag.schema.json +17 -0
- package/schemas/enrichment/phase-mapping.schema.json +14 -0
- package/schemas/enrichment/resource-pool.schema.json +36 -0
- package/schemas/enrichment/timing-flag.schema.json +28 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/terrain-layout.schema.json",
|
|
4
|
+
"title": "Terrain Layout",
|
|
5
|
+
"description": "A recommended arrangement of terrain pieces on the board, independent of the deployment map (a deployment-pattern references the layouts it recommends via recommended_terrain_layout_ids). Geometry is the source of truth; the GW standard piece templates are expressed as explicit footprints, with an optional descriptive `template` label. Footprints are deliberately open (not enum-locked) — the launch catalog and its size are unconfirmed, so this models any shape rather than a fixed set. No layout data is authored yet.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"$defs": {
|
|
8
|
+
"footprint": {
|
|
9
|
+
"description": "A terrain piece's 2D footprint, relative to the piece's `position`. Axis-aligned rectangle, right triangle (right angle at the local origin, legs along +x/+y), or an explicit polygon. GW's standard templates (e.g. 7\"×11.5\" rectangles, 8\"×11.5\" right triangles, 6\"×4\" rectangles, 10\"×2.5\" and 6\"×2\" lines) are all expressible here; lines are thin rectangles.",
|
|
10
|
+
"oneOf": [
|
|
11
|
+
{
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"type": { "const": "rectangle" },
|
|
15
|
+
"width": { "type": "number", "exclusiveMinimum": 0 },
|
|
16
|
+
"height": { "type": "number", "exclusiveMinimum": 0 }
|
|
17
|
+
},
|
|
18
|
+
"required": ["type", "width", "height"],
|
|
19
|
+
"additionalProperties": false
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"type": { "const": "right-triangle" },
|
|
25
|
+
"width": { "type": "number", "exclusiveMinimum": 0 },
|
|
26
|
+
"height": { "type": "number", "exclusiveMinimum": 0 }
|
|
27
|
+
},
|
|
28
|
+
"required": ["type", "width", "height"],
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"type": { "const": "polygon" },
|
|
35
|
+
"points": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/vec2" },
|
|
38
|
+
"minItems": 3
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"required": ["type", "points"],
|
|
42
|
+
"additionalProperties": false
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"terrain-area-keyword": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"enum": ["obscuring", "hidden", "plunging-fire"],
|
|
49
|
+
"description": "An 11e terrain-area keyword. Confirmed launch set; extend as further keywords publish on dataslate."
|
|
50
|
+
},
|
|
51
|
+
"piece": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "One terrain feature placed on the board.",
|
|
54
|
+
"properties": {
|
|
55
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
56
|
+
"footprint": { "$ref": "#/$defs/footprint" },
|
|
57
|
+
"position": {
|
|
58
|
+
"$ref": "../defs/common.schema.json#/$defs/vec2",
|
|
59
|
+
"description": "Board-inch placement of the footprint's local origin."
|
|
60
|
+
},
|
|
61
|
+
"rotation_degrees": {
|
|
62
|
+
"type": "number",
|
|
63
|
+
"minimum": 0,
|
|
64
|
+
"exclusiveMaximum": 360,
|
|
65
|
+
"description": "Clockwise rotation of the footprint about `position`. Absent or 0 means axis-aligned."
|
|
66
|
+
},
|
|
67
|
+
"template": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"minLength": 1,
|
|
70
|
+
"maxLength": 64,
|
|
71
|
+
"description": "Optional descriptive label for the GW standard template this piece uses (e.g. 'large-ruin', 'long-wall'). Free-form, not enum-locked — the geometry in `footprint` is authoritative."
|
|
72
|
+
},
|
|
73
|
+
"height_inches": {
|
|
74
|
+
"type": "number",
|
|
75
|
+
"minimum": 0,
|
|
76
|
+
"description": "Height of the piece in inches. Gates Plunging Fire (a piece 3\" or taller confers +1 BS on ground-level targets)."
|
|
77
|
+
},
|
|
78
|
+
"terrain_area_keywords": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"uniqueItems": true,
|
|
81
|
+
"description": "Terrain-area keywords this piece's area carries.",
|
|
82
|
+
"items": { "$ref": "#/$defs/terrain-area-keyword" }
|
|
83
|
+
},
|
|
84
|
+
"link_group": {
|
|
85
|
+
"type": "string",
|
|
86
|
+
"minLength": 1,
|
|
87
|
+
"maxLength": 64,
|
|
88
|
+
"description": "Pieces sharing a `link_group` value are linked terrain — treated as a single terrain feature (and, where an objective sits among them, a single objective)."
|
|
89
|
+
},
|
|
90
|
+
"is_objective": {
|
|
91
|
+
"type": "boolean",
|
|
92
|
+
"default": false,
|
|
93
|
+
"description": "Whether this piece carries an objective marker."
|
|
94
|
+
},
|
|
95
|
+
"objective": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "Objective-marker metadata. Only meaningful when `is_objective` is true.",
|
|
98
|
+
"properties": {
|
|
99
|
+
"position": {
|
|
100
|
+
"$ref": "../defs/common.schema.json#/$defs/vec2",
|
|
101
|
+
"description": "Board-inch position of the marker. Absent means the piece's `position`."
|
|
102
|
+
},
|
|
103
|
+
"control_range_inches": {
|
|
104
|
+
"type": "number",
|
|
105
|
+
"exclusiveMinimum": 0,
|
|
106
|
+
"description": "Range from the marker within which models contribute to control."
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"additionalProperties": false
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"required": ["footprint", "position"],
|
|
113
|
+
"additionalProperties": false
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"properties": {
|
|
117
|
+
"id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
118
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
119
|
+
"source": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1,
|
|
122
|
+
"maxLength": 64,
|
|
123
|
+
"description": "Mission pack or source the layout originates from."
|
|
124
|
+
},
|
|
125
|
+
"description": { "type": "string" },
|
|
126
|
+
"pieces": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"description": "Terrain pieces composing the layout. May be empty while a layout is registered by name ahead of its confirmed geometry.",
|
|
129
|
+
"items": { "$ref": "#/$defs/piece" }
|
|
130
|
+
},
|
|
131
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
132
|
+
},
|
|
133
|
+
"required": ["id", "name", "game_version"],
|
|
134
|
+
"additionalProperties": false
|
|
135
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/unit-composition.schema.json",
|
|
4
|
+
"title": "Unit Composition",
|
|
5
|
+
"description": "Describes the internal model-type breakdown of a unit.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"unit_id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"models": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"name": { "type": "string", "minLength": 1 },
|
|
15
|
+
"profile_name": {
|
|
16
|
+
"oneOf": [
|
|
17
|
+
{ "type": "string", "minLength": 1 },
|
|
18
|
+
{ "type": "null" }
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"min": { "type": "integer", "minimum": 0 },
|
|
22
|
+
"max": { "type": "integer", "minimum": 1 },
|
|
23
|
+
"default_weapon_ids": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/entity-id" }
|
|
26
|
+
},
|
|
27
|
+
"is_leader_model": { "type": "boolean", "default": false }
|
|
28
|
+
},
|
|
29
|
+
"required": ["name", "min", "max"],
|
|
30
|
+
"additionalProperties": false
|
|
31
|
+
},
|
|
32
|
+
"minItems": 1
|
|
33
|
+
},
|
|
34
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
35
|
+
},
|
|
36
|
+
"required": ["unit_id", "models", "game_version"],
|
|
37
|
+
"additionalProperties": false
|
|
38
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/unit.schema.json",
|
|
4
|
+
"title": "Unit",
|
|
5
|
+
"description": "A unit datasheet entry with stat profiles and point costs.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
10
|
+
"faction_id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
11
|
+
"role": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["character", "battleline", "dedicated-transport", "fortification", "allied", "epic-hero"],
|
|
14
|
+
"description": "Battlefield role from the datasheet header. Unit types (Infantry, Vehicle, etc.) belong in keywords."
|
|
15
|
+
},
|
|
16
|
+
"attachment_role": {
|
|
17
|
+
"oneOf": [
|
|
18
|
+
{ "enum": ["leader", "support"] },
|
|
19
|
+
{ "type": "null" }
|
|
20
|
+
],
|
|
21
|
+
"description": "Character attachment role (11e). 'support' implies the unit is only legal when attached to a host unit (cannot be taken solo); 'leader' is valid as a standalone list entry. null/absent for non-attaching units."
|
|
22
|
+
},
|
|
23
|
+
"profiles": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"name": { "type": "string", "description": "Profile name (e.g., 'Wounded' for degrading)" },
|
|
29
|
+
"M": { "$ref": "../defs/common.schema.json#/$defs/stat-value" },
|
|
30
|
+
"T": { "type": "integer", "minimum": 1 },
|
|
31
|
+
"W": { "type": "integer", "minimum": 1 },
|
|
32
|
+
"Sv": { "type": "integer", "minimum": 2, "maximum": 7 },
|
|
33
|
+
"invuln_sv": {
|
|
34
|
+
"oneOf": [
|
|
35
|
+
{ "type": "integer", "minimum": 2, "maximum": 6 },
|
|
36
|
+
{ "type": "null" }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"Ld": { "type": "integer", "minimum": 2, "maximum": 10 },
|
|
40
|
+
"OC": { "type": "integer", "minimum": 0 }
|
|
41
|
+
},
|
|
42
|
+
"required": ["M", "T", "W", "Sv", "Ld", "OC"]
|
|
43
|
+
},
|
|
44
|
+
"minItems": 1
|
|
45
|
+
},
|
|
46
|
+
"points": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {
|
|
51
|
+
"models": { "type": "integer", "minimum": 1 },
|
|
52
|
+
"cost": { "type": "integer", "minimum": 0 }
|
|
53
|
+
},
|
|
54
|
+
"required": ["models", "cost"]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"points_provisional": {
|
|
58
|
+
"type": "boolean",
|
|
59
|
+
"default": false,
|
|
60
|
+
"description": "True when point costs are carried over provisionally (e.g. seeded from a prior edition during migration) and not yet confirmed against the current dataslate."
|
|
61
|
+
},
|
|
62
|
+
"keywords": { "$ref": "../defs/common.schema.json#/$defs/keyword-list" },
|
|
63
|
+
"faction_keywords": { "$ref": "../defs/common.schema.json#/$defs/keyword-list" },
|
|
64
|
+
"base_size_mm": {
|
|
65
|
+
"oneOf": [
|
|
66
|
+
{
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"shape": { "enum": ["round", "oval"] },
|
|
70
|
+
"diameter": { "type": "number" },
|
|
71
|
+
"width": { "type": "number" },
|
|
72
|
+
"length": { "type": "number" }
|
|
73
|
+
},
|
|
74
|
+
"required": ["shape"]
|
|
75
|
+
},
|
|
76
|
+
{ "type": "null" }
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"model_count": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"properties": {
|
|
82
|
+
"min": { "type": "integer", "minimum": 1 },
|
|
83
|
+
"max": { "type": "integer", "minimum": 1 }
|
|
84
|
+
},
|
|
85
|
+
"required": ["min", "max"]
|
|
86
|
+
},
|
|
87
|
+
"weapon_ids": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/entity-id" }
|
|
90
|
+
},
|
|
91
|
+
"ability_ids": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/entity-id" }
|
|
94
|
+
},
|
|
95
|
+
"transport_capacity": {
|
|
96
|
+
"oneOf": [
|
|
97
|
+
{
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": {
|
|
100
|
+
"capacity": { "type": "integer", "minimum": 1 },
|
|
101
|
+
"keyword_restrictions": {
|
|
102
|
+
"oneOf": [
|
|
103
|
+
{ "$ref": "../defs/common.schema.json#/$defs/keyword-list" },
|
|
104
|
+
{ "type": "null" }
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"exclusion_keywords": {
|
|
108
|
+
"oneOf": [
|
|
109
|
+
{ "$ref": "../defs/common.schema.json#/$defs/keyword-list" },
|
|
110
|
+
{ "type": "null" }
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"required": ["capacity"],
|
|
115
|
+
"additionalProperties": false
|
|
116
|
+
},
|
|
117
|
+
{ "type": "null" }
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" },
|
|
121
|
+
"is_legend": { "type": "boolean", "default": false }
|
|
122
|
+
},
|
|
123
|
+
"required": ["id", "name", "faction_id", "profiles", "game_version"],
|
|
124
|
+
"additionalProperties": false
|
|
125
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/wargear-option.schema.json",
|
|
4
|
+
"title": "Wargear Option",
|
|
5
|
+
"description": "A weapon substitution option available to models within a unit.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"unit_id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
10
|
+
"model_constraint": {
|
|
11
|
+
"oneOf": [
|
|
12
|
+
{
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"model_name": { "type": "string", "minLength": 1 },
|
|
16
|
+
"per_n_models": { "type": "integer", "minimum": 1 },
|
|
17
|
+
"max_count": { "type": "integer", "minimum": 1 }
|
|
18
|
+
},
|
|
19
|
+
"additionalProperties": false
|
|
20
|
+
},
|
|
21
|
+
{ "type": "null" }
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"replaces": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
27
|
+
"minItems": 1,
|
|
28
|
+
"description": "Weapon IDs being removed"
|
|
29
|
+
},
|
|
30
|
+
"replacement": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
33
|
+
"minItems": 1,
|
|
34
|
+
"description": "Weapon IDs being added"
|
|
35
|
+
},
|
|
36
|
+
"is_free": { "type": "boolean", "default": true },
|
|
37
|
+
"additional_cost": {
|
|
38
|
+
"oneOf": [
|
|
39
|
+
{ "type": "integer", "minimum": 0 },
|
|
40
|
+
{ "type": "null" }
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
44
|
+
},
|
|
45
|
+
"required": ["id", "unit_id", "replaces", "replacement", "game_version"],
|
|
46
|
+
"additionalProperties": false
|
|
47
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/core/weapon.schema.json",
|
|
4
|
+
"title": "Weapon",
|
|
5
|
+
"description": "A weapon entry with one or more stat profiles (e.g., standard and overcharge modes).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": { "$ref": "../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
10
|
+
"type": { "enum": ["ranged", "melee"] },
|
|
11
|
+
"profiles": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
17
|
+
"range": {
|
|
18
|
+
"oneOf": [
|
|
19
|
+
{ "type": "integer", "minimum": 0 },
|
|
20
|
+
{ "type": "string", "const": "Melee" }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"stats": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"A": { "$ref": "../defs/common.schema.json#/$defs/stat-value" },
|
|
27
|
+
"BS": {
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{ "type": "integer", "minimum": 2, "maximum": 6 },
|
|
30
|
+
{ "type": "null" }
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"WS": {
|
|
34
|
+
"oneOf": [
|
|
35
|
+
{ "type": "integer", "minimum": 2, "maximum": 6 },
|
|
36
|
+
{ "type": "null" }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"S": { "$ref": "../defs/common.schema.json#/$defs/stat-value" },
|
|
40
|
+
"AP": { "type": "integer" },
|
|
41
|
+
"D": { "$ref": "../defs/common.schema.json#/$defs/stat-value" }
|
|
42
|
+
},
|
|
43
|
+
"required": ["A", "S", "AP", "D"]
|
|
44
|
+
},
|
|
45
|
+
"keywords": { "$ref": "../defs/common.schema.json#/$defs/keyword-list" }
|
|
46
|
+
},
|
|
47
|
+
"required": ["name", "stats"],
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
},
|
|
50
|
+
"minItems": 1
|
|
51
|
+
},
|
|
52
|
+
"game_version": { "$ref": "../defs/game-version-ref.schema.json" }
|
|
53
|
+
},
|
|
54
|
+
"required": ["id", "name", "type", "profiles", "game_version"],
|
|
55
|
+
"additionalProperties": false
|
|
56
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/enrichment/ability-dsl/ability.schema.json",
|
|
4
|
+
"title": "Ability DSL Entry",
|
|
5
|
+
"description": "Community-authored structured representation of what a game ability does. NOT GW text.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"ability_id": { "$ref": "../../defs/common.schema.json#/$defs/entity-id" },
|
|
9
|
+
"name": { "type": "string" },
|
|
10
|
+
"authored_by": { "$ref": "../../defs/common.schema.json#/$defs/contributor-ref" },
|
|
11
|
+
"game_version": { "$ref": "../../defs/game-version-ref.schema.json" },
|
|
12
|
+
"version": { "$ref": "../../defs/common.schema.json#/$defs/dataslate-version" },
|
|
13
|
+
"supersedes": {
|
|
14
|
+
"oneOf": [
|
|
15
|
+
{ "$ref": "../../defs/common.schema.json#/$defs/dataslate-version" },
|
|
16
|
+
{ "type": "null" }
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"unit_ids": { "type": "array", "items": { "$ref": "../../defs/common.schema.json#/$defs/entity-id" } },
|
|
20
|
+
"faction_id": {
|
|
21
|
+
"oneOf": [
|
|
22
|
+
{ "$ref": "../../defs/common.schema.json#/$defs/entity-id" },
|
|
23
|
+
{ "type": "null" }
|
|
24
|
+
],
|
|
25
|
+
"description": "For faction-type abilities, the faction this rule belongs to"
|
|
26
|
+
},
|
|
27
|
+
"detachment_id": {
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{ "$ref": "../../defs/common.schema.json#/$defs/entity-id" },
|
|
30
|
+
{ "type": "null" }
|
|
31
|
+
],
|
|
32
|
+
"description": "For detachment/enhancement/stratagem-type abilities, the associated detachment"
|
|
33
|
+
},
|
|
34
|
+
"ability_type": { "type": "string", "enum": ["core", "faction", "detachment", "unit", "enhancement", "stratagem"] },
|
|
35
|
+
"behavior": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": ["passive", "activated", "reactive", "aura"],
|
|
38
|
+
"description": "How this ability interacts with the game flow — not a runtime predicate"
|
|
39
|
+
},
|
|
40
|
+
"effect": { "$ref": "effect.schema.json" },
|
|
41
|
+
"scope": { "$ref": "scope.schema.json" },
|
|
42
|
+
"interactions": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"ability_ref": { "$ref": "../../defs/common.schema.json#/$defs/entity-id" },
|
|
48
|
+
"type": { "type": "string", "enum": ["conflicts-with", "combos-with", "superseded-by", "requires", "replaces"] },
|
|
49
|
+
"notes": { "type": "string" }
|
|
50
|
+
},
|
|
51
|
+
"required": ["ability_ref", "type"]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"disputed": { "type": "boolean", "default": false },
|
|
55
|
+
"dispute_notes": { "type": "string" },
|
|
56
|
+
"community_notes": { "type": "string" }
|
|
57
|
+
},
|
|
58
|
+
"required": ["ability_id", "name", "authored_by", "game_version", "effect", "scope"],
|
|
59
|
+
"additionalProperties": false
|
|
60
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/enrichment/ability-dsl/condition.schema.json",
|
|
4
|
+
"title": "Ability Condition",
|
|
5
|
+
"$defs": {
|
|
6
|
+
"condition-node": {
|
|
7
|
+
"oneOf": [
|
|
8
|
+
{ "$ref": "#/$defs/simple-condition" },
|
|
9
|
+
{ "$ref": "#/$defs/compound-condition" }
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"simple-condition": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"$comment": "Board/meta-state and scoring predicates. `parameters` is intentionally open (additionalProperties: true); each type documents its own param convention. Scoring predicates added for mission cards: `units-destroyed` { side: 'enemy'|'friendly', window: 'this-turn'|'previous-turn', count_min: int } — at least count_min units of `side` were destroyed in `window`. `units-destroyed-comparison` { subject: {side, window}, comparator: 'greater-than'|'greater-or-equal', reference: {side, window} } — compares two destruction tallies (e.g. more enemy units destroyed this turn than friendly last turn). `objective-majority` { relative_to: 'opponent' } — you control more objectives than the named party. `controls-objective` params: { count_min: int, objective_role?: 'central', exclude?: 'home', objective?: 'opponent-home' }.",
|
|
15
|
+
"properties": {
|
|
16
|
+
"type": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"enum": [
|
|
19
|
+
"phase-is", "timing-is", "player-turn-is",
|
|
20
|
+
"unit-below-starting-strength", "unit-below-half-strength",
|
|
21
|
+
"unit-has-keyword", "unit-within-range-of",
|
|
22
|
+
"model-is-leader", "target-has-keyword",
|
|
23
|
+
"charged-this-turn", "advanced-this-turn", "remained-stationary",
|
|
24
|
+
"is-battle-shocked", "has-lost-wounds",
|
|
25
|
+
"opponent-unit-within-range", "within-range-of-objective",
|
|
26
|
+
"attack-is-type", "has-fought-this-phase",
|
|
27
|
+
"destroyed-by-attack-type", "controls-objective", "is-attached",
|
|
28
|
+
"terrain-area-control", "engagement-state", "territory-control",
|
|
29
|
+
"fights-first", "disposition-matches",
|
|
30
|
+
"units-destroyed", "units-destroyed-comparison", "objective-majority"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"parameters": { "type": "object", "additionalProperties": true },
|
|
34
|
+
"negated": { "type": "boolean", "default": false }
|
|
35
|
+
},
|
|
36
|
+
"required": ["type"]
|
|
37
|
+
},
|
|
38
|
+
"compound-condition": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"properties": {
|
|
41
|
+
"operator": { "type": "string", "enum": ["and", "or", "not"] },
|
|
42
|
+
"operands": { "type": "array", "items": { "$ref": "#/$defs/condition-node" }, "minItems": 1 }
|
|
43
|
+
},
|
|
44
|
+
"required": ["operator", "operands"]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"$ref": "#/$defs/condition-node"
|
|
48
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://40kdc.dev/schemas/enrichment/ability-dsl/effect.schema.json",
|
|
4
|
+
"title": "Ability Effect",
|
|
5
|
+
"$defs": {
|
|
6
|
+
"effect-node": {
|
|
7
|
+
"oneOf": [
|
|
8
|
+
{ "$ref": "#/$defs/single-effect" },
|
|
9
|
+
{ "$ref": "#/$defs/choice-effect" },
|
|
10
|
+
{ "$ref": "#/$defs/sequence-effect" },
|
|
11
|
+
{ "$ref": "#/$defs/dice-gated-effect" },
|
|
12
|
+
{ "$ref": "#/$defs/conditional-effect" },
|
|
13
|
+
{ "$ref": "#/$defs/dice-pool-allocation-effect" }
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"single-effect": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"type": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"enum": [
|
|
22
|
+
"stat-modifier", "roll-modifier", "re-roll",
|
|
23
|
+
"mortal-wounds", "feel-no-pain", "invulnerable-save", "ward",
|
|
24
|
+
"keyword-grant", "movement-modifier", "deep-strike",
|
|
25
|
+
"fallback-and-act", "fight-first", "fight-last",
|
|
26
|
+
"shoot-on-death", "fight-on-death",
|
|
27
|
+
"objective-control-modifier", "leadership-modifier",
|
|
28
|
+
"damage-reduction", "attack-restriction",
|
|
29
|
+
"ability-grant", "cp-gain", "cp-refund",
|
|
30
|
+
"model-destruction", "resurrection",
|
|
31
|
+
"resource-gain", "resource-spend",
|
|
32
|
+
"charge-roll-modifier", "terrain-area-tag",
|
|
33
|
+
"bs-modifier", "engagement-passthrough"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"target": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"enum": [
|
|
39
|
+
"self", "bearer", "unit", "attached-unit",
|
|
40
|
+
"attacker", "defender",
|
|
41
|
+
"friendly-within-aura", "enemy-within-aura",
|
|
42
|
+
"all-friendly", "all-enemy"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"modifier": { "type": "object", "additionalProperties": true }
|
|
46
|
+
},
|
|
47
|
+
"required": ["type", "target"]
|
|
48
|
+
},
|
|
49
|
+
"choice-effect": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"properties": {
|
|
52
|
+
"type": { "const": "choice" },
|
|
53
|
+
"options": { "type": "array", "items": { "$ref": "#/$defs/effect-node" }, "minItems": 2 },
|
|
54
|
+
"choice_label": { "type": "string" }
|
|
55
|
+
},
|
|
56
|
+
"required": ["type", "options"]
|
|
57
|
+
},
|
|
58
|
+
"sequence-effect": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"type": { "const": "sequence" },
|
|
62
|
+
"steps": { "type": "array", "items": { "$ref": "#/$defs/effect-node" }, "minItems": 1 }
|
|
63
|
+
},
|
|
64
|
+
"required": ["type", "steps"]
|
|
65
|
+
},
|
|
66
|
+
"dice-gated-effect": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"type": { "const": "dice-gated" },
|
|
70
|
+
"dice": { "type": "string", "description": "Dice expression, e.g. 'D6', '2D6'" },
|
|
71
|
+
"threshold": {
|
|
72
|
+
"oneOf": [
|
|
73
|
+
{ "type": "integer" },
|
|
74
|
+
{ "type": "string", "enum": ["leadership", "toughness", "save"] }
|
|
75
|
+
],
|
|
76
|
+
"description": "Fixed threshold or model characteristic to compare against"
|
|
77
|
+
},
|
|
78
|
+
"comparison": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"enum": ["gte", "lte", "gt", "lt", "eq"],
|
|
81
|
+
"default": "gte"
|
|
82
|
+
},
|
|
83
|
+
"on_success": {
|
|
84
|
+
"oneOf": [
|
|
85
|
+
{ "$ref": "#/$defs/effect-node" },
|
|
86
|
+
{ "type": "null" }
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"on_fail": {
|
|
90
|
+
"oneOf": [
|
|
91
|
+
{ "$ref": "#/$defs/effect-node" },
|
|
92
|
+
{ "type": "null" }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"required": ["type", "dice", "threshold"]
|
|
97
|
+
},
|
|
98
|
+
"conditional-effect": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"properties": {
|
|
101
|
+
"type": { "const": "conditional" },
|
|
102
|
+
"condition": { "$ref": "condition.schema.json" },
|
|
103
|
+
"effect": { "$ref": "#/$defs/effect-node" }
|
|
104
|
+
},
|
|
105
|
+
"required": ["type", "condition", "effect"]
|
|
106
|
+
},
|
|
107
|
+
"dice-pool-allocation-effect": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"type": { "const": "dice-pool-allocation" },
|
|
111
|
+
"pool": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"properties": {
|
|
114
|
+
"count": { "type": "integer", "minimum": 1 },
|
|
115
|
+
"die": { "type": "string" }
|
|
116
|
+
},
|
|
117
|
+
"required": ["count", "die"]
|
|
118
|
+
},
|
|
119
|
+
"max_activations": { "type": "integer", "minimum": 1 },
|
|
120
|
+
"options": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"properties": {
|
|
125
|
+
"name": { "type": "string" },
|
|
126
|
+
"requirement": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"properties": {
|
|
129
|
+
"type": { "type": "string", "enum": ["pair", "triple", "single", "run"] },
|
|
130
|
+
"min_value": { "type": "integer", "minimum": 1, "maximum": 6 }
|
|
131
|
+
},
|
|
132
|
+
"required": ["type", "min_value"]
|
|
133
|
+
},
|
|
134
|
+
"effect": { "$ref": "#/$defs/effect-node" }
|
|
135
|
+
},
|
|
136
|
+
"required": ["name", "requirement", "effect"]
|
|
137
|
+
},
|
|
138
|
+
"minItems": 1
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"required": ["type", "pool", "max_activations", "options"]
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"$ref": "#/$defs/effect-node"
|
|
145
|
+
}
|