@optolith/entity-descriptions 0.4.11 → 0.4.13

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 (87) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/creator.d.ts +1 -1
  3. package/lib/entities/activatable.d.ts +1 -1
  4. package/lib/entities/activatable.js +68 -0
  5. package/lib/entities/culture.d.ts +2 -0
  6. package/lib/entities/culture.js +20 -14
  7. package/lib/entities/curriculum.js +103 -19
  8. package/lib/entities/disease.d.ts +1 -1
  9. package/lib/entities/elixir.d.ts +1 -1
  10. package/lib/entities/equipment.d.ts +2 -2
  11. package/lib/entities/equipmentPackage.d.ts +1 -1
  12. package/lib/entities/influence.d.ts +1 -1
  13. package/lib/entities/liturgicalChant.d.ts +1 -1
  14. package/lib/entities/partial/activatableNameChunks.d.ts +11 -3
  15. package/lib/entities/partial/activatableNameChunks.js +27 -12
  16. package/lib/entities/partial/adventurePointsValue.d.ts +2 -2
  17. package/lib/entities/partial/animalTypes.d.ts +1 -1
  18. package/lib/entities/partial/animalTypes.js +2 -1
  19. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.d.ts +4 -4
  20. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.js +56 -13
  21. package/lib/entities/partial/dice.d.ts +1 -1
  22. package/lib/entities/partial/enhancements.d.ts +1 -1
  23. package/lib/entities/partial/herbary.d.ts +1 -1
  24. package/lib/entities/partial/map.d.ts +1 -1
  25. package/lib/entities/partial/map.js +1 -1
  26. package/lib/entities/partial/markdown.d.ts +2 -2
  27. package/lib/entities/partial/markdown.js +4 -1
  28. package/lib/entities/partial/mathOperation.d.ts +1 -1
  29. package/lib/entities/partial/prerequisites/displayOption.d.ts +1 -1
  30. package/lib/entities/partial/prerequisites/index.d.ts +1 -1
  31. package/lib/entities/partial/prerequisites/part.d.ts +1 -1
  32. package/lib/entities/partial/prerequisites/prerequisiteGroups.d.ts +1 -1
  33. package/lib/entities/partial/prerequisites/single/activatable.d.ts +2 -2
  34. package/lib/entities/partial/prerequisites/single/animistPower.d.ts +1 -1
  35. package/lib/entities/partial/prerequisites/single/blessedTradition.d.ts +1 -1
  36. package/lib/entities/partial/prerequisites/single/culture.d.ts +1 -1
  37. package/lib/entities/partial/prerequisites/single/enhancement.d.ts +1 -1
  38. package/lib/entities/partial/prerequisites/single/influence.d.ts +1 -1
  39. package/lib/entities/partial/prerequisites/single/magicalTradition.d.ts +1 -1
  40. package/lib/entities/partial/prerequisites/single/pact.d.ts +1 -1
  41. package/lib/entities/partial/prerequisites/single/personalityTrait.d.ts +1 -1
  42. package/lib/entities/partial/prerequisites/single/primaryAttribute.d.ts +1 -1
  43. package/lib/entities/partial/prerequisites/single/profession.d.ts +1 -1
  44. package/lib/entities/partial/prerequisites/single/publication.d.ts +1 -1
  45. package/lib/entities/partial/prerequisites/single/race.d.ts +1 -1
  46. package/lib/entities/partial/prerequisites/single/rated.d.ts +1 -1
  47. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.d.ts +1 -1
  48. package/lib/entities/partial/prerequisites/single/ratedSum.d.ts +1 -1
  49. package/lib/entities/partial/prerequisites/single/rule.d.ts +1 -1
  50. package/lib/entities/partial/prerequisites/single/sex.d.ts +1 -1
  51. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.d.ts +1 -1
  52. package/lib/entities/partial/prerequisites/single/socialStatus.d.ts +1 -1
  53. package/lib/entities/partial/prerequisites/single/state.d.ts +1 -1
  54. package/lib/entities/partial/prerequisites/single/text.d.ts +1 -1
  55. package/lib/entities/partial/professions.d.ts +1 -1
  56. package/lib/entities/partial/professions.js +2 -4
  57. package/lib/entities/partial/rated/activatable/castingTime.d.ts +1 -1
  58. package/lib/entities/partial/rated/activatable/checkResultBased.d.ts +1 -1
  59. package/lib/entities/partial/rated/activatable/cost.d.ts +1 -1
  60. package/lib/entities/partial/rated/activatable/duration.d.ts +1 -1
  61. package/lib/entities/partial/rated/activatable/effect.d.ts +1 -1
  62. package/lib/entities/partial/rated/activatable/index.d.ts +1 -1
  63. package/lib/entities/partial/rated/activatable/range.d.ts +1 -1
  64. package/lib/entities/partial/rated/activatable/speed.d.ts +1 -1
  65. package/lib/entities/partial/rated/activatable/targetCategory.d.ts +1 -1
  66. package/lib/entities/partial/rated/improvementCost.d.ts +1 -1
  67. package/lib/entities/partial/rated/skillCheck.d.ts +1 -1
  68. package/lib/entities/partial/rated/skillCheck.js +5 -3
  69. package/lib/entities/partial/reader.d.ts +7 -1
  70. package/lib/entities/partial/reader.js +4 -0
  71. package/lib/entities/partial/responsiveText.d.ts +1 -1
  72. package/lib/entities/poison.d.ts +1 -1
  73. package/lib/entities/profession.d.ts +1 -1
  74. package/lib/entities/profession.js +19 -16
  75. package/lib/entities/race.d.ts +2 -0
  76. package/lib/entities/race.js +71 -52
  77. package/lib/entities/skill.d.ts +1 -1
  78. package/lib/entities/spell.d.ts +1 -1
  79. package/lib/helpers/getTypes.d.ts +1 -1
  80. package/lib/helpers/locale.d.ts +1 -1
  81. package/lib/helpers/translate.d.ts +1 -1
  82. package/lib/index.d.ts +128 -126
  83. package/lib/references/index.d.ts +1 -1
  84. package/lib/references/page.d.ts +1 -1
  85. package/lib/references/pageRange.d.ts +1 -1
  86. package/lib/tsconfig.tsbuildinfo +1 -1
  87. package/package.json +12 -12
@@ -1,4 +1,4 @@
1
- import type { ImprovementCost } from "optolith-database-schema/gen";
1
+ import type { ImprovementCost } from "@optolith/database-schema/gen";
2
2
  import { type RawDefinitionListEntityDescriptionSectionItem } from "../../../index.js";
3
3
  import { type StdReader } from "../reader.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import type { SkillCheckPenalty as GeneralSkillCheckPenalty, MagicalRuneCombatTechniqueCheckPenalty, SkillCheck } from "optolith-database-schema/gen";
1
+ import type { SkillCheckPenalty as GeneralSkillCheckPenalty, MagicalRuneCombatTechniqueCheckPenalty, SkillCheck } from "@optolith/database-schema/gen";
2
2
  import { type IdMap } from "../../../index.js";
3
3
  import { type StdReader } from "../reader.js";
4
4
  /**
@@ -8,8 +8,8 @@ import { MISSING_VALUE } from "../unknown.js";
8
8
  export const renderSkillCheck = (check) => Reader.asks(({ translate, translateMap, getInstanceById }) => ({
9
9
  label: translate("Check"),
10
10
  value: check
11
- .map(id => translateMap(getInstanceById("Attribute", id)?.translations)
12
- ?.abbreviation ?? MISSING_VALUE)
11
+ .map(id => translateMap(getInstanceById("Attribute", id)?.translations)?.abbreviation ??
12
+ MISSING_VALUE)
13
13
  .join("/"),
14
14
  }));
15
15
  const renderSkillCheckPenalty = (idMap, penalty) => {
@@ -53,7 +53,9 @@ const renderSkillCheckPenalty = (idMap, penalty) => {
53
53
  export const renderSkillCheckWithPenalty = (check, checkPenalty, idMap) => checkPenalty === undefined
54
54
  ? renderSkillCheck(check)
55
55
  : renderSkillCheck(check).thenW(checkText => renderSkillCheckPenalty(idMap, checkPenalty)
56
- .then(penaltyText => responsiveTranslateR(" (modified by {$modifier})", " (−{$modifier})", { modifier: penaltyText }))
56
+ .then(penaltyText => responsiveTranslateR(" (modified by {$modifier})", " (−{$modifier})", {
57
+ modifier: penaltyText,
58
+ }))
57
59
  .map(penaltyText => ({
58
60
  ...checkText,
59
61
  value: checkText.value + penaltyText,
@@ -1,5 +1,5 @@
1
1
  import { Reader } from "@elyukai/utils/reader";
2
- import type { ChildEntityMap, EntityMap, FastSkillModificationLevelConfig, ResponsiveText, ResponsiveTextOptional, SkillModificationLevel, SlowSkillModificationLevelConfig } from "optolith-database-schema/gen";
2
+ import type { ChildEntityMap, EntityMap, FastSkillModificationLevelConfig, ResponsiveText, ResponsiveTextOptional, SkillModificationLevel, SlowSkillModificationLevelConfig } from "@optolith/database-schema/gen";
3
3
  import type { IdArgsVariant } from "tsondb/schema/gen";
4
4
  import type { GetAllChildInstancesForParent, GetAllInstances, GetInstanceById } from "../../helpers/getTypes.js";
5
5
  import type { FormatNumber, LocaleCompare, LocaleJoin, LocaleJoinType } from "../../helpers/locale.js";
@@ -202,6 +202,12 @@ export declare const getChildInstancesForInstanceIdR: <CE extends keyof ChildEnt
202
202
  id: string;
203
203
  content: ChildEntityMap[CE][0];
204
204
  }[]>;
205
+ /**
206
+ * Gets a function to retrieve all child instances of an entity from the database by their child entity name and their parent’s identifier.
207
+ */
208
+ export declare const getChildInstancesForInstanceIdFnR: <CE extends keyof ChildEntityMap>() => Reader<{
209
+ getChildInstancesForInstanceId: GetAllChildInstancesForParent<CE>;
210
+ }, GetAllChildInstancesForParent<CE>>;
205
211
  /**
206
212
  * Joins a list of strings according to the locale’s rules for the given type.
207
213
  */
@@ -83,6 +83,10 @@ export const getAllInstancesR = (entityName) => Reader.asks(env => env.getAllIns
83
83
  * Retrieves all child instances of an entity from the database by their child entity name and their parent’s identifier.
84
84
  */
85
85
  export const getChildInstancesForInstanceIdR = (entityName, parentId) => Reader.asks(env => env.getChildInstancesForInstanceId(entityName, parentId));
86
+ /**
87
+ * Gets a function to retrieve all child instances of an entity from the database by their child entity name and their parent’s identifier.
88
+ */
89
+ export const getChildInstancesForInstanceIdFnR = () => Reader.asks(env => env.getChildInstancesForInstanceId);
86
90
  /**
87
91
  * Joins a list of strings according to the locale’s rules for the given type.
88
92
  */
@@ -1,5 +1,5 @@
1
1
  import { Reader } from "@elyukai/utils/reader";
2
- import type { ResponsiveText, ResponsiveTextOptional, ResponsiveTextReplace } from "optolith-database-schema/gen";
2
+ import type { ResponsiveText, ResponsiveTextOptional, ResponsiveTextReplace } from "@optolith/database-schema/gen";
3
3
  import { type LocaleMap } from "../../helpers/translate.js";
4
4
  import { type StdEnv } from "./reader.js";
5
5
  /**
@@ -1,4 +1,4 @@
1
- import type { ActivatableIdentifier, RatedIdentifier } from "optolith-database-schema/gen";
1
+ import type { ActivatableIdentifier, RatedIdentifier } from "@optolith/database-schema/gen";
2
2
  import type { GetInstanceById } from "../helpers/getTypes.js";
3
3
  import type { IdMap } from "../index.js";
4
4
  import type { GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
@@ -1,4 +1,4 @@
1
- import type { MagicalActionIdentifier, ProfessionSpecialAbilityIdentifier, RatedIdentifier } from "optolith-database-schema/gen";
1
+ import type { MagicalActionIdentifier, ProfessionSpecialAbilityIdentifier, RatedIdentifier } from "@optolith/database-schema/gen";
2
2
  import type { GetAllChildInstancesForParent, GetAllInstances, GetInstanceById } from "../helpers/getTypes.js";
3
3
  import { type GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
4
4
  /**
@@ -11,10 +11,10 @@ import { Case, fromUniformCase } from "tsondb/schema/gen";
11
11
  import { createEntityDescriptionCreator } from "../creator.js";
12
12
  import { combineNameComponents, getNameComponents, renderActivatableNameComponents, renderCombinedActivatableNameComponents, } from "./partial/activatableNameChunks.js";
13
13
  import { renderCommonnessRatedAdvantagesOrDisadvantages, renderValueWithPossibleTranslation, } from "./partial/commonnessRatedAdvantagesAndDisadvantages.js";
14
- import { attributedCustomName, attributedInstance, attributedName } from "./partial/markdown.js";
14
+ import { attributedCustomName, attributedInstance, attributedName, attributedNameFromInstance, } from "./partial/markdown.js";
15
15
  import { printProfessionPrerequisites } from "./partial/prerequisites/index.js";
16
16
  import { parensIf } from "./partial/rated/activatable/parensIf.js";
17
- import { attributedCustomNameR, attributedNameR, customNameR, formatR, getChildInstancesForInstanceIdR, getInstanceByIdR, localeCompareR, localeJoinR, localeSortR, strictNameR, translateMapFnR, translateR, translationR, } from "./partial/reader.js";
17
+ import { attributedCustomNameR, attributedNameR, customNameR, formatR, getChildInstancesForInstanceIdFnR, getChildInstancesForInstanceIdR, getInstanceByIdR, localeCompareR, localeJoinR, localeSortR, strictNameR, translateMapFnR, translateR, translationR, } from "./partial/reader.js";
18
18
  import { MISSING_VALUE, UNHANDLED_VALUE } from "./partial/unknown.js";
19
19
  const prepareProfessionPackages = (professionId) => Reader.asks(({ getInstanceById, getChildInstancesForInstanceId }) => getChildInstancesForInstanceId("ProfessionPackage", professionId)
20
20
  .map((professionPackage) => ({
@@ -133,10 +133,10 @@ const renderSkillsOption = (professionPackages, skillGroup) => allSame(professio
133
133
  })
134
134
  : Reader.traverse(professionPackages[0].content.options.skills.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
135
135
  .thenW(localeSortR)
136
- .thenW(list => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
136
+ .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: 8 }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
137
137
  apValue,
138
- list: list.join(", "),
139
- }))) ?? Reader.of(undefined))
138
+ list: list.join(", ") + parensIf(maxSRText),
139
+ })))) ?? Reader.of(undefined))
140
140
  : Reader.traverse(professionPackages, pkg => {
141
141
  const skillsOption = pkg.content.options?.skills;
142
142
  return skillsOption === undefined
@@ -148,10 +148,10 @@ const renderSkillsOption = (professionPackages, skillGroup) => allSame(professio
148
148
  })
149
149
  : Reader.traverse(skillsOption.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
150
150
  .thenW(localeSortR)
151
- .thenW(list => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
151
+ .thenW(list => translateR("maximum SR per skill: {$maxSR}", { maxSR: 8 }).then(maxSRText => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
152
152
  apValue: skillsOption.ap_value,
153
- list: list.join(", "),
154
- }));
153
+ list: list.join(", ") + parensIf(maxSRText),
154
+ })));
155
155
  }).map(list => list.join(" / "));
156
156
  const renderCantripList = (cantripIds) => Reader.traverse(cantripIds, id => attributedNameR("profession", "Cantrip", id).map(name => name ?? MISSING_VALUE))
157
157
  .thenW(localeSortR)
@@ -308,7 +308,8 @@ const getEnhancementNameComponents = (getInstanceById, translate, translateMap,
308
308
  id: Case("Enhancement", id),
309
309
  parent: instance.parent,
310
310
  base: getEnhancementBaseName(translate, instance, attributedName(translateMap, getInstanceById, "profession", instance.parent) ?? MISSING_VALUE),
311
- options: translateMap(instance.translations)?.name ?? MISSING_VALUE,
311
+ options: attributedNameFromInstance(translateMap, instance, "prerequisite", "Enhancement", id) ??
312
+ MISSING_VALUE,
312
313
  };
313
314
  };
314
315
  const renderEnhancementNameComponents = (chunk) => [chunk.base, chunk.options].join(" ");
@@ -354,9 +355,9 @@ const getSpecialAbilityNameComponents = (getInstanceById, getResolvedSelectOptio
354
355
  const wrapActivatableInAttributedString = (text, id) => attributedInstance(text, id.kind, fromUniformCase(id), { context: '"prerequisite"' });
355
356
  const renderSingleActivatableNameChunk = (translateMap, chunk) => chunk === undefined
356
357
  ? MISSING_VALUE
357
- : wrapActivatableInAttributedString(isEnhancementNameComponents(chunk)
358
+ : isEnhancementNameComponents(chunk)
358
359
  ? renderEnhancementNameComponents(chunk)
359
- : renderActivatableNameComponents(translateMap, chunk, false), chunk.id);
360
+ : wrapActivatableInAttributedString(renderActivatableNameComponents(translateMap, chunk, false), chunk.id);
360
361
  const renderSpecialAbilityName = (specialAbility) => Reader.asks(({ translate, translateMap, localeJoin, getInstanceById, getResolvedSelectOptionById, }) => {
361
362
  switch (specialAbility.kind) {
362
363
  case "Constant": {
@@ -598,7 +599,9 @@ const groupProfessionVariantsThatContainTheSameChanges = (variants) => Reader.as
598
599
  return acc;
599
600
  }, []));
600
601
  const renderProfessionVariants = (professionPackages) => professionPackages.length > 1
601
- ? Reader.of(UNHANDLED_VALUE)
602
+ ? getChildInstancesForInstanceIdFnR().map(getChildInstancesForInstanceId => professionPackages.some(professionPackage => getChildInstancesForInstanceId("ProfessionVariant", professionPackage.id).length > 0)
603
+ ? UNHANDLED_VALUE
604
+ : undefined)
602
605
  : getChildInstancesForInstanceIdR("ProfessionVariant", professionPackages[0].id).thenW(variants => groupProfessionVariantsThatContainTheSameChanges(variants).thenW(groupedVariants => Reader.traverse(groupedVariants, variant => renderProfessionVariant(professionPackages[0].content, variant))
603
606
  .map(list => list.filter(isNotNullish))
604
607
  .thenW(list => list.length === 0
@@ -707,10 +710,10 @@ export const getProfessionVersionEntityDescription = createEntityDescriptionCrea
707
710
  value,
708
711
  })
709
712
  .run(env),
710
- renderValueWithPossibleTranslation("Suggested Advantages", entry.suggested_advantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", values).run(env), translation.suggested_advantages).run(env),
711
- renderValueWithPossibleTranslation("Suggested Disadvantages", entry.suggested_disadvantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", values).run(env), translation.suggested_disadvantages).run(env),
712
- renderValueWithPossibleTranslation("Unsuitable Advantages", entry.unsuitable_advantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", values).run(env), translation.unsuitable_advantages).run(env),
713
- renderValueWithPossibleTranslation("Unsuitable Disadvantages", entry.unsuitable_disadvantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", values).run(env), translation.unsuitable_disadvantages).run(env),
713
+ renderValueWithPossibleTranslation("Suggested Advantages", entry.suggested_advantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", values, translate("none")).run(env), translation.suggested_advantages).run(env),
714
+ renderValueWithPossibleTranslation("Suggested Disadvantages", entry.suggested_disadvantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", values, translate("none")).run(env), translation.suggested_disadvantages).run(env),
715
+ renderValueWithPossibleTranslation("Unsuitable Advantages", entry.unsuitable_advantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", values, translate("none")).run(env), translation.unsuitable_advantages).run(env),
716
+ renderValueWithPossibleTranslation("Unsuitable Disadvantages", entry.unsuitable_disadvantages, values => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", values, translate("none")).run(env), translation.unsuitable_disadvantages).run(env),
714
717
  renderProfessionVariants(professionPackages)
715
718
  .map(value => value === undefined
716
719
  ? undefined
@@ -1,4 +1,5 @@
1
1
  import type { CountInstances, GetAllChildInstancesForParent, GetInstanceById } from "../helpers/getTypes.js";
2
+ import type { GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
2
3
  /**
3
4
  * Get a JSON representation of the rules text for a race.
4
5
  */
@@ -6,4 +7,5 @@ export declare const getRaceEntityDescription: import("../creator.js").EntityDes
6
7
  getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Advantage" | "Disadvantage" | "Culture" | "DerivedCharacteristic">;
7
8
  countInstances: CountInstances<"Attribute">;
8
9
  getChildInstancesForInstanceId: GetAllChildInstancesForParent<"RaceVariant">;
10
+ getResolvedSelectOptionById: GetResolvedSelectOptionById;
9
11
  }, import("../index.js").EntityDescription>;
@@ -1,21 +1,21 @@
1
1
  import { anySameIndices } from "@elyukai/utils/array/filters";
2
- import { isNotEmpty } from "@elyukai/utils/array/nonEmpty";
2
+ import { ensureNonEmpty, isNotEmpty } from "@elyukai/utils/array/nonEmpty";
3
3
  import { deepEqual } from "@elyukai/utils/equality";
4
4
  import { on } from "@elyukai/utils/function";
5
- import { isNotNullish } from "@elyukai/utils/nullable";
5
+ import { isNotNullish, mapNullable } from "@elyukai/utils/nullable";
6
6
  import { compareNumber } from "@elyukai/utils/ordering";
7
7
  import { Reader } from "@elyukai/utils/reader";
8
8
  import { sign } from "@elyukai/utils/string/number";
9
9
  import { createEntityDescriptionCreator } from "../creator.js";
10
- import { renderCommonnessRatedAdvantagesAndDisadvantages, renderCommonnessRatedAdvantagesOrDisadvantages, renderValueWithPossibleTranslation, } from "./partial/commonnessRatedAdvantagesAndDisadvantages.js";
11
- import { attributedCustomName, attributedName } from "./partial/markdown.js";
10
+ import { renderCommonnessRatedAdvantagesAndDisadvantages, renderCommonnessRatedAdvantagesOrDisadvantages, } from "./partial/commonnessRatedAdvantagesAndDisadvantages.js";
11
+ import { attributedCustomName, attributedName, attributedNameFromTranslation, } from "./partial/markdown.js";
12
12
  import { getInstanceByIdR, translateMapR, } from "./partial/reader.js";
13
13
  import { MISSING_VALUE } from "./partial/unknown.js";
14
14
  const renderBaseValues = (values) => Reader.traverse(Object.entries(values), ([id, { value }]) => getInstanceByIdR("DerivedCharacteristic", id).thenW(derivedCharacteristic => translateMapR(derivedCharacteristic?.translations).thenW(translation => Reader.asks(({ translate }) => [
15
15
  derivedCharacteristic?.position ?? 0,
16
16
  {
17
17
  label: translate("{$derivedCharacteristic} Base Value", {
18
- derivedCharacteristic: translation?.name ?? MISSING_VALUE,
18
+ derivedCharacteristic: attributedNameFromTranslation(translation, "base-values", "DerivedCharacteristic", id) ?? MISSING_VALUE,
19
19
  }),
20
20
  value: value < 0 ? sign(value) : value.toFixed(),
21
21
  },
@@ -28,7 +28,7 @@ const renderAttributeAdjustmentsItem = (totalAttributesCount, adjustments) => Re
28
28
  ...(adjustments.selectable?.map(adj => `${adj.list.length === totalAttributesCount ? translate("one attribute of your choice") : localeJoin(adj.list.map(getAttributeAbbreviation), "disjunction")} ${sign(adj.value)}`) ?? []),
29
29
  ].join("; ");
30
30
  });
31
- const renderVariantValues = (label, variants, selector, renderValue, translationSelector) => Reader.asks(({ translate, translateMap, localeCompare, localeJoin, }) => {
31
+ const renderVariantValues = (label, variants, selector, renderValue, translationSelector, allowEmpty = false, textPrefix) => Reader.asks(({ translate, translateMap, localeCompare, localeJoin, }) => {
32
32
  const values = variants.map(variant => {
33
33
  const translation = translateMap(variant.translations);
34
34
  return {
@@ -39,37 +39,52 @@ const renderVariantValues = (label, variants, selector, renderValue, translation
39
39
  : undefined,
40
40
  };
41
41
  });
42
- const sameValues = anySameIndices(values, on(value => [value.value, value.valueTranslation], deepEqual));
43
- if (isNotEmpty(sameValues) &&
44
- sameValues.length === 1 &&
45
- sameValues[0].length === values.length) {
46
- return {
47
- label: translate(label),
48
- value: values[0] === undefined
49
- ? MISSING_VALUE
50
- : (values[0].valueTranslation ?? renderValue(values[0].value)),
51
- };
42
+ if (isNotEmpty(values)) {
43
+ const sameValues = anySameIndices(values, on(value => [value.value, value.valueTranslation], deepEqual));
44
+ if (values.length === 1 ||
45
+ (isNotEmpty(sameValues) &&
46
+ sameValues.length === 1 &&
47
+ sameValues[0].length === values.length)) {
48
+ return values[0].value === undefined &&
49
+ values[0].valueTranslation === undefined &&
50
+ allowEmpty
51
+ ? undefined
52
+ : mapNullable(
53
+ /* values[0].valueTranslation ?? */ renderValue(values[0].value, false), renderedValue => ({
54
+ label: translate(label),
55
+ value: (textPrefix ?? "") + renderedValue,
56
+ }));
57
+ }
58
+ else {
59
+ return {
60
+ label: translate(label),
61
+ value: [
62
+ ...(textPrefix !== undefined ? [{ type: "plain", text: textPrefix }] : []),
63
+ {
64
+ type: "definitionList",
65
+ style: "nested",
66
+ items: Map.groupBy(values
67
+ .toSorted(on(item => item.name, localeCompare))
68
+ .map(value => mapNullable(
69
+ /* value.valueTranslation ?? */ renderValue(value.value, true), renderedValue => ({
70
+ label: value.name,
71
+ value: renderedValue,
72
+ })))
73
+ .filter(isNotNullish), item => item.value)
74
+ .entries()
75
+ .map(([value, items]) => ({
76
+ label: localeJoin(items.map(item => item.label), "conjunction"),
77
+ value,
78
+ }))
79
+ .toArray(),
80
+ },
81
+ ],
82
+ };
83
+ }
52
84
  }
53
85
  else {
54
- return {
55
- label: translate(label),
56
- value: [
57
- {
58
- type: "definitionList",
59
- style: "nested",
60
- items: Map.groupBy(values.toSorted(on(item => item.name, localeCompare)).map(value => ({
61
- label: value.name,
62
- value: value.valueTranslation ?? renderValue(value.value),
63
- })), item => item.value)
64
- .entries()
65
- .map(([value, items]) => ({
66
- label: localeJoin(items.map(item => item.label), "conjunction"),
67
- value,
68
- }))
69
- .toArray(),
70
- },
71
- ],
72
- };
86
+ // at least one value and thus one variant is required
87
+ return undefined;
73
88
  }
74
89
  });
75
90
  const renderAutomaticAdvantagesOrDisadvantages = (entity, items) => Reader.asks(({ translate, translateMap, getInstanceById, localeCompare }) => items === undefined || !isNotEmpty(items)
@@ -88,7 +103,7 @@ const renderCommonCultures = (items) => Reader.asks(({ translate, translateMap,
88
103
  /**
89
104
  * Get a JSON representation of the rules text for a race.
90
105
  */
91
- export const getRaceEntityDescription = createEntityDescriptionCreator(({ getInstanceById, countInstances, getChildInstancesForInstanceId }, { translate, translateMap, join: localeJoin, compare: localeCompare }, { id, content: entry }) => {
106
+ export const getRaceEntityDescription = createEntityDescriptionCreator(({ getInstanceById, countInstances, getChildInstancesForInstanceId, getResolvedSelectOptionById, }, { translate, translateMap, join: localeJoin, compare: localeCompare }, { id, content: entry }) => {
92
107
  const translation = translateMap(entry.translations);
93
108
  if (translation === undefined) {
94
109
  return undefined;
@@ -100,6 +115,7 @@ export const getRaceEntityDescription = createEntityDescriptionCreator(({ getIns
100
115
  translateMap,
101
116
  localeJoin,
102
117
  localeCompare,
118
+ getResolvedSelectOptionById,
103
119
  getInstanceById,
104
120
  };
105
121
  return {
@@ -118,23 +134,26 @@ export const getRaceEntityDescription = createEntityDescriptionCreator(({ getIns
118
134
  ...renderBaseValues(entry.base_values).run(env),
119
135
  renderVariantValues("Attribute Adjustments", raceVariants, v => v.attribute_adjustments, attrs => renderAttributeAdjustmentsItem(totalAttributesCount, attrs).run(env)).run(env),
120
136
  renderVariantValues("Common Cultures", raceVariants, v => v.common_cultures, cultures => renderCommonCultures(cultures).run(env)).run(env),
121
- entry.automatic_advantages === undefined
122
- ? undefined
123
- : renderValueWithPossibleTranslation("Automatic Advantages", entry.automatic_advantages, v => renderAutomaticAdvantagesOrDisadvantages("Advantage", v).run(env), translation.automatic_advantages).run(env),
124
- entry.automatic_disadvantages === undefined
125
- ? undefined
126
- : renderValueWithPossibleTranslation("Automatic Disadvantages", entry.automatic_disadvantages, v => renderAutomaticAdvantagesOrDisadvantages("Disadvantage", v).run(env), translation.automatic_disadvantages).run(env),
127
- entry.strongly_recommended_advantages === undefined &&
128
- entry.strongly_recommended_disadvantages === undefined
137
+ renderVariantValues("Automatic Advantages", raceVariants, v => v.automatic_advantages, advs => renderAutomaticAdvantagesOrDisadvantages("Advantage", advs).run(env), vt => vt.automatic_advantages, true).run(env),
138
+ renderVariantValues("Automatic Disadvantages", raceVariants, v => v.automatic_disadvantages, advs => renderAutomaticAdvantagesOrDisadvantages("Disadvantage", advs).run(env), vt => vt.automatic_disadvantages, true).run(env),
139
+ renderVariantValues("Strongly recommended Advantages and Disadvantages", raceVariants, v => v.strongly_recommended_advantages === undefined &&
140
+ v.strongly_recommended_disadvantages === undefined
129
141
  ? undefined
130
- : {
131
- label: translate("Strongly recommended Advantages and Disadvantages"),
132
- value: `${translate("The following advantages and disadvantages distinguish Aventurian {$race}. You should choose these advantages and disadvantages. If you don’t want to take them, talk to your GM.", { race: translation.name })} ${renderCommonnessRatedAdvantagesAndDisadvantages(entry.strongly_recommended_advantages, entry.strongly_recommended_disadvantages).run(env)}`,
133
- },
134
- renderVariantValues("Common Advantages", raceVariants, v => v.common_advantages, advs => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", advs).run(env), vt => vt.common_advantages).run(env),
135
- renderVariantValues("Common Disadvantages", raceVariants, v => v.common_disadvantages, advs => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", advs).run(env), vt => vt.common_disadvantages).run(env),
136
- renderVariantValues("Uncommon Advantages", raceVariants, v => v.uncommon_advantages, advs => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", advs).run(env), vt => vt.uncommon_advantages).run(env),
137
- renderVariantValues("Uncommon Disadvantages", raceVariants, v => v.uncommon_disadvantages, advs => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", advs).run(env), vt => vt.uncommon_disadvantages).run(env),
142
+ : [
143
+ v.strongly_recommended_advantages,
144
+ v.strongly_recommended_disadvantages,
145
+ ], (advsDisadvs, isSplit) => advsDisadvs === undefined
146
+ ? isSplit
147
+ ? undefined
148
+ : translate("none")
149
+ : renderCommonnessRatedAdvantagesAndDisadvantages(...advsDisadvs, isSplit ? undefined : translate("none")).run(env), vt => ensureNonEmpty([
150
+ vt.strongly_recommended_advantages,
151
+ vt.strongly_recommended_disadvantages,
152
+ ].filter(isNotNullish))?.join("; "), true, `${translate("The following advantages and disadvantages distinguish Aventurian {$race}. You should choose these advantages and disadvantages. If you don’t want to take them, talk to your GM.", { race: translation.name })} `).run(env),
153
+ renderVariantValues("Common Advantages", raceVariants, v => v.common_advantages, (advs, isSplit) => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", advs, isSplit ? undefined : translate("none")).run(env), vt => vt.common_advantages).run(env),
154
+ renderVariantValues("Common Disadvantages", raceVariants, v => v.common_disadvantages, (advs, isSplit) => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", advs, isSplit ? undefined : translate("none")).run(env), vt => vt.common_disadvantages).run(env),
155
+ renderVariantValues("Uncommon Advantages", raceVariants, v => v.uncommon_advantages, (advs, isSplit) => renderCommonnessRatedAdvantagesOrDisadvantages("Advantage", advs, isSplit ? undefined : translate("none")).run(env), vt => vt.uncommon_advantages).run(env),
156
+ renderVariantValues("Uncommon Disadvantages", raceVariants, v => v.uncommon_disadvantages, (advs, isSplit) => renderCommonnessRatedAdvantagesOrDisadvantages("Disadvantage", advs, isSplit ? undefined : translate("none")).run(env), vt => vt.uncommon_disadvantages).run(env),
138
157
  ],
139
158
  },
140
159
  ],
@@ -1,4 +1,4 @@
1
- import type { ActivatableIdentifier } from "optolith-database-schema/gen";
1
+ import type { ActivatableIdentifier } from "@optolith/database-schema/gen";
2
2
  import type { GetAllChildInstancesForParent, GetAllInstances, GetInstanceById } from "../helpers/getTypes.js";
3
3
  import type { GetAllResolvedNewSkillApplications, GetAllResolvedSkillUses } from "../index.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { type ActivatableIdentifier, type RatedIdentifier } from "optolith-database-schema/gen";
1
+ import { type ActivatableIdentifier, type RatedIdentifier } from "@optolith/database-schema/gen";
2
2
  import type { GetAllChildInstancesForParent, GetInstanceById } from "../helpers/getTypes.js";
3
3
  import { type IdMap } from "../index.js";
4
4
  import type { GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
@@ -1,4 +1,4 @@
1
- import type * as Database from "optolith-database-schema/gen";
1
+ import type * as Database from "@optolith/database-schema/gen";
2
2
  import type { IdArgsVariant } from "tsondb/schema/gen";
3
3
  export type GetInstanceById<in T extends Extract<keyof Database.EntityMap, string>> = <U extends T>(...args: IdArgsVariant<Database.EntityMap, U>) => Database.EntityMap[U] | undefined;
4
4
  export type GetAllInstances<T extends keyof Database.EntityMap> = <U extends T>(entity: U) => {
@@ -1,5 +1,5 @@
1
+ import type { LocaleMeasurementAdjustments } from "@optolith/database-schema/gen";
1
2
  import type { Compare } from "@optolith/helpers/compare";
2
- import type { LocaleMeasurementAdjustments } from "optolith-database-schema/gen";
3
3
  import type { Format, Translate, TranslateMap } from "./translate.js";
4
4
  /**
5
5
  * The type of list to join in a locale-aware way.
@@ -1,4 +1,4 @@
1
- import type { Locale } from "optolith-database-schema/gen";
1
+ import type { Locale } from "@optolith/database-schema/gen";
2
2
  import { ResponsiveTextSize } from "../entities/partial/responsiveText.js";
3
3
  /**
4
4
  * The type of all translations