@optolith/entity-descriptions 0.4.10 → 0.4.11
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.js +1 -1
- package/lib/entities/derivedCharacteristic.d.ts +0 -2
- package/lib/entities/derivedCharacteristic.js +5 -10
- package/lib/entities/disease.js +5 -1
- package/lib/entities/elixir.js +12 -10
- package/lib/entities/equipment.d.ts +6 -5
- package/lib/entities/equipment.js +19 -6
- package/lib/entities/partial/prerequisites/index.d.ts +3 -3
- package/lib/entities/partial/prerequisites/index.js +1 -1
- package/lib/entities/partial/prerequisites/prerequisiteGroups.d.ts +1 -1
- package/lib/entities/partial/prerequisites/prerequisiteGroups.js +10 -7
- package/lib/entities/partial/prerequisites/single/rated.js +2 -2
- package/lib/entities/partial/rated/activatable/checkResultBased.js +3 -1
- package/lib/entities/poison.js +20 -9
- package/lib/entities/profession.d.ts +2 -2
- package/lib/entities/profession.js +112 -17
- package/lib/entities/race.d.ts +1 -1
- package/lib/entities/race.js +19 -17
- package/lib/entities/spell.d.ts +4 -2
- package/lib/entities/spell.js +4 -4
- package/lib/index.d.ts +64 -64
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
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.4.11](https://github.com/Optolith/entity-descriptions/compare/v0.4.10...v0.4.11) (2026-03-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* support schema version 0.42.0 ([80b2eaa](https://github.com/Optolith/entity-descriptions/commit/80b2eaacbcf445cf3222c11b86c1be77b7d973d6))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* activatable cost by level separator ([a0119ff](https://github.com/Optolith/entity-descriptions/commit/a0119ffdafcc6027801c0ff7b502c9c65af107dd))
|
|
16
|
+
* render attribute prerequisite as abbreviation ([6f258b1](https://github.com/Optolith/entity-descriptions/commit/6f258b1f6f4fb1c88b09fe9fb2013b180d91fc4b))
|
|
17
|
+
|
|
5
18
|
## [0.4.10](https://github.com/Optolith/entity-descriptions/compare/v0.4.9...v0.4.10) (2026-03-17)
|
|
6
19
|
|
|
7
20
|
## [0.4.9](https://github.com/Optolith/entity-descriptions/compare/v0.4.8...v0.4.9) (2026-03-17)
|
|
@@ -392,7 +392,7 @@ const renderArcaneEnergyCost = (translate, translateMap, localeJoin, responsiveT
|
|
|
392
392
|
cost: translate("{$value} AE", {
|
|
393
393
|
value: cost.ByLevel.levels.map(level => level.value).join("/"),
|
|
394
394
|
}),
|
|
395
|
-
level: Array.from({ length: cost.ByLevel.levels.length }, (_, index) => romanize(index + 1)),
|
|
395
|
+
level: Array.from({ length: cost.ByLevel.levels.length }, (_, index) => romanize(index + 1)).join("/"),
|
|
396
396
|
});
|
|
397
397
|
case "Verbose":
|
|
398
398
|
return cost.ByLevel.levels
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { GetInstanceById } from "../helpers/getTypes.js";
|
|
2
|
-
import type { IdMap } from "../index.js";
|
|
3
2
|
/**
|
|
4
3
|
* Get a JSON representation of the rules text for a derived characteristic.
|
|
5
4
|
*/
|
|
6
5
|
export declare const getDerivedCharacteristicEntityDescription: import("../creator.js").EntityDescriptionCreator<"DerivedCharacteristic", {
|
|
7
6
|
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "DerivedCharacteristic">;
|
|
8
|
-
idMap: IdMap;
|
|
9
7
|
}, import("../index.js").EntityDescription>;
|
|
@@ -14,12 +14,7 @@ const renderAttributeNameForStyle = (style, translation) => {
|
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
const getAttribute = (getInstanceById, translateMap, attributeId, style = "full") => attributedCustomName(translateMap, getInstanceById, "derived-characteristic-calculation", translation => renderAttributeNameForStyle(style, translation), "Attribute", attributeId) ?? MISSING_VALUE;
|
|
17
|
-
const getRaceBaseValue = (translate,
|
|
18
|
-
const instance = getInstanceById("DerivedCharacteristic", idMap.DerivedCharacteristic[raceBaseValue.kind]);
|
|
19
|
-
const translation = translateMap(instance?.translations);
|
|
20
|
-
if (translation === undefined) {
|
|
21
|
-
return MISSING_VALUE;
|
|
22
|
-
}
|
|
17
|
+
const getRaceBaseValue = (translate, translation, style = "full") => {
|
|
23
18
|
switch (style) {
|
|
24
19
|
case "full":
|
|
25
20
|
return translate("Base {$name} from Race", translation);
|
|
@@ -29,14 +24,14 @@ const getRaceBaseValue = (translate, translateMap, getInstanceById, idMap, raceB
|
|
|
29
24
|
return assertExhaustive(style);
|
|
30
25
|
}
|
|
31
26
|
};
|
|
32
|
-
const renderBaseCalculation = (getInstanceById, translate, translateMap,
|
|
27
|
+
const renderBaseCalculation = (getInstanceById, translate, translateMap, translation, calculation, style = "full") => renderMathOperation(calculation, value => {
|
|
33
28
|
switch (value.kind) {
|
|
34
29
|
case "Constant":
|
|
35
30
|
return value.Constant.toFixed();
|
|
36
31
|
case "Attribute":
|
|
37
32
|
return getAttribute(getInstanceById, translateMap, value.Attribute, style);
|
|
38
33
|
case "RaceBaseValue":
|
|
39
|
-
return getRaceBaseValue(translate,
|
|
34
|
+
return getRaceBaseValue(translate, translation, style);
|
|
40
35
|
case "PrimaryAttribute":
|
|
41
36
|
switch (style) {
|
|
42
37
|
case "full":
|
|
@@ -60,7 +55,7 @@ const renderBaseCalculation = (getInstanceById, translate, translateMap, idMap,
|
|
|
60
55
|
/**
|
|
61
56
|
* Get a JSON representation of the rules text for a derived characteristic.
|
|
62
57
|
*/
|
|
63
|
-
export const getDerivedCharacteristicEntityDescription = createEntityDescriptionCreator(({ getInstanceById
|
|
58
|
+
export const getDerivedCharacteristicEntityDescription = createEntityDescriptionCreator(({ getInstanceById }, { translate, translateMap }, { content: entry }) => {
|
|
64
59
|
const translation = translateMap(entry.translations);
|
|
65
60
|
if (translation === undefined) {
|
|
66
61
|
return undefined;
|
|
@@ -80,7 +75,7 @@ export const getDerivedCharacteristicEntityDescription = createEntityDescription
|
|
|
80
75
|
items: [
|
|
81
76
|
{
|
|
82
77
|
label: translate("Base Value"),
|
|
83
|
-
value: renderBaseCalculation(getInstanceById, translate, translateMap,
|
|
78
|
+
value: renderBaseCalculation(getInstanceById, translate, translateMap, translation, entry.calculation.base),
|
|
84
79
|
},
|
|
85
80
|
],
|
|
86
81
|
},
|
package/lib/entities/disease.js
CHANGED
|
@@ -25,7 +25,11 @@ export const getDiseaseEntityDescription = createEntityDescriptionCreator(({ get
|
|
|
25
25
|
return undefined;
|
|
26
26
|
}
|
|
27
27
|
return {
|
|
28
|
-
title: translation.name
|
|
28
|
+
title: translation.name +
|
|
29
|
+
parensIf(ensureNonEmpty([
|
|
30
|
+
baseEntry.isChildhoodDisease === true ? translate("childhood disease") : undefined,
|
|
31
|
+
baseEntry.isMagicalDisease === true ? translate("magical disease") : undefined,
|
|
32
|
+
].filter(isNotNullish))?.join(", ")),
|
|
29
33
|
className: "disease",
|
|
30
34
|
body: [
|
|
31
35
|
{
|
package/lib/entities/elixir.js
CHANGED
|
@@ -58,16 +58,18 @@ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getI
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
label: translate("Quality Levels"),
|
|
61
|
-
value:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
61
|
+
value: translation.quality_levels.kind === "Plain"
|
|
62
|
+
? translation.quality_levels.Plain.text
|
|
63
|
+
: [
|
|
64
|
+
{
|
|
65
|
+
type: "definitionList",
|
|
66
|
+
style: "nested",
|
|
67
|
+
items: translation.quality_levels.ForEachQualityLevel.qualityLevels.map((effectForLevel, index) => ({
|
|
68
|
+
label: (index + 1).toFixed(),
|
|
69
|
+
value: effectForLevel,
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
71
73
|
},
|
|
72
74
|
],
|
|
73
75
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { EquipmentIdentifier, GenMeleeWeapon, GenRangedWeapon, LocaleMeasurementAdjustments } from "optolith-database-schema/gen";
|
|
1
|
+
import type { AmmunitionishIdentifier, EquipmentIdentifier, GenMeleeWeapon, GenRangedWeapon, LocaleMeasurementAdjustments } from "optolith-database-schema/gen";
|
|
2
2
|
import { type TaggedEntity } from "../creator.js";
|
|
3
3
|
import type { GetInstanceById } from "../helpers/getTypes.js";
|
|
4
|
+
import type { LocaleJoin } from "../helpers/locale.js";
|
|
4
5
|
import type { Translate, TranslateMap } from "../helpers/translate.js";
|
|
5
6
|
import type { IdMap, LabeledEntityDescriptionSection, RawEntityDescriptionSectionContent } from "../index.js";
|
|
6
7
|
/**
|
|
@@ -10,15 +11,15 @@ export declare const getEquipmentName: (translate: Translate, translateMap: Tran
|
|
|
10
11
|
/**
|
|
11
12
|
* Render combat values of a melee weapon.
|
|
12
13
|
*/
|
|
13
|
-
export declare const renderMeleeWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"Attribute" | "CloseCombatTechnique" | "Reach">, measurements: Required<LocaleMeasurementAdjustments>, renderDamage: (damage: Damage) => string, closeCombatTechniqueId: string, use: GenMeleeWeapon<Damage>) => LabeledEntityDescriptionSection<RawEntityDescriptionSectionContent>;
|
|
14
|
+
export declare const renderMeleeWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, localeJoin: LocaleJoin, getInstanceById: GetInstanceById<"Attribute" | "CloseCombatTechnique" | "Reach">, measurements: Required<LocaleMeasurementAdjustments>, renderDamage: (damage: Damage) => string, closeCombatTechniqueId: string, use: GenMeleeWeapon<Damage>) => LabeledEntityDescriptionSection<RawEntityDescriptionSectionContent>;
|
|
14
15
|
/**
|
|
15
16
|
* Render combat values of a ranged weapon.
|
|
16
17
|
*/
|
|
17
|
-
export declare const renderRangedWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"RangedCombatTechnique" | "
|
|
18
|
+
export declare const renderRangedWeapon: <Damage>(translate: Translate, translateMap: TranslateMap, getInstanceById: GetInstanceById<"RangedCombatTechnique" | AmmunitionishIdentifier["kind"]>, measurements: Required<LocaleMeasurementAdjustments>, renderDamage: (damage: Damage) => string, rangedCombatTechniqueId: string, use: GenRangedWeapon<Damage>) => LabeledEntityDescriptionSection<RawEntityDescriptionSectionContent>;
|
|
18
19
|
/**
|
|
19
20
|
* Get a JSON representation of the rules text for equipment.
|
|
20
21
|
*/
|
|
21
|
-
export declare const getEquipmentEntityDescription: import("../creator.js").EntityDescriptionCreator<"
|
|
22
|
-
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Reach" | "SocialStatus" | "CloseCombatTechnique" | "RangedCombatTechnique" | "MagicalTradition" | "BlessedTradition" | "DerivedCharacteristic" | "
|
|
22
|
+
export declare const getEquipmentEntityDescription: import("../creator.js").EntityDescriptionCreator<"Ammunition" | "Weapon" | "Armor" | "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", {
|
|
23
|
+
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Reach" | "SocialStatus" | "CloseCombatTechnique" | "RangedCombatTechnique" | "MagicalTradition" | "BlessedTradition" | "DerivedCharacteristic" | AmmunitionishIdentifier["kind"] | "Race" | "Culture" | "Profession" | "Skill">;
|
|
23
24
|
idMap: IdMap;
|
|
24
25
|
}, import("../index.js").EntityDescription>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ensureNonEmpty, isNotEmpty } from "@elyukai/utils/array/nonEmpty";
|
|
2
|
+
import { on } from "@elyukai/utils/function";
|
|
2
3
|
import { isNotNullish } from "@elyukai/utils/nullable";
|
|
4
|
+
import { compareNumber } from "@elyukai/utils/ordering";
|
|
3
5
|
import { romanize } from "@elyukai/utils/roman";
|
|
4
6
|
import { sign } from "@elyukai/utils/string/number";
|
|
5
7
|
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
6
8
|
import { mapNullable } from "@optolith/helpers/nullable";
|
|
7
9
|
import { createEntityDescriptionCreator } from "../creator.js";
|
|
8
10
|
import { renderDice, renderDiceAndFlat } from "./partial/dice.js";
|
|
11
|
+
import { attributedName, attributedNameFromInstance } from "./partial/markdown.js";
|
|
9
12
|
import { additionFormatter, subtractionFormatter } from "./partial/mathOperation.js";
|
|
10
13
|
import { parensIf } from "./partial/rated/activatable/parensIf.js";
|
|
11
14
|
import { ResponsiveTextSize } from "./partial/responsiveText.js";
|
|
@@ -91,9 +94,19 @@ const renderPrimaryAttributeAndDamageThreshold = (translateMap, getInstanceById,
|
|
|
91
94
|
const renderAttackParryModifier = (attackModifier, parryModifier) => attackModifier === undefined && parryModifier === undefined
|
|
92
95
|
? "—"
|
|
93
96
|
: `${attackModifier === undefined ? "—" : sign(attackModifier)}/${parryModifier === undefined ? "—" : sign(parryModifier)}`;
|
|
94
|
-
const renderReach = (translateMap, getInstanceById,
|
|
97
|
+
const renderReach = (translateMap, localeJoin, getInstanceById, reaches) => reaches === undefined
|
|
95
98
|
? "—"
|
|
96
|
-
: (
|
|
99
|
+
: localeJoin(reaches
|
|
100
|
+
.map((reach) => {
|
|
101
|
+
const instance = getInstanceById("Reach", reach);
|
|
102
|
+
return [
|
|
103
|
+
instance?.position ?? 0,
|
|
104
|
+
attributedNameFromInstance(translateMap, instance, "equipment", "Reach", reach) ??
|
|
105
|
+
MISSING_VALUE,
|
|
106
|
+
];
|
|
107
|
+
})
|
|
108
|
+
.toSorted(on(e => e[0], compareNumber))
|
|
109
|
+
.map(e => e[1]), "conjunction");
|
|
97
110
|
const renderLength = (translate, measurements, length) => length === undefined
|
|
98
111
|
? "—"
|
|
99
112
|
: translate(".input {$value :number} {{{$value} inches}}", {
|
|
@@ -102,7 +115,7 @@ const renderLength = (translate, measurements, length) => length === undefined
|
|
|
102
115
|
/**
|
|
103
116
|
* Render combat values of a melee weapon.
|
|
104
117
|
*/
|
|
105
|
-
export const renderMeleeWeapon = (translate, translateMap, getInstanceById, measurements, renderDamage, closeCombatTechniqueId, use) => {
|
|
118
|
+
export const renderMeleeWeapon = (translate, translateMap, localeJoin, getInstanceById, measurements, renderDamage, closeCombatTechniqueId, use) => {
|
|
106
119
|
const combatTechnique = getInstanceById("CloseCombatTechnique", closeCombatTechniqueId);
|
|
107
120
|
const fields = combatTechnique?.special ?? {
|
|
108
121
|
can_parry: { kind: "Prohibited" },
|
|
@@ -137,7 +150,7 @@ export const renderMeleeWeapon = (translate, translateMap, getInstanceById, meas
|
|
|
137
150
|
? undefined
|
|
138
151
|
: {
|
|
139
152
|
label: translate("Reach"),
|
|
140
|
-
value: renderReach(translateMap, getInstanceById, use.reach),
|
|
153
|
+
value: renderReach(translateMap, localeJoin, getInstanceById, use.reach),
|
|
141
154
|
},
|
|
142
155
|
fields.has_length.kind === "Prohibited"
|
|
143
156
|
? undefined
|
|
@@ -159,7 +172,7 @@ const renderReloadTime = (translate, reloadTime) => isNotEmpty(reloadTime)
|
|
|
159
172
|
const renderRangeBrackets = (rangeBrackets) => `${rangeBrackets.close.toFixed()}/${rangeBrackets.medium.toFixed()}/${rangeBrackets.far.toFixed()}`;
|
|
160
173
|
const renderAmmunition = (translateMap, getInstanceById, ammunition) => ammunition === undefined
|
|
161
174
|
? "—"
|
|
162
|
-
: (translateMap
|
|
175
|
+
: (attributedName(translateMap, getInstanceById, "equipment", ammunition) ?? MISSING_VALUE);
|
|
163
176
|
const renderMeleeDamage = (translate) => (damage) => renderDiceAndFlat(translate, damage.dice, damage.flat);
|
|
164
177
|
/**
|
|
165
178
|
* Render combat values of a ranged weapon.
|
|
@@ -713,7 +726,7 @@ export const getEquipmentEntityDescription = createEntityDescriptionCreator(({ g
|
|
|
713
726
|
className: "equipment",
|
|
714
727
|
body: [
|
|
715
728
|
...(combatValues?.type === "Weapon"
|
|
716
|
-
? Object.entries(combatValues.values.melee_uses ?? {}).map(([combatTechniqueId, use]) => renderMeleeWeapon(translate, translateMap, getInstanceById, locale.measurementAdjustments, renderMeleeDamage(translate), combatTechniqueId, use))
|
|
729
|
+
? Object.entries(combatValues.values.melee_uses ?? {}).map(([combatTechniqueId, use]) => renderMeleeWeapon(translate, translateMap, locale.join, getInstanceById, locale.measurementAdjustments, renderMeleeDamage(translate), combatTechniqueId, use))
|
|
717
730
|
: []),
|
|
718
731
|
...(combatValues?.type === "Weapon"
|
|
719
732
|
? Object.entries(combatValues.values.ranged_uses ?? {}).map(([combatTechniqueId, use]) => renderRangedWeapon(translate, translateMap, getInstanceById, locale.measurementAdjustments, renderRangedDamage(translate), combatTechniqueId, use))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActivatableIdentifier, AdvantageDisadvantagePrerequisites, AnimistPowerPrerequisites, ArcaneTraditionPrerequisites, DerivedCharacteristicPrerequisites, EnhancementPrerequisites, GeneralPrerequisites, GeodeRitualPrerequisites, InfluencePrerequisites, LanguagePrerequisites, LiturgyPrerequisites, PersonalityTraitPrerequisites, PlainGeneralPrerequisites, ProfessionPrerequisites, PublicationPrerequisites, RatedIdentifier,
|
|
1
|
+
import type { ActivatableIdentifier, AdvantageDisadvantagePrerequisites, AnimistPowerPrerequisites, ArcaneTraditionPrerequisites, DerivedCharacteristicPrerequisites, EnhancementPrerequisites, GeneralPrerequisites, GeodeRitualPrerequisites, InfluencePrerequisites, LanguagePrerequisites, LiturgyPrerequisites, PersonalityTraitPrerequisites, PlainGeneralPrerequisites, ProfessionPrerequisites, PublicationPrerequisites, RatedIdentifier, SpellworkPrerequisites } from "optolith-database-schema/gen";
|
|
2
2
|
import type { GetAllChildInstancesForParent, GetInstanceById } from "../../../helpers/getTypes.js";
|
|
3
3
|
import type { LocaleEnvironment } from "../../../helpers/locale.js";
|
|
4
4
|
import type { GetResolvedSelectOptionById } from "./single/activatable.js";
|
|
@@ -18,7 +18,7 @@ export declare const printPlainGeneralPrerequisites: (getInstanceById: GetInstan
|
|
|
18
18
|
* Print general prerequisites as a string.
|
|
19
19
|
*/
|
|
20
20
|
export declare const printGeneralPrerequisites: (getInstanceById: GetInstanceById<"Race" | "Culture" | "PactCategory" | "PactDomain" | "SocialStatus" | "State" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "Property" | "Aspect" | "Enhancement">, getResolvedSelectOptionById: GetResolvedSelectOptionById, locale: LocaleEnvironment, value: GeneralPrerequisites, printPreviousLevelPrerequisites?: {
|
|
21
|
-
id:
|
|
21
|
+
id: ActivatableIdentifier;
|
|
22
22
|
levels: number;
|
|
23
23
|
}, trailingText?: string) => string;
|
|
24
24
|
/**
|
|
@@ -60,7 +60,7 @@ export declare const printAnimistPowerPrerequisites: (getInstanceById: GetInstan
|
|
|
60
60
|
/**
|
|
61
61
|
* Print geode ritual prerequisites as a string.
|
|
62
62
|
*/
|
|
63
|
-
export declare const printGeodeRitualPrerequisites: (getInstanceById: GetInstanceById<"Influence">, locale: LocaleEnvironment, value: GeodeRitualPrerequisites) => string;
|
|
63
|
+
export declare const printGeodeRitualPrerequisites: (getInstanceById: GetInstanceById<"Influence" | ActivatableIdentifier["kind"] | "Aspect">, getResolvedSelectOptionById: GetResolvedSelectOptionById, locale: LocaleEnvironment, value: GeodeRitualPrerequisites) => string;
|
|
64
64
|
/**
|
|
65
65
|
* Print enhancement prerequisites as a string.
|
|
66
66
|
*/
|
|
@@ -201,7 +201,7 @@ export const printAnimistPowerPrerequisites = (getInstanceById, locale, value) =
|
|
|
201
201
|
/**
|
|
202
202
|
* Print geode ritual prerequisites as a string.
|
|
203
203
|
*/
|
|
204
|
-
export const printGeodeRitualPrerequisites = (getInstanceById, locale, value) => printPlainPrerequisites(prerequisite => printGeodeRitualPrerequisiteGroup(getInstanceById, locale, prerequisite), locale, value);
|
|
204
|
+
export const printGeodeRitualPrerequisites = (getInstanceById, getResolvedSelectOptionById, locale, value) => printPlainPrerequisites(prerequisite => printGeodeRitualPrerequisiteGroup(getInstanceById, getResolvedSelectOptionById, locale, prerequisite), locale, value);
|
|
205
205
|
/**
|
|
206
206
|
* Print enhancement prerequisites as a string.
|
|
207
207
|
*/
|
|
@@ -54,7 +54,7 @@ export declare const printAnimistPowerPrerequisiteGroup: (getInstanceById: GetIn
|
|
|
54
54
|
/**
|
|
55
55
|
* Print the translation of a geode ritual prerequisite group.
|
|
56
56
|
*/
|
|
57
|
-
export declare const printGeodeRitualPrerequisiteGroup: (getInstanceById: GetInstanceById<"Influence">, locale: LocaleEnvironment, prerequisite: GeodeRitualPrerequisiteGroup) => PrerequisitePart | undefined;
|
|
57
|
+
export declare const printGeodeRitualPrerequisiteGroup: (getInstanceById: GetInstanceById<"Influence" | ActivatableIdentifier["kind"] | "Aspect">, getResolvedSelectOptionById: GetResolvedSelectOptionById, locale: LocaleEnvironment, prerequisite: GeodeRitualPrerequisiteGroup) => PrerequisitePart | undefined;
|
|
58
58
|
/**
|
|
59
59
|
* Print the translation of an enhancement prerequisite group.
|
|
60
60
|
*/
|
|
@@ -241,13 +241,16 @@ printAnimistPowerPrerequisite(getInstanceById, locale, prerequisite.AnimistPower
|
|
|
241
241
|
/**
|
|
242
242
|
* Print the translation of a geode ritual prerequisite group.
|
|
243
243
|
*/
|
|
244
|
-
export const printGeodeRitualPrerequisiteGroup = (getInstanceById, locale, prerequisite) =>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
244
|
+
export const printGeodeRitualPrerequisiteGroup = (getInstanceById, getResolvedSelectOptionById, locale, prerequisite) => {
|
|
245
|
+
switch (prerequisite.kind) {
|
|
246
|
+
case "Activatable":
|
|
247
|
+
return printActivatablePrerequisite(getInstanceById, getResolvedSelectOptionById, locale, prerequisite.Activatable, false);
|
|
248
|
+
case "Influence":
|
|
249
|
+
return printInfluencePrerequisite(getInstanceById, locale, prerequisite.Influence);
|
|
250
|
+
default:
|
|
251
|
+
return assertExhaustive(prerequisite);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
251
254
|
/**
|
|
252
255
|
* Print the translation of an enhancement prerequisite group.
|
|
253
256
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { attributedCustomName } from "../../markdown.js";
|
|
2
2
|
import { MISSING_VALUE } from "../../unknown.js";
|
|
3
3
|
import { printDisplayOption } from "../displayOption.js";
|
|
4
4
|
/**
|
|
@@ -9,7 +9,7 @@ export const printRatedPrerequisite = (getInstanceById, locale, prerequisite) =>
|
|
|
9
9
|
return printDisplayOption(locale.translateMap, prerequisite.display_option);
|
|
10
10
|
}
|
|
11
11
|
return {
|
|
12
|
-
value: `${
|
|
12
|
+
value: `${attributedCustomName(locale.translateMap, getInstanceById, "prerequisite", (t) => t.abbreviation ?? t.name, prerequisite.id) ?? MISSING_VALUE} ${prerequisite.value.toFixed()}`,
|
|
13
13
|
sentenceType: undefined,
|
|
14
14
|
isMeta: false,
|
|
15
15
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mapNullableDefault } from "@optolith/helpers/nullable";
|
|
2
2
|
import { assertExhaustive } from "@optolith/helpers/typeSafety";
|
|
3
|
-
import { divisionFormatter, multiplicationFormatter
|
|
3
|
+
import { divisionFormatter, multiplicationFormatter } from "../../mathOperation.js";
|
|
4
4
|
import { translateR } from "../../reader.js";
|
|
5
5
|
const renderCheckResultBaseValue = (baseValue) => {
|
|
6
6
|
switch (baseValue.kind) {
|
|
@@ -8,6 +8,8 @@ const renderCheckResultBaseValue = (baseValue) => {
|
|
|
8
8
|
return translateR("QL");
|
|
9
9
|
case "SkillPoints":
|
|
10
10
|
return translateR("SP");
|
|
11
|
+
case "SkillRating":
|
|
12
|
+
return translateR("SR");
|
|
11
13
|
default:
|
|
12
14
|
return assertExhaustive(baseValue);
|
|
13
15
|
}
|
package/lib/entities/poison.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isNotNullish, mapNullable } from "@elyukai/utils/nullable";
|
|
|
3
3
|
import { sign } from "@elyukai/utils/string/number";
|
|
4
4
|
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
5
5
|
import { createEntityDescriptionCreator } from "../creator.js";
|
|
6
|
-
import { renderDice
|
|
6
|
+
import { renderDice } from "./partial/dice.js";
|
|
7
7
|
import { renderAlternativeNames, renderChance, renderLaboratoryLevel, renderResistance, } from "./partial/herbary.js";
|
|
8
8
|
import { renderMathOperation } from "./partial/mathOperation.js";
|
|
9
9
|
import { printPlainGeneralPrerequisites } from "./partial/prerequisites/index.js";
|
|
@@ -93,6 +93,12 @@ const renderSourceTypeBasedValues = (translate, translateMap, getInstanceById, s
|
|
|
93
93
|
return {
|
|
94
94
|
level: renderLevel(translate, translateMap, sourceType.AnimalVenom.level),
|
|
95
95
|
sourceType: translate("animal venom"),
|
|
96
|
+
tradeSecret: mapNullable(sourceType.AnimalVenom.complexity, complexity => complexity.kind === "Complex"
|
|
97
|
+
? {
|
|
98
|
+
apValue: complexity.Complex.ap_value,
|
|
99
|
+
prerequisites: complexity.Complex.prerequisites,
|
|
100
|
+
}
|
|
101
|
+
: undefined),
|
|
96
102
|
};
|
|
97
103
|
case "AlchemicalPoison": {
|
|
98
104
|
const translation = translateMap(sourceType.AlchemicalPoison.translations);
|
|
@@ -156,10 +162,19 @@ const renderStart = (translate, translateMap, start) => {
|
|
|
156
162
|
switch (start.kind) {
|
|
157
163
|
case "Immediate":
|
|
158
164
|
return translate("immediate");
|
|
159
|
-
case "
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
case "ExpressionBased":
|
|
166
|
+
return renderMathOperation(start.ExpressionBased.value, value => {
|
|
167
|
+
switch (value.kind) {
|
|
168
|
+
case "Constant":
|
|
169
|
+
return value.Constant.toFixed();
|
|
170
|
+
case "Dice":
|
|
171
|
+
return renderDice(translate, value.Dice);
|
|
172
|
+
case "CircleOfDamnation":
|
|
173
|
+
return translate("CoD");
|
|
174
|
+
default:
|
|
175
|
+
return assertExhaustive(value);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
163
178
|
case "Indefinite":
|
|
164
179
|
return translateMap(start.Indefinite.translations)?.description ?? MISSING_VALUE;
|
|
165
180
|
default:
|
|
@@ -170,10 +185,6 @@ const renderDuration = (translate, translateMap, duration) => {
|
|
|
170
185
|
switch (duration.kind) {
|
|
171
186
|
case "Instant":
|
|
172
187
|
return translate("instant");
|
|
173
|
-
case "Constant":
|
|
174
|
-
return formatTimeSpan(translate, ResponsiveTextSize.Full, duration.Constant.unit, duration.Constant.value);
|
|
175
|
-
case "DiceBased":
|
|
176
|
-
return formatTimeSpan(translate, ResponsiveTextSize.Full, duration.DiceBased.unit, renderDiceAndFlat(translate, duration.DiceBased.dice, duration.DiceBased.flat));
|
|
177
188
|
case "ExpressionBased":
|
|
178
189
|
return renderMathOperation(duration.ExpressionBased.value, value => {
|
|
179
190
|
switch (value.kind) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { MagicalActionIdentifier,
|
|
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
|
/**
|
|
5
5
|
* Get a JSON representation of the rules text for a profession version.
|
|
6
6
|
*/
|
|
7
7
|
export declare const getProfessionVersionEntityDescription: import("../creator.js").EntityDescriptionCreator<"ProfessionVersion", {
|
|
8
|
-
getInstanceById: GetInstanceById<"Publication" | "ExperienceLevel" | "Advantage" | "Disadvantage" |
|
|
8
|
+
getInstanceById: GetInstanceById<"Publication" | "ExperienceLevel" | "Advantage" | "Disadvantage" | ProfessionSpecialAbilityIdentifier["kind"] | "Aspect" | RatedIdentifier["kind"] | "Race" | "Culture" | MagicalActionIdentifier["kind"] | "SkillGroup" | "Cantrip" | "Blessing">;
|
|
9
9
|
getAllInstances: GetAllInstances<"SkillGroup">;
|
|
10
10
|
getChildInstancesForInstanceId: GetAllChildInstancesForParent<"ProfessionPackage" | "ProfessionVariant">;
|
|
11
11
|
getResolvedSelectOptionById: GetResolvedSelectOptionById;
|
|
@@ -7,7 +7,7 @@ import { omitKeys } from "@elyukai/utils/object";
|
|
|
7
7
|
import { compareNumber } from "@elyukai/utils/ordering";
|
|
8
8
|
import { Reader } from "@elyukai/utils/reader";
|
|
9
9
|
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
10
|
-
import { fromUniformCase } from "tsondb/schema/gen";
|
|
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";
|
|
@@ -103,7 +103,7 @@ const renderCombatTechniquesOption = (option) => isNotEmpty(option.fixed)
|
|
|
103
103
|
})), firstTextR);
|
|
104
104
|
const completeTextR = fixedTextR.then(fixedText => option.rest_rating_modifier === undefined
|
|
105
105
|
? Reader.of(fixedText)
|
|
106
|
-
: translateR("{$previous},
|
|
106
|
+
: translateR("{$previous}, the others {$rating}", {
|
|
107
107
|
previous: fixedText,
|
|
108
108
|
rating: option.rest_rating_modifier + 6,
|
|
109
109
|
}));
|
|
@@ -123,10 +123,36 @@ const getTotalingAPValues = (professionPackages, selector) => {
|
|
|
123
123
|
options[0].ap_value
|
|
124
124
|
: options.map(option => option?.ap_value ?? 0).join("/");
|
|
125
125
|
};
|
|
126
|
-
const renderSkillsOption = (professionPackages, skillGroup) =>
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
const renderSkillsOption = (professionPackages, skillGroup) => allSame(professionPackages.filter(pkg => pkg.content.options?.skills?.group === skillGroup.id), on(pkg => pkg.content.options?.skills?.specific, deepEqual))
|
|
127
|
+
? (mapNullable(getTotalingAPValues(professionPackages, pkg => pkg.content.options?.skills?.group === skillGroup.id
|
|
128
|
+
? pkg.content.options.skills
|
|
129
|
+
: undefined), apValue => professionPackages[0].content.options?.skills?.specific === undefined
|
|
130
|
+
? translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
|
|
131
|
+
apValue,
|
|
132
|
+
skillsOfGroup: skillGroup.nameOfSkillsOfGroup,
|
|
133
|
+
})
|
|
134
|
+
: Reader.traverse(professionPackages[0].content.options.skills.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
|
|
135
|
+
.thenW(localeSortR)
|
|
136
|
+
.thenW(list => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
|
|
137
|
+
apValue,
|
|
138
|
+
list: list.join(", "),
|
|
139
|
+
}))) ?? Reader.of(undefined))
|
|
140
|
+
: Reader.traverse(professionPackages, pkg => {
|
|
141
|
+
const skillsOption = pkg.content.options?.skills;
|
|
142
|
+
return skillsOption === undefined
|
|
143
|
+
? Reader.of("—")
|
|
144
|
+
: skillsOption.specific === undefined
|
|
145
|
+
? translateR("{$apValue} AP to improve other {$skillsOfGroup}", {
|
|
146
|
+
apValue: skillsOption.ap_value,
|
|
147
|
+
skillsOfGroup: skillGroup.nameOfSkillsOfGroup,
|
|
148
|
+
})
|
|
149
|
+
: Reader.traverse(skillsOption.specific, id => attributedNameR("profession", "Skill", id).map(name => name ?? MISSING_VALUE))
|
|
150
|
+
.thenW(localeSortR)
|
|
151
|
+
.thenW(list => translateR("{$apValue} AP to distribute among the following skills: {$list}", {
|
|
152
|
+
apValue: skillsOption.ap_value,
|
|
153
|
+
list: list.join(", "),
|
|
154
|
+
}));
|
|
155
|
+
}).map(list => list.join(" / "));
|
|
130
156
|
const renderCantripList = (cantripIds) => Reader.traverse(cantripIds, id => attributedNameR("profession", "Cantrip", id).map(name => name ?? MISSING_VALUE))
|
|
131
157
|
.thenW(localeSortR)
|
|
132
158
|
.map(list => list.join(", "));
|
|
@@ -256,7 +282,69 @@ const renderVariantLiturgiesOption = (baseOptions, variantOptions) => renderVari
|
|
|
256
282
|
apValue,
|
|
257
283
|
})),
|
|
258
284
|
});
|
|
259
|
-
const
|
|
285
|
+
const getEnhancementBaseName = (translate, enhancement, parentName) => {
|
|
286
|
+
switch (enhancement.parent.kind) {
|
|
287
|
+
case "Spell":
|
|
288
|
+
return translate("Spell Enhancement {$spell}", { spell: parentName });
|
|
289
|
+
case "Ritual":
|
|
290
|
+
return translate("Ritual Enhancement {$ritual}", { ritual: parentName });
|
|
291
|
+
case "LiturgicalChant":
|
|
292
|
+
case "Ceremony":
|
|
293
|
+
return translate("Liturgical Enhancement {$liturgicalChantOrCeremony}", {
|
|
294
|
+
liturgicalChantOrCeremony: parentName,
|
|
295
|
+
});
|
|
296
|
+
default:
|
|
297
|
+
return assertExhaustive(enhancement.parent);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const isEnhancementNameComponents = (components) => components.id.kind === "Enhancement";
|
|
301
|
+
const isActivatableNameComponents = (components) => !isEnhancementNameComponents(components);
|
|
302
|
+
const getEnhancementNameComponents = (getInstanceById, translate, translateMap, id) => {
|
|
303
|
+
const instance = getInstanceById("Enhancement", id);
|
|
304
|
+
if (instance === undefined) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
id: Case("Enhancement", id),
|
|
309
|
+
parent: instance.parent,
|
|
310
|
+
base: getEnhancementBaseName(translate, instance, attributedName(translateMap, getInstanceById, "profession", instance.parent) ?? MISSING_VALUE),
|
|
311
|
+
options: translateMap(instance.translations)?.name ?? MISSING_VALUE,
|
|
312
|
+
};
|
|
313
|
+
};
|
|
314
|
+
const renderEnhancementNameComponents = (chunk) => [chunk.base, chunk.options].join(" ");
|
|
315
|
+
const isCombinedEnhancementNameComponents = (components) => Array.isArray(components.id);
|
|
316
|
+
const combineEnhancementNameComponents = (chunks) => {
|
|
317
|
+
if (allSame(chunks, (a, b) => deepEqual(a.parent, b.parent)) && isNotEmpty(chunks)) {
|
|
318
|
+
const [first, ...rest] = chunks;
|
|
319
|
+
return {
|
|
320
|
+
id: [first.id, ...rest.map(chunk => chunk.id)],
|
|
321
|
+
parent: first.parent,
|
|
322
|
+
base: first.base,
|
|
323
|
+
options: [
|
|
324
|
+
[first.id, first.options],
|
|
325
|
+
...rest.map((chunk) => [
|
|
326
|
+
chunk.id,
|
|
327
|
+
chunk.options,
|
|
328
|
+
]),
|
|
329
|
+
],
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
return undefined;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
const renderCombinedEnhancementNameComponents = (chunk) => [
|
|
337
|
+
chunk.base,
|
|
338
|
+
chunk.options
|
|
339
|
+
.map(([optionId, optionName]) => attributedInstance(optionName, optionId.kind, optionId.Enhancement, {
|
|
340
|
+
context: `"profession"`,
|
|
341
|
+
}))
|
|
342
|
+
.join(" + "),
|
|
343
|
+
].join(" ");
|
|
344
|
+
const getSpecialAbilityNameComponents = (getInstanceById, getResolvedSelectOptionById, translate, translateMap, option) => {
|
|
345
|
+
if (option.id.kind === "Enhancement") {
|
|
346
|
+
return getEnhancementNameComponents(getInstanceById, translate, translateMap, option.id.Enhancement);
|
|
347
|
+
}
|
|
260
348
|
const instance = getInstanceById(option.id);
|
|
261
349
|
if (instance === undefined) {
|
|
262
350
|
return undefined;
|
|
@@ -264,26 +352,33 @@ const getSpecialAbilityNameComponents = (getInstanceById, getResolvedSelectOptio
|
|
|
264
352
|
return getNameComponents(translate, option.id, option.options, option.level, "nameBuilderRules" in instance ? instance.nameBuilderRules : undefined, instance.translations, t => t.name, getResolvedSelectOptionById, true);
|
|
265
353
|
};
|
|
266
354
|
const wrapActivatableInAttributedString = (text, id) => attributedInstance(text, id.kind, fromUniformCase(id), { context: '"prerequisite"' });
|
|
355
|
+
const renderSingleActivatableNameChunk = (translateMap, chunk) => chunk === undefined
|
|
356
|
+
? MISSING_VALUE
|
|
357
|
+
: wrapActivatableInAttributedString(isEnhancementNameComponents(chunk)
|
|
358
|
+
? renderEnhancementNameComponents(chunk)
|
|
359
|
+
: renderActivatableNameComponents(translateMap, chunk, false), chunk.id);
|
|
267
360
|
const renderSpecialAbilityName = (specialAbility) => Reader.asks(({ translate, translateMap, localeJoin, getInstanceById, getResolvedSelectOptionById, }) => {
|
|
268
361
|
switch (specialAbility.kind) {
|
|
269
362
|
case "Constant": {
|
|
270
|
-
const chunk = getSpecialAbilityNameComponents(getInstanceById, getResolvedSelectOptionById, translate, specialAbility.Constant);
|
|
271
|
-
return chunk
|
|
272
|
-
? MISSING_VALUE
|
|
273
|
-
: wrapActivatableInAttributedString(renderActivatableNameComponents(translateMap, chunk, false), chunk.id);
|
|
363
|
+
const chunk = getSpecialAbilityNameComponents(getInstanceById, getResolvedSelectOptionById, translate, translateMap, specialAbility.Constant);
|
|
364
|
+
return renderSingleActivatableNameChunk(translateMap, chunk);
|
|
274
365
|
}
|
|
275
366
|
case "Selection": {
|
|
276
|
-
const chunks = specialAbility.Selection.options.map(option => getSpecialAbilityNameComponents(getInstanceById, getResolvedSelectOptionById, translate, option));
|
|
367
|
+
const chunks = specialAbility.Selection.options.map(option => getSpecialAbilityNameComponents(getInstanceById, getResolvedSelectOptionById, translate, translateMap, option));
|
|
277
368
|
const possiblyCombined = isNotEmpty(specialAbility.Selection.options) && chunks.every(isNotNullish)
|
|
278
|
-
?
|
|
369
|
+
? chunks.every(isEnhancementNameComponents)
|
|
370
|
+
? combineEnhancementNameComponents(chunks)
|
|
371
|
+
: chunks.every(isActivatableNameComponents)
|
|
372
|
+
? combineNameComponents(chunks)
|
|
373
|
+
: undefined
|
|
279
374
|
: undefined;
|
|
280
375
|
if (possiblyCombined === undefined) {
|
|
281
|
-
return localeJoin(chunks.map(chunk => chunk
|
|
282
|
-
? MISSING_VALUE
|
|
283
|
-
: wrapActivatableInAttributedString(renderActivatableNameComponents(translateMap, chunk, false), chunk.id)), "disjunction");
|
|
376
|
+
return localeJoin(chunks.map(chunk => renderSingleActivatableNameChunk(translateMap, chunk)), "disjunction");
|
|
284
377
|
}
|
|
285
378
|
else {
|
|
286
|
-
return
|
|
379
|
+
return isCombinedEnhancementNameComponents(possiblyCombined)
|
|
380
|
+
? renderCombinedEnhancementNameComponents(possiblyCombined)
|
|
381
|
+
: wrapActivatableInAttributedString(renderCombinedActivatableNameComponents(translateMap, possiblyCombined, false, list => localeJoin(list, "disjunction")), possiblyCombined.id);
|
|
287
382
|
}
|
|
288
383
|
}
|
|
289
384
|
default:
|
package/lib/entities/race.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { CountInstances, GetAllChildInstancesForParent, GetInstanceById } f
|
|
|
3
3
|
* Get a JSON representation of the rules text for a race.
|
|
4
4
|
*/
|
|
5
5
|
export declare const getRaceEntityDescription: import("../creator.js").EntityDescriptionCreator<"Race", {
|
|
6
|
-
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Advantage" | "Disadvantage" | "Culture">;
|
|
6
|
+
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "Advantage" | "Disadvantage" | "Culture" | "DerivedCharacteristic">;
|
|
7
7
|
countInstances: CountInstances<"Attribute">;
|
|
8
8
|
getChildInstancesForInstanceId: GetAllChildInstancesForParent<"RaceVariant">;
|
|
9
9
|
}, import("../index.js").EntityDescription>;
|