@optolith/entity-descriptions 0.4.0 → 0.4.2

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 (96) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/lib/creator.d.ts +2 -2
  3. package/lib/entities/activatable.js +35 -64
  4. package/lib/entities/condition.js +19 -24
  5. package/lib/entities/culture.js +18 -26
  6. package/lib/entities/curriculum.js +30 -33
  7. package/lib/entities/derivedCharacteristic.js +2 -1
  8. package/lib/entities/disease.js +3 -6
  9. package/lib/entities/elixir.js +6 -4
  10. package/lib/entities/equipment.js +17 -17
  11. package/lib/entities/equipmentPackage.js +4 -3
  12. package/lib/entities/experienceLevel.js +7 -7
  13. package/lib/entities/focusRule.js +2 -2
  14. package/lib/entities/influence.js +2 -2
  15. package/lib/entities/liturgicalChant.d.ts +1 -1
  16. package/lib/entities/liturgicalChant.js +11 -59
  17. package/lib/entities/partial/adventurePointsValue.js +14 -19
  18. package/lib/entities/partial/enhancements.d.ts +1 -1
  19. package/lib/entities/partial/enhancements.js +1 -1
  20. package/lib/entities/partial/herbary.js +13 -9
  21. package/lib/entities/partial/map.d.ts +3 -1
  22. package/lib/entities/partial/map.js +21 -8
  23. package/lib/entities/partial/mathOperation.js +12 -17
  24. package/lib/entities/partial/prerequisites/displayOption.d.ts +2 -2
  25. package/lib/entities/partial/prerequisites/index.d.ts +3 -3
  26. package/lib/entities/partial/prerequisites/index.js +10 -4
  27. package/lib/entities/partial/prerequisites/part.d.ts +1 -1
  28. package/lib/entities/partial/prerequisites/prerequisiteGroups.d.ts +4 -4
  29. package/lib/entities/partial/prerequisites/prerequisiteGroups.js +1 -1
  30. package/lib/entities/partial/prerequisites/single/activatable.d.ts +3 -3
  31. package/lib/entities/partial/prerequisites/single/animistPower.d.ts +2 -2
  32. package/lib/entities/partial/prerequisites/single/animistPower.js +1 -1
  33. package/lib/entities/partial/prerequisites/single/blessedTradition.d.ts +2 -2
  34. package/lib/entities/partial/prerequisites/single/commonSuggestedByRCP.d.ts +2 -2
  35. package/lib/entities/partial/prerequisites/single/culture.d.ts +4 -4
  36. package/lib/entities/partial/prerequisites/single/enhancement.d.ts +4 -4
  37. package/lib/entities/partial/prerequisites/single/influence.d.ts +3 -3
  38. package/lib/entities/partial/prerequisites/single/magicalTradition.d.ts +2 -2
  39. package/lib/entities/partial/prerequisites/single/noOtherAncestorBloodAdvantage.d.ts +2 -2
  40. package/lib/entities/partial/prerequisites/single/pact.d.ts +3 -3
  41. package/lib/entities/partial/prerequisites/single/personalityTrait.d.ts +4 -4
  42. package/lib/entities/partial/prerequisites/single/primaryAttribute.d.ts +3 -3
  43. package/lib/entities/partial/prerequisites/single/primaryAttribute.js +1 -1
  44. package/lib/entities/partial/prerequisites/single/profession.d.ts +4 -4
  45. package/lib/entities/partial/prerequisites/single/publication.d.ts +4 -4
  46. package/lib/entities/partial/prerequisites/single/race.d.ts +4 -4
  47. package/lib/entities/partial/prerequisites/single/rated.d.ts +2 -2
  48. package/lib/entities/partial/prerequisites/single/rated.js +2 -2
  49. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.d.ts +3 -3
  50. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.js +1 -1
  51. package/lib/entities/partial/prerequisites/single/ratedSum.d.ts +4 -4
  52. package/lib/entities/partial/prerequisites/single/rule.d.ts +3 -3
  53. package/lib/entities/partial/prerequisites/single/sex.d.ts +1 -1
  54. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.d.ts +3 -3
  55. package/lib/entities/partial/prerequisites/single/socialStatus.d.ts +3 -3
  56. package/lib/entities/partial/prerequisites/single/state.d.ts +4 -4
  57. package/lib/entities/partial/prerequisites/single/text.d.ts +3 -3
  58. package/lib/entities/partial/rated/activatable/castingTime.d.ts +1 -1
  59. package/lib/entities/partial/rated/activatable/castingTime.js +6 -8
  60. package/lib/entities/partial/rated/activatable/cost.d.ts +1 -1
  61. package/lib/entities/partial/rated/activatable/cost.js +17 -14
  62. package/lib/entities/partial/rated/activatable/duration.js +4 -4
  63. package/lib/entities/partial/rated/activatable/effect.js +1 -1
  64. package/lib/entities/partial/rated/activatable/index.d.ts +6 -1
  65. package/lib/entities/partial/rated/activatable/index.js +25 -0
  66. package/lib/entities/partial/rated/activatable/isMinimumMaximum.js +2 -2
  67. package/lib/entities/partial/rated/activatable/range.js +6 -6
  68. package/lib/entities/partial/rated/activatable/speed.d.ts +1 -1
  69. package/lib/entities/partial/rated/activatable/targetCategory.js +2 -2
  70. package/lib/entities/partial/reader.d.ts +4 -2
  71. package/lib/entities/partial/responsiveText.d.ts +5 -1
  72. package/lib/entities/partial/responsiveText.js +3 -5
  73. package/lib/entities/partial/units/length.d.ts +1 -1
  74. package/lib/entities/partial/units/length.js +2 -10
  75. package/lib/entities/partial/units/timeSpan.d.ts +4 -4
  76. package/lib/entities/partial/units/timeSpan.js +21 -17
  77. package/lib/entities/personalityTrait.js +3 -4
  78. package/lib/entities/poison.js +4 -4
  79. package/lib/entities/profession.d.ts +1 -1
  80. package/lib/entities/profession.js +19 -14
  81. package/lib/entities/race.js +11 -13
  82. package/lib/entities/sexPractice.js +1 -3
  83. package/lib/entities/skill.js +2 -3
  84. package/lib/entities/spell.js +2 -14
  85. package/lib/helpers/getTypes.d.ts +2 -2
  86. package/lib/helpers/locale.d.ts +7 -2
  87. package/lib/helpers/translate.d.ts +1 -1
  88. package/lib/index.d.ts +3 -1
  89. package/lib/index.js +1 -0
  90. package/lib/references/index.d.ts +1 -1
  91. package/lib/references/index.js +1 -1
  92. package/lib/references/page.d.ts +3 -3
  93. package/lib/references/page.js +1 -1
  94. package/lib/references/pageRange.d.ts +2 -2
  95. package/lib/tsconfig.tsbuildinfo +1 -1
  96. package/package.json +4 -3
@@ -19,8 +19,8 @@ const renderElectiveSpellworks = (translate, translateMap, localeCompare, getIns
19
19
  return name;
20
20
  }
21
21
  return (name +
22
- parensIf(translateMap(getInstanceById("Element", item.restriction.Element)
23
- ?.translations)?.name ?? MISSING_VALUE));
22
+ parensIf(translateMap(getInstanceById("Element", item.restriction.Element)?.translations)
23
+ ?.name ?? MISSING_VALUE));
24
24
  }))
25
25
  .filter(isNotNullish)
26
26
  .toSorted(localeCompare)
@@ -32,11 +32,9 @@ const renderElectiveSpellworks = (translate, translateMap, localeCompare, getIns
32
32
  const renderRestrictedSpellworks = (translate, translateMap, localeCompare, localeJoin, getInstanceById, restrictedSpellworks) => {
33
33
  const restrictedGroups = Dictionary.groupBy(restrictedSpellworks, restriction => restriction.kind === "Spellwork"
34
34
  ? "spellwork"
35
- : restriction.kind === "Property" &&
36
- restriction.Property.maximum !== undefined
35
+ : restriction.kind === "Property" && restriction.Property.maximum !== undefined
37
36
  ? "restrictedProperty"
38
- : restriction.kind === "Property" ||
39
- restriction.kind === "DemonSummoning"
37
+ : restriction.kind === "Property" || restriction.kind === "DemonSummoning"
40
38
  ? "property"
41
39
  : "other");
42
40
  const addExclusion = (excludedSpellworks) => {
@@ -55,16 +53,16 @@ const renderRestrictedSpellworks = (translate, translateMap, localeCompare, loca
55
53
  };
56
54
  const restrictedProperties = restrictedGroups.get("restrictedProperty")?.map(restriction => translate(".input {$count :number} {{only {$count} additional spellworks with the Property {$property}}}", {
57
55
  count: restriction.Property.maximum,
58
- property: translateMap(getInstanceById("Property", restriction.Property.id)
59
- ?.translations)?.name ?? MISSING_VALUE,
56
+ property: translateMap(getInstanceById("Property", restriction.Property.id)?.translations)
57
+ ?.name ?? MISSING_VALUE,
60
58
  }) + addExclusion(restriction.Property.exclude)) ?? [];
61
59
  const propertyGroup = restrictedGroups.get("property");
62
60
  const translatedProperties = propertyGroup
63
61
  ?.map(restriction => {
64
62
  switch (restriction.kind) {
65
63
  case "Property":
66
- return translateMap(getInstanceById("Property", restriction.Property.id)
67
- ?.translations)?.name;
64
+ return translateMap(getInstanceById("Property", restriction.Property.id)?.translations)
65
+ ?.name;
68
66
  case "DemonSummoning":
69
67
  return translate("Demon Summoning");
70
68
  default:
@@ -82,8 +80,7 @@ const renderRestrictedSpellworks = (translate, translateMap, localeCompare, loca
82
80
  : [];
83
81
  const spellworkGroup = restrictedGroups.get("spellwork");
84
82
  const translatedSpellworks = spellworkGroup
85
- ?.map(restriction => translateMap(getInstanceById(restriction.Spellwork)?.translations)
86
- ?.name)
83
+ ?.map(restriction => translateMap(getInstanceById(restriction.Spellwork)?.translations)?.name)
87
84
  .filter(isNotNullish)
88
85
  .toSorted(localeCompare) ?? [];
89
86
  const spellworks = translatedSpellworks.length > 0
@@ -104,29 +101,26 @@ const renderRestrictedSpellworks = (translate, translateMap, localeCompare, loca
104
101
  return assertExhaustive(restriction);
105
102
  }
106
103
  }) ?? [];
107
- return [
108
- ...restrictedProperties,
109
- ...properties,
110
- ...others,
111
- ...spellworks,
112
- ].join("; ");
104
+ return [...restrictedProperties, ...properties, ...others, ...spellworks].join("; ");
113
105
  };
114
- const renderSpellworkAdjustment = (translateMap, getInstanceById, adjustment) => `${translateMap(getInstanceById(adjustment.id)?.translations)?.name ??
115
- MISSING_VALUE} ${adjustment.points}${parensIf(adjustment.tradition === undefined
106
+ const renderSpellworkAdjustment = (translateMap, getInstanceById, adjustment) => `${translateMap(getInstanceById(adjustment.id)?.translations)?.name ?? MISSING_VALUE} ${adjustment.points.toFixed()}${parensIf(adjustment.tradition === undefined
116
107
  ? undefined
117
- : translateMap(getInstanceById("MagicalTradition", adjustment.tradition)
118
- ?.translations)?.name)}`;
108
+ : translateMap(getInstanceById("MagicalTradition", adjustment.tradition)?.translations)?.name)}`;
119
109
  const renderAbilityAdjustmentName = (translateMap, getInstanceById, abilityAdjustment) => {
120
110
  switch (abilityAdjustment.kind) {
121
111
  case "Skill":
122
- return (translateMap(getInstanceById("Skill", abilityAdjustment.Skill.id)?.translations)?.name ?? MISSING_VALUE);
112
+ return (translateMap(getInstanceById("Skill", abilityAdjustment.Skill.id)?.translations)?.name ??
113
+ MISSING_VALUE);
123
114
  case "CombatTechnique":
124
- return (translateMap(getInstanceById(abilityAdjustment.CombatTechnique.id)?.translations)?.name ?? MISSING_VALUE);
115
+ return (translateMap(getInstanceById(abilityAdjustment.CombatTechnique.id)?.translations)?.name ??
116
+ MISSING_VALUE);
125
117
  case "Spellwork":
126
- return ((translateMap(getInstanceById(abilityAdjustment.Spellwork.id)?.translations)?.name ?? MISSING_VALUE) +
118
+ return ((translateMap(getInstanceById(abilityAdjustment.Spellwork.id)?.translations)?.name ??
119
+ MISSING_VALUE) +
127
120
  parensIf(abilityAdjustment.Spellwork.tradition === undefined
128
121
  ? undefined
129
- : translateMap(getInstanceById("MagicalTradition", abilityAdjustment.Spellwork.tradition)?.translations)?.name));
122
+ : translateMap(getInstanceById("MagicalTradition", abilityAdjustment.Spellwork.tradition)
123
+ ?.translations)?.name));
130
124
  default:
131
125
  return assertExhaustive(abilityAdjustment);
132
126
  }
@@ -134,7 +128,8 @@ const renderAbilityAdjustmentName = (translateMap, getInstanceById, abilityAdjus
134
128
  const renderAbilityAdjustmentBaseValue = (baseProfessionPackage, abilityAdjustment) => {
135
129
  switch (abilityAdjustment.kind) {
136
130
  case "Skill":
137
- return baseProfessionPackage.skills?.find(skill => skill.id === abilityAdjustment.Skill.id)?.rating_modifier;
131
+ return baseProfessionPackage.skills?.find(skill => skill.id === abilityAdjustment.Skill.id)
132
+ ?.rating_modifier;
138
133
  case "CombatTechnique":
139
134
  return baseProfessionPackage.combat_techniques?.find(skill => deepEqual(skill.id, abilityAdjustment.CombatTechnique.id))?.rating_modifier;
140
135
  case "Spellwork":
@@ -171,16 +166,17 @@ const renderAbilityAdjustmentDefaultValue = (abilityAdjustment) => {
171
166
  const renderAbilityAdjustment = (translate, translateMap, getInstanceById, baseProfessionPackage) => baseProfessionPackage === undefined
172
167
  ? abilityAdjustment => `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${sign(renderAbilityAdjustmentModifierValue(abilityAdjustment))}`
173
168
  : abilityAdjustment => {
174
- const basePoints = (renderAbilityAdjustmentBaseValue(baseProfessionPackage, abilityAdjustment) ?? 0) + renderAbilityAdjustmentDefaultValue(abilityAdjustment);
169
+ const basePoints = (renderAbilityAdjustmentBaseValue(baseProfessionPackage, abilityAdjustment) ?? 0) +
170
+ renderAbilityAdjustmentDefaultValue(abilityAdjustment);
175
171
  return translate("{$replacement} instead of {$base}", {
176
172
  base: basePoints,
177
- replacement: `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${basePoints + renderAbilityAdjustmentModifierValue(abilityAdjustment)}`,
173
+ replacement: `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${(basePoints + renderAbilityAdjustmentModifierValue(abilityAdjustment)).toFixed()}`,
178
174
  });
179
175
  };
180
176
  const renderAbilityAdjustments = (translate, translateMap, localeCompare, getInstanceById, baseProfessionPackage, list) => list
181
- ?.map(renderAbilityAdjustment(translate, translateMap, getInstanceById, baseProfessionPackage))
177
+ .map(renderAbilityAdjustment(translate, translateMap, getInstanceById, baseProfessionPackage))
182
178
  .toSorted(localeCompare)
183
- .join(", ") ?? translate("none");
179
+ .join(", ");
184
180
  /**
185
181
  * Get a JSON representation of the rules text for a curriculum.
186
182
  */
@@ -199,7 +195,8 @@ export const getCurriculumEntityDescription = createEntityDescriptionCreator(({
199
195
  items: [
200
196
  {
201
197
  label: translate("Guideline"),
202
- value: translateMap(getInstanceById("Guideline", entry.guideline)?.translations)?.name ?? MISSING_VALUE,
198
+ value: translateMap(getInstanceById("Guideline", entry.guideline)?.translations)?.name ??
199
+ MISSING_VALUE,
203
200
  },
204
201
  {
205
202
  label: translate("Elective Spellworks Package"),
@@ -237,7 +234,7 @@ export const getCurriculumEntityDescription = createEntityDescriptionCreator(({
237
234
  items: [
238
235
  {
239
236
  label: translate("Spellwork Changes"),
240
- value: lessonPackageTranslation?.spellwork_changes ??
237
+ value: lessonPackageTranslation.spellwork_changes ??
241
238
  lessonPackage.content.spellwork_changes
242
239
  ?.map(change => translate("{$replacement} instead of {$base}", {
243
240
  base: renderSpellworkAdjustment(translateMap, getInstanceById, change.base),
@@ -34,7 +34,7 @@ const getRaceBaseValue = (translate, translateMap, getInstanceById, idMap, raceB
34
34
  const renderBaseCalculation = (getInstanceById, translate, translateMap, idMap, calculation, style = "full") => renderMathOperation(calculation, value => {
35
35
  switch (value.kind) {
36
36
  case "Constant":
37
- return value.Constant.toString(10);
37
+ return value.Constant.toFixed();
38
38
  case "Attribute":
39
39
  return getAttribute(getInstanceById, translateMap, value.Attribute, style);
40
40
  case "RaceBaseValue":
@@ -87,5 +87,6 @@ export const getDerivedCharacteristicEntityDescription = createEntityDescription
87
87
  ],
88
88
  },
89
89
  ],
90
+ references: entry.src,
90
91
  };
91
92
  });
@@ -2,7 +2,7 @@ import { ensureNonEmpty } from "@elyukai/utils/array/nonEmpty";
2
2
  import { isNotNullish } from "@elyukai/utils/nullable";
3
3
  import { createEntityDescriptionCreator } from "../creator.js";
4
4
  import { renderAnimalTypesSection } from "./partial/animalTypes.js";
5
- import { renderAlternativeNames, renderChance, renderResistance, } from "./partial/herbary.js";
5
+ import { renderAlternativeNames, renderChance, renderResistance } from "./partial/herbary.js";
6
6
  import { parensIf } from "./partial/rated/activatable/parensIf.js";
7
7
  import { MISSING_VALUE } from "./partial/unknown.js";
8
8
  const renderCauses = (translate, translateMap, causes) => causes
@@ -12,10 +12,7 @@ const renderCauses = (translate, translateMap, causes) => causes
12
12
  return MISSING_VALUE;
13
13
  }
14
14
  return (causeTranslation.name +
15
- parensIf(ensureNonEmpty([
16
- renderChance(translate, translateMap, cause, true),
17
- causeTranslation.note,
18
- ].filter(isNotNullish))?.join("; ")));
15
+ parensIf(ensureNonEmpty([renderChance(translate, translateMap, cause, true), causeTranslation.note].filter(isNotNullish))?.join("; ")));
19
16
  })
20
17
  .join(", ");
21
18
  /**
@@ -35,7 +32,7 @@ export const getDiseaseEntityDescription = createEntityDescriptionCreator(({ get
35
32
  type: "definitionList",
36
33
  items: [
37
34
  renderAlternativeNames(translate, translation.alternative_names),
38
- { label: translate("Level"), value: baseEntry.level.toString() },
35
+ { label: translate("Level"), value: baseEntry.level.toFixed() },
39
36
  { label: translate("Progress"), value: translation.progress },
40
37
  {
41
38
  label: translate("Resistance"),
@@ -1,7 +1,7 @@
1
1
  import { mapNullable } from "@elyukai/utils/nullable";
2
2
  import { sign } from "@elyukai/utils/string/number";
3
3
  import { createEntityDescriptionCreator } from "../creator.js";
4
- import { renderAlternativeNames, renderLaboratoryLevel, } from "./partial/herbary.js";
4
+ import { renderAlternativeNames, renderLaboratoryLevel } from "./partial/herbary.js";
5
5
  import { printPlainGeneralPrerequisites } from "./partial/prerequisites/index.js";
6
6
  import { parensIf } from "./partial/rated/activatable/parensIf.js";
7
7
  /**
@@ -27,7 +27,9 @@ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getI
27
27
  },
28
28
  {
29
29
  label: translate("Price of Ingredients/Level"),
30
- value: translate(".input {$value :number} {{{$value} silverthalers}}", { value: entry.cost_per_ingredient_level }),
30
+ value: translate(".input {$value :number} {{{$value} silverthalers}}", {
31
+ value: entry.cost_per_ingredient_level,
32
+ }),
31
33
  },
32
34
  {
33
35
  label: translate("Laboratory"),
@@ -39,7 +41,7 @@ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getI
39
41
  },
40
42
  {
41
43
  label: `${translate("Prerequisites")} (${translate("Brewing Process")})`,
42
- value: translation?.brewing_process_prerequisites ?? translate("none"),
44
+ value: translation.brewing_process_prerequisites ?? translate("none"),
43
45
  },
44
46
  {
45
47
  label: `${translate("AP Value")} (${translate("Trade Secret")})`,
@@ -61,7 +63,7 @@ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getI
61
63
  type: "definitionList",
62
64
  style: "nested",
63
65
  items: translation.quality_levels.map((effectForLevel, index) => ({
64
- label: (index + 1).toString(),
66
+ label: (index + 1).toFixed(),
65
67
  value: effectForLevel,
66
68
  })),
67
69
  },
@@ -66,15 +66,17 @@ const renderPrimaryAttributeAndDamageThreshold = (translateMap, getInstanceById,
66
66
  const getAttrAbbrv = (attrId) => translateMap(getInstanceById("Attribute", attrId)?.translations)?.abbreviation ?? MISSING_VALUE;
67
67
  switch (damageThreshold.kind) {
68
68
  case "Default":
69
- return `${closeCombatTechnique?.primary_attribute.map(getAttrAbbrv).join("/") ?? MISSING_VALUE} ${damageThreshold.Default.threshold}`;
69
+ return `${closeCombatTechnique?.primary_attribute.map(getAttrAbbrv).join("/") ?? MISSING_VALUE} ${damageThreshold.Default.threshold.toFixed()}`;
70
70
  case "List":
71
71
  if (isNotEmpty(damageThreshold.List.list)) {
72
72
  const { list } = damageThreshold.List;
73
73
  if (list.some(item => item.threshold !== list[0].threshold)) {
74
- return list.map(item => `${getAttrAbbrv(item.attribute)} ${item.threshold}`).join("/");
74
+ return list
75
+ .map(item => `${getAttrAbbrv(item.attribute)} ${item.threshold.toFixed()}`)
76
+ .join("/");
75
77
  }
76
78
  else {
77
- return `${list.map(item => getAttrAbbrv(item.attribute)).join("/")} ${list[0].threshold}`;
79
+ return `${list.map(item => getAttrAbbrv(item.attribute)).join("/")} ${list[0].threshold.toFixed()}`;
78
80
  }
79
81
  }
80
82
  else {
@@ -150,11 +152,9 @@ const renderReloadTime = (translate, reloadTime) => isNotEmpty(reloadTime)
150
152
  ? translate("{$value} actions", {
151
153
  value: reloadTime.map(time => time.value).join("/"),
152
154
  })
153
- : translate(".input {$value :number} {{{$value} actions}}", {
154
- value: reloadTime[0].value,
155
- })
155
+ : formatTimeSpan(translate, ResponsiveTextSize.Full, "Actions", reloadTime[0].value)
156
156
  : MISSING_VALUE;
157
- const renderRangeBrackets = (rangeBrackets) => `${rangeBrackets.close}/${rangeBrackets.medium}/${rangeBrackets.far}`;
157
+ const renderRangeBrackets = (rangeBrackets) => `${rangeBrackets.close.toFixed()}/${rangeBrackets.medium.toFixed()}/${rangeBrackets.far.toFixed()}`;
158
158
  const renderAmmunition = (translateMap, getInstanceById, ammunition) => ammunition === undefined
159
159
  ? "—"
160
160
  : (translateMap(getInstanceById("Ammunition", ammunition)?.translations)?.name ?? MISSING_VALUE);
@@ -320,7 +320,7 @@ const renderNote = (translate, translateMap, getInstanceById, localeJoin, melee_
320
320
  : renderMagicalTraditionRestriction(translate, translateMap, getInstanceById, localeJoin, name, restrictedTo.magicalTraditions),
321
321
  note,
322
322
  ].filter(isNotNullish))?.join("; ");
323
- const renderWeight = (translate, measurements, weight) => {
323
+ const renderWeight = (translate, formatNumber, measurements, weight) => {
324
324
  if (typeof weight === "number") {
325
325
  return {
326
326
  label: translate("Weight"),
@@ -334,18 +334,18 @@ const renderWeight = (translate, measurements, weight) => {
334
334
  label: translate("Weight (Bronze/Silver/Gold)"),
335
335
  value: translate("{$value} pounds", {
336
336
  value: [weight.bronze, weight.silver, weight.gold]
337
- .map(value => value * measurements.stonesMultiplier)
337
+ .map(value => formatNumber(value * measurements.stonesMultiplier))
338
338
  .join("/"),
339
339
  }),
340
340
  };
341
341
  }
342
342
  };
343
- const renderCost = (translate, translateMap, cost) => {
343
+ const renderCost = (translate, translateMap, formatNumber, cost) => {
344
344
  const renderBookCostVariant = (bookCostVariant) => {
345
345
  switch (bookCostVariant.kind) {
346
346
  case "Definite": {
347
347
  const translation = translateMap(bookCostVariant.Definite.translations);
348
- return (renderCost(translate, translateMap, bookCostVariant.Definite.cost) +
348
+ return (renderCost(translate, translateMap, formatNumber, bookCostVariant.Definite.cost).value +
349
349
  parensIf(translation?.label));
350
350
  }
351
351
  case "Indefinite": {
@@ -360,7 +360,7 @@ const renderCost = (translate, translateMap, cost) => {
360
360
  return {
361
361
  label: translate("Cost (Bronze/Silver/Gold)"),
362
362
  value: translate("{$value} silverthalers", {
363
- value: [cost.bronze, cost.silver, cost.gold].join("/"),
363
+ value: [cost.bronze, cost.silver, cost.gold].map(formatNumber).join("/"),
364
364
  }),
365
365
  };
366
366
  }
@@ -404,8 +404,8 @@ const renderCost = (translate, translateMap, cost) => {
404
404
  }
405
405
  };
406
406
  const renderArmorValues = (translate, translateMap, localeCompare, getInstanceById, idMap, values) => [
407
- { label: translate("Protection"), value: values.protection.toString() },
408
- { label: translate("Encumbrance"), value: values.encumbrance.toString() },
407
+ { label: translate("Protection"), value: values.protection.toFixed() },
408
+ { label: translate("Encumbrance"), value: values.encumbrance.toFixed() },
409
409
  {
410
410
  label: translate("Additional Penalties"),
411
411
  value: values.has_additional_penalties
@@ -525,7 +525,7 @@ export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ g
525
525
  baseItemTranslation?.language !== undefined || baseItemTranslation?.script !== undefined
526
526
  ? {
527
527
  label: translate("Language/Script"),
528
- value: [baseItemTranslation?.language, baseItemTranslation?.script]
528
+ value: [baseItemTranslation.language, baseItemTranslation.script]
529
529
  .map(value => value ?? "—")
530
530
  .join(" / "),
531
531
  }
@@ -542,8 +542,8 @@ export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ g
542
542
  }),
543
543
  }
544
544
  : undefined,
545
- mapNullable(baseItem.weight, weight => renderWeight(translate, locale.measurementAdjustments, weight)),
546
- mapNullable(baseItem.cost, cost => renderCost(translate, translateMap, cost)),
545
+ mapNullable(baseItem.weight, weight => renderWeight(translate, locale.formatNumber, locale.measurementAdjustments, weight)),
546
+ mapNullable(baseItem.cost, cost => renderCost(translate, translateMap, locale.formatNumber, cost)),
547
547
  mapNullable(renderNote(translate, translateMap, getInstanceById, locale.join, combatValues?.type === "Weapon" ? combatValues.values.melee_uses : undefined, combatValues?.values.restrictedTo, name, baseItemTranslation?.note), note => ({
548
548
  label: translate("Note"),
549
549
  value: note,
@@ -115,7 +115,7 @@ const getAtomicEquipmentCost = (entry) => {
115
115
  entry.content.cost.silver,
116
116
  entry.content.cost.gold,
117
117
  ];
118
- return costs.map(getAtomicCost).reduce(rangeAtomicEquipmentCost);
118
+ return costs.reduce(rangeAtomicEquipmentCost);
119
119
  }
120
120
  case "Ammunition":
121
121
  case "Animal":
@@ -188,7 +188,8 @@ const getAtomicEquipmentWeight = (entry) => {
188
188
  return assertExhaustive(entry.content.type);
189
189
  }
190
190
  case "Jewelry": {
191
- const values = Object.values(entry.content.weight);
191
+ const { bronze, silver, gold } = entry.content.weight;
192
+ const values = [bronze, silver, gold];
192
193
  return [Math.min(...values), Math.max(...values)];
193
194
  }
194
195
  case "Armor":
@@ -269,7 +270,7 @@ export const getEquipmentPackageEntityDescription = createEntityDescriptionCreat
269
270
  ...item,
270
271
  content: { entity: item.id.kind, content: getInstanceById(item.id) },
271
272
  }))
272
- .filter((item) => item.content !== undefined) ?? [];
273
+ .filter((item) => item.content.content !== undefined) ?? [];
273
274
  return {
274
275
  title: translation.name,
275
276
  className: "equipment-package",
@@ -16,31 +16,31 @@ export const getExperienceLevelEntityDescription = createEntityDescriptionCreato
16
16
  items: [
17
17
  {
18
18
  label: translate("Adventure Points"),
19
- value: entry.adventure_points.toString(),
19
+ value: entry.adventure_points.toFixed(),
20
20
  },
21
21
  {
22
22
  label: translate("Maximum Attribute Value"),
23
- value: entry.max_attribute_value.toString(),
23
+ value: entry.max_attribute_value.toFixed(),
24
24
  },
25
25
  {
26
26
  label: translate("Maximum Skill Value"),
27
- value: entry.max_skill_rating.toString(),
27
+ value: entry.max_skill_rating.toFixed(),
28
28
  },
29
29
  {
30
30
  label: translate("Maximum Combat Technique"),
31
- value: entry.max_combat_technique_rating.toString(),
31
+ value: entry.max_combat_technique_rating.toFixed(),
32
32
  },
33
33
  {
34
34
  label: translate("Maximum Attribute Total"),
35
- value: entry.max_attribute_total.toString(),
35
+ value: entry.max_attribute_total.toFixed(),
36
36
  },
37
37
  {
38
38
  label: translate("Number of Spells/Liturgical Chants"),
39
- value: entry.max_number_of_spells_liturgical_chants.toString(),
39
+ value: entry.max_number_of_spells_liturgical_chants.toFixed(),
40
40
  },
41
41
  {
42
42
  label: translate("Number from other Traditions"),
43
- value: entry.max_number_of_unfamiliar_spells.toString(),
43
+ value: entry.max_number_of_unfamiliar_spells.toFixed(),
44
44
  },
45
45
  ],
46
46
  },
@@ -10,8 +10,8 @@ export const getFocusRuleEntityDescription = createEntityDescriptionCreator(({ g
10
10
  return undefined;
11
11
  }
12
12
  return {
13
- title: `${translation.name} (${romanize(entry.level)})`,
14
- subtitle: topicTranslation.name,
13
+ title: translation.name,
14
+ badge: entry.level,
15
15
  className: "focus-rule",
16
16
  body: [
17
17
  {
@@ -24,10 +24,10 @@ export const getInfluenceEntityDescription = createEntityDescriptionCreator(({ g
24
24
  : {
25
25
  type: "definitionList",
26
26
  items: [
27
- ...(translation.effects?.map(effect => ({
27
+ ...translation.effects.map(effect => ({
28
28
  label: effect.label,
29
29
  value: effect.text,
30
- })) ?? []),
30
+ })),
31
31
  entry.prerequisites === undefined
32
32
  ? undefined
33
33
  : {
@@ -1,6 +1,6 @@
1
1
  import { type RatedIdentifier } from "optolith-database-schema/gen";
2
2
  import type { GetAllChildInstancesForParent, GetInstanceById } from "../helpers/getTypes.js";
3
- import { type IdMap } from "../index.js";
3
+ import type { IdMap } from "../index.js";
4
4
  /**
5
5
  * Get a JSON representation of the rules text for a blessing.
6
6
  */
@@ -5,7 +5,7 @@ import { createEntityDescriptionCreator } from "../creator.js";
5
5
  import { renderEnhancements } from "./partial/enhancements.js";
6
6
  import { renderOneTimeDuration } from "./partial/rated/activatable/duration.js";
7
7
  import { renderEffect } from "./partial/rated/activatable/effect.js";
8
- import { renderFastPerformanceParameters, renderSlowPerformanceParameters, } from "./partial/rated/activatable/index.js";
8
+ import { combineGeneratedTextWithStaticTranslation, renderFastPerformanceParameters, renderSlowPerformanceParameters, } from "./partial/rated/activatable/index.js";
9
9
  import { ModifiableParameter } from "./partial/rated/activatable/nonModifiableSuffix.js";
10
10
  import { renderNonModifiableRange } from "./partial/rated/activatable/range.js";
11
11
  import { renderTargetCategory } from "./partial/rated/activatable/targetCategory.js";
@@ -73,16 +73,8 @@ export const getBlessingEntityDescription = createEntityDescriptionCreator(({ ge
73
73
  label: translate("Effect"),
74
74
  value: translation.effect,
75
75
  },
76
- {
77
- label: translate("Range"),
78
- value: range !== translation.range ? `***${range}*** (${translation.range})` : range,
79
- },
80
- {
81
- label: translate("Duration"),
82
- value: duration !== translation.duration
83
- ? `***${duration}*** (${translation.duration})`
84
- : duration,
85
- },
76
+ combineGeneratedTextWithStaticTranslation(translate("Range"), range, translation.range),
77
+ combineGeneratedTextWithStaticTranslation(translate("Duration"), duration, translation.duration),
86
78
  renderTargetCategory(entry.target).run(env),
87
79
  ],
88
80
  },
@@ -132,30 +124,10 @@ export const getLiturgicalChantEntityDescription = createEntityDescriptionCreato
132
124
  items: [
133
125
  renderSkillCheckWithPenalty(entry.check, entry.check_penalty, idMap).run(env),
134
126
  renderEffect(translation.effect).run(env),
135
- {
136
- label: translate("Liturgical Time"),
137
- value: translation.casting_time && castingTime !== translation.casting_time.full
138
- ? `***${castingTime}*** (${translation.casting_time.full})`
139
- : castingTime,
140
- },
141
- {
142
- label: translate("KP Cost"),
143
- value: translation.cost && cost !== translation.cost.full
144
- ? `***${cost}*** (${translation.cost.full})`
145
- : cost,
146
- },
147
- {
148
- label: translate("Range"),
149
- value: translation.range && range !== translation.range.full
150
- ? `***${range}*** (${translation.range.full})`
151
- : range,
152
- },
153
- {
154
- label: translate("Duration"),
155
- value: translation.duration && duration !== translation.duration.full
156
- ? `***${duration}*** (${translation.duration.full})`
157
- : duration,
158
- },
127
+ combineGeneratedTextWithStaticTranslation(translate("Liturgical Time"), castingTime, translation.casting_time),
128
+ combineGeneratedTextWithStaticTranslation(translate("KP Cost"), cost, translation.cost),
129
+ combineGeneratedTextWithStaticTranslation(translate("Range"), range, translation.range),
130
+ combineGeneratedTextWithStaticTranslation(translate("Duration"), duration, translation.duration),
159
131
  renderTargetCategory(entry.target).run(env),
160
132
  getTextForTraditions({
161
133
  translate,
@@ -213,30 +185,10 @@ export const getCeremonyEntityDescription = createEntityDescriptionCreator(({ ge
213
185
  items: [
214
186
  renderSkillCheckWithPenalty(entry.check, entry.check_penalty, idMap).run(env),
215
187
  renderEffect(translation.effect).run(env),
216
- {
217
- label: translate("Ceremonial Time"),
218
- value: translation.casting_time && castingTime !== translation.casting_time.full
219
- ? `***${castingTime}*** (${translation.casting_time.full})`
220
- : castingTime,
221
- },
222
- {
223
- label: translate("KP Cost"),
224
- value: translation.cost && cost !== translation.cost.full
225
- ? `***${cost}*** (${translation.cost.full})`
226
- : cost,
227
- },
228
- {
229
- label: translate("Range"),
230
- value: translation.range && range !== translation.range.full
231
- ? `***${range}*** (${translation.range.full})`
232
- : range,
233
- },
234
- {
235
- label: translate("Duration"),
236
- value: translation.duration && duration !== translation.duration.full
237
- ? `***${duration}*** (${translation.duration.full})`
238
- : duration,
239
- },
188
+ combineGeneratedTextWithStaticTranslation(translate("Ceremonial Time"), castingTime, translation.casting_time),
189
+ combineGeneratedTextWithStaticTranslation(translate("KP Cost"), cost, translation.cost),
190
+ combineGeneratedTextWithStaticTranslation(translate("Range"), range, translation.range),
191
+ combineGeneratedTextWithStaticTranslation(translate("Duration"), duration, translation.duration),
240
192
  renderTargetCategory(entry.target).run(env),
241
193
  getTextForTraditions({
242
194
  translate,
@@ -19,8 +19,8 @@ const renderSelectOptionsAdventurePointsValue = (locale, derivedLabel, getAllSel
19
19
  }
20
20
  case "Fixed":
21
21
  return Map.groupBy(getAllSelectOptions().map((item) => [
22
- config.Fixed.map.find(mapItem => deepEqual(mapItem.id, item.id))
23
- ?.ap_value ?? config.Fixed.default,
22
+ config.Fixed.map.find(mapItem => deepEqual(mapItem.id, item.id))?.ap_value ??
23
+ config.Fixed.default,
24
24
  item,
25
25
  ]), item => item[0])
26
26
  .entries()
@@ -52,10 +52,14 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
52
52
  switch (value.kind) {
53
53
  case "Fixed": {
54
54
  if (entry.levels === undefined) {
55
- return translate(".input {$value :number} {{{$value} Adventure Points}}", { value: value.Fixed });
55
+ return translate(".input {$value :number} {{{$value} Adventure Points}}", {
56
+ value: value.Fixed,
57
+ });
56
58
  }
57
59
  else {
58
- return translate(".input {$value :number} {{{$value} Adventure Points per level}}", { value: value.Fixed });
60
+ return translate(".input {$value :number} {{{$value} Adventure Points per level}}", {
61
+ value: value.Fixed,
62
+ });
59
63
  }
60
64
  }
61
65
  case "ByLevel": {
@@ -70,19 +74,11 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
70
74
  return mainValue;
71
75
  }
72
76
  else {
73
- const sizeCategories = [
74
- "tiny",
75
- "small",
76
- "medium",
77
- "large",
78
- "huge",
79
- ];
77
+ const sizeCategories = ["tiny", "small", "medium", "large", "huge"];
80
78
  const values = sizeCategories
81
79
  .map(sizeCategory => additionalBySizeCategory[sizeCategory])
82
80
  .join("/");
83
- const labels = sizeCategories
84
- .map(sizeCategory => translate(sizeCategory))
85
- .join("/");
81
+ const labels = sizeCategories.map(sizeCategory => translate(sizeCategory)).join("/");
86
82
  return `${mainValue} + ${translate("{$values} AP for size category {$labels} (per level)", { values, labels })}`;
87
83
  }
88
84
  }
@@ -111,8 +107,7 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
111
107
  return translate("{$values} adventure points for a {$sized} animal shape", {
112
108
  values: sizes.map(size => size.content.ap_value).join("/"),
113
109
  sized: sizes
114
- .map(size => translateMap(size.content.translations)?.name ??
115
- MISSING_VALUE)
110
+ .map(size => translateMap(size.content.translations)?.name ?? MISSING_VALUE)
116
111
  .join("/"),
117
112
  });
118
113
  }
@@ -158,6 +153,7 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
158
153
  return renderSelectOptionsAdventurePointsValue(locale, () => {
159
154
  switch (derivedSelectOptions.Skills.categories.length) {
160
155
  case 1: {
156
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- ensured by the schema
161
157
  const first = derivedSelectOptions.Skills.categories[0];
162
158
  switch (first.kind) {
163
159
  case "Skills":
@@ -177,8 +173,7 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
177
173
  case 2:
178
174
  return derivedSelectOptions.Skills.categories.every(category => category.kind === "Spells" || category.kind === "Rituals")
179
175
  ? translate("A/B/C/D spellwork")
180
- : derivedSelectOptions.Skills.categories.every(category => category.kind === "LiturgicalChants" ||
181
- category.kind === "Ceremonies")
176
+ : derivedSelectOptions.Skills.categories.every(category => category.kind === "LiturgicalChants" || category.kind === "Ceremonies")
182
177
  ? translate("A/B/C/D liturgical chant or ceremony")
183
178
  : translate("A/B/C/D ability");
184
179
  default:
@@ -218,7 +213,7 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
218
213
  return assertExhaustive(exprValue);
219
214
  }
220
215
  })).join("/");
221
- const labels = Array.from({ length: entry.maximum ?? 3 }, (_, index) => `${index + 1}.`).join("/");
216
+ const labels = Array.from({ length: entry.maximum ?? 3 }, (_, index) => `${(index + 1).toFixed()}.`).join("/");
222
217
  if (entry.maximum !== undefined) {
223
218
  return translate("{$values} Adventure Points for the {$labels} purchase", {
224
219
  values,
@@ -1,4 +1,4 @@
1
- import { RatedIdentifier, type ImprovementCost, type SkillWithEnhancementsIdentifier } from "optolith-database-schema/gen";
1
+ import type { ImprovementCost, RatedIdentifier, SkillWithEnhancementsIdentifier } from "optolith-database-schema/gen";
2
2
  import type { RawEntityDescriptionSection } from "../../index.js";
3
3
  import { type StdReader } from "./reader.js";
4
4
  /**