@optolith/entity-descriptions 0.5.1 → 0.6.0
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 +13 -0
- package/lib/entities/activatable.d.ts +1 -1
- package/lib/entities/activatable.js +43 -8
- package/lib/entities/liturgicalChant.js +12 -9
- package/lib/entities/profession.js +17 -15
- package/lib/index.d.ts +56 -56
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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.6.0](https://github.com/Optolith/entity-descriptions/compare/v0.5.1...v0.6.0) (2026-09-08)
|
|
6
|
+
|
|
7
|
+
### ⚠ BREAKING CHANGES
|
|
8
|
+
|
|
9
|
+
* **deps:** upgrade to schema 0.55.0
|
|
10
|
+
|
|
11
|
+
### build
|
|
12
|
+
|
|
13
|
+
* **deps:** upgrade to schema 0.55.0 ([0dff095](https://github.com/Optolith/entity-descriptions/commit/0dff0950d939beec0e688e792c58d6d0a2ce44d7))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* restricted blessings for traditions ([ca26c4c](https://github.com/Optolith/entity-descriptions/commit/ca26c4cadc77198b164967074735707ac6ec8593)), closes [#42](https://github.com/Optolith/entity-descriptions/issues/42)
|
|
5
18
|
## [0.5.1](https://github.com/Optolith/entity-descriptions/compare/v0.5.0...v0.5.1) (2026-09-08)
|
|
6
19
|
## [0.5.0](https://github.com/Optolith/entity-descriptions/compare/v0.4.26...v0.5.0) (2026-09-08)
|
|
7
20
|
|
|
@@ -47,7 +47,7 @@ export type BaseActivatableTranslation = {
|
|
|
47
47
|
* Get a JSON representation of the rules text for a special ability.
|
|
48
48
|
*/
|
|
49
49
|
export declare const getActivatableEntityDescription: import("../creator.js").EntityDescriptionCreator<"Advantage" | "Disadvantage" | "AdvancedCombatSpecialAbility" | "AdvancedKarmaSpecialAbility" | "AdvancedMagicalSpecialAbility" | "AdvancedSkillSpecialAbility" | "AncestorGlyph" | "ArcaneOrbEnchantment" | "AttireEnchantment" | "Beutelzauber" | "BlessedTradition" | "BowlEnchantment" | "BrawlingSpecialAbility" | "CauldronEnchantment" | "CeremonialItemSpecialAbility" | "ChronicleEnchantment" | "CombatSpecialAbility" | "CombatStyleSpecialAbility" | "CommandSpecialAbility" | "DaggerRitual" | "FamiliarSpecialAbility" | "FatePointSexSpecialAbility" | "FatePointSpecialAbility" | "FoolsHatEnchantment" | "GeneralSpecialAbility" | "Haubenzauber" | "Hauerkettenzauber" | "InstrumentEnchantment" | "KarmaSpecialAbility" | "Keulenzauber" | "Krallenkettenzauber" | "Kristallkugelzauber" | "LiturgicalStyleSpecialAbility" | "LycantropicGift" | "MagicalSign" | "MagicalSpecialAbility" | "MagicalTradition" | "MagicStyleSpecialAbility" | "OrbEnchantment" | "PactGift" | "ProtectiveWardingCircleSpecialAbility" | "RingEnchantment" | "Schweinetrommelzauber" | "Sermon" | "SexSpecialAbility" | "SickleRitual" | "SikaryanDrainSpecialAbility" | "SkillStyleSpecialAbility" | "SpellSwordEnchantment" | "StaffEnchantment" | "ToyEnchantment" | "Trinkhornzauber" | "VampiricGift" | "Vision" | "WandEnchantment" | "WeaponEnchantment", {
|
|
50
|
-
getInstanceById: GetInstanceById<"Publication" | "Subject" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "TradeSecret" | "Aspect" | "Property" | "Race" | "Culture" | "State" | "Enhancement" | "PactCategory" | "PactDomain" | "SocialStatus" | "Weapon" | "Patron" | "PersonalityTrait">;
|
|
50
|
+
getInstanceById: GetInstanceById<"Publication" | "Subject" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "TradeSecret" | "Aspect" | "Property" | "Race" | "Culture" | "State" | "Enhancement" | "PactCategory" | "PactDomain" | "SocialStatus" | "Weapon" | "Patron" | "PersonalityTrait" | "Blessing">;
|
|
51
51
|
getAllInstances: GetAllInstances<"Script">;
|
|
52
52
|
getResolvedSelectOptionById: GetResolvedSelectOptionById;
|
|
53
53
|
getAllResolvedSelectOptions: GetAllResolvedSelectOptions;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isNotEmpty } from "@elyukai/utils/array/nonEmpty";
|
|
2
2
|
import { count } from "@elyukai/utils/array/reductions";
|
|
3
3
|
import { deepEqual } from "@elyukai/utils/equality";
|
|
4
|
-
import { on } from "@elyukai/utils/function";
|
|
4
|
+
import { constant, on } from "@elyukai/utils/function";
|
|
5
5
|
import { isNotNullish } from "@elyukai/utils/nullable";
|
|
6
6
|
import { Reader } from "@elyukai/utils/reader";
|
|
7
7
|
import { numAsc } from "@optolith/helpers/compare";
|
|
@@ -651,6 +651,37 @@ const renderFavoredSkillsSelection = (baseList, favoredSkillsSelection) => favor
|
|
|
651
651
|
baseList,
|
|
652
652
|
selection: names.join(", "),
|
|
653
653
|
}));
|
|
654
|
+
const getRestrictedBlessingsSpecialRuleLabelKey = (restrictedBlessings) => {
|
|
655
|
+
if (restrictedBlessings === "All") {
|
|
656
|
+
return "No Blessings";
|
|
657
|
+
}
|
|
658
|
+
switch (restrictedBlessings.kind) {
|
|
659
|
+
case "Three":
|
|
660
|
+
return "Restricted Blessings";
|
|
661
|
+
case "Six":
|
|
662
|
+
return "Strongly Restricted Blessings";
|
|
663
|
+
default:
|
|
664
|
+
return assertExhaustive(restrictedBlessings);
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
const renderRestrictedBlessingsSpecialRule = (restrictedBlessings, nameOfPeopleWithThisTradition) => translateR(getRestrictedBlessingsSpecialRuleLabelKey(restrictedBlessings)).thenW(label => restrictedBlessings === "All"
|
|
668
|
+
? translateR("{$nameOfBlessedOnes} cannot use blessings.", {
|
|
669
|
+
nameOfBlessedOnes: nameOfPeopleWithThisTradition,
|
|
670
|
+
}).map(text => ({
|
|
671
|
+
label,
|
|
672
|
+
text,
|
|
673
|
+
}))
|
|
674
|
+
: Reader.traverse(restrictedBlessings.kind === "Three"
|
|
675
|
+
? restrictedBlessings.Three
|
|
676
|
+
: restrictedBlessings.Six, id => attributedNameR("restricted-blessings", "Blessing", id).map(name => name ?? MISSING_VALUE))
|
|
677
|
+
.thenW(localeSortR)
|
|
678
|
+
.thenW(list => translateR("{$nameOfBlessedOnes} cannot use {$blessings :list type=disjunction}.", {
|
|
679
|
+
nameOfBlessedOnes: nameOfPeopleWithThisTradition,
|
|
680
|
+
blessings: list,
|
|
681
|
+
}).map(text => ({
|
|
682
|
+
label,
|
|
683
|
+
text,
|
|
684
|
+
}))));
|
|
654
685
|
const renderFavoredSkillsSpecialRule = (favoredCombatTechniques, favoredSkills, favoredSkillsSelection) => translateR("Favored Skills").thenW(label => renderFavoredCombatTechniques(favoredCombatTechniques)
|
|
655
686
|
.thenW(favoredCombatTechniquesText => renderFavoredSkillsBaseList(favoredCombatTechniquesText, favoredSkills))
|
|
656
687
|
.thenW(list => renderFavoredSkillsSelection(list, favoredSkillsSelection))
|
|
@@ -670,7 +701,11 @@ const renderPrimaryAttributeSpecialRule = (traditionName, nameOfPeopleWithThisTr
|
|
|
670
701
|
}))).map(description => ({
|
|
671
702
|
text: description,
|
|
672
703
|
}));
|
|
673
|
-
const renderAdditionalSpecialRules = (traditionName, nameOfPeopleWithThisTradition, favoredCombatTechniques, favoredSkills, favoredSkillsSelection, primaryAttribute) => Reader.sequence([
|
|
704
|
+
const renderAdditionalSpecialRules = (fixedSpecialRules, traditionName, nameOfPeopleWithThisTradition, restrictedBlessings, favoredCombatTechniques, favoredSkills, favoredSkillsSelection, primaryAttribute) => Reader.sequence([
|
|
705
|
+
restrictedBlessings === undefined
|
|
706
|
+
? Reader.of(undefined)
|
|
707
|
+
: renderRestrictedBlessingsSpecialRule(restrictedBlessings, nameOfPeopleWithThisTradition),
|
|
708
|
+
...fixedSpecialRules.map(rule => Reader.of(rule)),
|
|
674
709
|
favoredSkills === undefined
|
|
675
710
|
? Reader.of(undefined)
|
|
676
711
|
: renderFavoredSkillsSpecialRule(favoredCombatTechniques, favoredSkills, favoredSkillsSelection),
|
|
@@ -691,14 +726,15 @@ export const getActivatableEntityDescription = createEntityDescriptionCreator(({
|
|
|
691
726
|
translateMap,
|
|
692
727
|
getInstanceById,
|
|
693
728
|
localeCompare: locale.compare,
|
|
729
|
+
localeJoin: locale.join,
|
|
694
730
|
};
|
|
695
731
|
const baseEntry = entry;
|
|
696
732
|
const wrappedId = Case(entityName, id);
|
|
697
|
-
const
|
|
698
|
-
? renderAdditionalSpecialRules(translation.name, translation.nameOfBlessedOnes, entry.favored_combat_techniques, entry.favored_skills, entry.favored_skills_selection, entry.primary).run(env)
|
|
733
|
+
const addAdditionalSpecialRules = entityName === "BlessedTradition"
|
|
734
|
+
? (baseList) => renderAdditionalSpecialRules(baseList, translation.name, translation.nameOfBlessedOnes, entry.type.kind === "Church" ? entry.type.Church.restrictedBlessings : "All", entry.favored_combat_techniques, entry.favored_skills, entry.favored_skills_selection, entry.primary).run(env)
|
|
699
735
|
: entityName === "MagicalTradition"
|
|
700
|
-
? renderAdditionalSpecialRules(translation.name, translation.nameOfSpellcasters, undefined, undefined, undefined, entry.primary).run(env)
|
|
701
|
-
: [];
|
|
736
|
+
? (baseList) => renderAdditionalSpecialRules(baseList, translation.name, translation.nameOfSpellcasters, undefined, undefined, undefined, undefined, entry.primary).run(env)
|
|
737
|
+
: constant([]);
|
|
702
738
|
const makeTraditionName = entityName === "BlessedTradition" || entityName === "MagicalTradition"
|
|
703
739
|
? name => translate("Tradition ({$tradition})", { tradition: name })
|
|
704
740
|
: name => name;
|
|
@@ -723,8 +759,7 @@ export const getActivatableEntityDescription = createEntityDescriptionCreator(({
|
|
|
723
759
|
body: [
|
|
724
760
|
mapNullable(translation.special_rules, specialRules => ({
|
|
725
761
|
type: "plain",
|
|
726
|
-
text: specialRules
|
|
727
|
-
.concat(additionalSpecialRules)
|
|
762
|
+
text: addAdditionalSpecialRules(specialRules)
|
|
728
763
|
.map(specialRule => specialRule.label === undefined
|
|
729
764
|
? `- ${specialRule.text}`
|
|
730
765
|
: `- *${specialRule.label}*: ${specialRule.text}`)
|
|
@@ -17,16 +17,19 @@ const getTextForBlessingTraditions = (deps, id) => {
|
|
|
17
17
|
const blessedTraditions = deps.getAllInstances("BlessedTradition");
|
|
18
18
|
const primaryTradition = blessedTraditions.find(trad => trad.content.primaryBlessing === id);
|
|
19
19
|
const secondaryTraditions = blessedTraditions.filter(trad => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
if (trad.content.type.kind === "Church") {
|
|
21
|
+
switch (trad.content.type.Church.restrictedBlessings?.kind) {
|
|
22
|
+
case "Six":
|
|
23
|
+
return !trad.content.type.Church.restrictedBlessings.Six.includes(id);
|
|
24
|
+
case "Three":
|
|
25
|
+
return !trad.content.type.Church.restrictedBlessings.Three.includes(id);
|
|
26
|
+
case undefined:
|
|
27
|
+
return false;
|
|
28
|
+
default:
|
|
29
|
+
return assertExhaustive(trad.content.type.Church.restrictedBlessings);
|
|
30
|
+
}
|
|
29
31
|
}
|
|
32
|
+
return false;
|
|
30
33
|
});
|
|
31
34
|
const translateTradition = (trad) => {
|
|
32
35
|
const traditionTranslation = deps.translateMap(trad.content.translations);
|
|
@@ -471,25 +471,27 @@ const renderRestrictedBlessings = (restrictedBlessings) => {
|
|
|
471
471
|
return assertExhaustive(restrictedBlessings);
|
|
472
472
|
}
|
|
473
473
|
};
|
|
474
|
-
const renderSingleBlessings = (traditions) => Reader.traverse(traditions, traditionId => getInstanceByIdR("BlessedTradition", traditionId).map(tradition => tradition
|
|
475
|
-
|
|
476
|
-
|
|
474
|
+
const renderSingleBlessings = (traditions) => Reader.traverse(traditions, traditionId => getInstanceByIdR("BlessedTradition", traditionId).map(tradition => tradition?.type))
|
|
475
|
+
.map(traditionTypes => traditionTypes.filter(isNotNullish))
|
|
476
|
+
.thenW(traditionTypes => !isNotEmpty(traditionTypes)
|
|
477
477
|
? Reader.of(undefined)
|
|
478
|
-
:
|
|
478
|
+
: traditionTypes.length === 1
|
|
479
479
|
? (() => {
|
|
480
|
-
const [first] =
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
480
|
+
const [first] = traditionTypes;
|
|
481
|
+
if (first.kind === "Shamanistic") {
|
|
482
|
+
return Reader.of(undefined);
|
|
483
|
+
}
|
|
484
|
+
const { restrictedBlessings } = first.Church;
|
|
485
|
+
return restrictedBlessings === undefined
|
|
486
|
+
? translateR("The Twelve Blessings")
|
|
487
|
+
: translateR("The Twelve Blessings").thenW(base => renderRestrictedBlessings(restrictedBlessings).thenW(list => translateR("except for {$list :list type=conjunction}", {
|
|
488
|
+
list,
|
|
489
|
+
}).map(note => base + parensIf(note))));
|
|
489
490
|
})()
|
|
490
|
-
:
|
|
491
|
+
: traditionTypes.every(trad => trad.kind === "Shamanistic")
|
|
491
492
|
? Reader.of(undefined)
|
|
492
|
-
:
|
|
493
|
+
: traditionTypes.some(trad => (trad.kind === "Church" && trad.Church.restrictedBlessings !== undefined) ||
|
|
494
|
+
trad.kind === "Shamanistic")
|
|
493
495
|
? translateR("The Twelve Blessings").map2(translateR("depends on selected tradition"), (base, note) => base + parensIf(note))
|
|
494
496
|
: translateR("The Twelve Blessings"));
|
|
495
497
|
const renderBlessings = (traditions) => {
|