optolith-database-schema 0.16.2 → 0.16.4

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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.16.4](https://github.com/elyukai/optolith-database-schema/compare/v0.16.3...v0.16.4) (2024-01-21)
6
+
7
+
8
+ ### Features
9
+
10
+ * magical and blessed advantages and disadvantages identifier cache ([4dc6e3d](https://github.com/elyukai/optolith-database-schema/commit/4dc6e3dec721019af728db6b68138498da4b1775))
11
+
12
+ ### [0.16.3](https://github.com/elyukai/optolith-database-schema/compare/v0.16.2...v0.16.3) (2024-01-18)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * resolve intersection types ([829da00](https://github.com/elyukai/optolith-database-schema/commit/829da0079a60693dbeec94cbfb02b447c5105da5))
18
+
5
19
  ### [0.16.2](https://github.com/elyukai/optolith-database-schema/compare/v0.16.1...v0.16.2) (2024-01-18)
6
20
 
7
21
 
@@ -0,0 +1,20 @@
1
+ import type { CacheConfig } from "../cacheConfig.js";
2
+ export type MagicalAndBlessedAdvantagesAndDisadvantagesCache = {
3
+ advantages: {
4
+ magical: {
5
+ ids: number[];
6
+ };
7
+ blessed: {
8
+ ids: number[];
9
+ };
10
+ };
11
+ disadvantages: {
12
+ magical: {
13
+ ids: number[];
14
+ };
15
+ blessed: {
16
+ ids: number[];
17
+ };
18
+ };
19
+ };
20
+ export declare const config: CacheConfig<MagicalAndBlessedAdvantagesAndDisadvantagesCache>;
@@ -0,0 +1,163 @@
1
+ import { assertExhaustive } from "../helpers/typeSafety.js";
2
+ const BLESSED_ID = 12;
3
+ const SPELLCASTER_ID = 47;
4
+ const getAdvantageId = (type) => {
5
+ switch (type) {
6
+ case "Magical":
7
+ return SPELLCASTER_ID;
8
+ case "Blessed":
9
+ return BLESSED_ID;
10
+ default:
11
+ return assertExhaustive(type);
12
+ }
13
+ };
14
+ const isRatedFor = (type, ratedId) => {
15
+ switch (ratedId.tag) {
16
+ case "Spell":
17
+ case "Ritual":
18
+ return type === "Magical";
19
+ case "LiturgicalChant":
20
+ case "Ceremony":
21
+ return type === "Blessed";
22
+ case "Attribute":
23
+ case "Skill":
24
+ case "CloseCombatTechnique":
25
+ case "RangedCombatTechnique":
26
+ return false;
27
+ default:
28
+ return assertExhaustive(ratedId);
29
+ }
30
+ };
31
+ const isPrerequisiteFor = (type, prerequisite, getById, traversedIds) => {
32
+ switch (prerequisite.tag) {
33
+ case "Activatable": {
34
+ if (prerequisite.activatable.id.tag === "Advantage" &&
35
+ prerequisite.activatable.id.advantage === getAdvantageId(type) &&
36
+ prerequisite.activatable.active) {
37
+ return true;
38
+ }
39
+ const entry = getById(prerequisite.activatable.id);
40
+ return entry !== undefined && is(type, entry, getById, traversedIds);
41
+ }
42
+ case "Rated":
43
+ return isRatedFor(type, prerequisite.rated.id);
44
+ case "CommonSuggestedByRCP":
45
+ case "Sex":
46
+ case "Race":
47
+ case "Culture":
48
+ case "Pact":
49
+ case "SocialStatus":
50
+ case "State":
51
+ case "Rule":
52
+ case "PrimaryAttribute":
53
+ case "BlessedTradition":
54
+ case "MagicalTradition":
55
+ case "RatedMinimumNumber":
56
+ case "RatedSum":
57
+ case "ExternalEnhancement":
58
+ case "Text":
59
+ case "NoOtherAncestorBloodAdvantage":
60
+ case "SexualCharacteristic":
61
+ return false;
62
+ default:
63
+ return assertExhaustive(prerequisite);
64
+ }
65
+ };
66
+ const is = (type, entry, getById, traversedIds) => {
67
+ if (!entry.prerequisites || traversedIds.includes(entry.id)) {
68
+ return false;
69
+ }
70
+ const newTraversedIds = [...traversedIds, entry.id];
71
+ return (entry.prerequisites !== undefined &&
72
+ entry.prerequisites.some(prerequisite => {
73
+ switch (prerequisite.prerequisite.tag) {
74
+ case "Single":
75
+ return isPrerequisiteFor(type, prerequisite.prerequisite.single, getById, newTraversedIds);
76
+ case "Disjunction":
77
+ return prerequisite.prerequisite.disjunction.list.some(p => isPrerequisiteFor(type, p, getById, newTraversedIds));
78
+ case "Group":
79
+ return prerequisite.prerequisite.group.list.some(p => isPrerequisiteFor(type, p, getById, newTraversedIds));
80
+ default:
81
+ return assertExhaustive(prerequisite.prerequisite);
82
+ }
83
+ }));
84
+ };
85
+ export const config = {
86
+ builder(database) {
87
+ const getActivatableById = (id) => {
88
+ // prettier-ignore
89
+ switch (id.tag) {
90
+ case "AdvancedCombatSpecialAbility": return database.advancedCombatSpecialAbilities.find(([entryId]) => entryId === id.advanced_combat_special_ability)?.[1];
91
+ case "AdvancedKarmaSpecialAbility": return database.advancedKarmaSpecialAbilities.find(([entryId]) => entryId === id.advanced_karma_special_ability)?.[1];
92
+ case "AdvancedMagicalSpecialAbility": return database.advancedMagicalSpecialAbilities.find(([entryId]) => entryId === id.advanced_magical_special_ability)?.[1];
93
+ case "AdvancedSkillSpecialAbility": return database.advancedSkillSpecialAbilities.find(([entryId]) => entryId === id.advanced_skill_special_ability)?.[1];
94
+ case "Advantage": return database.advantages.find(([entryId]) => entryId === id.advantage)?.[1];
95
+ case "AncestorGlyph": return database.ancestorGlyphs.find(([entryId]) => entryId === id.ancestor_glyph)?.[1];
96
+ case "ArcaneOrbEnchantment": return database.arcaneOrbEnchantments.find(([entryId]) => entryId === id.arcane_orb_enchantment)?.[1];
97
+ case "AttireEnchantment": return database.attireEnchantments.find(([entryId]) => entryId === id.attire_enchantment)?.[1];
98
+ case "BlessedTradition": return database.blessedTraditions.find(([entryId]) => entryId === id.blessed_tradition)?.[1];
99
+ case "BowlEnchantment": return database.bowlEnchantments.find(([entryId]) => entryId === id.bowl_enchantment)?.[1];
100
+ case "BrawlingSpecialAbility": return database.brawlingSpecialAbilities.find(([entryId]) => entryId === id.brawling_special_ability)?.[1];
101
+ case "CauldronEnchantment": return database.cauldronEnchantments.find(([entryId]) => entryId === id.cauldron_enchantment)?.[1];
102
+ case "CeremonialItemSpecialAbility": return database.ceremonialItemSpecialAbilities.find(([entryId]) => entryId === id.ceremonial_item_special_ability)?.[1];
103
+ case "ChronicleEnchantment": return database.chronicleEnchantments.find(([entryId]) => entryId === id.chronicle_enchantment)?.[1];
104
+ case "CombatSpecialAbility": return database.combatSpecialAbilities.find(([entryId]) => entryId === id.combat_special_ability)?.[1];
105
+ case "CombatStyleSpecialAbility": return database.combatStyleSpecialAbilities.find(([entryId]) => entryId === id.combat_style_special_ability)?.[1];
106
+ case "CommandSpecialAbility": return database.commandSpecialAbilities.find(([entryId]) => entryId === id.command_special_ability)?.[1];
107
+ case "DaggerRitual": return database.daggerRituals.find(([entryId]) => entryId === id.dagger_ritual)?.[1];
108
+ case "Disadvantage": return database.disadvantages.find(([entryId]) => entryId === id.disadvantage)?.[1];
109
+ case "FamiliarSpecialAbility": return database.familiarSpecialAbilities.find(([entryId]) => entryId === id.familiar_special_ability)?.[1];
110
+ case "FatePointSexSpecialAbility": return database.fatePointSexSpecialAbilities.find(([entryId]) => entryId === id.fate_point_sex_special_ability)?.[1];
111
+ case "FatePointSpecialAbility": return database.fatePointSpecialAbilities.find(([entryId]) => entryId === id.fate_point_special_ability)?.[1];
112
+ case "FoolsHatEnchantment": return database.foolsHatEnchantments.find(([entryId]) => entryId === id.fools_hat_enchantment)?.[1];
113
+ case "GeneralSpecialAbility": return database.generalSpecialAbilities.find(([entryId]) => entryId === id.general_special_ability)?.[1];
114
+ case "InstrumentEnchantment": return database.instrumentEnchantments.find(([entryId]) => entryId === id.instrument_enchantment)?.[1];
115
+ case "KarmaSpecialAbility": return database.karmaSpecialAbilities.find(([entryId]) => entryId === id.karma_special_ability)?.[1];
116
+ case "Krallenkettenzauber": return database.krallenkettenzauber.find(([entryId]) => entryId === id.krallenkettenzauber)?.[1];
117
+ case "LiturgicalStyleSpecialAbility": return database.liturgicalStyleSpecialAbilities.find(([entryId]) => entryId === id.liturgical_style_special_ability)?.[1];
118
+ case "LycantropicGift": return database.lycantropicGifts.find(([entryId]) => entryId === id.lycantropic_gift)?.[1];
119
+ case "MagicalSpecialAbility": return database.magicalSpecialAbilities.find(([entryId]) => entryId === id.magical_special_ability)?.[1];
120
+ case "MagicalTradition": return database.magicalTraditions.find(([entryId]) => entryId === id.magical_tradition)?.[1];
121
+ case "MagicStyleSpecialAbility": return database.magicStyleSpecialAbilities.find(([entryId]) => entryId === id.magic_style_special_ability)?.[1];
122
+ case "OrbEnchantment": return database.orbEnchantments.find(([entryId]) => entryId === id.orb_enchantment)?.[1];
123
+ case "PactGift": return database.pactGifts.find(([entryId]) => entryId === id.pact_gift)?.[1];
124
+ case "ProtectiveWardingCircleSpecialAbility": return database.protectiveWardingCircleSpecialAbilities.find(([entryId]) => entryId === id.protective_warding_circle_special_ability)?.[1];
125
+ case "RingEnchantment": return database.ringEnchantments.find(([entryId]) => entryId === id.ring_enchantment)?.[1];
126
+ case "Sermon": return database.sermons.find(([entryId]) => entryId === id.sermon)?.[1];
127
+ case "SexSpecialAbility": return database.sexSpecialAbilities.find(([entryId]) => entryId === id.sex_special_ability)?.[1];
128
+ case "SickleRitual": return database.sickleRituals.find(([entryId]) => entryId === id.sickle_ritual)?.[1];
129
+ case "SikaryanDrainSpecialAbility": return database.sikaryanDrainSpecialAbilities.find(([entryId]) => entryId === id.sikaryan_drain_special_ability)?.[1];
130
+ case "SkillStyleSpecialAbility": return database.skillStyleSpecialAbilities.find(([entryId]) => entryId === id.skill_style_special_ability)?.[1];
131
+ case "SpellSwordEnchantment": return database.spellSwordEnchantments.find(([entryId]) => entryId === id.spell_sword_enchantment)?.[1];
132
+ case "StaffEnchantment": return database.staffEnchantments.find(([entryId]) => entryId === id.staff_enchantment)?.[1];
133
+ case "ToyEnchantment": return database.toyEnchantments.find(([entryId]) => entryId === id.toy_enchantment)?.[1];
134
+ case "Trinkhornzauber": return database.trinkhornzauber.find(([entryId]) => entryId === id.trinkhornzauber)?.[1];
135
+ case "VampiricGift": return database.vampiricGifts.find(([entryId]) => entryId === id.vampiric_gift)?.[1];
136
+ case "Vision": return database.visions.find(([entryId]) => entryId === id.vision)?.[1];
137
+ case "WandEnchantment": return database.wandEnchantments.find(([entryId]) => entryId === id.wand_enchantment)?.[1];
138
+ case "WeaponEnchantment": return database.weaponEnchantments.find(([entryId]) => entryId === id.weapon_enchantment)?.[1];
139
+ default:
140
+ return assertExhaustive(id);
141
+ }
142
+ };
143
+ // prettier-ignore
144
+ return {
145
+ advantages: {
146
+ magical: {
147
+ ids: database.advantages.filter(([_, entry]) => is("Magical", entry, getActivatableById, [])).map(([id]) => id),
148
+ },
149
+ blessed: {
150
+ ids: database.advantages.filter(([_, entry]) => is("Blessed", entry, getActivatableById, [])).map(([id]) => id),
151
+ },
152
+ },
153
+ disadvantages: {
154
+ magical: {
155
+ ids: database.disadvantages.filter(([_, entry]) => is("Magical", entry, getActivatableById, [])).map(([id]) => id),
156
+ },
157
+ blessed: {
158
+ ids: database.disadvantages.filter(([_, entry]) => is("Blessed", entry, getActivatableById, [])).map(([id]) => id),
159
+ },
160
+ },
161
+ };
162
+ },
163
+ };
@@ -1,13 +1,16 @@
1
1
  import * as ActivatableSelectOptions from "../cache/activatableSelectOptions.js";
2
2
  import * as AncestorBloodAdvantages from "../cache/ancestorBloodAdvantages.js";
3
+ import * as MagicalAndBlessedAdvantagesAndDisadvantages from "../cache/magicalAndBlessedAdvantagesAndDisadvantages.js";
3
4
  import * as NewApplicationsAndUses from "../cache/newApplicationsAndUses.js";
4
5
  export type CacheMap = {
5
6
  activatableSelectOptions: ActivatableSelectOptions.ActivatableSelectOptionsCache;
6
7
  ancestorBloodAdvantages: AncestorBloodAdvantages.AncestorBloodAdvantagesCache;
8
+ magicalAndBlessedAdvantagesAndDisadvantages: MagicalAndBlessedAdvantagesAndDisadvantages.MagicalAndBlessedAdvantagesAndDisadvantagesCache;
7
9
  newApplicationsAndUses: NewApplicationsAndUses.NewApplicationsAndUsesCache;
8
10
  };
9
11
  export declare const cacheMap: {
10
12
  activatableSelectOptions: import("../cacheConfig.js").CacheConfig<ActivatableSelectOptions.ActivatableSelectOptionsCache>;
11
13
  ancestorBloodAdvantages: import("../cacheConfig.js").CacheConfig<AncestorBloodAdvantages.AncestorBloodAdvantagesCache>;
14
+ magicalAndBlessedAdvantagesAndDisadvantages: import("../cacheConfig.js").CacheConfig<MagicalAndBlessedAdvantagesAndDisadvantages.MagicalAndBlessedAdvantagesAndDisadvantagesCache>;
12
15
  newApplicationsAndUses: import("../cacheConfig.js").CacheConfig<NewApplicationsAndUses.NewApplicationsAndUsesCache, [generatedSelectOptions: ActivatableSelectOptions.ActivatableSelectOptionsCache]>;
13
16
  };
@@ -1,8 +1,10 @@
1
1
  import * as ActivatableSelectOptions from "../cache/activatableSelectOptions.js";
2
2
  import * as AncestorBloodAdvantages from "../cache/ancestorBloodAdvantages.js";
3
+ import * as MagicalAndBlessedAdvantagesAndDisadvantages from "../cache/magicalAndBlessedAdvantagesAndDisadvantages.js";
3
4
  import * as NewApplicationsAndUses from "../cache/newApplicationsAndUses.js";
4
5
  export const cacheMap = {
5
6
  activatableSelectOptions: ActivatableSelectOptions.config,
6
7
  ancestorBloodAdvantages: AncestorBloodAdvantages.config,
8
+ magicalAndBlessedAdvantagesAndDisadvantages: MagicalAndBlessedAdvantagesAndDisadvantages.config,
7
9
  newApplicationsAndUses: NewApplicationsAndUses.config,
8
10
  };
package/lib/main.js CHANGED
@@ -78,10 +78,12 @@ export const buildCache = async (cachePaths, validResults, options = {}) => {
78
78
  const { pretty = false } = options;
79
79
  const activatableSelectOptionsCache = cacheMap.activatableSelectOptions.builder(validResults);
80
80
  const ancestorBloodAdvantagesCache = cacheMap.ancestorBloodAdvantages.builder(validResults);
81
+ const magicalAndBlessedAdvantagesAndDisadvantagesCache = cacheMap.magicalAndBlessedAdvantagesAndDisadvantages.builder(validResults);
81
82
  const newApplicationsAndUsesCache = cacheMap.newApplicationsAndUses.builder(validResults, activatableSelectOptionsCache);
82
83
  const cacheData = {
83
84
  activatableSelectOptions: activatableSelectOptionsCache,
84
85
  ancestorBloodAdvantages: ancestorBloodAdvantagesCache,
86
+ magicalAndBlessedAdvantagesAndDisadvantages: magicalAndBlessedAdvantagesAndDisadvantagesCache,
85
87
  newApplicationsAndUses: newApplicationsAndUsesCache,
86
88
  };
87
89
  for (const [cacheName, cachePath] of Object.entries(cachePaths)) {
@@ -341,12 +341,28 @@ export type VariantSpecialAbility = {
341
341
  tag: "Selection";
342
342
  selection: VariantSpecialAbilitySelection;
343
343
  };
344
- export type FixedVariantSpecialAbility = SpecialAbilityDefinition & {
344
+ export type FixedVariantSpecialAbility = {
345
+ /**
346
+ * The identifier of the combat technique to provide the rating for.
347
+ */
348
+ id: SpecialAbilityIdentifier;
345
349
  /**
346
350
  * if set to `false`, if the selection is granted by the basic package, it
347
351
  * is removed.
348
352
  */
349
353
  active?: false;
354
+ /**
355
+ * The level of the received special ability.
356
+ * @integer
357
+ * @minimum 1
358
+ */
359
+ level?: number;
360
+ /**
361
+ * Received select options. Order is important. Typically, you only need the
362
+ * first array index, though.
363
+ * @minItems 1
364
+ */
365
+ options?: RequirableSelectOptionIdentifier[];
350
366
  };
351
367
  export type VariantSpecialAbilitySelection = {
352
368
  /**
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { TypeConfig } from "../typeConfig.js";
5
5
  import { CommonnessRatedAdvantageDisadvantage } from "./_CommonnessRatedAdvantageDisadvantage.js";
6
- import { Dice } from "./_Dice.js";
6
+ import { Dice, DieType } from "./_Dice.js";
7
7
  import { AdvantageIdentifier, AttributeIdentifier, DisadvantageIdentifier, ExperienceLevelIdentifier } from "./_Identifier.js";
8
8
  import { LocaleMap } from "./_LocaleMap.js";
9
9
  import { NonEmptyString } from "./_NonEmptyString.js";
@@ -176,7 +176,17 @@ export type Weight = {
176
176
  */
177
177
  random: WeightDice[];
178
178
  };
179
- export type WeightDice = Dice & {
179
+ export type WeightDice = {
180
+ /**
181
+ * Number of dice of the same type. Example: 2 in 2D6.
182
+ * @integer
183
+ * @minimum 1
184
+ */
185
+ number: number;
186
+ /**
187
+ * Number of sides on every die. Example: 6 in 2D6.
188
+ */
189
+ sides: DieType;
180
190
  /**
181
191
  * The strategy how to offset the randomly generated values against the
182
192
  * base value. Either they are all added or subtracted or even results are
@@ -1,4 +1,4 @@
1
- import { CheckResultBased } from "./_ActivatableSkillCheckResultBased.js";
1
+ import { CheckResultBasedModifier, CheckResultValue } from "./_ActivatableSkillCheckResultBased.js";
2
2
  import { LocaleMap } from "./_LocaleMap.js";
3
3
  import { ResponsiveText, ResponsiveTextReplace } from "./_ResponsiveText.js";
4
4
  export type DurationForOneTime = {
@@ -74,11 +74,19 @@ export type FixedDurationTranslation = {
74
74
  /**
75
75
  * Defines the duration being based on a check result.
76
76
  */
77
- export type CheckResultBasedDuration = CheckResultBased & {
77
+ export type CheckResultBasedDuration = {
78
78
  /**
79
79
  * If the duration is the maximum duration, so it may end earlier.
80
80
  */
81
81
  is_maximum?: true;
82
+ /**
83
+ * The base value that is derived from the check result.
84
+ */
85
+ base: CheckResultValue;
86
+ /**
87
+ * If defined, it modifies the base value.
88
+ */
89
+ modifier?: CheckResultBasedModifier;
82
90
  /**
83
91
  * The duration unit.
84
92
  */
@@ -1,4 +1,4 @@
1
- import { CheckResultBased } from "./_ActivatableSkillCheckResultBased.js";
1
+ import { CheckResultBasedModifier, CheckResultValue } from "./_ActivatableSkillCheckResultBased.js";
2
2
  import { LocaleMap } from "./_LocaleMap.js";
3
3
  import { ResponsiveTextOptional, ResponsiveTextReplace } from "./_ResponsiveText.js";
4
4
  export type Range = {
@@ -74,11 +74,19 @@ export type FixedRange = {
74
74
  /**
75
75
  * Defines the range being based on a check result.
76
76
  */
77
- export type CheckResultBasedRange = CheckResultBased & {
77
+ export type CheckResultBasedRange = {
78
78
  /**
79
79
  * If the range is the maximum range.
80
80
  */
81
81
  is_maximum?: true;
82
+ /**
83
+ * The base value that is derived from the check result.
84
+ */
85
+ base: CheckResultValue;
86
+ /**
87
+ * If defined, it modifies the base value.
88
+ */
89
+ modifier?: CheckResultBasedModifier;
82
90
  /**
83
91
  * The duration unit.
84
92
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "optolith-database-schema",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
4
4
  "description": "Definitions and utilities for the flat-file database of Optolith, a character creation tool for the Pen and Paper RPG “The Dark Eye 5”, and its external integrations into other software.",
5
5
  "keywords": [
6
6
  "tde",
@@ -648,23 +648,34 @@
648
648
  ]
649
649
  },
650
650
  "FixedVariantSpecialAbility": {
651
- "allOf": [
652
- {
653
- "$ref": "#/$defs/SpecialAbilityDefinition"
651
+ "type": "object",
652
+ "properties": {
653
+ "id": {
654
+ "description": "The identifier of the combat technique to provide the rating for.",
655
+ "$ref": "./_IdentifierGroup.schema.json#/$defs/SpecialAbilityIdentifier"
654
656
  },
655
- {
656
- "type": "object",
657
- "properties": {
658
- "active": {
659
- "description": "if set to `false`, if the selection is granted by the basic package, it\nis removed.",
660
- "const": false
661
- }
657
+ "active": {
658
+ "description": "if set to `false`, if the selection is granted by the basic package, it\nis removed.",
659
+ "const": false
660
+ },
661
+ "level": {
662
+ "description": "The level of the received special ability.",
663
+ "type": "integer",
664
+ "minimum": 1
665
+ },
666
+ "options": {
667
+ "description": "Received select options. Order is important. Typically, you only need the\nfirst array index, though.",
668
+ "type": "array",
669
+ "items": {
670
+ "$ref": "./_IdentifierGroup.schema.json#/$defs/RequirableSelectOptionIdentifier"
662
671
  },
663
- "required": []
672
+ "minItems": 1
664
673
  }
674
+ },
675
+ "required": [
676
+ "id"
665
677
  ],
666
- "type": "object",
667
- "unevaluatedProperties": false
678
+ "additionalProperties": false
668
679
  },
669
680
  "VariantSpecialAbilitySelection": {
670
681
  "type": "object",
@@ -240,25 +240,28 @@
240
240
  "additionalProperties": false
241
241
  },
242
242
  "WeightDice": {
243
- "allOf": [
244
- {
245
- "$ref": "./_Dice.schema.json#/$defs/Dice"
243
+ "type": "object",
244
+ "properties": {
245
+ "number": {
246
+ "description": "Number of dice of the same type. Example: 2 in 2D6.",
247
+ "type": "integer",
248
+ "minimum": 1
246
249
  },
247
- {
248
- "type": "object",
249
- "properties": {
250
- "offset_strategy": {
251
- "description": "The strategy how to offset the randomly generated values against the\nbase value. Either they are all added or subtracted or even results are\nadded and odd results are subtracted.",
252
- "$ref": "#/$defs/WeightDiceOffsetStrategy"
253
- }
254
- },
255
- "required": [
256
- "offset_strategy"
257
- ]
250
+ "sides": {
251
+ "description": "Number of sides on every die. Example: 6 in 2D6.",
252
+ "$ref": "./_Dice.schema.json#/$defs/DieType"
253
+ },
254
+ "offset_strategy": {
255
+ "description": "The strategy how to offset the randomly generated values against the\nbase value. Either they are all added or subtracted or even results are\nadded and odd results are subtracted.",
256
+ "$ref": "#/$defs/WeightDiceOffsetStrategy"
258
257
  }
258
+ },
259
+ "required": [
260
+ "number",
261
+ "sides",
262
+ "offset_strategy"
259
263
  ],
260
- "type": "object",
261
- "unevaluatedProperties": false
264
+ "additionalProperties": false
262
265
  },
263
266
  "WeightDiceOffsetStrategy": {
264
267
  "description": "The strategy how to offset the randomly generated values against the\nbase value. Either they are all added or subtracted or even results are\nadded and odd results are subtracted.",
@@ -201,40 +201,41 @@
201
201
  },
202
202
  "CheckResultBasedDuration": {
203
203
  "description": "Defines the duration being based on a check result.",
204
- "allOf": [
205
- {
206
- "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultBased"
204
+ "type": "object",
205
+ "properties": {
206
+ "is_maximum": {
207
+ "description": "If the duration is the maximum duration, so it may end earlier.",
208
+ "const": true
207
209
  },
208
- {
210
+ "base": {
211
+ "description": "The base value that is derived from the check result.",
212
+ "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultValue"
213
+ },
214
+ "modifier": {
215
+ "description": "If defined, it modifies the base value.",
216
+ "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultBasedModifier"
217
+ },
218
+ "unit": {
219
+ "description": "The duration unit.",
220
+ "$ref": "#/$defs/DurationUnit"
221
+ },
222
+ "translations": {
223
+ "description": "All translations for the entry, identified by IETF language tag (BCP47).",
209
224
  "type": "object",
210
- "properties": {
211
- "is_maximum": {
212
- "description": "If the duration is the maximum duration, so it may end earlier.",
213
- "const": true
214
- },
215
- "unit": {
216
- "description": "The duration unit.",
217
- "$ref": "#/$defs/DurationUnit"
218
- },
219
- "translations": {
220
- "description": "All translations for the entry, identified by IETF language tag (BCP47).",
221
- "type": "object",
222
- "patternProperties": {
223
- "^[a-z]{2}-[A-Z]{2}$": {
224
- "$ref": "#/$defs/CheckResultBasedDurationTranslation"
225
- }
226
- },
227
- "minProperties": 1,
228
- "additionalProperties": false
225
+ "patternProperties": {
226
+ "^[a-z]{2}-[A-Z]{2}$": {
227
+ "$ref": "#/$defs/CheckResultBasedDurationTranslation"
229
228
  }
230
229
  },
231
- "required": [
232
- "unit"
233
- ]
230
+ "minProperties": 1,
231
+ "additionalProperties": false
234
232
  }
233
+ },
234
+ "required": [
235
+ "base",
236
+ "unit"
235
237
  ],
236
- "type": "object",
237
- "unevaluatedProperties": false
238
+ "additionalProperties": false
238
239
  },
239
240
  "CheckResultBasedDurationTranslation": {
240
241
  "type": "object",
@@ -205,33 +205,34 @@
205
205
  },
206
206
  "CheckResultBasedRange": {
207
207
  "description": "Defines the range being based on a check result.",
208
- "allOf": [
209
- {
210
- "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultBased"
208
+ "type": "object",
209
+ "properties": {
210
+ "is_maximum": {
211
+ "description": "If the range is the maximum range.",
212
+ "const": true
211
213
  },
212
- {
213
- "type": "object",
214
- "properties": {
215
- "is_maximum": {
216
- "description": "If the range is the maximum range.",
217
- "const": true
218
- },
219
- "unit": {
220
- "description": "The duration unit.",
221
- "$ref": "#/$defs/RangeUnit"
222
- },
223
- "is_radius": {
224
- "description": "If `true`, the range is a radius.",
225
- "const": true
226
- }
227
- },
228
- "required": [
229
- "unit"
230
- ]
214
+ "base": {
215
+ "description": "The base value that is derived from the check result.",
216
+ "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultValue"
217
+ },
218
+ "modifier": {
219
+ "description": "If defined, it modifies the base value.",
220
+ "$ref": "./_ActivatableSkillCheckResultBased.schema.json#/$defs/CheckResultBasedModifier"
221
+ },
222
+ "unit": {
223
+ "description": "The duration unit.",
224
+ "$ref": "#/$defs/RangeUnit"
225
+ },
226
+ "is_radius": {
227
+ "description": "If `true`, the range is a radius.",
228
+ "const": true
231
229
  }
230
+ },
231
+ "required": [
232
+ "base",
233
+ "unit"
232
234
  ],
233
- "type": "object",
234
- "unevaluatedProperties": false
235
+ "additionalProperties": false
235
236
  },
236
237
  "RangeTranslation": {
237
238
  "type": "object",