@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
@@ -1,149 +1,217 @@
1
- import { mapNullable, mapNullableDefault } from "@optolith/helpers/nullable";
1
+ import { identity } from "@elyukai/utils/function";
2
+ import { Reader } from "@elyukai/utils/reader";
3
+ import { mapNullable } from "@optolith/helpers/nullable";
2
4
  import { assertExhaustive } from "@optolith/helpers/typeSafety";
3
- import { appendNoteIfRequested, getResponsiveText, replaceTextIfRequested, responsive, } from "../../responsiveText.js";
4
- import { formatEnergyByEntity } from "../../units/energy.js";
5
- import { formatTimeSpan } from "../../units/timeSpan.js";
5
+ import { renderResponsiveMap } from "../../map.js";
6
+ import { additionFormatter } from "../../mathOperation.js";
7
+ import { formatEnergyFnR, formatEnergyR, getInstanceByIdFnR, modifiableBySpeedR, responsiveLocaleJoinR, responsiveR, responsiveTextR, responsiveTranslateR, translateMapR, translateR, } from "../../reader.js";
8
+ import { appendNoteIfNeeded, replaceTextIfNeeded, } from "../../responsiveText.js";
9
+ import { formatCombinedTimeSpanR } from "../../units/timeSpan.js";
6
10
  import { MISSING_VALUE } from "../../unknown.js";
11
+ import { appendCheckResultModifier } from "./checkResultBased.js";
7
12
  import { wrapIfMinimum } from "./isMinimumMaximum.js";
8
- import { getNonModifiableSuffixTranslation, ModifiableParameter, } from "./nonModifiableSuffix.js";
9
- import { getModifiableBySpeed } from "./speed.js";
10
- const getModifiableOneTimeCostTranslation = (getSkillModificationLevelById, locale, responsiveTextSize, entity, speed, value) => mapNullable(getSkillModificationLevelById(value.initial_modification_level), (modificationLevel) => {
11
- const cost = getModifiableBySpeed((config) => config.cost, (config) => config.cost, speed, modificationLevel);
12
- return replaceTextIfRequested("replacement", value.translations, locale.translateMap, responsiveTextSize, formatEnergyByEntity(locale, entity, cost));
13
- }) ?? MISSING_VALUE;
14
- const getNonModifiableOneTimeCostPerCountableTranslation = (formatCost, locale, responsiveTextSize, value) => mapNullable(value, (perCountable) => {
15
- const entity = getResponsiveText(locale.translateMap(perCountable.translations)?.countable, responsiveTextSize);
16
- const countableText = responsive(responsiveTextSize, () => locale.translate(" per {0}", entity), () => locale.translate("/{0}", entity));
17
- const minimumTotalText = mapNullable(perCountable.minimum_total, (minimumTotal) => locale.translate(", minimum of {0}", formatCost(minimumTotal))) ?? "";
18
- return countableText + minimumTotalText;
19
- }) ?? "";
20
- const getPermanentValueTranslation = (locale, responsiveTextSize, permanentValue) => permanentValue === undefined
21
- ? ""
22
- : responsive(responsiveTextSize, () => locale.translate(", {0} of which are permanent", permanentValue), () => locale.translate(" ({0} perm.)", permanentValue));
23
- const getNonModifiableOneTimeCostTranslation = (locale, entity, responsiveTextSize, value) => {
24
- const formatCostP = formatEnergyByEntity.bind(this, locale, entity);
25
- const perCountable = getNonModifiableOneTimeCostPerCountableTranslation(formatCostP, locale, responsiveTextSize, value.per);
26
- const permanentValue = getPermanentValueTranslation(locale, responsiveTextSize, value.permanent_value);
27
- const costWrappedIfMinimum = wrapIfMinimum(locale, responsiveTextSize, value.is_minimum, formatCostP(value.value) + perCountable + permanentValue);
28
- const withNote = appendNoteIfRequested("note", value.translations, locale.translateMap, responsiveTextSize, costWrappedIfMinimum);
29
- const cannotModify = getNonModifiableSuffixTranslation(locale, entity, ModifiableParameter.Cost, responsiveTextSize);
30
- return withNote + cannotModify;
13
+ import { appendNonModifiableSuffix, ModifiableParameter, } from "./nonModifiableSuffix.js";
14
+ const deriveModifiableCost = (modificationLevelId) => getInstanceByIdFnR().thenW(getInstanceById => mapNullable(getInstanceById("SkillModificationLevel", modificationLevelId), modificationLevel => modifiableBySpeedR("cost", modificationLevel)) ?? Reader.of(undefined));
15
+ const appendPerCountableToCostIfNeeded = (value, baseCost) => {
16
+ if (value === undefined) {
17
+ return Reader.of(baseCost);
18
+ }
19
+ const { translations, minimum_total } = value;
20
+ return translateMapR(translations).thenW(translation => {
21
+ if (translation === undefined) {
22
+ return Reader.of(baseCost);
23
+ }
24
+ return responsiveTextR(translation.countable)
25
+ .thenW(countable => responsiveTranslateR("{$cost} per {$countable}", "{$cost}/{$countable}", { cost: baseCost, countable }))
26
+ .thenW(text => minimum_total === undefined
27
+ ? Reader.of(text)
28
+ : formatEnergyR(minimum_total).then(cost => translateR("{$baseCost}, minimum of {$value}", {
29
+ baseCost: text,
30
+ value: cost,
31
+ })));
32
+ });
31
33
  };
32
- const getIndefiniteOneTimeCostTranslation = (locale, entity, responsiveTextSize, value) => getResponsiveText(locale.translateMap(value.translations)?.description, responsiveTextSize) +
33
- getNonModifiableSuffixTranslation(locale, entity, ModifiableParameter.Cost, responsiveTextSize);
34
- const getSingleOneTimeCostTranslation = (getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value) => {
35
- switch (value.tag) {
34
+ const appendPermanentCostIfNeeded = (permanentValue, baseCost) => mapNullable(permanentValue, value => responsiveTranslateR(".input {$value :number} {{, {$value} of which are permanent}}", " ({$value} perm.)", { value }).map(text => baseCost + text)) ?? Reader.of(baseCost);
35
+ const appendElvenPermanentCostIfNeeded = (permanent, baseCost) => mapNullable(permanent, value => responsiveTranslateR(".input {$value :number} {{{$value} permanent AE}}", "{$value} pAE", { value: value.value })
36
+ .thenW(text => replaceTextIfNeeded(value.translations, text))
37
+ .map(text => baseCost + text)) ?? Reader.of(baseCost);
38
+ const appendFamiliarsTrickLPCostIfNeeded = (lpValue, baseCost) => lpValue === undefined
39
+ ? Reader.of(baseCost)
40
+ : formatEnergyR(lpValue)
41
+ .with((env) => ({ ...env, energyUnit: "LifePoints" }))
42
+ .thenW(formattedLpCost => responsiveLocaleJoinR([baseCost, formattedLpCost], "conjunction"));
43
+ /**
44
+ * Returns the text for the modifiable one-time cost of an activatable skill.
45
+ */
46
+ export const renderModifiableOneTimeCost = (value) => deriveModifiableCost(value.initial_modification_level).thenW(cost => cost === undefined
47
+ ? Reader.of(MISSING_VALUE)
48
+ : formatEnergyR(cost)
49
+ .thenW(text => replaceTextIfNeeded(value.translations, text))
50
+ .then(text => translateMapR(value.translations).thenW(translation => {
51
+ if (translation?.additional === undefined) {
52
+ return Reader.of(text);
53
+ }
54
+ return responsiveTextR(translation.additional).map(additional => additionFormatter(text, additional));
55
+ })));
56
+ const appendIntervalToCost = (interval, baseCost) => interval === undefined
57
+ ? Reader.of(baseCost)
58
+ : formatCombinedTimeSpanR(interval).then(formattedInterval => responsiveTranslateR("{$cost} per {$interval}", "{$cost}/{$interval}", {
59
+ cost: baseCost,
60
+ interval: formattedInterval,
61
+ }));
62
+ /**
63
+ * Returns the text for a non-modifiable one-time cost of an activatable skill.
64
+ */
65
+ export const renderNonModifiableOneTimeCost = (value, shouldAppendNonModifiableSuffix) => formatEnergyR(value.value)
66
+ .thenW(base => appendFamiliarsTrickLPCostIfNeeded(value.lp_value, base))
67
+ .thenW(base => appendPerCountableToCostIfNeeded(value.per, base))
68
+ .then(base => appendPermanentCostIfNeeded(value.permanent_value, base))
69
+ .then(base => appendIntervalToCost(value.interval, base))
70
+ .then(base => appendElvenPermanentCostIfNeeded(value.permanent, base))
71
+ .then(base => wrapIfMinimum(value.is_minimum, base))
72
+ .then(base => appendNoteIfNeeded(value.translations, base))
73
+ .then(shouldAppendNonModifiableSuffix
74
+ ? base => appendNonModifiableSuffix(ModifiableParameter.Cost, base)
75
+ : Reader.of);
76
+ /**
77
+ * Returns the text for the indefinite cost of an activatable skill.
78
+ */
79
+ export const renderIndefiniteCost = (value, shouldAppendNonModifiableSuffix) => {
80
+ const { modifier, translations } = value;
81
+ return translateMapR(translations)
82
+ .thenW(translation => translation === undefined
83
+ ? Reader.of(MISSING_VALUE)
84
+ : responsiveTextR(translation.description))
85
+ .map(modifier === undefined
86
+ ? identity
87
+ : base => appendCheckResultModifier(base, modifier))
88
+ .thenW(shouldAppendNonModifiableSuffix
89
+ ? base => appendNonModifiableSuffix(ModifiableParameter.Cost, base)
90
+ : Reader.of);
91
+ };
92
+ const renderSingleOneTimeCost = (value) => {
93
+ switch (value.kind) {
36
94
  case "Modifiable":
37
- return getModifiableOneTimeCostTranslation(getSkillModificationLevelById, locale, responsiveTextSize, entity, speed, value.modifiable);
95
+ return renderModifiableOneTimeCost(value.Modifiable);
38
96
  case "NonModifiable":
39
- return getNonModifiableOneTimeCostTranslation(locale, entity, responsiveTextSize, value.non_modifiable);
97
+ return renderNonModifiableOneTimeCost(value.NonModifiable, true);
40
98
  case "Indefinite":
41
- return getIndefiniteOneTimeCostTranslation(locale, entity, responsiveTextSize, value.indefinite);
99
+ return renderIndefiniteCost(value.Indefinite, true);
42
100
  default:
43
101
  return assertExhaustive(value);
44
102
  }
45
103
  };
46
- const getMultipleOneTimeCostsTranslation = (type, getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value) => {
47
- const modifiable = !value.every((part) => part.tag === "Modifiable")
48
- ? getNonModifiableSuffixTranslation(locale, entity, ModifiableParameter.Cost, responsiveTextSize)
49
- : "";
50
- return (value
51
- .map((part) => getSingleOneTimeCostTranslation(getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, part))
52
- .join((() => {
53
- switch (type) {
54
- case "conjunction":
55
- return responsive(responsiveTextSize, () => locale.translate(" and "), () => locale.translate(" + "));
56
- case "disjunction":
57
- return responsive(responsiveTextSize, () => locale.translate(" or "), () => locale.translate(" / "));
58
- default:
59
- return assertExhaustive(type);
60
- }
61
- })()) + modifiable);
104
+ const renderMultipleOneTimeCosts = (type, value) => {
105
+ const appendNonModifiableIfRequested = !value.every(part => part.kind === "Modifiable")
106
+ ? (text) => appendNonModifiableSuffix(ModifiableParameter.Cost, text)
107
+ : Reader.of;
108
+ return Reader.sequence(value.map(renderSingleOneTimeCost))
109
+ .thenW(list => responsiveLocaleJoinR(list, type))
110
+ .then(text => appendNonModifiableIfRequested(text));
62
111
  };
63
- const getCostMapTranslation = (locale, entity, responsiveTextSize, value) => {
64
- const translation = locale.translateMap(value.translations);
65
- if (value.translations !== undefined && translation === undefined) {
66
- return MISSING_VALUE;
67
- }
68
- if (translation?.replacement !== undefined) {
69
- return translation.replacement;
112
+ /**
113
+ * Returns the text for a one-time cost map of an activatable skill.
114
+ */
115
+ export const renderOneTimeCostMap = (value) => Reader.asks(({ translate }) => translate).thenW(translate => formatEnergyFnR
116
+ .thenW(formatEnergy => renderResponsiveMap(value, option => option.value, formatEnergy, value.options.every(option => option.permanent_value !== undefined)
117
+ ? {
118
+ surround: values => translate(", {$value} of which are permanent", {
119
+ value: values,
120
+ }),
121
+ getAdditionalValue: option => option.permanent_value,
70
122
  }
71
- const labels = value.options
72
- .map((option) => locale.translateMap(option.translations)?.label ?? MISSING_VALUE)
73
- .join("/");
74
- const costs = value.options.map((option) => option.value).join("/");
75
- const permanentCosts = value.options.every((option) => option.permanent_value !== undefined)
76
- ? value.options.map((option) => option.permanent_value).join("/")
77
- : undefined;
78
- const formatCostP = formatEnergyByEntity.bind(this, locale, entity);
79
- const notModifiable = getNonModifiableSuffixTranslation(locale, entity, ModifiableParameter.Cost, responsiveTextSize);
80
- return (formatCostP(costs) +
81
- locale.translate(" for ") +
82
- mapNullableDefault(translation?.list_prepend, (listPrepend) => `${listPrepend} `, "") +
83
- labels +
84
- (translation?.list_append ?? "") +
85
- (permanentCosts !== undefined
86
- ? locale.translate(", {0} of which are permanent", formatCostP(permanentCosts))
87
- : "") +
88
- notModifiable);
89
- };
123
+ : undefined))
124
+ .then(text => appendNonModifiableSuffix(ModifiableParameter.Cost, text)));
125
+ const renderSustainedCostMap = (value) => formatEnergyFnR
126
+ .thenW(formatEnergy => renderResponsiveMap(value, option => option.value, formatEnergy))
127
+ .then(text => appendNonModifiableSuffix(ModifiableParameter.Cost, text));
90
128
  /**
91
129
  * Returns the text for the cost of a one-time activatable skill.
92
130
  */
93
- export const getOneTimeCostTranslation = (getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value) => {
94
- switch (value.tag) {
131
+ export const renderOneTimeCost = (value) => {
132
+ switch (value.kind) {
95
133
  case "Single":
96
- return getSingleOneTimeCostTranslation(getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value.single);
134
+ return renderSingleOneTimeCost(value.Single);
97
135
  case "Conjunction":
98
- return getMultipleOneTimeCostsTranslation("conjunction", getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value.conjunction);
136
+ return renderMultipleOneTimeCosts("conjunction", value.Conjunction);
99
137
  case "Disjunction":
100
- return getMultipleOneTimeCostsTranslation("disjunction", getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value.disjunction);
138
+ return renderMultipleOneTimeCosts("disjunction", value.Disjunction);
101
139
  case "Map":
102
- return getCostMapTranslation(locale, entity, responsiveTextSize, value.map);
140
+ return renderOneTimeCostMap(value.Map);
103
141
  default:
104
142
  return assertExhaustive(value);
105
143
  }
106
144
  };
107
- const getModifiableSustainedCostTranslation = (getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value) => mapNullable(getSkillModificationLevelById(value.initial_modification_level), (modificationLevel) => {
108
- const cost = getModifiableBySpeed((config) => config.cost, (config) => config.cost, speed, modificationLevel);
109
- const formatCostP = formatEnergyByEntity.bind(this, locale, entity);
110
- const interval = formatTimeSpan(locale, responsiveTextSize, value.interval.unit, value.interval.value);
111
- return responsive(responsiveTextSize, () => `${formatCostP(cost) + locale.translate(" (casting)")} + ${formatCostP(cost / 2) + locale.translate(" per {0}", interval)}`, () => `${formatCostP(cost)} + ${formatCostP(cost / 2) + locale.translate("/{0}", interval)}`);
112
- }) ?? MISSING_VALUE;
113
- const getNonModifiableSustainedCostTranslation = (locale, entity, responsiveTextSize, value) => {
114
- const formatCostP = formatEnergyByEntity.bind(this, locale, entity);
115
- const per = (() => {
116
- if (value.per === undefined) {
117
- return { countable: "", minimumTotal: "" };
118
- }
119
- const countable = responsive(responsiveTextSize, (entity) => locale.translate(" per {0}", entity), (entity) => locale.translate("/{0}", entity), getResponsiveText(locale.translateMap(value.per.translations)?.countable, responsiveTextSize));
120
- const minimumTotal = value.per.minimum_total !== undefined
121
- ? locale.translate(", minimum of {0}", formatCostP(value.per.minimum_total))
122
- : "";
123
- return { countable, minimumTotal };
124
- })();
125
- const interval = formatTimeSpan(locale, responsiveTextSize, value.interval.unit, value.interval.value);
126
- const cost = responsive(responsiveTextSize, () => `${formatCostP(value.value) + locale.translate(" (casting)")} + ${(value.is_minimum === true
127
- ? locale.translate("half of the activation cost")
128
- : formatCostP(value.value / 2)) +
129
- per.countable +
130
- locale.translate(" per {0}", interval)}`, () => `${formatCostP(value.value)} + ${(value.is_minimum === true ? "50%" : formatCostP(value.value / 2)) +
131
- per.countable +
132
- locale.translate("/{0}", interval)}`) + per.minimumTotal;
133
- const costWrappedIfMinimum = wrapIfMinimum(locale, responsiveTextSize, value.is_minimum, cost);
134
- return (costWrappedIfMinimum +
135
- getNonModifiableSuffixTranslation(locale, entity, ModifiableParameter.Cost, responsiveTextSize));
145
+ const buildSustainedCost = (activationCost, intervalCost, interval) => {
146
+ const activationCostWithLabel = responsiveR(() => translateR("activation").map(label => `${activationCost} (${label})`), () => Reader.of(activationCost)).thenW(identity);
147
+ const intervalCostWithLabel = appendIntervalToCost(interval, intervalCost);
148
+ return activationCostWithLabel.map2(intervalCostWithLabel, additionFormatter);
136
149
  };
150
+ const renderModifiableSustainedCost = (value) => deriveModifiableCost(value.initial_modification_level).thenW(cost => cost === undefined
151
+ ? Reader.of(MISSING_VALUE)
152
+ : formatEnergyFnR.thenW(formatEnergy => {
153
+ const activationCost = formatEnergy(cost);
154
+ const intervalCost = formatEnergy(cost / 2);
155
+ return buildSustainedCost(activationCost, intervalCost, value.interval);
156
+ }));
157
+ /**
158
+ * Returns the text for the non-modifiable cost of a sustained activatable skill.
159
+ */
160
+ export const renderNonModifiableSustainedCost = (value) => formatEnergyFnR
161
+ .thenW(formatEnergy => {
162
+ const activationCost = formatEnergy(value.value);
163
+ const getIntervalCost = value.is_minimum === true
164
+ ? responsiveTranslateR("half of the activation cost", "50%")
165
+ : Reader.of(formatEnergy(value.value / 2));
166
+ return getIntervalCost.then(intervalCost => buildSustainedCost(activationCost, intervalCost, value.interval));
167
+ })
168
+ .thenW(base => appendPerCountableToCostIfNeeded(value.per, base))
169
+ .then(base => wrapIfMinimum(value.is_minimum, base))
170
+ .then(base => appendNonModifiableSuffix(ModifiableParameter.Cost, base));
137
171
  /**
138
172
  * Returns the text for the cost of a sustained activatable skill.
139
173
  */
140
- export const getSustainedCostTranslation = (getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value) => {
141
- switch (value.tag) {
174
+ export const renderSustainedCost = (value) => {
175
+ switch (value.kind) {
142
176
  case "Modifiable":
143
- return getModifiableSustainedCostTranslation(getSkillModificationLevelById, locale, speed, entity, responsiveTextSize, value.modifiable);
177
+ return renderModifiableSustainedCost(value.Modifiable);
144
178
  case "NonModifiable":
145
- return getNonModifiableSustainedCostTranslation(locale, entity, responsiveTextSize, value.non_modifiable);
179
+ return renderNonModifiableSustainedCost(value.NonModifiable);
180
+ case "Map":
181
+ return renderSustainedCostMap(value.Map);
146
182
  default:
147
183
  return assertExhaustive(value);
148
184
  }
149
185
  };
186
+ /**
187
+ * Generates the text for the cost specific to a magical action.
188
+ */
189
+ export const renderMagicalActionCost = (cost) => {
190
+ switch (cost.kind) {
191
+ case "Fixed":
192
+ return renderNonModifiableOneTimeCost(cost.Fixed, false);
193
+ case "Indefinite":
194
+ return renderIndefiniteCost(cost.Indefinite, false);
195
+ case "FirstPerson":
196
+ return Reader.asks(({ translate }) => translate("{$firstPersonValue} for the first person; {$additionalPersonValue} for each additional person", {
197
+ firstPersonValue: translate("{$value} AE", {
198
+ value: cost.FirstPerson.value,
199
+ }),
200
+ additionalPersonValue: translate("{$value} AE", {
201
+ value: cost.FirstPerson.value / 2,
202
+ }),
203
+ }));
204
+ case "ByPrimaryPatron":
205
+ return translateR("Depends on animal type").thenW(base => appendNoteIfNeeded(cost.ByPrimaryPatron?.translations, base));
206
+ case "All":
207
+ return Reader.asks(({ translate }) => cost.All.minimum === undefined
208
+ ? translate("All AE")
209
+ : translate("All AE, at least {$value} AE", {
210
+ value: cost.All.minimum,
211
+ }));
212
+ case "Map":
213
+ return renderOneTimeCostMap(cost.Map);
214
+ default:
215
+ return assertExhaustive(cost);
216
+ }
217
+ };
@@ -1,21 +1,44 @@
1
- import { DurationForOneTime, DurationForSustained } from "optolith-database-schema/types/_ActivatableSkillDuration";
2
- import { BlessingDuration } from "optolith-database-schema/types/Blessing";
3
- import { CantripDuration } from "optolith-database-schema/types/Cantrip";
4
- import { LocaleEnvironment } from "../../../../helpers/locale.js";
5
- import { ResponsiveTextSize } from "../../responsiveText.js";
1
+ import type { CastingTimeDuringLovemaking, CheckResultBasedDuration, DurationForSustained, FixedDuration, Immediate, MusicDuration, PermanentDuration, ResponsiveText } from "optolith-database-schema/gen";
2
+ import type { LocaleMap } from "../../../../helpers/translate.js";
3
+ import { type StdReader } from "../../reader.js";
6
4
  /**
7
- * Returns the text for the duration of a one-time activatable skill.
5
+ * Renders a duration that is based on the result of the skill check.
8
6
  */
9
- export declare const getDurationForOneTimeTranslation: (locale: LocaleEnvironment, responsiveTextSize: ResponsiveTextSize, value: DurationForOneTime) => string;
7
+ export declare const renderCheckResultBasedDuration: (value: CheckResultBasedDuration) => StdReader<string, "t" | "tm" | "rts">;
8
+ type OneTimeDuration = {
9
+ kind: "Immediate";
10
+ Immediate?: Immediate;
11
+ } | {
12
+ kind: "Permanent";
13
+ Permanent: PermanentDuration;
14
+ } | {
15
+ kind: "Fixed";
16
+ Fixed: FixedDuration;
17
+ } | {
18
+ kind: "CheckResultBased";
19
+ CheckResultBased: CheckResultBasedDuration;
20
+ } | {
21
+ kind: "Indefinite";
22
+ Indefinite: {
23
+ maximum?: OneTimeDuration;
24
+ translations: LocaleMap<{
25
+ description: ResponsiveText | string;
26
+ }>;
27
+ };
28
+ } | {
29
+ kind: "DuringLovemaking";
30
+ DuringLovemaking: CastingTimeDuringLovemaking;
31
+ };
10
32
  /**
11
- * Returns the text for the duration of a sustained activatable skill.
33
+ * Returns the text for the duration of a one-time activatable skill.
12
34
  */
13
- export declare const getDurationForSustainedTranslation: (locale: LocaleEnvironment, responsiveTextSize: ResponsiveTextSize, value: DurationForSustained | undefined) => string;
35
+ export declare const renderOneTimeDuration: (value: OneTimeDuration) => StdReader<string, "t" | "tm" | "rts">;
14
36
  /**
15
- * Returns the text for the duration of a cantrip.
37
+ * Returns the text for the duration of a sustained activatable skill.
16
38
  */
17
- export declare const getDurationTranslationForCantrip: (locale: LocaleEnvironment, responsiveTextSize: ResponsiveTextSize, value: CantripDuration) => string;
39
+ export declare const renderSustainedDuration: (value: DurationForSustained | undefined) => StdReader<string, "t" | "rts">;
18
40
  /**
19
- * Returns the text for the duration of a blessing.
41
+ * Returns the text for the duration of a musical activatable skill.
20
42
  */
21
- export declare const getDurationTranslationForBlessing: (locale: LocaleEnvironment, responsiveTextSize: ResponsiveTextSize, value: BlessingDuration) => string;
43
+ export declare const renderMusicDuration: (duration: MusicDuration) => StdReader<string, "t">;
44
+ export {};
@@ -1,43 +1,61 @@
1
+ import { Reader } from "@elyukai/utils/reader";
1
2
  import { mapNullable } from "@optolith/helpers/nullable";
2
3
  import { assertExhaustive } from "@optolith/helpers/typeSafety";
3
- import { getResponsiveText, replaceTextIfRequested, responsive, } from "../../responsiveText.js";
4
- import { formatTimeSpan } from "../../units/timeSpan.js";
5
- import { getCheckResultBasedValueTranslation } from "./checkResultBased.js";
4
+ import { responsiveTextR, responsiveTranslateR, translateMapR, translateR, } from "../../reader.js";
5
+ import { replaceTextIfNeeded } from "../../responsiveText.js";
6
+ import { formatCombinedTimeSpanR, formatTimeSpanR, } from "../../units/timeSpan.js";
7
+ import { MISSING_VALUE } from "../../unknown.js";
8
+ import { renderCheckResultBasedValue } from "./checkResultBased.js";
6
9
  import { wrapAsMaximum, wrapIfMaximum } from "./isMinimumMaximum.js";
7
10
  import { appendInParensIfNotEmpty } from "./parensIf.js";
8
- const getImmediateDurationTranslation = (locale, responsiveTextSize, value) => {
9
- const text = appendInParensIfNotEmpty(mapNullable(value.maximum, (max) => {
10
- const maxText = formatTimeSpan(locale, responsiveTextSize, max.unit, max.value);
11
- return responsive(responsiveTextSize, () => locale.translate("no more than {0}", maxText), () => locale.translate("max. {0}", maxText));
12
- }), locale.translate("Immediate"));
13
- return replaceTextIfRequested("replacement", value.translations, locale.translateMap, responsiveTextSize, text);
14
- };
15
- const getPermanentDurationTranslation = (locale, responsiveTextSize, value) => replaceTextIfRequested("replacement", value.translations, locale.translateMap, responsiveTextSize, locale.translate("Permanent"));
16
- const getFixedDurationTranslation = (locale, responsiveTextSize, value) => {
17
- const duration = formatTimeSpan(locale, responsiveTextSize, value.unit, value.value);
18
- const durationWrappedIfMaximum = wrapIfMaximum(locale, responsiveTextSize, value.is_maximum, duration);
19
- return replaceTextIfRequested("replacement", value.translations, locale.translateMap, responsiveTextSize, durationWrappedIfMaximum);
20
- };
21
- const getCheckResultBasedDurationTranslation = (locale, responsiveTextSize, value) => {
22
- const duration = formatTimeSpan(locale, responsiveTextSize, value.unit, getCheckResultBasedValueTranslation(locale.translate, value));
23
- return wrapIfMaximum(locale, responsiveTextSize, value.is_maximum, duration);
11
+ const renderImmediateDuration = (value) => translateR("Immediate")
12
+ .thenW(base => mapNullable(value?.maximum, max => formatTimeSpanR(max.unit, max.value)
13
+ .then(wrapAsMaximum)
14
+ .map(maxText => appendInParensIfNotEmpty(maxText, base))) ?? Reader.of(base))
15
+ .thenW(text => replaceTextIfNeeded(value?.translations, text));
16
+ const renderPermanentDuration = (value) => translateR("Permanent").thenW(text => replaceTextIfNeeded(value.translations, text));
17
+ const renderFixedDuration = (value) => formatCombinedTimeSpanR(value)
18
+ .then(text => wrapIfMaximum(value.is_maximum, text))
19
+ .thenW(text => replaceTextIfNeeded(value.translations, text));
20
+ /**
21
+ * Renders a duration that is based on the result of the skill check.
22
+ */
23
+ export const renderCheckResultBasedDuration = (value) => renderCheckResultBasedValue(value)
24
+ .thenW(text => formatTimeSpanR(value.unit, text))
25
+ .then(text => wrapIfMaximum(value.is_maximum, text));
26
+ const renderIndefiniteDuration = (value) => {
27
+ const { maximum, translations } = value;
28
+ return translateMapR(translations)
29
+ .thenW(translation => typeof translation?.description === "object"
30
+ ? responsiveTextR(translation.description)
31
+ : Reader.of(translation?.description ?? MISSING_VALUE))
32
+ .thenW(maximum === undefined
33
+ ? Reader.of
34
+ : text =>
35
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
36
+ renderOneTimeDuration(maximum).then(maximumText => translateR("{$defaultDuration}, but no more than {$maximumDuration}", {
37
+ defaultDuration: text,
38
+ maximumDuration: maximumText,
39
+ })));
24
40
  };
25
- const getIndefiniteDurationTranslation = (locale, responsiveTextSize, value) => getResponsiveText(locale.translateMap(value.translations)?.description, responsiveTextSize);
41
+ const renderDurationDuringLovemaking = (value) => formatCombinedTimeSpanR(value);
26
42
  /**
27
43
  * Returns the text for the duration of a one-time activatable skill.
28
44
  */
29
- export const getDurationForOneTimeTranslation = (locale, responsiveTextSize, value) => {
30
- switch (value.tag) {
45
+ export const renderOneTimeDuration = (value) => {
46
+ switch (value.kind) {
31
47
  case "Immediate":
32
- return getImmediateDurationTranslation(locale, responsiveTextSize, value.immediate);
48
+ return renderImmediateDuration(value.Immediate);
33
49
  case "Permanent":
34
- return getPermanentDurationTranslation(locale, responsiveTextSize, value.permanent);
50
+ return renderPermanentDuration(value.Permanent);
35
51
  case "Fixed":
36
- return getFixedDurationTranslation(locale, responsiveTextSize, value.fixed);
52
+ return renderFixedDuration(value.Fixed);
37
53
  case "CheckResultBased":
38
- return getCheckResultBasedDurationTranslation(locale, responsiveTextSize, value.check_result_based);
54
+ return renderCheckResultBasedDuration(value.CheckResultBased);
39
55
  case "Indefinite":
40
- return getIndefiniteDurationTranslation(locale, responsiveTextSize, value.indefinite);
56
+ return renderIndefiniteDuration(value.Indefinite);
57
+ case "DuringLovemaking":
58
+ return renderDurationDuringLovemaking(value.DuringLovemaking);
41
59
  default:
42
60
  return assertExhaustive(value);
43
61
  }
@@ -45,39 +63,32 @@ export const getDurationForOneTimeTranslation = (locale, responsiveTextSize, val
45
63
  /**
46
64
  * Returns the text for the duration of a sustained activatable skill.
47
65
  */
48
- export const getDurationForSustainedTranslation = (locale, responsiveTextSize, value) => value === undefined
49
- ? responsive(responsiveTextSize, () => locale.translate("Sustained"), () => locale.translate("(S)"))
50
- : wrapAsMaximum(locale, responsiveTextSize, formatTimeSpan(locale, responsiveTextSize, value.maximum.unit, value.maximum.value));
51
- const getDurationDuringLovemakingTranslation = (locale, responsiveTextSize, value) => formatTimeSpan(locale, responsiveTextSize, value.unit, value.value);
52
- /**
53
- * Returns the text for the duration of a cantrip.
54
- */
55
- export const getDurationTranslationForCantrip = (locale, responsiveTextSize, value) => {
56
- switch (value.tag) {
57
- case "Immediate":
58
- return getImmediateDurationTranslation(locale, responsiveTextSize, value.immediate);
59
- case "Fixed":
60
- return getFixedDurationTranslation(locale, responsiveTextSize, value.fixed);
61
- case "Indefinite":
62
- return getIndefiniteDurationTranslation(locale, responsiveTextSize, value.indefinite);
63
- case "DuringLovemaking":
64
- return getDurationDuringLovemakingTranslation(locale, responsiveTextSize, value.during_lovemaking);
65
- default:
66
- return assertExhaustive(value);
67
- }
68
- };
66
+ export const renderSustainedDuration = (value) => value === undefined
67
+ ? responsiveTranslateR("Sustained", "(S)")
68
+ : formatCombinedTimeSpanR(value.maximum).then(maxText => wrapAsMaximum(maxText));
69
69
  /**
70
- * Returns the text for the duration of a blessing.
70
+ * Returns the text for the duration of a musical activatable skill.
71
71
  */
72
- export const getDurationTranslationForBlessing = (locale, responsiveTextSize, value) => {
73
- switch (value.tag) {
74
- case "Immediate":
75
- return getImmediateDurationTranslation(locale, responsiveTextSize, value.immediate);
76
- case "Fixed":
77
- return getFixedDurationTranslation(locale, responsiveTextSize, value.fixed);
78
- case "Indefinite":
79
- return getIndefiniteDurationTranslation(locale, responsiveTextSize, value.indefinite);
80
- default:
81
- return assertExhaustive(value);
82
- }
83
- };
72
+ export const renderMusicDuration = (duration) => Reader.asks(({ translate }) => {
73
+ const length = (() => {
74
+ switch (duration.length.kind) {
75
+ case "Long":
76
+ return translate("long");
77
+ case "Short":
78
+ return translate("short");
79
+ default:
80
+ return assertExhaustive(duration.length);
81
+ }
82
+ })();
83
+ const reusability = (() => {
84
+ switch (duration.reusability.kind) {
85
+ case "OneTime":
86
+ return translate("one-time");
87
+ case "Sustainable":
88
+ return translate("sustainable");
89
+ default:
90
+ return assertExhaustive(duration.reusability);
91
+ }
92
+ })();
93
+ return `${length}, ${reusability}`;
94
+ });
@@ -1,7 +1,7 @@
1
- import { Effect } from "optolith-database-schema/types/_ActivatableSkillEffect";
2
- import { LocaleEnvironment } from "../../../../helpers/locale.js";
3
- import { EntityDescriptionSection } from "../../../../index.js";
1
+ import type { ActivatableSkillEffect } from "optolith-database-schema/gen";
2
+ import type { RawDefinitionListEntityDescriptionSectionItem } from "../../../../index.js";
3
+ import { type StdReader } from "../../reader.js";
4
4
  /**
5
5
  * Gets the text for the effect of an activatable skill.
6
6
  */
7
- export declare const getTextForEffect: (locale: LocaleEnvironment, effect: Effect) => EntityDescriptionSection[];
7
+ export declare const renderEffect: (effect: ActivatableSkillEffect) => StdReader<RawDefinitionListEntityDescriptionSectionItem, "t">;