@optolith/entity-descriptions 0.2.1 → 0.3.1

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 (187) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/lib/creator.d.ts +32 -0
  3. package/lib/creator.js +72 -0
  4. package/lib/entities/activatable.d.ts +52 -0
  5. package/lib/entities/activatable.js +609 -0
  6. package/lib/entities/alternativeRule.d.ts +7 -0
  7. package/lib/entities/alternativeRule.js +21 -0
  8. package/lib/entities/attribute.d.ts +6 -0
  9. package/lib/entities/attribute.js +15 -0
  10. package/lib/entities/combatTechnique.d.ts +5 -7
  11. package/lib/entities/combatTechnique.js +34 -24
  12. package/lib/entities/condition.d.ts +12 -0
  13. package/lib/entities/condition.js +63 -0
  14. package/lib/entities/culture.d.ts +8 -0
  15. package/lib/entities/culture.js +309 -0
  16. package/lib/entities/curriculum.d.ts +11 -0
  17. package/lib/entities/curriculum.js +266 -0
  18. package/lib/entities/derivedCharacteristic.d.ts +9 -0
  19. package/lib/entities/derivedCharacteristic.js +91 -0
  20. package/lib/entities/disease.d.ts +9 -0
  21. package/lib/entities/disease.js +88 -0
  22. package/lib/entities/elixir.d.ts +10 -0
  23. package/lib/entities/elixir.js +76 -0
  24. package/lib/entities/equipment.d.ts +24 -0
  25. package/lib/entities/equipment.js +613 -0
  26. package/lib/entities/equipmentPackage.d.ts +8 -0
  27. package/lib/entities/equipmentPackage.js +301 -0
  28. package/lib/entities/experienceLevel.d.ts +3 -2
  29. package/lib/entities/experienceLevel.js +33 -28
  30. package/lib/entities/focusRule.d.ts +3 -4
  31. package/lib/entities/focusRule.js +13 -5
  32. package/lib/entities/influence.d.ts +7 -0
  33. package/lib/entities/influence.js +35 -0
  34. package/lib/entities/liturgicalChant.d.ts +10 -23
  35. package/lib/entities/liturgicalChant.js +169 -131
  36. package/lib/entities/optionalRule.d.ts +3 -2
  37. package/lib/entities/optionalRule.js +4 -3
  38. package/lib/entities/partial/activatableNameChunks.d.ts +58 -0
  39. package/lib/entities/partial/activatableNameChunks.js +356 -0
  40. package/lib/entities/partial/adventurePointsValue.d.ts +9 -0
  41. package/lib/entities/partial/adventurePointsValue.js +243 -0
  42. package/lib/entities/partial/animalTypes.d.ts +11 -0
  43. package/lib/entities/partial/animalTypes.js +13 -0
  44. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.d.ts +16 -0
  45. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.js +40 -0
  46. package/lib/entities/partial/dice.d.ts +10 -0
  47. package/lib/entities/partial/dice.js +13 -0
  48. package/lib/entities/partial/herbary.d.ts +28 -0
  49. package/lib/entities/partial/herbary.js +65 -0
  50. package/lib/entities/partial/map.d.ts +49 -0
  51. package/lib/entities/partial/map.js +43 -0
  52. package/lib/entities/partial/mathOperation.d.ts +36 -0
  53. package/lib/entities/partial/mathOperation.js +107 -0
  54. package/lib/entities/partial/prerequisites/displayOption.d.ts +7 -0
  55. package/lib/entities/partial/prerequisites/displayOption.js +19 -0
  56. package/lib/entities/partial/prerequisites/index.d.ts +67 -0
  57. package/lib/entities/partial/prerequisites/index.js +189 -0
  58. package/lib/entities/partial/prerequisites/part.d.ts +26 -0
  59. package/lib/entities/partial/prerequisites/part.js +88 -0
  60. package/lib/entities/partial/prerequisites/prerequisiteGroups.d.ts +65 -0
  61. package/lib/entities/partial/prerequisites/prerequisiteGroups.js +269 -0
  62. package/lib/entities/partial/prerequisites/single/activatable.d.ts +18 -0
  63. package/lib/entities/partial/prerequisites/single/activatable.js +40 -0
  64. package/lib/entities/partial/prerequisites/single/animistPower.d.ts +8 -0
  65. package/lib/entities/partial/prerequisites/single/animistPower.js +23 -0
  66. package/lib/entities/partial/prerequisites/single/blessedTradition.d.ts +7 -0
  67. package/lib/entities/partial/prerequisites/single/blessedTradition.js +32 -0
  68. package/lib/entities/partial/prerequisites/single/commonSuggestedByRCP.d.ts +6 -0
  69. package/lib/entities/partial/prerequisites/single/commonSuggestedByRCP.js +19 -0
  70. package/lib/entities/partial/prerequisites/single/culture.d.ts +8 -0
  71. package/lib/entities/partial/prerequisites/single/culture.js +20 -0
  72. package/lib/entities/partial/prerequisites/single/enhancement.d.ts +8 -0
  73. package/lib/entities/partial/prerequisites/single/enhancement.js +41 -0
  74. package/lib/entities/partial/prerequisites/single/influence.d.ts +8 -0
  75. package/lib/entities/partial/prerequisites/single/influence.js +17 -0
  76. package/lib/entities/partial/prerequisites/single/magicalTradition.d.ts +7 -0
  77. package/lib/entities/partial/prerequisites/single/magicalTradition.js +27 -0
  78. package/lib/entities/partial/prerequisites/single/noOtherAncestorBloodAdvantage.d.ts +6 -0
  79. package/lib/entities/partial/prerequisites/single/noOtherAncestorBloodAdvantage.js +8 -0
  80. package/lib/entities/partial/prerequisites/single/pact.d.ts +8 -0
  81. package/lib/entities/partial/prerequisites/single/pact.js +30 -0
  82. package/lib/entities/partial/prerequisites/single/personalityTrait.d.ts +8 -0
  83. package/lib/entities/partial/prerequisites/single/personalityTrait.js +28 -0
  84. package/lib/entities/partial/prerequisites/single/primaryAttribute.d.ts +7 -0
  85. package/lib/entities/partial/prerequisites/single/primaryAttribute.js +15 -0
  86. package/lib/entities/partial/prerequisites/single/publication.d.ts +8 -0
  87. package/lib/entities/partial/prerequisites/single/publication.js +19 -0
  88. package/lib/entities/partial/prerequisites/single/race.d.ts +8 -0
  89. package/lib/entities/partial/prerequisites/single/race.js +20 -0
  90. package/lib/entities/partial/prerequisites/single/rated.d.ts +8 -0
  91. package/lib/entities/partial/prerequisites/single/rated.js +41 -0
  92. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.d.ts +8 -0
  93. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.js +89 -0
  94. package/lib/entities/partial/prerequisites/single/ratedSum.d.ts +8 -0
  95. package/lib/entities/partial/prerequisites/single/ratedSum.js +21 -0
  96. package/lib/entities/partial/prerequisites/single/rule.d.ts +7 -0
  97. package/lib/entities/partial/prerequisites/single/rule.js +4 -0
  98. package/lib/entities/partial/prerequisites/single/sex.d.ts +7 -0
  99. package/lib/entities/partial/prerequisites/single/sex.js +19 -0
  100. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.d.ts +7 -0
  101. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.js +21 -0
  102. package/lib/entities/partial/prerequisites/single/socialStatus.d.ts +8 -0
  103. package/lib/entities/partial/prerequisites/single/socialStatus.js +21 -0
  104. package/lib/entities/partial/prerequisites/single/state.d.ts +8 -0
  105. package/lib/entities/partial/prerequisites/single/state.js +20 -0
  106. package/lib/entities/partial/prerequisites/single/text.d.ts +7 -0
  107. package/lib/entities/partial/prerequisites/single/text.js +9 -0
  108. package/lib/entities/partial/professions.d.ts +15 -0
  109. package/lib/entities/partial/professions.js +19 -0
  110. package/lib/entities/partial/rated/activatable/castingTime.d.ts +16 -7
  111. package/lib/entities/partial/rated/activatable/castingTime.js +35 -20
  112. package/lib/entities/partial/rated/activatable/checkResultBased.d.ts +18 -3
  113. package/lib/entities/partial/rated/activatable/checkResultBased.js +18 -10
  114. package/lib/entities/partial/rated/activatable/cost.d.ts +88 -8
  115. package/lib/entities/partial/rated/activatable/cost.js +183 -115
  116. package/lib/entities/partial/rated/activatable/duration.d.ts +36 -13
  117. package/lib/entities/partial/rated/activatable/duration.js +72 -61
  118. package/lib/entities/partial/rated/activatable/effect.d.ts +4 -4
  119. package/lib/entities/partial/rated/activatable/effect.js +32 -25
  120. package/lib/entities/partial/rated/activatable/index.d.ts +31 -27
  121. package/lib/entities/partial/rated/activatable/index.js +63 -28
  122. package/lib/entities/partial/rated/activatable/isMinimumMaximum.d.ts +5 -6
  123. package/lib/entities/partial/rated/activatable/isMinimumMaximum.js +8 -5
  124. package/lib/entities/partial/rated/activatable/nonModifiableSuffix.d.ts +2 -4
  125. package/lib/entities/partial/rated/activatable/nonModifiableSuffix.js +7 -42
  126. package/lib/entities/partial/rated/activatable/range.d.ts +22 -14
  127. package/lib/entities/partial/rated/activatable/range.js +54 -54
  128. package/lib/entities/partial/rated/activatable/speed.d.ts +11 -2
  129. package/lib/entities/partial/rated/activatable/speed.js +14 -1
  130. package/lib/entities/partial/rated/activatable/targetCategory.d.ts +4 -5
  131. package/lib/entities/partial/rated/activatable/targetCategory.js +19 -24
  132. package/lib/entities/partial/rated/improvementCost.d.ts +16 -4
  133. package/lib/entities/partial/rated/improvementCost.js +63 -4
  134. package/lib/entities/partial/rated/skillCheck.d.ts +20 -17
  135. package/lib/entities/partial/rated/skillCheck.js +56 -54
  136. package/lib/entities/partial/reader.d.ts +266 -0
  137. package/lib/entities/partial/reader.js +175 -0
  138. package/lib/entities/partial/responsiveText.d.ts +10 -5
  139. package/lib/entities/partial/responsiveText.js +19 -3
  140. package/lib/entities/partial/units/energy.d.ts +5 -8
  141. package/lib/entities/partial/units/energy.js +5 -23
  142. package/lib/entities/partial/units/length.d.ts +20 -2
  143. package/lib/entities/partial/units/length.js +24 -5
  144. package/lib/entities/partial/units/timeSpan.d.ts +25 -4
  145. package/lib/entities/partial/units/timeSpan.js +27 -15
  146. package/lib/entities/partial/unknown.d.ts +5 -1
  147. package/lib/entities/partial/unknown.js +5 -1
  148. package/lib/entities/personalityTrait.d.ts +7 -0
  149. package/lib/entities/personalityTrait.js +56 -0
  150. package/lib/entities/poison.d.ts +12 -0
  151. package/lib/entities/poison.js +356 -0
  152. package/lib/entities/profession.d.ts +12 -0
  153. package/lib/entities/profession.js +585 -0
  154. package/lib/entities/race.d.ts +9 -0
  155. package/lib/entities/race.js +146 -0
  156. package/lib/entities/sexPractice.d.ts +6 -0
  157. package/lib/entities/sexPractice.js +33 -0
  158. package/lib/entities/skill.d.ts +9 -9
  159. package/lib/entities/skill.js +124 -91
  160. package/lib/entities/spell.d.ts +83 -26
  161. package/lib/entities/spell.js +835 -147
  162. package/lib/entities/state.d.ts +6 -0
  163. package/lib/entities/state.js +17 -0
  164. package/lib/helpers/enums.d.ts +11 -0
  165. package/lib/helpers/enums.js +6 -0
  166. package/lib/helpers/getTypes.d.ts +12 -482
  167. package/lib/helpers/getTypes.js +1 -0
  168. package/lib/helpers/identifiers.d.ts +314 -0
  169. package/lib/helpers/identifiers.js +333 -0
  170. package/lib/helpers/locale.d.ts +21 -2
  171. package/lib/helpers/translate.d.ts +47 -5
  172. package/lib/helpers/translate.js +13 -6
  173. package/lib/index.d.ts +848 -21
  174. package/lib/index.js +182 -17
  175. package/lib/references/index.d.ts +6 -3
  176. package/lib/references/index.js +25 -33
  177. package/lib/references/page.d.ts +1 -1
  178. package/lib/references/page.js +14 -14
  179. package/lib/references/pageRange.d.ts +1 -5
  180. package/lib/references/pageRange.js +7 -16
  181. package/lib/tsconfig.tsbuildinfo +1 -0
  182. package/package.json +30 -10
  183. package/.prettierrc.yml +0 -1
  184. package/lib/entities/partial/rated/activatable/entity.d.ts +0 -11
  185. package/lib/entities/partial/rated/activatable/entity.js +0 -12
  186. package/lib/references/occurrence.d.ts +0 -4
  187. package/lib/references/occurrence.js +0 -3
@@ -0,0 +1,266 @@
1
+ import { partition } from "@elyukai/utils/array/groups";
2
+ import { Dictionary } from "@elyukai/utils/dictionary";
3
+ import { deepEqual } from "@elyukai/utils/equality";
4
+ import { sign } from "@elyukai/utils/string/number";
5
+ import { assertExhaustive } from "@elyukai/utils/typeSafety";
6
+ import { isNotNullish, mapNullable } from "@optolith/helpers/nullable";
7
+ import { createEntityDescriptionCreator } from "../creator.js";
8
+ import { getBaseProfessionPackageForCurriculum } from "./partial/professions.js";
9
+ import { parensIf } from "./partial/rated/activatable/parensIf.js";
10
+ import { MISSING_VALUE } from "./partial/unknown.js";
11
+ const renderElectiveSpellworks = (translate, translateMap, localeCompare, getInstanceById, electiveSpellworks) => {
12
+ switch (electiveSpellworks.kind) {
13
+ case "DefinedByGameMaster":
14
+ return translate("All, at the GM’s discretion");
15
+ case "Specific":
16
+ return electiveSpellworks.Specific.list
17
+ .map(item => mapNullable(translateMap(getInstanceById(item.id)?.translations)?.name, name => {
18
+ if (item.restriction === undefined) {
19
+ return name;
20
+ }
21
+ return (name +
22
+ parensIf(translateMap(getInstanceById("Element", item.restriction.Element)
23
+ ?.translations)?.name ?? MISSING_VALUE));
24
+ }))
25
+ .filter(isNotNullish)
26
+ .toSorted(localeCompare)
27
+ .join(", ");
28
+ default:
29
+ return assertExhaustive(electiveSpellworks);
30
+ }
31
+ };
32
+ const renderRestrictedSpellworks = (translate, translateMap, localeCompare, localeJoin, getInstanceById, restrictedSpellworks) => {
33
+ const restrictedGroups = Dictionary.groupBy(restrictedSpellworks, restriction => restriction.kind === "Spellwork"
34
+ ? "spellwork"
35
+ : restriction.kind === "Property" &&
36
+ restriction.Property.maximum !== undefined
37
+ ? "restrictedProperty"
38
+ : restriction.kind === "Property" ||
39
+ restriction.kind === "DemonSummoning"
40
+ ? "property"
41
+ : "other");
42
+ const addExclusion = (excludedSpellworks) => {
43
+ if (excludedSpellworks === undefined) {
44
+ return "";
45
+ }
46
+ const translatedSpellworks = excludedSpellworks
47
+ .map(excludedSpellwork => translateMap(getInstanceById(excludedSpellwork)?.translations)?.name)
48
+ .filter(isNotNullish);
49
+ if (translatedSpellworks.length === 0) {
50
+ return "";
51
+ }
52
+ return ` (${translate("except {$list}", {
53
+ list: localeJoin(translatedSpellworks, "conjunction"),
54
+ })})`;
55
+ };
56
+ const restrictedProperties = restrictedGroups.get("restrictedProperty")?.map(restriction => translate(".input {$count :number} {{only {$count} additional spellworks with the Property {$property}}}", {
57
+ count: restriction.Property.maximum,
58
+ property: translateMap(getInstanceById("Property", restriction.Property.id)
59
+ ?.translations)?.name ?? MISSING_VALUE,
60
+ }) + addExclusion(restriction.Property.exclude)) ?? [];
61
+ const propertyGroup = restrictedGroups.get("property");
62
+ const translatedProperties = propertyGroup
63
+ ?.map(restriction => {
64
+ switch (restriction.kind) {
65
+ case "Property":
66
+ return translateMap(getInstanceById("Property", restriction.Property.id)
67
+ ?.translations)?.name;
68
+ case "DemonSummoning":
69
+ return translate("Demon Summoning");
70
+ default:
71
+ return assertExhaustive(restriction);
72
+ }
73
+ })
74
+ .filter(isNotNullish)
75
+ .toSorted(localeCompare) ?? [];
76
+ const properties = translatedProperties.length > 0
77
+ ? [
78
+ translate("no spellworks with the Property {$property}", {
79
+ property: localeJoin(translatedProperties, "disjunction"),
80
+ }),
81
+ ]
82
+ : [];
83
+ const spellworkGroup = restrictedGroups.get("spellwork");
84
+ const translatedSpellworks = spellworkGroup
85
+ ?.map(restriction => translateMap(getInstanceById(restriction.Spellwork)?.translations)
86
+ ?.name)
87
+ .filter(isNotNullish)
88
+ .toSorted(localeCompare) ?? [];
89
+ const spellworks = translatedSpellworks.length > 0
90
+ ? [
91
+ translate("the following spells are not taught: {$spells}", {
92
+ spells: translatedSpellworks.join(", "),
93
+ }),
94
+ ]
95
+ : [];
96
+ const otherGroup = restrictedGroups.get("other");
97
+ const others = otherGroup?.map(restriction => {
98
+ switch (restriction.kind) {
99
+ case "Borbaradian":
100
+ return translate("no Borbaradian spellworks");
101
+ case "DamageIntelligent":
102
+ return translate("no spellworks that inflict DP or sDP on intelligent creatures");
103
+ default:
104
+ return assertExhaustive(restriction);
105
+ }
106
+ }) ?? [];
107
+ return [
108
+ ...restrictedProperties,
109
+ ...properties,
110
+ ...others,
111
+ ...spellworks,
112
+ ].join("; ");
113
+ };
114
+ const renderSpellworkAdjustment = (translateMap, getInstanceById, adjustment) => `${translateMap(getInstanceById(adjustment.id)?.translations)?.name ??
115
+ MISSING_VALUE} ${adjustment.points}${parensIf(adjustment.tradition === undefined
116
+ ? undefined
117
+ : translateMap(getInstanceById("MagicalTradition", adjustment.tradition)
118
+ ?.translations)?.name)}`;
119
+ const renderAbilityAdjustmentName = (translateMap, getInstanceById, abilityAdjustment) => {
120
+ switch (abilityAdjustment.kind) {
121
+ case "Skill":
122
+ return (translateMap(getInstanceById("Skill", abilityAdjustment.Skill.id)?.translations)?.name ?? MISSING_VALUE);
123
+ case "CombatTechnique":
124
+ return (translateMap(getInstanceById(abilityAdjustment.CombatTechnique.id)?.translations)?.name ?? MISSING_VALUE);
125
+ case "Spellwork":
126
+ return ((translateMap(getInstanceById(abilityAdjustment.Spellwork.id)?.translations)?.name ?? MISSING_VALUE) +
127
+ parensIf(abilityAdjustment.Spellwork.tradition === undefined
128
+ ? undefined
129
+ : translateMap(getInstanceById("MagicalTradition", abilityAdjustment.Spellwork.tradition)?.translations)?.name));
130
+ default:
131
+ return assertExhaustive(abilityAdjustment);
132
+ }
133
+ };
134
+ const renderAbilityAdjustmentBaseValue = (baseProfessionPackage, abilityAdjustment) => {
135
+ switch (abilityAdjustment.kind) {
136
+ case "Skill":
137
+ return baseProfessionPackage.skills?.find(skill => skill.id === abilityAdjustment.Skill.id)?.rating_modifier;
138
+ case "CombatTechnique":
139
+ return baseProfessionPackage.combat_techniques?.find(skill => deepEqual(skill.id, abilityAdjustment.CombatTechnique.id))?.rating_modifier;
140
+ case "Spellwork":
141
+ return baseProfessionPackage.spells?.find(spell => spell.id.some(someSpell => someSpell.kind === "Spellwork" &&
142
+ deepEqual(someSpell.Spellwork.id, abilityAdjustment.Spellwork.id)))?.rating_modifier;
143
+ default:
144
+ return assertExhaustive(abilityAdjustment);
145
+ }
146
+ };
147
+ const renderAbilityAdjustmentModifierValue = (abilityAdjustment) => {
148
+ switch (abilityAdjustment.kind) {
149
+ case "Skill":
150
+ return abilityAdjustment.Skill.points;
151
+ case "CombatTechnique":
152
+ return abilityAdjustment.CombatTechnique.points;
153
+ case "Spellwork":
154
+ return abilityAdjustment.Spellwork.points;
155
+ default:
156
+ return assertExhaustive(abilityAdjustment);
157
+ }
158
+ };
159
+ const renderAbilityAdjustmentDefaultValue = (abilityAdjustment) => {
160
+ switch (abilityAdjustment.kind) {
161
+ case "Skill":
162
+ return 0;
163
+ case "CombatTechnique":
164
+ return 6;
165
+ case "Spellwork":
166
+ return 0;
167
+ default:
168
+ return assertExhaustive(abilityAdjustment);
169
+ }
170
+ };
171
+ const renderAbilityAdjustment = (translate, translateMap, getInstanceById, baseProfessionPackage) => baseProfessionPackage === undefined
172
+ ? abilityAdjustment => `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${sign(renderAbilityAdjustmentModifierValue(abilityAdjustment))}`
173
+ : abilityAdjustment => {
174
+ const basePoints = (renderAbilityAdjustmentBaseValue(baseProfessionPackage, abilityAdjustment) ?? 0) + renderAbilityAdjustmentDefaultValue(abilityAdjustment);
175
+ return translate("{$replacement} instead of {$base}", {
176
+ base: basePoints,
177
+ replacement: `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${basePoints + renderAbilityAdjustmentModifierValue(abilityAdjustment)}`,
178
+ });
179
+ };
180
+ const renderAbilityAdjustments = (translate, translateMap, localeCompare, getInstanceById, baseProfessionPackage, list) => list
181
+ ?.map(renderAbilityAdjustment(translate, translateMap, getInstanceById, baseProfessionPackage))
182
+ .toSorted(localeCompare)
183
+ .join(", ") ?? translate("none");
184
+ /**
185
+ * Get a JSON representation of the rules text for a curriculum.
186
+ */
187
+ export const getCurriculumEntityDescription = createEntityDescriptionCreator(({ getInstanceById, getAllInstances, getChildInstancesForInstanceId, idMap }, { translate, translateMap, compare: localeCompare, join: localeJoin }, { content: entry, id }) => {
188
+ const translation = translateMap(entry.translations);
189
+ if (translation === undefined) {
190
+ return undefined;
191
+ }
192
+ const baseProfessionPackage = getBaseProfessionPackageForCurriculum(getAllInstances, getChildInstancesForInstanceId, idMap, id)?.content;
193
+ return {
194
+ title: translation.name,
195
+ className: "curriculum",
196
+ body: [
197
+ {
198
+ type: "definitionList",
199
+ items: [
200
+ {
201
+ label: translate("Guideline"),
202
+ value: translateMap(getInstanceById("Guideline", entry.guideline)?.translations)?.name ?? MISSING_VALUE,
203
+ },
204
+ {
205
+ label: translate("Elective Spellworks Package"),
206
+ value: entry.elective_spellworks === undefined
207
+ ? translate("none")
208
+ : renderElectiveSpellworks(translate, translateMap, localeCompare, getInstanceById, entry.elective_spellworks),
209
+ },
210
+ {
211
+ label: translate("Restricted Spellworks"),
212
+ value: entry.restricted_spellworks === undefined
213
+ ? translate("none")
214
+ : renderRestrictedSpellworks(translate, translateMap, localeCompare, localeJoin, getInstanceById, entry.restricted_spellworks),
215
+ },
216
+ ],
217
+ },
218
+ ...getChildInstancesForInstanceId("LessonPackage", id)
219
+ .map(lessonPackage => mapNullable(translateMap(lessonPackage.content.translations), (lessonPackageTranslation) => {
220
+ const [boni, mali] = partition(lessonPackage.content.skills ?? [], adjustment => {
221
+ switch (adjustment.kind) {
222
+ case "Skill":
223
+ return adjustment.Skill.points > 0;
224
+ case "CombatTechnique":
225
+ return adjustment.CombatTechnique.points > 0;
226
+ case "Spellwork":
227
+ return adjustment.Spellwork.points > 0;
228
+ default:
229
+ return assertExhaustive(adjustment);
230
+ }
231
+ });
232
+ return {
233
+ type: "labeled",
234
+ label: lessonPackageTranslation.name,
235
+ value: {
236
+ type: "definitionList",
237
+ items: [
238
+ {
239
+ label: translate("Spellwork Changes"),
240
+ value: lessonPackageTranslation?.spellwork_changes ??
241
+ lessonPackage.content.spellwork_changes
242
+ ?.map(change => translate("{$replacement} instead of {$base}", {
243
+ base: renderSpellworkAdjustment(translateMap, getInstanceById, change.base),
244
+ replacement: renderSpellworkAdjustment(translateMap, getInstanceById, change.replacement),
245
+ }))
246
+ .join(", ") ??
247
+ translate("none"),
248
+ },
249
+ {
250
+ label: translate("Skills (+)"),
251
+ value: renderAbilityAdjustments(translate, translateMap, localeCompare, getInstanceById, baseProfessionPackage, boni),
252
+ },
253
+ {
254
+ label: translate("Skills (−)"),
255
+ value: renderAbilityAdjustments(translate, translateMap, localeCompare, getInstanceById, baseProfessionPackage, mali),
256
+ },
257
+ ],
258
+ },
259
+ };
260
+ }))
261
+ .filter(isNotNullish),
262
+ ],
263
+ errata: translation.errata,
264
+ references: entry.src,
265
+ };
266
+ });
@@ -0,0 +1,9 @@
1
+ import type { GetInstanceById } from "../helpers/getTypes.js";
2
+ import type { IdMap } from "../index.js";
3
+ /**
4
+ * Get a JSON representation of the rules text for a derived characteristic.
5
+ */
6
+ export declare const getDerivedCharacteristicEntityDescription: import("../creator.js").EntityDescriptionCreator<"DerivedCharacteristic", {
7
+ getInstanceById: GetInstanceById<"Publication" | "Attribute" | "DerivedCharacteristic">;
8
+ idMap: IdMap;
9
+ }, import("../index.js").EntityDescription>;
@@ -0,0 +1,91 @@
1
+ import { assertExhaustive } from "@optolith/helpers/typeSafety";
2
+ import { createEntityDescriptionCreator } from "../creator.js";
3
+ import { renderMathOperation } from "./partial/mathOperation.js";
4
+ import { MISSING_VALUE } from "./partial/unknown.js";
5
+ const getAttribute = (getInstanceById, translateMap, attributeId, style = "full") => {
6
+ const attribute = getInstanceById("Attribute", attributeId);
7
+ if (attribute === undefined) {
8
+ return MISSING_VALUE;
9
+ }
10
+ switch (style) {
11
+ case "full":
12
+ return translateMap(attribute.translations)?.name ?? MISSING_VALUE;
13
+ case "compact":
14
+ return translateMap(attribute.translations)?.abbreviation ?? MISSING_VALUE;
15
+ default:
16
+ return assertExhaustive(style);
17
+ }
18
+ };
19
+ const getRaceBaseValue = (translate, translateMap, getInstanceById, idMap, raceBaseValue, style = "full") => {
20
+ const instance = getInstanceById("DerivedCharacteristic", idMap.DerivedCharacteristic[raceBaseValue.kind]);
21
+ const translation = translateMap(instance?.translations);
22
+ if (translation === undefined) {
23
+ return MISSING_VALUE;
24
+ }
25
+ switch (style) {
26
+ case "full":
27
+ return translate("Base {$name} from Race", translation);
28
+ case "compact":
29
+ return translate("Race Base {$abbreviation}", translation);
30
+ default:
31
+ return assertExhaustive(style);
32
+ }
33
+ };
34
+ const renderBaseCalculation = (getInstanceById, translate, translateMap, idMap, calculation, style = "full") => renderMathOperation(calculation, value => {
35
+ switch (value.kind) {
36
+ case "Constant":
37
+ return value.Constant.toString(10);
38
+ case "Attribute":
39
+ return getAttribute(getInstanceById, translateMap, value.Attribute, style);
40
+ case "RaceBaseValue":
41
+ return getRaceBaseValue(translate, translateMap, getInstanceById, idMap, value.RaceBaseValue, style);
42
+ case "PrimaryAttribute":
43
+ switch (style) {
44
+ case "full":
45
+ switch (value.PrimaryAttribute.kind) {
46
+ case "Magical":
47
+ return translate("Primary attribute for the magic user’s Tradition");
48
+ case "Blessed":
49
+ return translate("Primary attribute for the Blessed One’s Tradition");
50
+ default:
51
+ return assertExhaustive(value.PrimaryAttribute);
52
+ }
53
+ case "compact":
54
+ return translate("Primary Attribute");
55
+ default:
56
+ return assertExhaustive(style);
57
+ }
58
+ default:
59
+ return assertExhaustive(value);
60
+ }
61
+ });
62
+ /**
63
+ * Get a JSON representation of the rules text for a derived characteristic.
64
+ */
65
+ export const getDerivedCharacteristicEntityDescription = createEntityDescriptionCreator(({ getInstanceById, idMap }, { translate, translateMap }, { content: entry }) => {
66
+ const translation = translateMap(entry.translations);
67
+ if (translation === undefined) {
68
+ return undefined;
69
+ }
70
+ return {
71
+ title: `${translation.name} (${translation.abbreviation})`,
72
+ className: "derived-characteristic",
73
+ body: [
74
+ translation.description === undefined
75
+ ? undefined
76
+ : {
77
+ type: "plain",
78
+ text: translation.description,
79
+ },
80
+ {
81
+ type: "definitionList",
82
+ items: [
83
+ {
84
+ label: translate("Base Value"),
85
+ value: renderBaseCalculation(getInstanceById, translate, translateMap, idMap, entry.calculation.base),
86
+ },
87
+ ],
88
+ },
89
+ ],
90
+ };
91
+ });
@@ -0,0 +1,9 @@
1
+ import type { GetInstanceById } from "../helpers/getTypes.js";
2
+ import type { IdMap } from "../index.js";
3
+ /**
4
+ * Get a JSON representation of the rules text for an optional rule.
5
+ */
6
+ export declare const getDiseaseEntityDescription: import("../creator.js").EntityDescriptionCreator<"AnimalDisease" | "Disease", {
7
+ getInstanceById: GetInstanceById<"Publication" | "AnimalType" | "DerivedCharacteristic">;
8
+ idMap: IdMap;
9
+ }, import("../index.js").EntityDescription>;
@@ -0,0 +1,88 @@
1
+ import { ensureNonEmpty } from "@elyukai/utils/array/nonEmpty";
2
+ import { isNotNullish } from "@elyukai/utils/nullable";
3
+ import { createEntityDescriptionCreator } from "../creator.js";
4
+ import { renderAnimalTypesSection } from "./partial/animalTypes.js";
5
+ import { renderAlternativeNames, renderChance, renderResistance, } from "./partial/herbary.js";
6
+ import { parensIf } from "./partial/rated/activatable/parensIf.js";
7
+ import { MISSING_VALUE } from "./partial/unknown.js";
8
+ const renderCauses = (translate, translateMap, causes) => causes
9
+ .map(cause => {
10
+ const causeTranslation = translateMap(cause.translations);
11
+ if (causeTranslation === undefined) {
12
+ return MISSING_VALUE;
13
+ }
14
+ return (causeTranslation.name +
15
+ parensIf(ensureNonEmpty([
16
+ renderChance(translate, translateMap, cause, true),
17
+ causeTranslation.note,
18
+ ].filter(isNotNullish))?.join("; ")));
19
+ })
20
+ .join(", ");
21
+ /**
22
+ * Get a JSON representation of the rules text for an optional rule.
23
+ */
24
+ export const getDiseaseEntityDescription = createEntityDescriptionCreator(({ getInstanceById, idMap }, { translate, translateMap, compare: localeCompare }, { entity, content: entry }) => {
25
+ const baseEntry = entry;
26
+ const translation = translateMap(baseEntry.translations);
27
+ if (translation === undefined) {
28
+ return undefined;
29
+ }
30
+ return {
31
+ title: translation.name,
32
+ className: "disease",
33
+ body: [
34
+ {
35
+ type: "definitionList",
36
+ items: [
37
+ renderAlternativeNames(translate, translation.alternative_names),
38
+ { label: translate("Level"), value: baseEntry.level.toString() },
39
+ { label: translate("Progress"), value: translation.progress },
40
+ {
41
+ label: translate("Resistance"),
42
+ value: renderResistance(translate, translateMap, getInstanceById, idMap, baseEntry.resistance),
43
+ },
44
+ {
45
+ label: translate("Incubation Time"),
46
+ value: translation.incubation_time,
47
+ },
48
+ {
49
+ label: translate("Damage"),
50
+ value: translation.damage.default +
51
+ (translation.damage.reduced === undefined
52
+ ? ""
53
+ : ` / ${translation.damage.reduced}`),
54
+ },
55
+ {
56
+ label: translate("Duration"),
57
+ value: translation.duration.default +
58
+ (translation.duration.reduced === undefined
59
+ ? ""
60
+ : ` / ${translation.duration.reduced}`),
61
+ },
62
+ {
63
+ label: translate("Causes"),
64
+ value: renderCauses(translate, translateMap, baseEntry.cause),
65
+ },
66
+ translation.special === undefined
67
+ ? undefined
68
+ : { label: translate("Special"), value: translation.special },
69
+ { label: translate("Treatment"), value: translation.treatment },
70
+ { label: translate("Antidote"), value: translation.cure },
71
+ entity === "AnimalDisease"
72
+ ? renderAnimalTypesSection(translate, translateMap, localeCompare, getInstanceById, entry.animal_types)
73
+ : undefined,
74
+ entity === "AnimalDisease"
75
+ ? {
76
+ label: translate("Communicability to Intelligent Creatures"),
77
+ value: entry.communicability_to_intelligent_creatures.length === 0
78
+ ? translate("No")
79
+ : `${translate("Yes")}; ${renderCauses(translate, translateMap, entry.communicability_to_intelligent_creatures)}`,
80
+ }
81
+ : undefined,
82
+ ],
83
+ },
84
+ ],
85
+ errata: translation.errata,
86
+ references: baseEntry.src,
87
+ };
88
+ });
@@ -0,0 +1,10 @@
1
+ import type { ActivatableIdentifier, RatedIdentifier } from "optolith-database-schema/gen";
2
+ import type { GetInstanceById } from "../helpers/getTypes.js";
3
+ import type { GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
4
+ /**
5
+ * Get a JSON representation of the rules text for an elixir.
6
+ */
7
+ export declare const getElixirEntityDescription: import("../creator.js").EntityDescriptionCreator<"Elixir", {
8
+ getInstanceById: GetInstanceById<"Publication" | "DerivedCharacteristic" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "Race" | "Culture" | "State" | "Enhancement" | "PactCategory" | "PactDomain" | "SocialStatus" | "Aspect" | "Property">;
9
+ getResolvedSelectOptionById: GetResolvedSelectOptionById;
10
+ }, import("../index.js").EntityDescription>;
@@ -0,0 +1,76 @@
1
+ import { mapNullable } from "@elyukai/utils/nullable";
2
+ import { sign } from "@elyukai/utils/string/number";
3
+ import { createEntityDescriptionCreator } from "../creator.js";
4
+ import { renderAlternativeNames, renderLaboratoryLevel, } from "./partial/herbary.js";
5
+ import { printPlainGeneralPrerequisites } from "./partial/prerequisites/index.js";
6
+ import { parensIf } from "./partial/rated/activatable/parensIf.js";
7
+ /**
8
+ * Get a JSON representation of the rules text for an elixir.
9
+ */
10
+ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getInstanceById, getResolvedSelectOptionById }, locale, { content: entry }) => {
11
+ const { translate, translateMap } = locale;
12
+ const translation = translateMap(entry.translations);
13
+ if (translation === undefined) {
14
+ return undefined;
15
+ }
16
+ return {
17
+ title: translation.name,
18
+ className: "elixir",
19
+ body: [
20
+ {
21
+ type: "definitionList",
22
+ items: [
23
+ renderAlternativeNames(translate, translation.alternative_names),
24
+ {
25
+ label: translate("Typical Ingredients"),
26
+ value: translation.typical_ingredients.join(", "),
27
+ },
28
+ {
29
+ label: translate("Price of Ingredients/Level"),
30
+ value: translate(".input {$value :number} {{{$value} silverthalers}}", { value: entry.cost_per_ingredient_level }),
31
+ },
32
+ {
33
+ label: translate("Laboratory"),
34
+ value: renderLaboratoryLevel(translate, entry.laboratory),
35
+ },
36
+ {
37
+ label: translate("Brewing Difficulty"),
38
+ value: sign(entry.brewing_difficulty),
39
+ },
40
+ {
41
+ label: `${translate("Prerequisites")} (${translate("Brewing Process")})`,
42
+ value: translation?.brewing_process_prerequisites ?? translate("none"),
43
+ },
44
+ {
45
+ label: `${translate("AP Value")} (${translate("Trade Secret")})`,
46
+ value: translate("{$value} AP", {
47
+ value: entry.trade_secret.ap_value,
48
+ }) +
49
+ parensIf(mapNullable(entry.trade_secret.prerequisites, prerequisites => `${translate("Prerequisites")}: ${printPlainGeneralPrerequisites(getInstanceById, getResolvedSelectOptionById, locale, prerequisites)}`)),
50
+ },
51
+ translation.special === undefined
52
+ ? undefined
53
+ : {
54
+ label: translate("Special"),
55
+ value: translation.special,
56
+ },
57
+ {
58
+ label: translate("Quality Levels"),
59
+ value: [
60
+ {
61
+ type: "definitionList",
62
+ style: "nested",
63
+ items: translation.quality_levels.map((effectForLevel, index) => ({
64
+ label: (index + 1).toString(),
65
+ value: effectForLevel,
66
+ })),
67
+ },
68
+ ],
69
+ },
70
+ ],
71
+ },
72
+ ],
73
+ errata: translation.errata,
74
+ references: entry.src,
75
+ };
76
+ });
@@ -0,0 +1,24 @@
1
+ import type { EquipmentIdentifier, GenMeleeWeapon, GenRangedWeapon, LocaleMeasurementAdjustments } from "optolith-database-schema/gen";
2
+ import { type TaggedEntity } from "../creator.js";
3
+ import type { GetInstanceById } from "../helpers/getTypes.js";
4
+ import type { Translate, TranslateMap } from "../helpers/translate.js";
5
+ import type { IdMap, LabeledEntityDescriptionSection, RawEntityDescriptionSectionContent } from "../index.js";
6
+ /**
7
+ * Get the name of an equipment item.
8
+ */
9
+ export declare const getEquipmentName: (translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"SocialStatus">, entry: TaggedEntity<EquipmentIdentifier["kind"]>) => string;
10
+ /**
11
+ * Render combat values of a melee weapon.
12
+ */
13
+ export declare const renderMeleeWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"Attribute" | "CloseCombatTechnique" | "Reach">, measurements: Required<LocaleMeasurementAdjustments>, renderDamage: (damage: Damage) => string, closeCombatTechniqueId: string, use: GenMeleeWeapon<Damage>) => LabeledEntityDescriptionSection<RawEntityDescriptionSectionContent>;
14
+ /**
15
+ * Render combat values of a ranged weapon.
16
+ */
17
+ export declare const renderRangedWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"RangedCombatTechnique" | "Ammunition">, measurements: Required<LocaleMeasurementAdjustments>, renderDamage: (damage: Damage) => string, rangedCombatTechniqueId: string, use: GenRangedWeapon<Damage>) => LabeledEntityDescriptionSection<RawEntityDescriptionSectionContent>;
18
+ /**
19
+ * Get a JSON representation of the rules text for equipment.
20
+ */
21
+ export declare const getEquipmentEntityDescription: import("../creator.js").EntityDescriptionCreator<"Weapon" | "Armor" | "Ammunition" | "Animal" | "AnimalCare" | "BandageOrRemedy" | "Book" | "CeremonialItem" | "Clothes" | "ClothingPackage" | "Container" | "EquipmentOfBlessedOnes" | "GemOrPreciousStone" | "IlluminationLightSource" | "IlluminationRefillOrSupply" | "Jewelry" | "Laboratory" | "Liebesspielzeug" | "LuxuryGood" | "MagicalArtifact" | "MusicalInstrument" | "Newspaper" | "OrienteeringAid" | "RopeOrChain" | "Stationery" | "ThievesTool" | "ToolOfTheTrade" | "TravelGearOrTool" | "Vehicle" | "WeaponAccessory", {
22
+ getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Reach" | "SocialStatus" | "CloseCombatTechnique" | "RangedCombatTechnique" | "MagicalTradition" | "BlessedTradition" | "DerivedCharacteristic" | "Ammunition" | "Race" | "Culture" | "Profession">;
23
+ idMap: IdMap;
24
+ }, import("../index.js").EntityDescription>;