@optolith/entity-descriptions 0.13.1 → 0.14.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/lib/creator.js +1 -1
  3. package/lib/entities/activatable.d.ts +1 -1
  4. package/lib/entities/activatable.js +28 -18
  5. package/lib/entities/culture.js +3 -3
  6. package/lib/entities/curriculum.js +1 -1
  7. package/lib/entities/elixir.js +1 -1
  8. package/lib/entities/equipment.js +1 -1
  9. package/lib/entities/liturgicalChant.d.ts +2 -2
  10. package/lib/entities/liturgicalChant.js +4 -0
  11. package/lib/entities/partial/adventurePointsValue.js +8 -7
  12. package/lib/entities/partial/dice.js +2 -2
  13. package/lib/entities/partial/enhancements.js +2 -2
  14. package/lib/entities/partial/herbary.js +1 -1
  15. package/lib/entities/partial/prerequisites/index.d.ts +6 -1
  16. package/lib/entities/partial/prerequisites/index.js +24 -1
  17. package/lib/entities/partial/prerequisites/single/personalityTrait.js +1 -1
  18. package/lib/entities/partial/prerequisites/single/ratedSum.js +1 -1
  19. package/lib/entities/partial/profession/options/combatTechniquesForAdventurePoints.d.ts +16 -0
  20. package/lib/entities/partial/profession/options/combatTechniquesForAdventurePoints.js +43 -0
  21. package/lib/entities/partial/profession/options/numberOfSpellworksTotalingAdventurePoints.d.ts +16 -0
  22. package/lib/entities/partial/profession/options/numberOfSpellworksTotalingAdventurePoints.js +39 -0
  23. package/lib/entities/partial/profession/packages.d.ts +67 -0
  24. package/lib/entities/partial/profession/packages.js +84 -0
  25. package/lib/entities/partial/profession/variants.d.ts +21 -0
  26. package/lib/entities/partial/profession/variants.js +31 -0
  27. package/lib/entities/partial/rated/activatable/cost.js +11 -9
  28. package/lib/entities/partial/rated/activatable/effect.js +2 -2
  29. package/lib/entities/partial/reader.d.ts +25 -1
  30. package/lib/entities/partial/reader.js +20 -0
  31. package/lib/entities/partial/units/energy.js +2 -1
  32. package/lib/entities/partial/units/length.js +6 -3
  33. package/lib/entities/partial/units/timeSpan.js +11 -7
  34. package/lib/entities/partial/unknown.d.ts +4 -0
  35. package/lib/entities/partial/unknown.js +4 -0
  36. package/lib/entities/poison.js +1 -1
  37. package/lib/entities/profession.js +44 -62
  38. package/lib/entities/spell.d.ts +2 -2
  39. package/lib/entities/spell.js +3 -1
  40. package/lib/index.d.ts +69 -68
  41. package/lib/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +2 -2
@@ -2,7 +2,7 @@ import { allSame } from "@elyukai/utils/array/filters";
2
2
  import { ensureNonEmpty, isEmpty, isNotEmpty, } from "@elyukai/utils/array/nonEmpty";
3
3
  import { deepEqual, equal } from "@elyukai/utils/equality";
4
4
  import { on } from "@elyukai/utils/function";
5
- import { isNotNullish, isNullish, mapNullable, nullableToArray, } from "@elyukai/utils/nullable";
5
+ import { isNotNullish, isNullish, mapNullable } from "@elyukai/utils/nullable";
6
6
  import { omitKeys } from "@elyukai/utils/object";
7
7
  import { compareNumber } from "@elyukai/utils/ordering";
8
8
  import { Reader } from "@elyukai/utils/reader";
@@ -13,16 +13,13 @@ import { combineNameComponents, getNameComponents, renderActivatableNameComponen
13
13
  import { renderCommonnessRatedAdvantagesOrDisadvantages, renderValueWithPossibleTranslation, } from "./partial/commonnessRatedAdvantagesAndDisadvantages.js";
14
14
  import { attributedCustomName, attributedInstance, attributedName, attributedNameFromInstance, } from "./partial/markdown.js";
15
15
  import { printProfessionPrerequisites, printProfessionVariantPrerequisites, } from "./partial/prerequisites/index.js";
16
+ import { renderBaseCombatTechniquesForAdventurePointsOption, renderVariantCombatTechniquesForAdventurePointsOption, } from "./partial/profession/options/combatTechniquesForAdventurePoints.js";
17
+ import { renderBaseNumberOfSpellworksTotalingAdventurePoints, renderVariantNumberOfSpellworksTotalingAdventurePoints, } from "./partial/profession/options/numberOfSpellworksTotalingAdventurePoints.js";
18
+ import { prepareProfessionPackages, } from "./partial/profession/packages.js";
19
+ import { insteadOfR, renderVariantOption, renderVariantOptionPaths, } from "./partial/profession/variants.js";
16
20
  import { parensIf } from "./partial/rated/activatable/parensIf.js";
17
- import { attributedCustomNameR, attributedNameR, customNameR, formatR, getChildInstancesForInstanceIdFnR, getChildInstancesForInstanceIdR, getInstanceByIdR, localeCompareR, localeJoinR, localeSortR, strictNameR, translateMapFnR, translateR, translationR, } from "./partial/reader.js";
21
+ import { attributedCustomNameR, attributedNameR, customNameR, fixedNumberOrString, formatAPValue, formatR, getChildInstancesForInstanceIdFnR, getChildInstancesForInstanceIdR, getInstanceByIdR, localeCompareR, localeJoinR, localeSortR, strictNameR, translateMapFnR, translateR, translationR, } from "./partial/reader.js";
18
22
  import { MISSING_VALUE, UNHANDLED_VALUE } from "./partial/unknown.js";
19
- const prepareProfessionPackages = (professionId) => Reader.asks(({ getInstanceById, getChildInstancesForInstanceId }) => getChildInstancesForInstanceId("ProfessionPackage", professionId)
20
- .map((professionPackage) => ({
21
- ...professionPackage,
22
- experienceLevel: getInstanceById("ExperienceLevel", professionPackage.content.experience_level),
23
- }))
24
- .filter((professionPackage) => professionPackage.experienceLevel !== undefined)
25
- .toSorted(on(item => item.experienceLevel.adventure_points, compareNumber)));
26
23
  const renderNumericListAcrossPackages = (packages, selector, equalityFn, renderText, defaultValue) => packages
27
24
  .reduce((accR, pkg, pkgIndex) => accR.map2(selector(pkg), (acc, selected) => selected.reduce((filledAcc, [values, number]) => {
28
25
  const existing = filledAcc.findIndex(([value]) => equalityFn(value, values));
@@ -48,7 +45,6 @@ const renderNumericListAcrossPackages = (packages, selector, equalityFn, renderT
48
45
  .thenW(list => localeSortR(list))
49
46
  .map(list => ensureNonEmpty(list)?.join(", "));
50
47
  const renderSinglePackageValue = (professionPackages, selector, equalityFn, renderText) => Reader.traverse(professionPackages, selector).thenW(selected => (allSame(selected, equalityFn) ? renderText([selected[0]]) : renderText(selected)));
51
- const insteadOfR = (replacement, base) => translateR("{$replacement} instead of {$base}", { replacement, base });
52
48
  /**
53
49
  * If the selected values of the base and the variant are equal, only renders the value once. Otherwise, renders both values as the variant value replacing the base value.
54
50
  */
@@ -59,23 +55,14 @@ const plainOrInsteadOfR = (base, variant, selector, equality, render) => {
59
55
  ? render(baseValue)
60
56
  : render(variantValue).thenW(replacement => render(baseValue).thenW(baseRendered => insteadOfR(replacement, baseRendered)));
61
57
  };
62
- const renderVariantOptionPaths = (base, variant, paths) => {
63
- switch (variant.kind) {
64
- case "Remove":
65
- return base === undefined ? Reader.of(MISSING_VALUE) : paths.remove(base);
66
- case "Override":
67
- return base === undefined ? paths.add(variant.Override) : paths.update(base, variant.Override);
68
- default:
69
- return assertExhaustive(variant);
70
- }
71
- };
72
58
  const renderVariantLanguagesScriptsOption = (baseOptions, variantOptions) => renderVariantOptionPaths(baseOptions, variantOptions, {
73
- remove: base => translateR("no Languages and Literacy totaling {$apValue} AP", { apValue: base.ap_value }),
74
- add: override => translateR("Languages and Literacy totaling {$apValue} AP", { apValue: override.ap_value }),
75
- update: (base, override) => translateR("{$replacement} instead of {$base}", {
76
- replacement: override.ap_value,
77
- base: base.ap_value,
78
- }).then(apValue => translateR("Languages and Literacy totaling {$apValue} AP", {
59
+ remove: base => translateR("no Languages and Literacy totaling {$apValue} AP", {
60
+ apValue: base.ap_value.toFixed(),
61
+ }),
62
+ add: override => translateR("Languages and Literacy totaling {$apValue} AP", {
63
+ apValue: override.ap_value.toFixed(),
64
+ }),
65
+ update: (base, override) => insteadOfR(override.ap_value, base.ap_value).then(apValue => translateR("Languages and Literacy totaling {$apValue} AP", {
79
66
  apValue,
80
67
  })),
81
68
  });
@@ -101,17 +88,17 @@ const renderSkillSpecializationOption = (option) => Reader.asks(({ format, trans
101
88
  const renderCombatTechniquesOption = (option) => isNotEmpty(option.fixed)
102
89
  ? (() => {
103
90
  const [first, ...others] = option.fixed;
104
- const firstTextR = translateR(".input {$count :number} {{{$count} of the following combat techniques {$rating}}}", { count: first.number, rating: first.rating_modifier + 6 });
91
+ const firstTextR = translateR(".input {$count :number} {{{$count} of the following combat techniques {$rating}}}", { count: first.number, rating: (first.rating_modifier + 6).toFixed() });
105
92
  const fixedTextR = others.reduce((accTextR, other) => accTextR.then(accText => translateR(".input {$count :number} {{{$previous}, {$count} others {$rating}}}", {
106
93
  count: other.number,
107
94
  previous: accText,
108
- rating: other.rating_modifier + 6,
95
+ rating: (other.rating_modifier + 6).toFixed(),
109
96
  })), firstTextR);
110
97
  const completeTextR = fixedTextR.then(fixedText => option.rest_rating_modifier === undefined
111
98
  ? Reader.of(fixedText)
112
99
  : translateR("{$previous}, the others {$rating}", {
113
100
  previous: fixedText,
114
- rating: option.rest_rating_modifier + 6,
101
+ rating: (option.rest_rating_modifier + 6).toFixed(),
115
102
  }));
116
103
  const listR = Reader.traverse(option.options, id => attributedNameR("profession", id).map(name => name ?? MISSING_VALUE))
117
104
  .thenW(list => localeSortR(list))
@@ -134,13 +121,13 @@ const renderSkillsOption = (professionPackages, skillGroup) => allSame(professio
134
121
  ? pkg.content.options.skills
135
122
  : undefined), apValue => professionPackages[0].content.options?.skills?.specific === undefined
136
123
  ? translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
137
- apValue,
124
+ apValue: fixedNumberOrString(apValue),
138
125
  skillsOfGroup: skillGroup.nameOfSkillsOfGroup,
139
126
  })
140
127
  : Reader.traverse(professionPackages[0].content.options.skills.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
141
128
  .thenW(localeSortR)
142
- .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: 8 }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
143
- apValue,
129
+ .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: "8" }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
130
+ apValue: fixedNumberOrString(apValue),
144
131
  list: list.join(", ") + parensIf(maxSRText),
145
132
  })))) ?? Reader.of(undefined))
146
133
  : Reader.traverse(professionPackages, pkg => {
@@ -149,13 +136,13 @@ const renderSkillsOption = (professionPackages, skillGroup) => allSame(professio
149
136
  ? Reader.of("—")
150
137
  : skillsOption.specific === undefined
151
138
  ? translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
152
- apValue: skillsOption.ap_value,
139
+ apValue: skillsOption.ap_value.toFixed(),
153
140
  skillsOfGroup: skillGroup.nameOfSkillsOfGroup,
154
141
  })
155
142
  : Reader.traverse(skillsOption.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
156
143
  .thenW(localeSortR)
157
- .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: 8 }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
158
- apValue: skillsOption.ap_value,
144
+ .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: "8" }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
145
+ apValue: skillsOption.ap_value.toFixed(),
159
146
  list: list.join(", ") + parensIf(maxSRText),
160
147
  })));
161
148
  }).map(list => list.join(" / "));
@@ -175,10 +162,7 @@ const renderVariantCantripsOption = (baseOptions, variantOptions) => renderVaria
175
162
  }).then(baseCount => translateR(".input {$count :number} {{{$count} cantrips}}", {
176
163
  count: override.number,
177
164
  })
178
- .then(replacementCount => translateR("{$replacement} instead of {$base}", {
179
- replacement: replacementCount,
180
- base: baseCount,
181
- }).then(count => translateR("{$count} from the following list", { count })))
165
+ .then(replacementCount => insteadOfR(replacementCount, baseCount).then(count => translateR("{$count} from the following list", { count })))
182
166
  .map(text => `${text}: ${list}`)))
183
167
  : renderCantripList(override.options)
184
168
  .thenW(list => translateR(".input {$count :number} {{{$count} cantrips}}", {
@@ -192,10 +176,7 @@ const renderVariantCantripsOption = (baseOptions, variantOptions) => renderVaria
192
176
  })
193
177
  .then(count => translateR("{$count} from the following list", { count }))
194
178
  .map(text => `${text}: ${list}`))
195
- .then(baseText => translateR("{$replacement} instead of {$base}", {
196
- replacement: replacementText,
197
- base: baseText,
198
- }))),
179
+ .then(baseText => insteadOfR(replacementText, baseText))),
199
180
  });
200
181
  const renderSingleCantripsOption = (option) => renderVariantCantripsOption(undefined, { kind: "Override", Override: option });
201
182
  const renderCantripsOption = (professionPackages) => {
@@ -212,7 +193,7 @@ const renderCantripsOption = (professionPackages) => {
212
193
  }
213
194
  };
214
195
  const renderLiturgiesOption = (professionPackages) => mapNullable(getTotalingAPValues(professionPackages, pkg => pkg.content.options?.liturgies), apValue => translateR("Liturgies totaling {$apValue} AP", {
215
- apValue,
196
+ apValue: fixedNumberOrString(apValue),
216
197
  })) ?? Reader.of(undefined);
217
198
  const renderVariantSkillSpecializationOption = (baseOptions, variantOptions) => renderVariantOptionPaths(baseOptions, variantOptions, {
218
199
  remove: (base) => {
@@ -260,8 +241,8 @@ const renderVariantCombatTechniquesOption = (baseOptions, variantOptions) => ren
260
241
  update: (base, override) => renderCombatTechniquesOption(override).then(overrideText => renderCombatTechniquesOption(base).then(baseText => insteadOfR(overrideText, baseText))),
261
242
  });
262
243
  const renderVariantCursesOption = (baseOptions, variantOptions) => renderVariantOptionPaths(baseOptions, variantOptions, {
263
- remove: base => translateR("no Curses totaling {$apValue} AP", { apValue: base.ap_value }),
264
- add: override => translateR("Curses totaling {$apValue} AP", { apValue: override.ap_value }),
244
+ remove: base => translateR("no Curses totaling {$apValue} AP", { apValue: base.ap_value.toFixed() }),
245
+ add: override => translateR("Curses totaling {$apValue} AP", { apValue: override.ap_value.toFixed() }),
265
246
  update: (base, override) => insteadOfR(override.ap_value, base.ap_value).then(apValue => translateR("Curses totaling {$apValue} AP", {
266
247
  apValue,
267
248
  })),
@@ -273,17 +254,17 @@ const renderVariantSkillsOption = (baseOptions, variantOptions) => renderVariant
273
254
  skillsOfGroup: nameOfSkillsOfGroup,
274
255
  })),
275
256
  add: override => nameOfSkillsOfGroupR(override.group).thenW(nameOfSkillsOfGroup => translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
276
- apValue: override.ap_value,
257
+ apValue: override.ap_value.toFixed(),
277
258
  skillsOfGroup: nameOfSkillsOfGroup,
278
259
  })),
279
260
  update: (base, override) => plainOrInsteadOfR(base, override, b => b.ap_value, equal, b => Reader.of(b)).thenW(apValue => plainOrInsteadOfR(base, override, b => b.group, equal, nameOfSkillsOfGroupR).thenW(nameOfSkillsOfGroup => translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
280
- apValue,
281
- skillsOfGroup: nameOfSkillsOfGroup,
261
+ apValue: fixedNumberOrString(apValue),
262
+ skillsOfGroup: fixedNumberOrString(nameOfSkillsOfGroup),
282
263
  }))),
283
264
  });
284
265
  const renderVariantLiturgiesOption = (baseOptions, variantOptions) => renderVariantOptionPaths(baseOptions, variantOptions, {
285
- remove: base => translateR("no Liturgies totaling {$apValue} AP", { apValue: base.ap_value }),
286
- add: override => translateR("Liturgies totaling {$apValue} AP", { apValue: override.ap_value }),
266
+ remove: base => translateR("no Liturgies totaling {$apValue} AP", { apValue: base.ap_value.toFixed() }),
267
+ add: override => translateR("Liturgies totaling {$apValue} AP", { apValue: override.ap_value.toFixed() }),
287
268
  update: (base, override) => insteadOfR(override.ap_value, base.ap_value).then(apValue => translateR("Liturgies totaling {$apValue} AP", {
288
269
  apValue,
289
270
  })),
@@ -416,6 +397,9 @@ const renderCombatTechniques = (professionPackages) => Reader.sequence([
416
397
  professionPackages.some(pkg => pkg.content.options?.combat_techniques !== undefined)
417
398
  ? renderSinglePackageValue(professionPackages, pkg => Reader.of(pkg.content.options?.combat_techniques), deepEqual, options => Reader.traverse(options, option => option === undefined ? Reader.of("—") : renderCombatTechniquesOption(option)).map(renderedOptions => renderedOptions.join(" / ")))
418
399
  : Reader.of(undefined),
400
+ professionPackages.some(pkg => pkg.content.options?.combatTechniquesForAdventurePoints !== undefined)
401
+ ? renderBaseCombatTechniquesForAdventurePointsOption(professionPackages)
402
+ : Reader.of(undefined),
419
403
  ]).map(list => ensureNonEmpty(list.filter(isNotNullish))?.join(", ") ?? "—");
420
404
  const renderSkills = (professionPackages) => Reader.asks(({ getAllInstances }) => getAllInstances("SkillGroup")).thenW(skillGroups => Reader.traverse(skillGroups.toSorted(on(group => group.content.position, compareNumber)), ({ id: groupId, content: group }) => translationR(group).thenW(groupTranslation => Reader.sequence([
421
405
  renderNumericListAcrossPackages(professionPackages, pkg => Reader.asks(({ getInstanceById }) => pkg.content.skills
@@ -444,6 +428,9 @@ const renderSpellworkName = (spellworkIds) => Reader.traverse(spellworkIds, spel
444
428
  const renderSpellworks = (professionPackages) => Reader.sequence([
445
429
  renderCantripsOption(professionPackages),
446
430
  renderNumericListAcrossPackages(professionPackages, (pkg) => Reader.of(pkg.content.spells?.map(ct => [ct.id, ct.rating_modifier]) ?? []), deepEqual, renderSpellworkName, undefined),
431
+ professionPackages.some(pkg => pkg.content.options?.spellworks !== undefined)
432
+ ? renderBaseNumberOfSpellworksTotalingAdventurePoints(professionPackages)
433
+ : Reader.of(undefined),
447
434
  ]).map(list => ensureNonEmpty(list.filter(isNotNullish))?.join("; "));
448
435
  const retrieveBlessedTraditionIdentifierFromPrerequisiteGroup = (prerequisite) => prerequisite.kind === "Activatable" && prerequisite.Activatable.id.kind === "BlessedTradition"
449
436
  ? [prerequisite.Activatable.id.BlessedTradition]
@@ -533,17 +520,9 @@ const renderRatedVariantChanges = (baseList, variantList, renderInstance) => Rea
533
520
  return renderInstance(id).map(name => `${name} ${rating_modifier.toFixed()}`);
534
521
  }
535
522
  const baseValue = baseList?.find(item => deepEqual(item.id, id))?.rating_modifier ?? 0;
536
- return renderInstance(id).thenW(name => translateR("{$replacement} instead of {$base}", {
537
- replacement: `${name} ${(baseValue + rating_modifier).toFixed()}`,
538
- base: baseValue,
539
- }));
523
+ return renderInstance(id).thenW(name => insteadOfR(`${name} ${(baseValue + rating_modifier).toFixed()}`, baseValue));
540
524
  }).thenW(localeSortR);
541
- const renderVariantOption = (base, variant, key, render) => (variant.options?.[key] === undefined
542
- ? Reader.of(undefined)
543
- : render(base.options?.[key], variant.options[key])).map(text => nullableToArray(text));
544
- const renderProfessionVariantLabel = (base, variant, translations) => translateR("{$value} AP", {
545
- value: base.ap_value + (variant.ap_value ?? 0),
546
- }).thenW(apValueText => localeSortR(translations.map(({ id, content }) => `^[${content.name.default}](entity: "ProfessionVariant", instance: "${id}")`))
525
+ const renderProfessionVariantLabel = (base, variant, translations) => formatAPValue(base.ap_value + (variant.ap_value ?? 0)).thenW(apValueText => localeSortR(translations.map(({ id, content }) => `^[${content.name.default}](entity: "ProfessionVariant", instance: "${id}")`))
547
526
  .thenW(list => localeJoinR(list, "conjunction"))
548
527
  .map(names => names + parensIf(apValueText)));
549
528
  const renderProfessionVariantText = (base, variant, translation) => translation.full_text !== undefined
@@ -557,9 +536,11 @@ const renderProfessionVariantText = (base, variant, translation) => translation.
557
536
  renderVariantOption(base, variant, "skill_specialization", renderVariantSkillSpecializationOption),
558
537
  renderVariantOption(base, variant, "languages_scripts", renderVariantLanguagesScriptsOption),
559
538
  renderVariantOption(base, variant, "combat_techniques", renderVariantCombatTechniquesOption),
539
+ renderVariantOption(base, variant, "combatTechniquesForAdventurePoints", renderVariantCombatTechniquesForAdventurePointsOption),
560
540
  renderVariantOption(base, variant, "cantrips", renderVariantCantripsOption),
561
541
  renderVariantOption(base, variant, "curses", renderVariantCursesOption),
562
542
  renderVariantOption(base, variant, "skills", renderVariantSkillsOption),
543
+ renderVariantOption(base, variant, "spellworks", renderVariantNumberOfSpellworksTotalingAdventurePoints),
563
544
  renderVariantOption(base, variant, "liturgies", renderVariantLiturgiesOption),
564
545
  variant.special_abilities === undefined
565
546
  ? Reader.of([])
@@ -635,10 +616,11 @@ const renderProfessionVariants = (professionPackages) => professionPackages.leng
635
616
  * Get a JSON representation of the rules text for a profession version.
636
617
  */
637
618
  export const getProfessionVersionEntityDescription = createEntityDescriptionCreator(({ getInstanceById, getAllInstances, getChildInstancesForInstanceId, getResolvedSelectOptionById, }, locale, { id, content: entry }) => {
638
- const { format, translate, translateMap, compare: localeCompare, join: localeJoin } = locale;
619
+ const { format, formatNumber, translate, translateMap, compare: localeCompare, join: localeJoin, } = locale;
639
620
  const translation = translateMap(entry.translations);
640
621
  const env = {
641
622
  format,
623
+ formatNumber,
642
624
  translate,
643
625
  translateMap,
644
626
  localeCompare,
@@ -12,7 +12,7 @@ export declare const getCantripEntityDescription: import("../creator.js").Entity
12
12
  * Get a JSON representation of the rules text for a skill.
13
13
  */
14
14
  export declare const getSpellEntityDescription: import("../creator.js").EntityDescriptionCreator<"Spell", {
15
- getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Property" | "MagicalTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement">;
15
+ getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Property" | "MagicalTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement" | "FocusRule">;
16
16
  getChildInstancesForInstanceId: GetAllChildInstancesForParent<"Enhancement">;
17
17
  idMap: IdMap;
18
18
  }, import("../index.js").EntityDescription>;
@@ -20,7 +20,7 @@ export declare const getSpellEntityDescription: import("../creator.js").EntityDe
20
20
  * Get a JSON representation of the rules text for a ritual.
21
21
  */
22
22
  export declare const getRitualEntityDescription: import("../creator.js").EntityDescriptionCreator<"Ritual", {
23
- getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Property" | "MagicalTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement">;
23
+ getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Property" | "MagicalTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement" | "FocusRule">;
24
24
  getChildInstancesForInstanceId: GetAllChildInstancesForParent<"Enhancement">;
25
25
  idMap: IdMap;
26
26
  }, import("../index.js").EntityDescription>;
@@ -12,7 +12,7 @@ import { createEntityDescriptionCreator } from "../creator.js";
12
12
  import { renderAnimalTypesSection } from "./partial/animalTypes.js";
13
13
  import { renderEnhancements } from "./partial/enhancements.js";
14
14
  import { attributedCustomName, attributedName } from "./partial/markdown.js";
15
- import { printAnimistPowerPrerequisites, printGeodeRitualPrerequisites, } from "./partial/prerequisites/index.js";
15
+ import { getDerivedFocusRuleBadgeFromPrerequisites, printAnimistPowerPrerequisites, printGeodeRitualPrerequisites, } from "./partial/prerequisites/index.js";
16
16
  import { renderCastingTime, renderFastSkillNonModifiableCastingTime, renderSlowSkillNonModifiableCastingTime, } from "./partial/rated/activatable/castingTime.js";
17
17
  import { renderMagicalActionCost, renderModifiableOneTimeCost, renderNonModifiableOneTimeCost, renderNonModifiableSustainedCost, renderStandaloneCostMap, } from "./partial/rated/activatable/cost.js";
18
18
  import { renderExpressionBasedDuration, renderMusicDuration, renderOneTimeDuration, renderSustainedDuration, } from "./partial/rated/activatable/duration.js";
@@ -162,6 +162,7 @@ export const getSpellEntityDescription = createEntityDescriptionCreator(({ getIn
162
162
  return {
163
163
  title: translation.name,
164
164
  className: "spell",
165
+ badge: mapNullable(entry.prerequisites, getDerivedFocusRuleBadgeFromPrerequisites)?.run(env),
165
166
  body: [
166
167
  {
167
168
  type: "definitionList",
@@ -221,6 +222,7 @@ export const getRitualEntityDescription = createEntityDescriptionCreator(({ getI
221
222
  return {
222
223
  title: translation.name,
223
224
  className: "ritual",
225
+ badge: mapNullable(entry.prerequisites, getDerivedFocusRuleBadgeFromPrerequisites)?.run(env),
224
226
  body: [
225
227
  {
226
228
  type: "definitionList",