@optolith/entity-descriptions 0.4.3 → 0.4.5
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.
- package/CHANGELOG.md +17 -0
- package/lib/entities/equipment.d.ts +1 -1
- package/lib/entities/equipment.js +217 -12
- package/lib/entities/partial/activatableNameChunks.js +5 -13
- package/lib/entities/partial/prerequisites/part.js +2 -0
- package/lib/entities/profession.js +31 -16
- package/lib/index.d.ts +30 -30
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.4.5](https://github.com/Optolith/entity-descriptions/compare/v0.4.4...v0.4.5) (2026-03-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* do not display the twelve blessings for shamanistic professions ([e95cc0d](https://github.com/Optolith/entity-descriptions/commit/e95cc0df5312dfcd6fd8ae571e728eccf08601e2))
|
|
11
|
+
* join prerequisites of the same entry more reliably ([c317c62](https://github.com/Optolith/entity-descriptions/commit/c317c629a5f091cc23485717fad795538aabf0c2))
|
|
12
|
+
* rendering of blessings in packages and variants ([d04e247](https://github.com/Optolith/entity-descriptions/commit/d04e24761204303211157e1154446bc8f1828c43))
|
|
13
|
+
|
|
14
|
+
## [0.4.4](https://github.com/Optolith/entity-descriptions/compare/v0.4.3...v0.4.4) (2026-03-14)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* book display ([dfc07ee](https://github.com/Optolith/entity-descriptions/commit/dfc07eed999c02890a3516aaacd64313c226c9cb))
|
|
20
|
+
* working creature optional value guards ([11a283a](https://github.com/Optolith/entity-descriptions/commit/11a283af9082b64eb48823cb90107394fa8baa5b))
|
|
21
|
+
|
|
5
22
|
## [0.4.3](https://github.com/Optolith/entity-descriptions/compare/v0.4.2...v0.4.3) (2026-03-14)
|
|
6
23
|
|
|
7
24
|
|
|
@@ -19,6 +19,6 @@ export declare const renderRangedWeapon: <Damage>(translate: Translate, translat
|
|
|
19
19
|
* Get a JSON representation of the rules text for equipment.
|
|
20
20
|
*/
|
|
21
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" | "WorkingSupernaturalCreature", {
|
|
22
|
-
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Reach" | "SocialStatus" | "CloseCombatTechnique" | "RangedCombatTechnique" | "MagicalTradition" | "BlessedTradition" | "DerivedCharacteristic" | "Ammunition" | "Race" | "Culture" | "Profession">;
|
|
22
|
+
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Reach" | "SocialStatus" | "CloseCombatTechnique" | "RangedCombatTechnique" | "MagicalTradition" | "BlessedTradition" | "DerivedCharacteristic" | "Ammunition" | "Race" | "Culture" | "Profession" | "Skill">;
|
|
23
23
|
idMap: IdMap;
|
|
24
24
|
}, import("../index.js").EntityDescription>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ensureNonEmpty, isNotEmpty } from "@elyukai/utils/array/nonEmpty";
|
|
2
2
|
import { isNotNullish } from "@elyukai/utils/nullable";
|
|
3
|
+
import { romanize } from "@elyukai/utils/roman";
|
|
3
4
|
import { sign } from "@elyukai/utils/string/number";
|
|
4
5
|
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
5
6
|
import { mapNullable } from "@optolith/helpers/nullable";
|
|
@@ -22,12 +23,13 @@ export const getEquipmentName = (translate, translateMap, getInstanceById, entry
|
|
|
22
23
|
socialStatus: socialStatusName,
|
|
23
24
|
});
|
|
24
25
|
}
|
|
26
|
+
case "Book":
|
|
27
|
+
return translateMap(entry.content.translations)?.name ?? MISSING_VALUE;
|
|
25
28
|
case "Ammunition":
|
|
26
29
|
case "Animal":
|
|
27
30
|
case "AnimalCare":
|
|
28
31
|
case "Armor":
|
|
29
32
|
case "BandageOrRemedy":
|
|
30
|
-
case "Book":
|
|
31
33
|
case "CeremonialItem":
|
|
32
34
|
case "Clothes":
|
|
33
35
|
case "Container":
|
|
@@ -433,7 +435,6 @@ const normalizeCombatValues = (entity) => {
|
|
|
433
435
|
case "Animal":
|
|
434
436
|
case "AnimalCare":
|
|
435
437
|
case "BandageOrRemedy":
|
|
436
|
-
case "Book":
|
|
437
438
|
case "CeremonialItem":
|
|
438
439
|
case "Clothes":
|
|
439
440
|
case "ClothingPackage":
|
|
@@ -481,11 +482,223 @@ const normalizeCombatValues = (entity) => {
|
|
|
481
482
|
return assertExhaustive(entity);
|
|
482
483
|
}
|
|
483
484
|
};
|
|
485
|
+
const renderBookTypes = (translate, translateMap, localeJoin, localeCompare, getInstanceById, types) => types
|
|
486
|
+
.map((type) => {
|
|
487
|
+
switch (type.kind) {
|
|
488
|
+
case "Mundane":
|
|
489
|
+
switch (type.Mundane.kind) {
|
|
490
|
+
case "RomanceNovel":
|
|
491
|
+
return [translate("Romance Novel")];
|
|
492
|
+
case "Poetry":
|
|
493
|
+
return [translate("Poetry")];
|
|
494
|
+
case "PoliticalPamphlet":
|
|
495
|
+
return [translate("Political Pamphlet")];
|
|
496
|
+
case "CrimeStory":
|
|
497
|
+
return [translate("Crime Story")];
|
|
498
|
+
case "FairyTale":
|
|
499
|
+
return [translate("Fairy Tale")];
|
|
500
|
+
case "Novel":
|
|
501
|
+
return [translate("Novel")];
|
|
502
|
+
case "ProfessionalPublication":
|
|
503
|
+
return [
|
|
504
|
+
translate("Professional Publication"),
|
|
505
|
+
translateMap(getInstanceById("Skill", type.Mundane.ProfessionalPublication)?.translations)?.name ?? MISSING_VALUE,
|
|
506
|
+
];
|
|
507
|
+
default:
|
|
508
|
+
return assertExhaustive(type.Mundane);
|
|
509
|
+
}
|
|
510
|
+
case "Magical":
|
|
511
|
+
return [translate("Magical Book")];
|
|
512
|
+
case "Religious":
|
|
513
|
+
return [translate("Religious Works")];
|
|
514
|
+
default:
|
|
515
|
+
return assertExhaustive(type);
|
|
516
|
+
}
|
|
517
|
+
})
|
|
518
|
+
.reduce((accTypes, [main, sub]) => {
|
|
519
|
+
const last = accTypes.at(-1);
|
|
520
|
+
return last?.[1] === undefined || sub === undefined
|
|
521
|
+
? [...accTypes, [main, sub === undefined ? undefined : [sub]]]
|
|
522
|
+
: [...accTypes.slice(0, -1), [last[0], [...last[1], sub]]];
|
|
523
|
+
}, [])
|
|
524
|
+
.map(([main, sub]) => sub === undefined
|
|
525
|
+
? main
|
|
526
|
+
: `${main} (${localeJoin(sub.toSorted(localeCompare), "conjunction")})`)
|
|
527
|
+
.join(", ");
|
|
528
|
+
const renderBookRules = (translate, rules) => {
|
|
529
|
+
switch (rules.kind) {
|
|
530
|
+
case "Plain":
|
|
531
|
+
if (rules.Plain.reconstruction === undefined &&
|
|
532
|
+
rules.Plain.references === undefined &&
|
|
533
|
+
rules.Plain.textAfter === undefined) {
|
|
534
|
+
return rules.Plain.text;
|
|
535
|
+
}
|
|
536
|
+
return [
|
|
537
|
+
{
|
|
538
|
+
type: "plain",
|
|
539
|
+
text: rules.Plain.text,
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
type: "definitionList",
|
|
543
|
+
style: "nested",
|
|
544
|
+
items: [
|
|
545
|
+
mapNullable(rules.Plain.reconstruction, reconstruction => ({
|
|
546
|
+
label: translate("Reconstruction"),
|
|
547
|
+
value: reconstruction,
|
|
548
|
+
})),
|
|
549
|
+
mapNullable(rules.Plain.references, references => ({
|
|
550
|
+
label: translate("References"),
|
|
551
|
+
value: references,
|
|
552
|
+
})),
|
|
553
|
+
],
|
|
554
|
+
},
|
|
555
|
+
mapNullable(rules.Plain.textAfter, textAfter => ({
|
|
556
|
+
type: "plain",
|
|
557
|
+
text: textAfter,
|
|
558
|
+
})),
|
|
559
|
+
];
|
|
560
|
+
case "Entertainment":
|
|
561
|
+
return translate("Entertainment");
|
|
562
|
+
case "ByEdition":
|
|
563
|
+
return [
|
|
564
|
+
{
|
|
565
|
+
type: "definitionList",
|
|
566
|
+
style: "nested",
|
|
567
|
+
items: [
|
|
568
|
+
...rules.ByEdition.editions.map((edition) => {
|
|
569
|
+
if (edition.reconstruction === undefined && edition.references === undefined) {
|
|
570
|
+
return {
|
|
571
|
+
label: edition.label,
|
|
572
|
+
value: edition.text,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
return {
|
|
576
|
+
label: edition.label,
|
|
577
|
+
value: [
|
|
578
|
+
{
|
|
579
|
+
type: "plain",
|
|
580
|
+
text: edition.text,
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
type: "definitionList",
|
|
584
|
+
style: "nested",
|
|
585
|
+
items: [
|
|
586
|
+
mapNullable(edition.reconstruction, reconstruction => ({
|
|
587
|
+
label: translate("Reconstruction"),
|
|
588
|
+
value: reconstruction,
|
|
589
|
+
})),
|
|
590
|
+
mapNullable(edition.references, references => ({
|
|
591
|
+
label: translate("References"),
|
|
592
|
+
value: references,
|
|
593
|
+
})),
|
|
594
|
+
],
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
};
|
|
598
|
+
}),
|
|
599
|
+
],
|
|
600
|
+
},
|
|
601
|
+
mapNullable(rules.ByEdition.textAfter, textAfter => ({
|
|
602
|
+
type: "plain",
|
|
603
|
+
text: textAfter,
|
|
604
|
+
})),
|
|
605
|
+
];
|
|
606
|
+
default:
|
|
607
|
+
return assertExhaustive(rules);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
484
610
|
/**
|
|
485
611
|
* Get a JSON representation of the rules text for equipment.
|
|
486
612
|
*/
|
|
487
613
|
export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ getInstanceById, idMap }, locale, entry) => {
|
|
488
614
|
const { translate, translateMap } = locale;
|
|
615
|
+
if (entry.entity === "Book") {
|
|
616
|
+
const translation = translateMap(entry.content.translations);
|
|
617
|
+
if (translation === undefined) {
|
|
618
|
+
return undefined;
|
|
619
|
+
}
|
|
620
|
+
const name = getEquipmentName(translate, translateMap, getInstanceById, entry);
|
|
621
|
+
return {
|
|
622
|
+
title: name,
|
|
623
|
+
className: "equipment",
|
|
624
|
+
body: [
|
|
625
|
+
{
|
|
626
|
+
type: "definitionList",
|
|
627
|
+
items: [
|
|
628
|
+
{
|
|
629
|
+
label: translate("Name"),
|
|
630
|
+
value: name,
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
label: translate("Type"),
|
|
634
|
+
value: renderBookTypes(translate, translateMap, locale.join, locale.compare, getInstanceById, entry.content.types),
|
|
635
|
+
},
|
|
636
|
+
translation.language !== undefined || translation.script !== undefined
|
|
637
|
+
? {
|
|
638
|
+
label: translate("Language/Script"),
|
|
639
|
+
value: [translation.language, translation.script]
|
|
640
|
+
.map(value => value ?? "—")
|
|
641
|
+
.join(" / "),
|
|
642
|
+
}
|
|
643
|
+
: undefined,
|
|
644
|
+
entry.content.contentQuality === undefined
|
|
645
|
+
? undefined
|
|
646
|
+
: {
|
|
647
|
+
label: translate("Content Quality"),
|
|
648
|
+
value: (() => {
|
|
649
|
+
switch (entry.content.contentQuality.kind) {
|
|
650
|
+
case "Modest":
|
|
651
|
+
return translate("Modest");
|
|
652
|
+
case "Average":
|
|
653
|
+
return translate("Average");
|
|
654
|
+
case "Demanding":
|
|
655
|
+
return (translate("Demanding") +
|
|
656
|
+
parensIf(translate("CL {$level}", {
|
|
657
|
+
level: romanize(entry.content.contentQuality.Demanding),
|
|
658
|
+
})));
|
|
659
|
+
default:
|
|
660
|
+
return assertExhaustive(entry.content.contentQuality);
|
|
661
|
+
}
|
|
662
|
+
})(),
|
|
663
|
+
},
|
|
664
|
+
mapNullable(entry.content.cost, cost => renderCost(translate, translateMap, locale.formatNumber, cost)),
|
|
665
|
+
translation.note === undefined
|
|
666
|
+
? undefined
|
|
667
|
+
: {
|
|
668
|
+
label: translate("Note"),
|
|
669
|
+
value: translation.note,
|
|
670
|
+
},
|
|
671
|
+
translation.rules === undefined
|
|
672
|
+
? undefined
|
|
673
|
+
: {
|
|
674
|
+
label: translate("Rules"),
|
|
675
|
+
value: renderBookRules(translate, translation.rules),
|
|
676
|
+
},
|
|
677
|
+
translation.legality === undefined
|
|
678
|
+
? undefined
|
|
679
|
+
: {
|
|
680
|
+
label: translate("Legality"),
|
|
681
|
+
value: translation.legality,
|
|
682
|
+
},
|
|
683
|
+
translation.availability === undefined
|
|
684
|
+
? undefined
|
|
685
|
+
: {
|
|
686
|
+
label: translate("Availability"),
|
|
687
|
+
value: translation.availability,
|
|
688
|
+
},
|
|
689
|
+
translation.special === undefined
|
|
690
|
+
? undefined
|
|
691
|
+
: {
|
|
692
|
+
label: translate("Special"),
|
|
693
|
+
value: translation.special,
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
},
|
|
697
|
+
],
|
|
698
|
+
errata: translation.errata,
|
|
699
|
+
references: entry.content.src,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
489
702
|
const translation = entry.entity === "ClothingPackage" ? undefined : translateMap(entry.content.translations);
|
|
490
703
|
if (entry.entity !== "ClothingPackage" && translation === undefined) {
|
|
491
704
|
return undefined;
|
|
@@ -522,14 +735,6 @@ export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ g
|
|
|
522
735
|
label: translate("Color"),
|
|
523
736
|
value: color,
|
|
524
737
|
})),
|
|
525
|
-
baseItemTranslation?.language !== undefined || baseItemTranslation?.script !== undefined
|
|
526
|
-
? {
|
|
527
|
-
label: translate("Language/Script"),
|
|
528
|
-
value: [baseItemTranslation.language, baseItemTranslation.script]
|
|
529
|
-
.map(value => value ?? "—")
|
|
530
|
-
.join(" / "),
|
|
531
|
-
}
|
|
532
|
-
: undefined,
|
|
533
738
|
baseItem.structure_points !== undefined && isNotEmpty(baseItem.structure_points)
|
|
534
739
|
? {
|
|
535
740
|
label: translate("Structure Points"),
|
|
@@ -584,13 +789,13 @@ export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ g
|
|
|
584
789
|
value: baseItemTranslation.appearance,
|
|
585
790
|
}
|
|
586
791
|
: undefined,
|
|
587
|
-
baseItemTranslation?.
|
|
792
|
+
baseItemTranslation?.components !== undefined
|
|
588
793
|
? {
|
|
589
794
|
label: translate("Components"),
|
|
590
795
|
value: baseItemTranslation.components,
|
|
591
796
|
}
|
|
592
797
|
: undefined,
|
|
593
|
-
baseItemTranslation?.
|
|
798
|
+
baseItemTranslation?.use !== undefined
|
|
594
799
|
? {
|
|
595
800
|
label: translate("Use"),
|
|
596
801
|
value: baseItemTranslation.use,
|
|
@@ -57,13 +57,10 @@ const normalizeChunks = (chunk) => (Array.isArray(chunk) ? combinePair(chunk) :
|
|
|
57
57
|
*/
|
|
58
58
|
const zipChunks = (chunks) => chunks
|
|
59
59
|
.map(normalizeChunks)
|
|
60
|
-
.reduce((acc, chunk) => acc === "" ? chunk : combineChunks(acc, chunk, (a, b) => `${a}, ${b}`), "");
|
|
60
|
+
.reduce((acc, chunk) => (acc === "" ? chunk : combineChunks(acc, chunk, (a, b) => `${a}, ${b}`)), "");
|
|
61
61
|
const renderLevel = (formatAsPrerequisite, id, level) => level === undefined
|
|
62
62
|
? undefined
|
|
63
|
-
: formatAsPrerequisite ||
|
|
64
|
-
id.kind === "Advantage" ||
|
|
65
|
-
id.kind === "Disadvantage" ||
|
|
66
|
-
level === 1
|
|
63
|
+
: formatAsPrerequisite || id.kind === "Advantage" || id.kind === "Disadvantage" || level === 1
|
|
67
64
|
? romanize(level)
|
|
68
65
|
: `I–${romanize(level)}`;
|
|
69
66
|
/**
|
|
@@ -86,9 +83,7 @@ const renderActivatableNameChunk = (translateMap, chunk) => {
|
|
|
86
83
|
*/
|
|
87
84
|
export const renderActivatableNameComponentsWithoutLevel = (translateMap, components) => {
|
|
88
85
|
const { levelPlacement, useParenthesis } = components.nameBuilderRules;
|
|
89
|
-
const wrapParens = useParenthesis
|
|
90
|
-
? str => `(${str})`
|
|
91
|
-
: identity;
|
|
86
|
+
const wrapParens = useParenthesis ? str => `(${str})` : identity;
|
|
92
87
|
const base = renderActivatableNameChunk(translateMap, components.base);
|
|
93
88
|
const options = components.options === undefined
|
|
94
89
|
? undefined
|
|
@@ -313,13 +308,10 @@ export const renderActivatableNameComponentsCombinedIfPossible = (translateMap,
|
|
|
313
308
|
// }
|
|
314
309
|
const renderOptions = (displayedInProfession, getResolvedSelectOptionById, id, options) => {
|
|
315
310
|
const arr = options?.map(optionId => {
|
|
316
|
-
const optTranslations = getResolvedSelectOptionById(id, optionId)?.content
|
|
317
|
-
.translations;
|
|
311
|
+
const optTranslations = getResolvedSelectOptionById(id, optionId)?.content.translations;
|
|
318
312
|
return optTranslations === undefined
|
|
319
313
|
? MISSING_VALUE
|
|
320
|
-
: mapObject(optTranslations, t10n => displayedInProfession
|
|
321
|
-
? (t10n.name_in_profession ?? t10n.name)
|
|
322
|
-
: t10n.name);
|
|
314
|
+
: mapObject(optTranslations, t10n => displayedInProfession ? (t10n.name_in_profession ?? t10n.name) : t10n.name);
|
|
323
315
|
}) ?? [];
|
|
324
316
|
if (isNotEmpty(arr) && arr.length > 1) {
|
|
325
317
|
const [first, ...rest] = arr;
|
|
@@ -3,6 +3,7 @@ import { deepEqual, equal } from "@elyukai/utils/equality";
|
|
|
3
3
|
import { on } from "@elyukai/utils/function";
|
|
4
4
|
import { compareNumber, reduceCompare } from "@elyukai/utils/ordering";
|
|
5
5
|
import { assertExhaustive } from "@optolith/helpers/typeSafety";
|
|
6
|
+
import { fromUniformCase } from "tsondb/schema/gen";
|
|
6
7
|
import { renderActivatableNameComponents, renderActivatableNameComponentsCombinedIfPossible, } from "../activatableNameChunks.js";
|
|
7
8
|
/**
|
|
8
9
|
* Type guard for prerequisite parts with a value object.
|
|
@@ -53,6 +54,7 @@ const appendPrerequisitePartGroup = (previous, translateMap, localeCompare, part
|
|
|
53
54
|
}
|
|
54
55
|
else if (parts.every(hasPartValueObject)) {
|
|
55
56
|
return appendBySentenceType(previous, parts
|
|
57
|
+
.toSorted(on(part => fromUniformCase(part.value.id), localeCompare))
|
|
56
58
|
.reduce((acc, current, i, arr) => {
|
|
57
59
|
if (acc[1] > 0) {
|
|
58
60
|
return [acc[0], acc[1] - 1];
|
|
@@ -368,22 +368,28 @@ const renderRestrictedBlessings = (restrictedBlessings) => {
|
|
|
368
368
|
return assertExhaustive(restrictedBlessings);
|
|
369
369
|
}
|
|
370
370
|
};
|
|
371
|
-
const renderSingleBlessings = (traditions) => Reader.traverse(traditions, traditionId => getInstanceByIdR("BlessedTradition", traditionId).map(tradition => tradition
|
|
371
|
+
const renderSingleBlessings = (traditions) => Reader.traverse(traditions, traditionId => getInstanceByIdR("BlessedTradition", traditionId).map(tradition => tradition
|
|
372
|
+
? { restrictedBlessings: tradition.restricted_blessings, type: tradition.type }
|
|
373
|
+
: undefined)).thenW(restrictedBlessingsList => !isNotEmpty(restrictedBlessingsList)
|
|
372
374
|
? Reader.of(undefined)
|
|
373
375
|
: restrictedBlessingsList.length === 1
|
|
374
376
|
? (() => {
|
|
375
|
-
const [
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
377
|
+
const [first] = restrictedBlessingsList;
|
|
378
|
+
const { restrictedBlessings, type } = first ?? {};
|
|
379
|
+
return type?.kind === "Shamanistic"
|
|
380
|
+
? Reader.of(undefined)
|
|
381
|
+
: restrictedBlessings === undefined
|
|
382
|
+
? translateR("The Twelve Blessings")
|
|
383
|
+
: translateR("The Twelve Blessings").thenW(base => renderRestrictedBlessings(restrictedBlessings).thenW(list => translateR("except for {$list :list type=conjunction}", {
|
|
384
|
+
list,
|
|
385
|
+
}).map(note => base + parensIf(note))));
|
|
381
386
|
})()
|
|
382
|
-
: restrictedBlessingsList.
|
|
383
|
-
?
|
|
384
|
-
:
|
|
385
|
-
|
|
386
|
-
|
|
387
|
+
: restrictedBlessingsList.every(trad => trad?.type.kind === "Shamanistic")
|
|
388
|
+
? Reader.of(undefined)
|
|
389
|
+
: restrictedBlessingsList.some(trad => trad?.restrictedBlessings !== undefined || trad?.type.kind === "Shamanistic")
|
|
390
|
+
? translateR("The Twelve Blessings").map2(translateR("depends on selected tradition"), (base, note) => base + parensIf(note))
|
|
391
|
+
: translateR("The Twelve Blessings"));
|
|
392
|
+
const renderBlessings = (traditions) => {
|
|
387
393
|
if (traditions.every(isEmpty)) {
|
|
388
394
|
return Reader.of(undefined);
|
|
389
395
|
}
|
|
@@ -395,13 +401,21 @@ const renderBlessings = (professionPackages) => {
|
|
|
395
401
|
return Reader.traverse(traditions, option => option.length === 0 ? Reader.of("—") : renderSingleBlessings(option)).map(list => list.join(" / "));
|
|
396
402
|
}
|
|
397
403
|
};
|
|
404
|
+
const renderBlessingsForPackages = (professionPackages) => renderBlessings(professionPackages.map(pkg => retrieveBlessedTraditionIdentifierFromPrerequisites(pkg.content.prerequisites)));
|
|
405
|
+
const renderBlessingsForVariant = (professionVariant) => renderBlessings([
|
|
406
|
+
retrieveBlessedTraditionIdentifierFromPrerequisites(professionVariant.prerequisites),
|
|
407
|
+
]).map(blessingsText => (blessingsText !== undefined ? [blessingsText] : []));
|
|
398
408
|
const renderLiturgicalChantName = (liturgyIds) => Reader.traverse(liturgyIds, strictNameR).thenW(list => localeJoinR(list, "disjunction"));
|
|
399
409
|
const renderLiturgicalChants = (professionPackages) => Reader.sequence([
|
|
400
|
-
|
|
410
|
+
renderBlessingsForPackages(professionPackages),
|
|
401
411
|
renderNumericListAcrossPackages(professionPackages, (pkg) => Reader.of(pkg.content.liturgical_chants?.map(ct => [ct.id, ct.rating_modifier]) ?? []), deepEqual, renderLiturgicalChantName, 0),
|
|
402
412
|
renderLiturgiesOption(professionPackages),
|
|
403
413
|
]).map(list => ensureNonEmpty(list.filter(isNotNullish))?.join(", "));
|
|
414
|
+
const baseHasNoTradition = (base) => isEmpty(retrieveBlessedTraditionIdentifierFromPrerequisites(base.prerequisites));
|
|
404
415
|
const renderRatedVariantChanges = (baseList, variantList, renderInstance) => Reader.traverse(variantList ?? [], ({ id, rating_modifier }) => {
|
|
416
|
+
if (baseList === "ignore") {
|
|
417
|
+
return renderInstance(id).map(name => `${name} ${rating_modifier.toFixed()}`);
|
|
418
|
+
}
|
|
405
419
|
const baseValue = baseList?.find(item => deepEqual(item.id, id))?.rating_modifier ?? 0;
|
|
406
420
|
return renderInstance(id).thenW(name => translateR("{$replacement} instead of {$base}", {
|
|
407
421
|
replacement: `${name} ${(baseValue + rating_modifier).toFixed()}`,
|
|
@@ -420,11 +434,11 @@ const renderProfessionVariantText = (base, variant, translation) => translation.
|
|
|
420
434
|
Reader.asks(env => variant.prerequisites === undefined
|
|
421
435
|
? []
|
|
422
436
|
: [
|
|
423
|
-
printProfessionPrerequisites(env.getInstanceById, env.getResolvedSelectOptionById, {
|
|
437
|
+
`${env.translate("Prerequisites")}: ${printProfessionPrerequisites(env.getInstanceById, env.getResolvedSelectOptionById, {
|
|
424
438
|
...env,
|
|
425
439
|
join: env.localeJoin,
|
|
426
440
|
compare: env.localeCompare,
|
|
427
|
-
}, variant.prerequisites)
|
|
441
|
+
}, variant.prerequisites)}`,
|
|
428
442
|
]),
|
|
429
443
|
renderVariantOption(base, variant, "skill_specialization", renderVariantSkillSpecializationOption),
|
|
430
444
|
renderVariantOption(base, variant, "languages_scripts", renderVariantLanguagesScriptsOption),
|
|
@@ -448,7 +462,8 @@ const renderProfessionVariantText = (base, variant, translation) => translation.
|
|
|
448
462
|
renderRatedVariantChanges(base.combat_techniques, variant.combat_techniques, id => strictNameR(id)),
|
|
449
463
|
renderRatedVariantChanges(base.skills, variant.skills, id => strictNameR("Skill", id)),
|
|
450
464
|
renderRatedVariantChanges(base.spells, variant.spells, renderSpellworkName),
|
|
451
|
-
|
|
465
|
+
renderBlessingsForVariant(variant),
|
|
466
|
+
renderRatedVariantChanges(baseHasNoTradition(base) ? "ignore" : base.liturgical_chants, variant.liturgical_chants, renderLiturgicalChantName),
|
|
452
467
|
]).map(lists => lists
|
|
453
468
|
.filter(isNotEmpty)
|
|
454
469
|
.map(list => list.join(", "))
|