@optolith/entity-descriptions 0.13.1 → 0.14.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 +18 -0
- package/lib/creator.js +1 -1
- package/lib/entities/activatable.d.ts +1 -1
- package/lib/entities/activatable.js +28 -18
- package/lib/entities/culture.js +3 -3
- package/lib/entities/curriculum.js +1 -1
- package/lib/entities/elixir.js +1 -1
- package/lib/entities/equipment.js +1 -1
- package/lib/entities/liturgicalChant.d.ts +2 -2
- package/lib/entities/liturgicalChant.js +4 -0
- package/lib/entities/partial/adventurePointsValue.js +8 -7
- package/lib/entities/partial/dice.js +2 -2
- package/lib/entities/partial/enhancements.js +2 -2
- package/lib/entities/partial/herbary.js +1 -1
- package/lib/entities/partial/prerequisites/index.d.ts +6 -1
- package/lib/entities/partial/prerequisites/index.js +24 -1
- package/lib/entities/partial/prerequisites/single/personalityTrait.js +1 -1
- package/lib/entities/partial/prerequisites/single/ratedSum.js +1 -1
- package/lib/entities/partial/profession/options/combatTechniquesForAdventurePoints.d.ts +16 -0
- package/lib/entities/partial/profession/options/combatTechniquesForAdventurePoints.js +43 -0
- package/lib/entities/partial/profession/options/numberOfSpellworksTotalingAdventurePoints.d.ts +16 -0
- package/lib/entities/partial/profession/options/numberOfSpellworksTotalingAdventurePoints.js +39 -0
- package/lib/entities/partial/profession/packages.d.ts +67 -0
- package/lib/entities/partial/profession/packages.js +84 -0
- package/lib/entities/partial/profession/variants.d.ts +21 -0
- package/lib/entities/partial/profession/variants.js +31 -0
- package/lib/entities/partial/rated/activatable/cost.js +11 -9
- package/lib/entities/partial/rated/activatable/effect.js +2 -2
- package/lib/entities/partial/reader.d.ts +25 -1
- package/lib/entities/partial/reader.js +20 -0
- package/lib/entities/partial/units/energy.js +2 -1
- package/lib/entities/partial/units/length.js +6 -3
- package/lib/entities/partial/units/timeSpan.js +11 -7
- package/lib/entities/partial/unknown.d.ts +4 -0
- package/lib/entities/partial/unknown.js +4 -0
- package/lib/entities/poison.js +1 -1
- package/lib/entities/profession.js +44 -62
- package/lib/entities/spell.d.ts +2 -2
- package/lib/entities/spell.js +3 -1
- package/lib/index.d.ts +69 -68
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
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.14.0](https://github.com/Optolith/entity-descriptions/compare/v0.13.2...v0.14.0) (2026-09-24)
|
|
6
|
+
|
|
7
|
+
### ⚠ BREAKING CHANGES
|
|
8
|
+
|
|
9
|
+
* **deps:** upgrade to schema 0.65.0
|
|
10
|
+
|
|
11
|
+
### build
|
|
12
|
+
|
|
13
|
+
* **deps:** upgrade to schema 0.65.0 ([cb94c96](https://github.com/Optolith/entity-descriptions/commit/cb94c96df8dc3f1d4f5476db729df2ed85ce6b1d))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* missing adventure points label for AP value by level ([9aabd43](https://github.com/Optolith/entity-descriptions/commit/9aabd437d587e7b559c18a730249ea3c66bb8387))
|
|
18
|
+
## [0.13.2](https://github.com/Optolith/entity-descriptions/compare/v0.13.1...v0.13.2) (2026-09-16)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* add focus rule badges to activatable entries, spellworks and liturgical chants and ceremonies ([dd142b4](https://github.com/Optolith/entity-descriptions/commit/dd142b47f3cd29620d29a2561e4a8ae8ad1d2a2d)), closes [#41](https://github.com/Optolith/entity-descriptions/issues/41)
|
|
5
23
|
## [0.13.1](https://github.com/Optolith/entity-descriptions/compare/v0.13.0...v0.13.1) (2026-09-16)
|
|
6
24
|
|
|
7
25
|
### Bug Fixes
|
package/lib/creator.js
CHANGED
|
@@ -64,7 +64,7 @@ export const createEntityDescriptionCreator = (fn) => (databaseAccessors, locale
|
|
|
64
64
|
...rawEntry,
|
|
65
65
|
body: rawEntry.body.filter(isNotNullish).map(mapRawSection),
|
|
66
66
|
errata: rawEntry.errata?.map(({ date, description }) => ({
|
|
67
|
-
date: locale.formatDate(date),
|
|
67
|
+
date: locale.formatDate(new Date(date)),
|
|
68
68
|
description: description.trim(),
|
|
69
69
|
})),
|
|
70
70
|
references: rawEntry.references === undefined
|
|
@@ -51,7 +51,7 @@ export type BaseActivatableTranslation = {
|
|
|
51
51
|
* Get a JSON representation of the rules text for a special ability.
|
|
52
52
|
*/
|
|
53
53
|
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", {
|
|
54
|
-
getInstanceById: GetInstanceById<"Publication" | "Subject" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "TradeSecret" | "Aspect" | "Property" | "Race" | "Culture" | "State" | "Enhancement" | "PactCategory" | "PactDomain" | "SocialStatus" | "Weapon" | "Patron" | "PersonalityTrait" | "Brew" | "Blessing" | "Cantrip">;
|
|
54
|
+
getInstanceById: GetInstanceById<"Publication" | "Subject" | ActivatableIdentifier["kind"] | RatedIdentifier["kind"] | "TradeSecret" | "Aspect" | "Property" | "Race" | "Culture" | "State" | "Enhancement" | "PactCategory" | "PactDomain" | "SocialStatus" | "Weapon" | "Patron" | "PersonalityTrait" | "Brew" | "Blessing" | "Cantrip" | "FocusRule">;
|
|
55
55
|
getAllInstances: GetAllInstances<"Script">;
|
|
56
56
|
getResolvedSelectOptionById: GetResolvedSelectOptionById;
|
|
57
57
|
getAllResolvedSelectOptions: GetAllResolvedSelectOptions;
|
|
@@ -18,7 +18,7 @@ import { renderAdventurePointsValue } from "./partial/adventurePointsValue.js";
|
|
|
18
18
|
import { renderParameterMap } from "./partial/map.js";
|
|
19
19
|
import { attributedName } from "./partial/markdown.js";
|
|
20
20
|
import { additionFormatter } from "./partial/mathOperation.js";
|
|
21
|
-
import { printAdvantageDisadvantagePrerequisites, printGeneralPrerequisites, } from "./partial/prerequisites/index.js";
|
|
21
|
+
import { getDerivedFocusRuleBadgeFromPrerequisites, printAdvantageDisadvantagePrerequisites, printGeneralPrerequisites, } from "./partial/prerequisites/index.js";
|
|
22
22
|
import { printActivatableName, } from "./partial/prerequisites/single/activatable.js";
|
|
23
23
|
import { renderStandaloneCostMap } from "./partial/rated/activatable/cost.js";
|
|
24
24
|
import { parensIf } from "./partial/rated/activatable/parensIf.js";
|
|
@@ -44,6 +44,10 @@ const renderAdvantageDisadvantageSubtype = (subtype) => {
|
|
|
44
44
|
return translateR("Magical Rank");
|
|
45
45
|
case "MagicalTitle":
|
|
46
46
|
return translateR("Magical Title");
|
|
47
|
+
case "BlessedRank":
|
|
48
|
+
return translateR("Blessed Title");
|
|
49
|
+
case "BlessedTitle":
|
|
50
|
+
return translateR("Blessed Title");
|
|
47
51
|
default:
|
|
48
52
|
return assertExhaustive(subtype);
|
|
49
53
|
}
|
|
@@ -311,7 +315,9 @@ const renderVolumeValue = (translate, translateMap, getAllResolvedSelectOptions,
|
|
|
311
315
|
levels: volume.ByLevel.list.map((_, index) => romanize(index + 1)).join("/"),
|
|
312
316
|
});
|
|
313
317
|
case "Map":
|
|
314
|
-
return renderParameterMap(volume.Map, option => Reader.of(option.points), values => translateR("{$points} points", {
|
|
318
|
+
return renderParameterMap(volume.Map, option => Reader.of(option.points), values => translateR("{$points} points", {
|
|
319
|
+
points: typeof values === "number" ? values.toFixed() : values,
|
|
320
|
+
})).run({
|
|
315
321
|
translate,
|
|
316
322
|
translateMap,
|
|
317
323
|
responsiveTextSize,
|
|
@@ -342,7 +348,7 @@ const renderArcaneEnergyCost = (translate, translateMap, format, localeJoin, res
|
|
|
342
348
|
? value => translate(".input {$value :number} {{{$value} permanent AE}}", {
|
|
343
349
|
value,
|
|
344
350
|
})
|
|
345
|
-
: value => translate("{$value} AE", { value });
|
|
351
|
+
: value => translate("{$value} AE", { value: value.toFixed() });
|
|
346
352
|
const { interval } = cost.Fixed;
|
|
347
353
|
const wrapInInterval = interval === undefined
|
|
348
354
|
? str => str
|
|
@@ -370,40 +376,40 @@ const renderArcaneEnergyCost = (translate, translateMap, format, localeJoin, res
|
|
|
370
376
|
return wrapInPerLevel(value => wrapInInterval(translationWrapper(value))) + noteInParens;
|
|
371
377
|
}
|
|
372
378
|
case "Constant":
|
|
373
|
-
return (translate("{$value} AE", { value: cost.Constant.value }) +
|
|
379
|
+
return (translate("{$value} AE", { value: cost.Constant.value.toFixed() }) +
|
|
374
380
|
(cost.Constant.permanent_value === undefined
|
|
375
381
|
? ""
|
|
376
382
|
: translate(", {$value} of which are permanent", {
|
|
377
|
-
value: cost.Constant.permanent_value,
|
|
383
|
+
value: cost.Constant.permanent_value.toFixed(),
|
|
378
384
|
})));
|
|
379
385
|
case "PerCountable": {
|
|
380
386
|
const translation = translateMap(cost.PerCountable.translations);
|
|
381
387
|
return ((cost.PerCountable.base_value === undefined
|
|
382
388
|
? ""
|
|
383
|
-
: `${translate("{$value} AE", { value: cost.PerCountable.base_value })} + `) +
|
|
389
|
+
: `${translate("{$value} AE", { value: cost.PerCountable.base_value.toFixed() })} + `) +
|
|
384
390
|
translate("{$cost} per {$countable}", {
|
|
385
|
-
cost: translate("{$value} AE", { value: cost.PerCountable.value }),
|
|
391
|
+
cost: translate("{$value} AE", { value: cost.PerCountable.value.toFixed() }),
|
|
386
392
|
countable: getResponsiveText(translation?.per, responsiveTextSize),
|
|
387
393
|
}) +
|
|
388
394
|
parensIf(mapNullable(translation?.note, note => getResponsiveTextOptional(note, responsiveTextSize))));
|
|
389
395
|
}
|
|
390
396
|
case "Interval":
|
|
391
397
|
return translate("{$cost} per {$interval}", {
|
|
392
|
-
cost: translate("{$value} AE", { value: cost.Interval.value }),
|
|
398
|
+
cost: translate("{$value} AE", { value: cost.Interval.value.toFixed() }),
|
|
393
399
|
interval: formatTimeSpan(translate, translateMap, format, responsiveTextSize, cost.Interval.interval.unit, cost.Interval.interval.value, true),
|
|
394
400
|
});
|
|
395
401
|
case "ActivationAndHalfInterval":
|
|
396
402
|
return additionFormatter(translate("{$value} AE", {
|
|
397
|
-
value: cost.ActivationAndHalfInterval.value,
|
|
403
|
+
value: cost.ActivationAndHalfInterval.value.toFixed(),
|
|
398
404
|
}) + parensIf(translate("activation")), translate("{$cost} per {$interval}", {
|
|
399
405
|
cost: translate("{$value} AE", {
|
|
400
|
-
value: Math.round(cost.ActivationAndHalfInterval.value / 2),
|
|
406
|
+
value: Math.round(cost.ActivationAndHalfInterval.value / 2).toFixed(),
|
|
401
407
|
}),
|
|
402
408
|
interval: formatTimeSpan(translate, translateMap, format, responsiveTextSize, cost.ActivationAndHalfInterval.interval.unit, cost.ActivationAndHalfInterval.interval.value, true),
|
|
403
409
|
}));
|
|
404
410
|
case "Indefinite":
|
|
405
411
|
return ((mapNullable(translateMap(cost.Indefinite.translations)?.description, description => getResponsiveText(description, responsiveTextSize)) ?? MISSING_VALUE) +
|
|
406
|
-
mapNullableDefault(cost.Indefinite.modifier, modifier => ` + ${translate("{$value} AE", { value: modifier.value })}`, ""));
|
|
412
|
+
mapNullableDefault(cost.Indefinite.modifier, modifier => ` + ${translate("{$value} AE", { value: modifier.value.toFixed() })}`, ""));
|
|
407
413
|
case "Disjunction":
|
|
408
414
|
return translate("{$value} AE", {
|
|
409
415
|
value: localeJoin(cost.Disjunction.options.map(option => option.value.toFixed() +
|
|
@@ -430,7 +436,7 @@ const renderArcaneEnergyCost = (translate, translateMap, format, localeJoin, res
|
|
|
430
436
|
case "Verbose":
|
|
431
437
|
return cost.ByLevel.levels
|
|
432
438
|
.map((level, index) => translate("{$cost} for level {$level}", {
|
|
433
|
-
cost: translate("{$value} AE", { value: level.value }),
|
|
439
|
+
cost: translate("{$value} AE", { value: level.value.toFixed() }),
|
|
434
440
|
level: romanize(index + 1),
|
|
435
441
|
}))
|
|
436
442
|
.join("; ");
|
|
@@ -454,7 +460,9 @@ const renderBindingCost = (translate, translateMap, localeCompare, getAllResolve
|
|
|
454
460
|
}),
|
|
455
461
|
});
|
|
456
462
|
case "Map":
|
|
457
|
-
return renderParameterMap(cost.Map, option => Reader.of(option.permanentValue), values => translateR("{$value} permanent AE", {
|
|
463
|
+
return renderParameterMap(cost.Map, option => Reader.of(option.permanentValue), values => translateR("{$value} permanent AE", {
|
|
464
|
+
value: typeof values === "number" ? values.toFixed() : values,
|
|
465
|
+
})).run({
|
|
458
466
|
translate,
|
|
459
467
|
translateMap,
|
|
460
468
|
responsiveTextSize,
|
|
@@ -481,12 +489,12 @@ const renderBindingCost = (translate, translateMap, localeCompare, getAllResolve
|
|
|
481
489
|
const renderLifePointsCost = (translate, cost) => cost === undefined
|
|
482
490
|
? ""
|
|
483
491
|
: // eslint-disable-next-line no-irregular-whitespace
|
|
484
|
-
` (+ ${translate("{$value} LP", { value: cost.Fixed.value })})`;
|
|
492
|
+
` (+ ${translate("{$value} LP", { value: cost.Fixed.value.toFixed() })})`;
|
|
485
493
|
const renderCost = (translate, translateMap, format, localeJoin, localeCompare, getAllResolvedSelectOptions, responsiveTextSize, levels, cost) => {
|
|
486
494
|
if (typeof cost === "number") {
|
|
487
495
|
return {
|
|
488
496
|
label: translate("AE Cost"),
|
|
489
|
-
value: translate("{$value} AE", { value: cost }),
|
|
497
|
+
value: translate("{$value} AE", { value: cost.toFixed() }),
|
|
490
498
|
};
|
|
491
499
|
}
|
|
492
500
|
switch (cost.kind) {
|
|
@@ -826,9 +834,10 @@ export const getActivatableEntityDescription = createEntityDescriptionCreator(({
|
|
|
826
834
|
title: addLevels(makeTraditionName(translation.name_in_library ?? translation.name + parensIf(translation.additionalName))),
|
|
827
835
|
subtitle: mapNullable(baseEntry.subtype, subtype => renderAdvantageDisadvantageSubtype(subtype).run(env)) ??
|
|
828
836
|
mapNullable(baseEntry.usage_type, usageType => renderCombatSpecialAbilityType(usageType).run(env)),
|
|
829
|
-
badge: mapNullable(entityName === "CombatStyleSpecialAbility" ||
|
|
837
|
+
badge: mapNullable(entityName === "CombatStyleSpecialAbility" ||
|
|
838
|
+
entityName === "AdvancedCombatSpecialAbility"
|
|
830
839
|
? entry.type
|
|
831
|
-
: undefined, combatType => {
|
|
840
|
+
: undefined, (combatType) => {
|
|
832
841
|
switch (combatType.kind) {
|
|
833
842
|
case "Armed":
|
|
834
843
|
return { type: "armedCombat", value: translate("AC") };
|
|
@@ -837,7 +846,8 @@ export const getActivatableEntityDescription = createEntityDescriptionCreator(({
|
|
|
837
846
|
default:
|
|
838
847
|
return assertExhaustive(combatType);
|
|
839
848
|
}
|
|
840
|
-
})
|
|
849
|
+
}) ??
|
|
850
|
+
mapNullable(baseEntry.prerequisites, getDerivedFocusRuleBadgeFromPrerequisites)?.run(env),
|
|
841
851
|
className: "special-ability",
|
|
842
852
|
body: [
|
|
843
853
|
mapNullable(translation.special_rules, specialRules => ({
|
package/lib/entities/culture.js
CHANGED
|
@@ -248,14 +248,14 @@ export const getCultureEntityDescription = createEntityDescriptionCreator(({ get
|
|
|
248
248
|
if (allSame(processedScripts, on(([, apValue]) => apValue, equal))) {
|
|
249
249
|
return (localeJoin(processedScripts.map(([name]) => name).toSorted(localeCompare), "disjunction") +
|
|
250
250
|
parensIf(translate("{$value} AP", {
|
|
251
|
-
value: processedScripts[0][1],
|
|
251
|
+
value: processedScripts[0][1].toFixed(),
|
|
252
252
|
})));
|
|
253
253
|
}
|
|
254
254
|
else {
|
|
255
255
|
return localeJoin(processedScripts
|
|
256
256
|
.map(([name, apValue]) => name +
|
|
257
257
|
parensIf(translate("{$value} AP", {
|
|
258
|
-
value: apValue,
|
|
258
|
+
value: apValue.toFixed(),
|
|
259
259
|
})))
|
|
260
260
|
.toSorted(localeCompare), "disjunction");
|
|
261
261
|
}
|
|
@@ -306,7 +306,7 @@ export const getCultureEntityDescription = createEntityDescriptionCreator(({ get
|
|
|
306
306
|
type: "labeled",
|
|
307
307
|
label: translate("Cultural Package {$cultureName}", {
|
|
308
308
|
cultureName: translation.name,
|
|
309
|
-
}) + parensIf(translate("{$value} AP", { value: culturalPackageApValue })),
|
|
309
|
+
}) + parensIf(translate("{$value} AP", { value: culturalPackageApValue.toFixed() })),
|
|
310
310
|
value: {
|
|
311
311
|
type: "plain",
|
|
312
312
|
text: culturePackageText,
|
|
@@ -183,7 +183,7 @@ const renderAbilityAdjustment = (translate, translateMap, getInstanceById, baseP
|
|
|
183
183
|
const printedBaseValue = mapNullable(renderPrintedAbilityAdjustmentBaseValue(abilityAdjustment), value => value + defaultValue);
|
|
184
184
|
return translate("{$replacement} instead of {$base}", {
|
|
185
185
|
base: printedBaseValue === basePoints
|
|
186
|
-
? basePoints
|
|
186
|
+
? basePoints.toFixed()
|
|
187
187
|
: `<ins>${basePoints.toFixed()}</ins><del>${printedBaseValue?.toFixed() ?? "n/a"}</del>`,
|
|
188
188
|
replacement: `${renderAbilityAdjustmentName(translateMap, getInstanceById, abilityAdjustment)} ${(basePoints + renderAbilityAdjustmentModifierValue(abilityAdjustment)).toFixed()}`,
|
|
189
189
|
});
|
package/lib/entities/elixir.js
CHANGED
|
@@ -54,7 +54,7 @@ export const getElixirEntityDescription = createEntityDescriptionCreator(({ getI
|
|
|
54
54
|
{
|
|
55
55
|
label: `${translate("AP Value")} (${translate("Trade Secret")})`,
|
|
56
56
|
value: translate("{$value} AP", {
|
|
57
|
-
value: entry.trade_secret.ap_value,
|
|
57
|
+
value: entry.trade_secret.ap_value.toFixed(),
|
|
58
58
|
}) +
|
|
59
59
|
parensIf(mapNullable(entry.trade_secret.prerequisites, prerequisites => `${translate("Prerequisites")}: ${printPlainGeneralPrerequisites(prerequisites).run(env)}`)),
|
|
60
60
|
},
|
|
@@ -239,7 +239,7 @@ const renderComplexity = (translate, complexity) => mapNullable(complexity, c =>
|
|
|
239
239
|
return translate("Simple");
|
|
240
240
|
case "Complex":
|
|
241
241
|
return `${translate("Complex")} (${translate("{$value} AP", {
|
|
242
|
-
value: c.Complex.ap_value,
|
|
242
|
+
value: c.Complex.ap_value.toFixed(),
|
|
243
243
|
})})`;
|
|
244
244
|
case "Various":
|
|
245
245
|
return translate("Various");
|
|
@@ -12,7 +12,7 @@ export declare const getBlessingEntityDescription: import("../creator.js").Entit
|
|
|
12
12
|
* Get a JSON representation of the rules text for a liturgical chant.
|
|
13
13
|
*/
|
|
14
14
|
export declare const getLiturgicalChantEntityDescription: import("../creator.js").EntityDescriptionCreator<"LiturgicalChant", {
|
|
15
|
-
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Aspect" | "BlessedTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement">;
|
|
15
|
+
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Aspect" | "BlessedTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement" | "FocusRule">;
|
|
16
16
|
getChildInstancesForInstanceId: GetAllChildInstancesForParent<"Enhancement">;
|
|
17
17
|
idMap: IdMap;
|
|
18
18
|
}, import("../index.js").EntityDescription>;
|
|
@@ -20,7 +20,7 @@ export declare const getLiturgicalChantEntityDescription: import("../creator.js"
|
|
|
20
20
|
* Get a JSON representation of the rules text for a ceremony.
|
|
21
21
|
*/
|
|
22
22
|
export declare const getCeremonyEntityDescription: import("../creator.js").EntityDescriptionCreator<"Ceremony", {
|
|
23
|
-
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Aspect" | "BlessedTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement">;
|
|
23
|
+
getInstanceById: GetInstanceById<"Publication" | "Attribute" | "SkillModificationLevel" | "TargetCategory" | "Aspect" | "BlessedTradition" | "DerivedCharacteristic" | RatedIdentifier["kind"] | "Enhancement" | "FocusRule">;
|
|
24
24
|
getChildInstancesForInstanceId: GetAllChildInstancesForParent<"Enhancement">;
|
|
25
25
|
idMap: IdMap;
|
|
26
26
|
}, import("../index.js").EntityDescription>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { mapNullable } from "@elyukai/utils/nullable";
|
|
1
2
|
import { isNotNullish } from "@optolith/helpers/nullable";
|
|
2
3
|
import { assertExhaustive } from "@optolith/helpers/typeSafety";
|
|
3
4
|
import { Case } from "tsondb/schema/gen";
|
|
4
5
|
import { createEntityDescriptionCreator } from "../creator.js";
|
|
5
6
|
import { renderEnhancements } from "./partial/enhancements.js";
|
|
6
7
|
import { attributedInstance, attributedName } from "./partial/markdown.js";
|
|
8
|
+
import { getDerivedFocusRuleBadgeFromPrerequisites } from "./partial/prerequisites/index.js";
|
|
7
9
|
import { renderOneTimeDuration } from "./partial/rated/activatable/duration.js";
|
|
8
10
|
import { renderEffect } from "./partial/rated/activatable/effect.js";
|
|
9
11
|
import { combineGeneratedTextWithStaticTranslation, renderFastPerformanceParameters, renderSlowPerformanceParameters, } from "./partial/rated/activatable/index.js";
|
|
@@ -173,6 +175,7 @@ export const getLiturgicalChantEntityDescription = createEntityDescriptionCreato
|
|
|
173
175
|
return {
|
|
174
176
|
title: translation.name,
|
|
175
177
|
className: "liturgical-chant",
|
|
178
|
+
badge: mapNullable(entry.prerequisites, getDerivedFocusRuleBadgeFromPrerequisites)?.run(env),
|
|
176
179
|
body: [
|
|
177
180
|
{
|
|
178
181
|
type: "definitionList",
|
|
@@ -237,6 +240,7 @@ export const getCeremonyEntityDescription = createEntityDescriptionCreator(({ ge
|
|
|
237
240
|
return {
|
|
238
241
|
title: translation.name,
|
|
239
242
|
className: "ceremony",
|
|
243
|
+
badge: mapNullable(entry.prerequisites, getDerivedFocusRuleBadgeFromPrerequisites)?.run(env),
|
|
240
244
|
body: [
|
|
241
245
|
{
|
|
242
246
|
type: "definitionList",
|
|
@@ -35,7 +35,7 @@ const renderFixedSelectOptionsAdventurePointsValue = (locale, getAllSelectOption
|
|
|
35
35
|
.toSorted(locale.compare), "conjunction"),
|
|
36
36
|
])
|
|
37
37
|
.toSorted(on(item => item[1], locale.compare))
|
|
38
|
-
.map(([apValue, itemNames]) => `${itemNames}: ${locale.translate("{$value} Adventure Points", { value: typeof apValue === "number" ? applyNegative(apValue) : apValue })}`)
|
|
38
|
+
.map(([apValue, itemNames]) => `${itemNames}: ${locale.translate("{$value} Adventure Points", { value: typeof apValue === "number" ? applyNegative(apValue).toFixed() : apValue })}`)
|
|
39
39
|
.join("; ");
|
|
40
40
|
}
|
|
41
41
|
};
|
|
@@ -88,12 +88,13 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
|
|
|
88
88
|
if (entry.levels !== value.ByLevel.list.length) {
|
|
89
89
|
return MISSING_VALUE;
|
|
90
90
|
}
|
|
91
|
-
const
|
|
91
|
+
const levelsPrefix = translate("Level {$level}", {
|
|
92
92
|
level: Array.from({ length: entry.levels }, (_, index) => romanize(index + 1)).join("/"),
|
|
93
|
-
})
|
|
93
|
+
});
|
|
94
|
+
const mainValues = value.ByLevel.list.map(applyNegative).join("/");
|
|
94
95
|
const { additionalBySizeCategory } = value.ByLevel;
|
|
95
96
|
if (additionalBySizeCategory === undefined) {
|
|
96
|
-
return
|
|
97
|
+
return translate("{$value} Adventure Points", { value: mainValues });
|
|
97
98
|
}
|
|
98
99
|
else {
|
|
99
100
|
const sizeCategories = ["tiny", "small", "medium", "large", "huge"];
|
|
@@ -101,7 +102,7 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
|
|
|
101
102
|
.map(sizeCategory => applyNegative(additionalBySizeCategory[sizeCategory]))
|
|
102
103
|
.join("/");
|
|
103
104
|
const labels = sizeCategories.map(sizeCategory => translate(sizeCategory)).join("/");
|
|
104
|
-
return `${
|
|
105
|
+
return `${levelsPrefix}: ${mainValues} + ${translate("{$values} AP for size category {$labels} (per level)", { values, labels })}`;
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
case "DerivedFromSelection": {
|
|
@@ -281,13 +282,13 @@ export const renderAdventurePointsValue = (locale, getNameForId, getNameForSelec
|
|
|
281
282
|
const labels = Array.from({ length: entry.maximum ?? 3 }, (_, index) => `${(index + 1).toFixed()}.`).join("/");
|
|
282
283
|
if (entry.maximum !== undefined) {
|
|
283
284
|
return translate("{$values} Adventure Points for the {$labels} purchase", {
|
|
284
|
-
values,
|
|
285
|
+
values: values.join("/"),
|
|
285
286
|
labels,
|
|
286
287
|
});
|
|
287
288
|
}
|
|
288
289
|
else {
|
|
289
290
|
return translate("{$values}/and so on Adventure Points for the {$labels}/and so on purchase", {
|
|
290
|
-
values,
|
|
291
|
+
values: values.join("/"),
|
|
291
292
|
labels,
|
|
292
293
|
});
|
|
293
294
|
}
|
|
@@ -3,11 +3,11 @@ import { translateR } from "./reader.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Renders a dice expression like "2D6" into a localized string.
|
|
5
5
|
*/
|
|
6
|
-
export const renderDice = (translate, dice) => translate("{$count}D{$sides}", { count: dice.number, sides: dice.sides });
|
|
6
|
+
export const renderDice = (translate, dice) => translate("{$count}D{$sides}", { count: dice.number.toFixed(), sides: dice.sides.toFixed() });
|
|
7
7
|
/**
|
|
8
8
|
* Renders a dice expression like "2D6" into a localized string.
|
|
9
9
|
*/
|
|
10
|
-
export const renderDiceR = (dice) => translateR("{$count}D{$sides}", { count: dice.number, sides: dice.sides });
|
|
10
|
+
export const renderDiceR = (dice) => translateR("{$count}D{$sides}", { count: dice.number.toFixed(), sides: dice.sides.toFixed() });
|
|
11
11
|
/**
|
|
12
12
|
* Renders a dice expression with an additional flat modifier, like "2D6+3" or "2D6-1".
|
|
13
13
|
*/
|
|
@@ -22,8 +22,8 @@ const renderEnhancement = (enhancement, parentImprovementCost) => {
|
|
|
22
22
|
const { prerequisites } = enhancement.content;
|
|
23
23
|
return translateMapR(enhancement.content.translations).thenW(translation => translation === undefined
|
|
24
24
|
? Reader.of(undefined)
|
|
25
|
-
: translateR("SR {$value}", { value: enhancement.content.skill_rating }).thenW(sr => translateR("{$value} AP", {
|
|
26
|
-
value: getEnhancementAPValue(enhancement.content.adventurePoints, parentImprovementCost),
|
|
25
|
+
: translateR("SR {$value}", { value: enhancement.content.skill_rating.toFixed() }).thenW(sr => translateR("{$value} AP", {
|
|
26
|
+
value: getEnhancementAPValue(enhancement.content.adventurePoints, parentImprovementCost).toFixed(),
|
|
27
27
|
}).thenW(ap => (prerequisites === undefined
|
|
28
28
|
? Reader.of("")
|
|
29
29
|
: translateR(".input {$hiddenCount :number} {{Prerequisites}}", {
|
|
@@ -47,7 +47,7 @@ export const renderChance = (translate, translateMap, item, includePercentage =
|
|
|
47
47
|
(item.chance === undefined
|
|
48
48
|
? undefined
|
|
49
49
|
: translate("{$valueRange} on {$dice}", {
|
|
50
|
-
valueRange: item.chance === 5 ? 1 : `1–${(item.chance / 5).toFixed()}`,
|
|
50
|
+
valueRange: item.chance === 5 ? "1" : `1–${(item.chance / 5).toFixed()}`,
|
|
51
51
|
dice: renderDice(translate, { number: 1, sides: 20 }),
|
|
52
52
|
}) +
|
|
53
53
|
(includePercentage
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Reader } from "@elyukai/utils/reader";
|
|
2
2
|
import type { ActivatableIdentifier, AdvantageDisadvantagePrerequisites, AnimistPowerPrerequisites, ArcaneTraditionPrerequisites, DerivedCharacteristicPrerequisites, EnhancementPrerequisites, GeneralPrerequisites, GeodeRitualPrerequisites, InfluencePrerequisites, LanguagePrerequisites, LiturgyPrerequisites, PersonalityTraitPrerequisites, PlainGeneralPrerequisites, ProfessionPrerequisites, ProfessionVariantPrerequisites, PublicationPrerequisites, SpellworkPrerequisites } from "@optolith/database-schema/gen";
|
|
3
|
-
import type { StdEnv } from "../../../env.js";
|
|
3
|
+
import type { StdEnv, StdReader } from "../../../env.js";
|
|
4
|
+
import type { RawEntityDescriptionBadge } from "../../../index.js";
|
|
4
5
|
import { printAdvantageDisadvantagePrerequisiteGroup, printAnimistPowerPrerequisiteGroup, printArcaneTraditionPrerequisiteGroup, printDerivedCharacteristicPrerequisiteGroup, printEnhancementPrerequisiteGroup, printGeneralPrerequisiteGroup, printGeodeRitualPrerequisiteGroup, printInfluencePrerequisiteGroup, printLanguagePrerequisiteGroup, printLiturgyPrerequisiteGroup, printPersonalityTraitPrerequisiteGroup, printProfessionPrerequisiteGroup, printPublicationPrerequisiteGroup, printSpellworkPrerequisiteGroup } from "./prerequisiteGroups.js";
|
|
5
6
|
type DeriveEnvF<T extends (...args: any[]) => any> = ReturnType<T> extends Reader<infer E, unknown> ? E : never;
|
|
6
7
|
/**
|
|
@@ -70,4 +71,8 @@ export declare const printGeodeRitualPrerequisites: (value: GeodeRitualPrerequis
|
|
|
70
71
|
* Print enhancement prerequisites as a string.
|
|
71
72
|
*/
|
|
72
73
|
export declare const printEnhancementPrerequisites: (value: EnhancementPrerequisites) => Reader<DeriveEnvF<typeof printEnhancementPrerequisiteGroup> & StdEnv<"lj" | "lc">, string>;
|
|
74
|
+
/**
|
|
75
|
+
* Get the focus rule badge from prerequisites.
|
|
76
|
+
*/
|
|
77
|
+
export declare const getDerivedFocusRuleBadgeFromPrerequisites: (prerequisites: AdvantageDisadvantagePrerequisites | GeneralPrerequisites | PlainGeneralPrerequisites) => StdReader<RawEntityDescriptionBadge | undefined, "ibi", "FocusRule">;
|
|
73
78
|
export {};
|
|
@@ -7,7 +7,7 @@ import { isNotNullish } from "@optolith/helpers/nullable";
|
|
|
7
7
|
import { romanize } from "@optolith/helpers/roman";
|
|
8
8
|
import { assertExhaustive } from "@optolith/helpers/typeSafety";
|
|
9
9
|
import { renderActivatableNameComponents, renderActivatableNameComponentsCombinedIfPossible, } from "../activatableNameChunks.js";
|
|
10
|
-
import { localeJoinR, translateR } from "../reader.js";
|
|
10
|
+
import { getInstanceByIdR, localeJoinR, translateR } from "../reader.js";
|
|
11
11
|
import { MISSING_VALUE } from "../unknown.js";
|
|
12
12
|
import { printDisplayOption } from "./displayOption.js";
|
|
13
13
|
import { hasPartValueObject, joinPrerequisiteParts } from "./part.js";
|
|
@@ -230,3 +230,26 @@ export const printGeodeRitualPrerequisites = (value) => printPlainPrerequisites(
|
|
|
230
230
|
* Print enhancement prerequisites as a string.
|
|
231
231
|
*/
|
|
232
232
|
export const printEnhancementPrerequisites = (value) => printPlainPrerequisites(printEnhancementPrerequisiteGroup, value);
|
|
233
|
+
const getDerivedFocusRuleBadgeFromPrerequisite = (prerequisite) => prerequisite.kind === "Single" &&
|
|
234
|
+
prerequisite.Single.kind === "Rule" &&
|
|
235
|
+
prerequisite.Single.Rule.id.kind === "FocusRule"
|
|
236
|
+
? getInstanceByIdR(prerequisite.Single.Rule.id).map(focusRule => focusRule?.level)
|
|
237
|
+
: Reader.of(undefined);
|
|
238
|
+
/**
|
|
239
|
+
* Get the focus rule badge from prerequisites.
|
|
240
|
+
*/
|
|
241
|
+
export const getDerivedFocusRuleBadgeFromPrerequisites = (prerequisites) => Reader.asks(env => {
|
|
242
|
+
for (const element of prerequisites) {
|
|
243
|
+
const actualPrerequisite = "level" in element ? (element.level === 1 ? element.prerequisite : undefined) : element;
|
|
244
|
+
if (actualPrerequisite !== undefined) {
|
|
245
|
+
const badge = getDerivedFocusRuleBadgeFromPrerequisite(actualPrerequisite).run(env);
|
|
246
|
+
if (badge !== undefined) {
|
|
247
|
+
return {
|
|
248
|
+
type: "level",
|
|
249
|
+
value: romanize(badge),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return undefined;
|
|
255
|
+
});
|
|
@@ -12,7 +12,7 @@ export const printPersonalityTraitPrerequisite = (prerequisite) => prerequisite.
|
|
|
12
12
|
: attributedNameFromInstanceR(personalityTrait, "prerequisite", "PersonalityTrait", prerequisite.id)
|
|
13
13
|
.map(name => name ?? MISSING_VALUE)
|
|
14
14
|
.thenW(name => translateR("Level {$level}", {
|
|
15
|
-
level: personalityTrait.level,
|
|
15
|
+
level: personalityTrait.level.toFixed(),
|
|
16
16
|
}).map(level => `${name} (${level})`))
|
|
17
17
|
.then(name => prerequisite.active
|
|
18
18
|
? translateR("must have {$trait}", {
|
|
@@ -13,7 +13,7 @@ export const printRatedSumPrerequisite = (prerequisite) => prerequisite.display_
|
|
|
13
13
|
.thenW(skills => localeJoinR(skills, "conjunction"))
|
|
14
14
|
.thenW(skills => translateR("the SR for {$skill} combined must add up to at least {$minRating}", {
|
|
15
15
|
skill: skills,
|
|
16
|
-
minRating: prerequisite.sum,
|
|
16
|
+
minRating: prerequisite.sum.toFixed(),
|
|
17
17
|
}))
|
|
18
18
|
.map(value => ({
|
|
19
19
|
value,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NonEmptyArray } from "@elyukai/utils/array/nonEmpty";
|
|
2
|
+
import { Reader } from "@elyukai/utils/reader";
|
|
3
|
+
import type { CombatTechniquesForAdventurePointsOption, VariantOptionAction } from "@optolith/database-schema/gen";
|
|
4
|
+
import type { StdEnv } from "../../../../env.js";
|
|
5
|
+
import { type PreparedProfessionPackage } from "../packages.js";
|
|
6
|
+
type Option = CombatTechniquesForAdventurePointsOption;
|
|
7
|
+
type OptionEnv = StdEnv<"t" | "tm" | "ibi", "CloseCombatTechnique" | "RangedCombatTechnique">;
|
|
8
|
+
/**
|
|
9
|
+
* Renders the combat techniques for adventure points option for a list of profession packages.
|
|
10
|
+
*/
|
|
11
|
+
export declare const renderBaseCombatTechniquesForAdventurePointsOption: (professionPackages: NonEmptyArray<PreparedProfessionPackage>) => Reader<OptionEnv, string | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Renders the combat techniques for adventure points option for a variant of a profession package.
|
|
14
|
+
*/
|
|
15
|
+
export declare const renderVariantCombatTechniquesForAdventurePointsOption: (baseOptions: Option | undefined, variantOptions: VariantOptionAction<Option>) => Reader<OptionEnv, string>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { deepEqual, equal } from "@elyukai/utils/equality";
|
|
2
|
+
import { Reader } from "@elyukai/utils/reader";
|
|
3
|
+
import { attributedNameR, fixedNumberOrString, translateR } from "../../reader.js";
|
|
4
|
+
import { MISSING_VALUE } from "../../unknown.js";
|
|
5
|
+
import { renderParameterizedOptionForBaseAndVariant, renderParameterizedOptionForMultiplePackages, } from "../packages.js";
|
|
6
|
+
const renderCombatTechniquesForAdventurePointsOptionList = (options) => Reader.traverse(options, id => attributedNameR("profession", id).map(name => name ?? MISSING_VALUE)).map(list => list.join(", "));
|
|
7
|
+
const renderCombatTechniquesForAdventurePointsOptionText = (apValue, list) => translateR("{$apValue} AP to distribute among the following combat techniques: {$list}", {
|
|
8
|
+
apValue: fixedNumberOrString(apValue),
|
|
9
|
+
list,
|
|
10
|
+
});
|
|
11
|
+
const renderStandaloneOption = (option) => renderCombatTechniquesForAdventurePointsOptionList(option.options).thenW(list => renderCombatTechniquesForAdventurePointsOptionText(option.apValue.toFixed(), list));
|
|
12
|
+
const configs = [
|
|
13
|
+
{
|
|
14
|
+
selector: option => option.apValue,
|
|
15
|
+
equality: equal,
|
|
16
|
+
render: apValue => Reader.of(apValue),
|
|
17
|
+
renderAsString: apValue => Reader.of(apValue.toFixed()),
|
|
18
|
+
emptyText: "—",
|
|
19
|
+
joiner: "/",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
selector: option => option.options,
|
|
23
|
+
equality: deepEqual,
|
|
24
|
+
render: renderCombatTechniquesForAdventurePointsOptionList,
|
|
25
|
+
renderAsString: renderCombatTechniquesForAdventurePointsOptionList,
|
|
26
|
+
emptyText: "—",
|
|
27
|
+
joiner: " / ",
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
const render = (apValue, list) => translateR("{$apValue} AP to distribute among the following combat techniques: {$list}", {
|
|
31
|
+
apValue: fixedNumberOrString(apValue),
|
|
32
|
+
list,
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Renders the combat techniques for adventure points option for a list of profession packages.
|
|
36
|
+
*/
|
|
37
|
+
export const renderBaseCombatTechniquesForAdventurePointsOption = (professionPackages) => renderParameterizedOptionForMultiplePackages(professionPackages, pkg => pkg.content.options?.combatTechniquesForAdventurePoints, { type: "separate", emptyText: "—", joiner: " / " }, render, ...configs);
|
|
38
|
+
/**
|
|
39
|
+
* Renders the combat techniques for adventure points option for a variant of a profession package.
|
|
40
|
+
*/
|
|
41
|
+
export const renderVariantCombatTechniquesForAdventurePointsOption = (baseOptions, variantOptions) => renderParameterizedOptionForBaseAndVariant(baseOptions, variantOptions, { type: "separate", emptyText: "—", joiner: " / " }, base => renderCombatTechniquesForAdventurePointsOptionList(base.options).thenW(list => translateR("no AP to distribute among the following combat techniques: {$list}", {
|
|
42
|
+
list,
|
|
43
|
+
})), renderStandaloneOption, render, ...configs);
|
package/lib/entities/partial/profession/options/numberOfSpellworksTotalingAdventurePoints.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NonEmptyArray } from "@elyukai/utils/array/nonEmpty";
|
|
2
|
+
import { Reader } from "@elyukai/utils/reader";
|
|
3
|
+
import type { SpellworksOptions, VariantOptionAction } from "@optolith/database-schema/gen";
|
|
4
|
+
import type { StdEnv } from "../../../../env.js";
|
|
5
|
+
import { type PreparedProfessionPackage } from "../packages.js";
|
|
6
|
+
type Option = SpellworksOptions;
|
|
7
|
+
type OptionEnv = StdEnv<"t">;
|
|
8
|
+
/**
|
|
9
|
+
* Renders the combat techniques for adventure points option for a list of profession packages.
|
|
10
|
+
*/
|
|
11
|
+
export declare const renderBaseNumberOfSpellworksTotalingAdventurePoints: (professionPackages: NonEmptyArray<PreparedProfessionPackage>) => Reader<OptionEnv, string | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Renders the combat techniques for adventure points option for a variant of a profession package.
|
|
14
|
+
*/
|
|
15
|
+
export declare const renderVariantNumberOfSpellworksTotalingAdventurePoints: (baseOptions: Option | undefined, variantOptions: VariantOptionAction<Option>) => Reader<OptionEnv, string>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { equal } from "@elyukai/utils/equality";
|
|
2
|
+
import { Reader } from "@elyukai/utils/reader";
|
|
3
|
+
import { fixedNumberOrString, translateR } from "../../reader.js";
|
|
4
|
+
import { renderParameterizedOptionForBaseAndVariant, renderParameterizedOptionForMultiplePackages, } from "../packages.js";
|
|
5
|
+
const configs = [
|
|
6
|
+
{
|
|
7
|
+
selector: option => option.number,
|
|
8
|
+
equality: equal,
|
|
9
|
+
render: apValue => Reader.of(apValue),
|
|
10
|
+
renderAsString: apValue => Reader.of(apValue.toFixed()),
|
|
11
|
+
emptyText: "—",
|
|
12
|
+
joiner: "/",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
selector: option => option.apValue,
|
|
16
|
+
equality: equal,
|
|
17
|
+
render: apValue => Reader.of(apValue),
|
|
18
|
+
renderAsString: apValue => Reader.of(apValue.toFixed()),
|
|
19
|
+
emptyText: "—",
|
|
20
|
+
joiner: "/",
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
const render = (count, apValue) => typeof count === "number"
|
|
24
|
+
? translateR(".input {$count :number} {{{$count} more spellworks totaling {$apValue} AP}}", {
|
|
25
|
+
count,
|
|
26
|
+
apValue: fixedNumberOrString(apValue),
|
|
27
|
+
})
|
|
28
|
+
: translateR("{$count} more spellworks totaling {$apValue} AP", {
|
|
29
|
+
count,
|
|
30
|
+
apValue: fixedNumberOrString(apValue),
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Renders the combat techniques for adventure points option for a list of profession packages.
|
|
34
|
+
*/
|
|
35
|
+
export const renderBaseNumberOfSpellworksTotalingAdventurePoints = (professionPackages) => renderParameterizedOptionForMultiplePackages(professionPackages, pkg => pkg.content.options?.spellworks, { type: "separate", emptyText: "—", joiner: " / " }, render, ...configs);
|
|
36
|
+
/**
|
|
37
|
+
* Renders the combat techniques for adventure points option for a variant of a profession package.
|
|
38
|
+
*/
|
|
39
|
+
export const renderVariantNumberOfSpellworksTotalingAdventurePoints = (baseOptions, variantOptions) => renderParameterizedOptionForBaseAndVariant(baseOptions, variantOptions, { type: "separate", emptyText: "—", joiner: " / " }, base => render(0, base.apValue), base => render(base.number, base.apValue), render, ...configs);
|