@archivist-gg/dnd5e 0.3.13 → 0.3.19
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/dist/background/background.codec.js +5 -5
- package/dist/background/background.parser.js +4 -4
- package/dist/background/background.schema.js +3 -3
- package/dist/chunk-3LWMFYKS.js +57 -0
- package/dist/{chunk-4SLOJXJ4.js → chunk-3SFGWFVQ.js} +1 -1
- package/dist/{chunk-Q6UOHCCT.js → chunk-3SIUAFDQ.js} +1 -1
- package/dist/chunk-4J6DS3EJ.js +30 -0
- package/dist/{chunk-RLGQ5PZZ.js → chunk-5JXFJ5AU.js} +11 -1
- package/dist/{chunk-4BZ47YJ4.js → chunk-64VNLMSG.js} +59 -16
- package/dist/{chunk-XY6X2APM.js → chunk-7Q2VPKCD.js} +17 -0
- package/dist/{chunk-Q5XTEYHD.js → chunk-7XJHI5H5.js} +16 -9
- package/dist/{chunk-FPGXFD2M.js → chunk-B2QHP6UF.js} +2 -2
- package/dist/{chunk-HJQNK3J5.js → chunk-B3DP42OM.js} +1 -4
- package/dist/{chunk-MC5YJ4PB.js → chunk-BJGOSM76.js} +1 -1
- package/dist/{chunk-VDPRBUU5.js → chunk-BJWSOQUC.js} +1 -1
- package/dist/{chunk-QEO7LYTG.js → chunk-EJD47JHL.js} +181 -93
- package/dist/{chunk-X7VZY4ON.js → chunk-FJYBLXV7.js} +2 -2
- package/dist/{chunk-QSBJ6NEM.js → chunk-FMUD3LDV.js} +1 -1
- package/dist/{chunk-LVX6TQ3R.js → chunk-FMYWORTP.js} +2 -2
- package/dist/{chunk-PX25R3DK.js → chunk-FVXLP7P3.js} +1 -1
- package/dist/{chunk-XJRNEQPD.js → chunk-GVWEFECG.js} +1 -1
- package/dist/{chunk-R2V5LN3I.js → chunk-HY2SRSVM.js} +1 -1
- package/dist/{chunk-ZMJQUZQH.js → chunk-JXWNXIIZ.js} +24 -0
- package/dist/chunk-KR6JF3BF.js +14 -0
- package/dist/{chunk-DPM6V7YX.js → chunk-LICYHPI3.js} +82 -6
- package/dist/{chunk-J53ERF6K.js → chunk-LNT64X7C.js} +1 -1
- package/dist/{chunk-RQNJXADQ.js → chunk-NKZMQV2C.js} +1 -1
- package/dist/{chunk-UE6LKRXQ.js → chunk-NTU2DXNG.js} +24 -1
- package/dist/{chunk-T5GZBKIQ.js → chunk-NXUY5XQN.js} +168 -33
- package/dist/{chunk-M2OWVAZG.js → chunk-NZO7M5GV.js} +1 -1
- package/dist/{chunk-BRGLDWUP.js → chunk-OOL4KMG2.js} +7 -3
- package/dist/{chunk-MWCCGPG3.js → chunk-OOSRUJBI.js} +3 -2
- package/dist/{chunk-H5PTKYXL.js → chunk-QA3YCOML.js} +1 -1
- package/dist/{chunk-MUIU7RZ3.js → chunk-QFWQKS3M.js} +1 -1
- package/dist/chunk-RD2MID3M.js +292 -0
- package/dist/chunk-TRBGC4ZG.js +112 -0
- package/dist/{chunk-PLOSP4XQ.js → chunk-UJCK5IW4.js} +11 -2
- package/dist/{chunk-5KGV6TF7.js → chunk-UNYR5GLI.js} +1 -1
- package/dist/{chunk-JNNNBEUH.js → chunk-VN5DLURA.js} +7 -2
- package/dist/{chunk-EL6QPF6I.js → chunk-VP5TIXDK.js} +1 -1
- package/dist/chunk-WOHX7YTH.js +165 -0
- package/dist/{chunk-G7ED5H2G.js → chunk-XTEFPUSN.js} +1 -1
- package/dist/{chunk-6ZY3U6BQ.js → chunk-ZOWKWMD2.js} +1 -1
- package/dist/class/class.codec.js +6 -6
- package/dist/class/class.parser.js +5 -5
- package/dist/class/class.schema.d.ts +8 -0
- package/dist/class/class.schema.js +4 -4
- package/dist/class/class.standard-array.d.ts +16 -0
- package/dist/class/class.standard-array.js +20 -0
- package/dist/class/class.types.d.ts +3 -0
- package/dist/dnd/amount-text.d.ts +42 -0
- package/dist/dnd/amount-text.js +15 -0
- package/dist/dnd/resource-words.d.ts +4 -0
- package/dist/dnd/resource-words.js +30 -0
- package/dist/entities/registry-revision.d.ts +25 -0
- package/dist/entities/registry-revision.js +10 -0
- package/dist/feat/feat.codec.js +5 -5
- package/dist/feat/feat.parser.js +4 -4
- package/dist/feat/feat.schema.d.ts +34 -0
- package/dist/feat/feat.schema.js +3 -3
- package/dist/index.js +4027 -383
- package/dist/monster/monster.parser.js +5 -5
- package/dist/monster/monster.schema.js +4 -4
- package/dist/optional-feature/optional-feature.codec.js +5 -4
- package/dist/optional-feature/optional-feature.parser.js +4 -3
- package/dist/optional-feature/optional-feature.schema.d.ts +35 -0
- package/dist/optional-feature/optional-feature.schema.js +3 -2
- package/dist/pc/pc.additional-spells.d.ts +16 -2
- package/dist/pc/pc.additional-spells.js +5 -2
- package/dist/pc/pc.amount-bindings.d.ts +41 -0
- package/dist/pc/pc.amount-bindings.js +28 -0
- package/dist/pc/pc.decision-engine.d.ts +11 -0
- package/dist/pc/pc.decision-engine.js +20 -16
- package/dist/pc/pc.entry-overrides.js +3 -2
- package/dist/pc/pc.equipment.js +7 -5
- package/dist/pc/pc.feature-effects.d.ts +21 -2
- package/dist/pc/pc.feature-effects.js +15 -2
- package/dist/pc/pc.infusions.d.ts +9 -1
- package/dist/pc/pc.infusions.js +3 -2
- package/dist/pc/pc.member-choices.d.ts +122 -0
- package/dist/pc/pc.member-choices.js +39 -0
- package/dist/pc/pc.parser.js +1 -1
- package/dist/pc/pc.pools.d.ts +7 -0
- package/dist/pc/pc.pools.js +5 -2
- package/dist/pc/pc.proficiencies.d.ts +14 -0
- package/dist/pc/pc.proficiencies.js +72 -22
- package/dist/pc/pc.proficiency-normalize.d.ts +14 -0
- package/dist/pc/pc.proficiency-normalize.js +9 -3
- package/dist/pc/pc.proficiency-query.js +7 -1
- package/dist/pc/pc.recalc.js +212 -99
- package/dist/pc/pc.resolver.d.ts +6 -2
- package/dist/pc/pc.resolver.js +16 -14
- package/dist/pc/pc.rest.js +4 -3
- package/dist/pc/pc.schema.d.ts +48 -2
- package/dist/pc/pc.schema.js +1 -1
- package/dist/pc/pc.spell-scope.d.ts +22 -0
- package/dist/pc/pc.tool-picks.js +2 -2
- package/dist/pc/pc.types.d.ts +110 -6
- package/dist/pc/pc.weapon-grant.d.ts +15 -0
- package/dist/pc/pool-layout.d.ts +3 -9
- package/dist/pc/pool-layout.js +1 -3
- package/dist/pc/resource-equivalents.d.ts +44 -0
- package/dist/pc/spell-source.js +4 -9
- package/dist/race/race.codec.js +6 -6
- package/dist/race/race.parser.js +5 -5
- package/dist/race/race.schema.js +4 -4
- package/dist/schemas/choice-schema.js +2 -2
- package/dist/schemas/feature-effect-schema.d.ts +34 -0
- package/dist/schemas/feature-effect-schema.js +1 -1
- package/dist/schemas/feature-schema.js +3 -3
- package/dist/spell/spell.codec.js +2 -2
- package/dist/spell/spell.parser.d.ts +6 -1
- package/dist/spell/spell.parser.js +5 -3
- package/dist/spell/spell.types.d.ts +10 -0
- package/dist/subclass/subclass.codec.js +6 -6
- package/dist/subclass/subclass.parser.js +5 -5
- package/dist/subclass/subclass.schema.js +4 -4
- package/dist/types/choice.d.ts +7 -2
- package/dist/types/feature-effect.d.ts +24 -0
- package/dist/types/optional-feature.types.d.ts +6 -1
- package/dist/types/selection-pool.d.ts +2 -2
- package/package.json +1 -1
|
@@ -9,21 +9,11 @@ import {
|
|
|
9
9
|
classToolPicks,
|
|
10
10
|
expandToolPool,
|
|
11
11
|
toolCategoriesOf
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import {
|
|
14
|
-
resolveFeatureResources,
|
|
15
|
-
resolveResourceIndex
|
|
16
|
-
} from "./chunk-KSTV7J2U.js";
|
|
17
|
-
import {
|
|
18
|
-
attributeUnclassedSpell,
|
|
19
|
-
effectiveSpellcastingAbility,
|
|
20
|
-
normalizeKnownSpell,
|
|
21
|
-
resolveSpellcasting
|
|
22
|
-
} from "./chunk-DPUJDOKV.js";
|
|
12
|
+
} from "./chunk-QA3YCOML.js";
|
|
23
13
|
import {
|
|
24
14
|
assembleEffectFeatures,
|
|
25
15
|
collectProficiencyEffectGrants
|
|
26
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-64VNLMSG.js";
|
|
27
17
|
import {
|
|
28
18
|
ALL_LANGUAGES,
|
|
29
19
|
ALL_SKILL_SLUGS,
|
|
@@ -33,13 +23,41 @@ import {
|
|
|
33
23
|
humanizeProficiency,
|
|
34
24
|
proficiencyLabel,
|
|
35
25
|
toProfSlug
|
|
36
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-5JXFJ5AU.js";
|
|
27
|
+
import {
|
|
28
|
+
featOfSite,
|
|
29
|
+
featPickSites,
|
|
30
|
+
isTargetChoice,
|
|
31
|
+
memberChoices,
|
|
32
|
+
poolMemberSites,
|
|
33
|
+
poolMemberSitesOf,
|
|
34
|
+
raceFeatSites
|
|
35
|
+
} from "./chunk-RD2MID3M.js";
|
|
36
|
+
import {
|
|
37
|
+
collectAdditionalSpells
|
|
38
|
+
} from "./chunk-LICYHPI3.js";
|
|
37
39
|
import {
|
|
40
|
+
resolveFeatureResources,
|
|
41
|
+
resolveResourceIndex
|
|
42
|
+
} from "./chunk-KSTV7J2U.js";
|
|
43
|
+
import {
|
|
44
|
+
attributeUnclassedSpell,
|
|
45
|
+
effectiveSpellcastingAbility,
|
|
46
|
+
normalizeKnownSpell,
|
|
47
|
+
resolveSpellcasting
|
|
48
|
+
} from "./chunk-DPUJDOKV.js";
|
|
49
|
+
import {
|
|
50
|
+
convertibleLegacyAsi,
|
|
51
|
+
flattenAsiOrFeat,
|
|
52
|
+
resolveLegacyAsiFeat
|
|
53
|
+
} from "./chunk-LBEXLN6I.js";
|
|
54
|
+
import {
|
|
55
|
+
bindFeatureConsumers,
|
|
38
56
|
buildInfusionContext,
|
|
39
57
|
resolveAllPools,
|
|
40
58
|
resolveOptionRows,
|
|
41
59
|
strandedPicks
|
|
42
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-NXUY5XQN.js";
|
|
43
61
|
import {
|
|
44
62
|
countColumnsFor,
|
|
45
63
|
readTableColumn
|
|
@@ -47,35 +65,30 @@ import {
|
|
|
47
65
|
import {
|
|
48
66
|
recognizeDecision
|
|
49
67
|
} from "./chunk-YHYTW5QA.js";
|
|
50
|
-
import {
|
|
51
|
-
collectAdditionalSpells
|
|
52
|
-
} from "./chunk-DPM6V7YX.js";
|
|
53
|
-
import {
|
|
54
|
-
convertibleLegacyAsi,
|
|
55
|
-
flattenAsiOrFeat,
|
|
56
|
-
resolveLegacyAsiFeat
|
|
57
|
-
} from "./chunk-LBEXLN6I.js";
|
|
58
68
|
import {
|
|
59
69
|
isItemEntity,
|
|
60
70
|
resolveEntityForEntry
|
|
61
71
|
} from "./chunk-LHZXYFBU.js";
|
|
62
|
-
import {
|
|
63
|
-
warnOnce
|
|
64
|
-
} from "./chunk-LVQLWRCU.js";
|
|
65
|
-
import {
|
|
66
|
-
bareEntitySlug,
|
|
67
|
-
wikilinkTailSlug
|
|
68
|
-
} from "./chunk-ZCTUYGNV.js";
|
|
69
72
|
import {
|
|
70
73
|
FEATURE_TYPE_FOR_CATEGORY,
|
|
71
74
|
featProgressionCategory
|
|
72
75
|
} from "./chunk-YBLDE5CG.js";
|
|
76
|
+
import {
|
|
77
|
+
warnOnce
|
|
78
|
+
} from "./chunk-LVQLWRCU.js";
|
|
79
|
+
import {
|
|
80
|
+
bucketOf
|
|
81
|
+
} from "./chunk-4J6DS3EJ.js";
|
|
73
82
|
import {
|
|
74
83
|
isValidMaxFormula
|
|
75
84
|
} from "./chunk-EVMUJYUD.js";
|
|
85
|
+
import {
|
|
86
|
+
bareEntitySlug,
|
|
87
|
+
wikilinkTailSlug
|
|
88
|
+
} from "./chunk-ZCTUYGNV.js";
|
|
76
89
|
import {
|
|
77
90
|
mirrorSpellShapes
|
|
78
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-7Q2VPKCD.js";
|
|
79
92
|
import {
|
|
80
93
|
ABILITY_KEYS
|
|
81
94
|
} from "./chunk-WELIKLZF.js";
|
|
@@ -205,6 +218,7 @@ function matchesFilter(e, where, ownerBare) {
|
|
|
205
218
|
if (where.list && !((_a = d.classes) != null ? _a : []).includes(where.list)) return false;
|
|
206
219
|
if (where.level !== void 0 && ((_b = d.level) != null ? _b : 0) !== where.level) return false;
|
|
207
220
|
if (where.edition && d.edition !== where.edition) return false;
|
|
221
|
+
if (where.ritual && d.ritual !== true) return false;
|
|
208
222
|
if (where.weapon_category) {
|
|
209
223
|
const cat = ((_c = d.category) != null ? _c : "").toLowerCase();
|
|
210
224
|
if (!cat.startsWith(`${where.weapon_category}-`) && cat !== where.weapon_category) return false;
|
|
@@ -512,7 +526,7 @@ function buildSubclassItem(choice, source, level, featureName, c, ctx, ownerBare
|
|
|
512
526
|
};
|
|
513
527
|
}
|
|
514
528
|
function visitProficiencyChoices(resolved, visit) {
|
|
515
|
-
var _a, _b, _c;
|
|
529
|
+
var _a, _b, _c, _d, _e;
|
|
516
530
|
const walk = (choices, read) => {
|
|
517
531
|
for (const ch of choices != null ? choices : []) {
|
|
518
532
|
visit(ch, read(ch.id));
|
|
@@ -527,8 +541,13 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
527
541
|
const originRead = (ns) => (id) => oc[`${ns}:${id}`];
|
|
528
542
|
const stripRef = (ref) => ref.replace(/^\[\[/, "").replace(/\]\]$/, "");
|
|
529
543
|
const featBySlug = new Map(((_b = resolved.feats) != null ? _b : []).map((f) => [f.slug, f]));
|
|
544
|
+
const memberSites = poolMemberSitesOf(resolved);
|
|
545
|
+
const featSites = featPickSites(resolved.classes, memberSites, (ci) => {
|
|
546
|
+
var _a2, _b2, _c2, _d2;
|
|
547
|
+
return (_d2 = (_c2 = (_b2 = (_a2 = resolved.classes) == null ? void 0 : _a2[ci]) == null ? void 0 : _b2.entity) == null ? void 0 : _c2.slug) != null ? _d2 : null;
|
|
548
|
+
});
|
|
530
549
|
resolved.classes.forEach((c, i) => {
|
|
531
|
-
var _a2, _b2, _c2,
|
|
550
|
+
var _a2, _b2, _c2, _d2, _e2;
|
|
532
551
|
if (!c.entity) return;
|
|
533
552
|
const entity = c.entity;
|
|
534
553
|
const readAt = (lvl) => (id) => {
|
|
@@ -553,14 +572,13 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
553
572
|
for (const copy of (_c2 = rf.foldedFrom) != null ? _c2 : []) walk(copy.choices, readAt(copy.level));
|
|
554
573
|
walk(rf.feature.choices, readAt(rf.source.level));
|
|
555
574
|
}
|
|
556
|
-
for (const
|
|
557
|
-
|
|
558
|
-
const
|
|
559
|
-
if (!block || typeof featRef !== "string") continue;
|
|
560
|
-
const feat = featBySlug.get(stripRef(featRef));
|
|
575
|
+
for (const site of featSites) {
|
|
576
|
+
if (site.classIndex !== i) continue;
|
|
577
|
+
const feat = (_e2 = featBySlug.get(stripRef(site.slug))) != null ? _e2 : featOfSite(site, (_d2 = resolved.feats) != null ? _d2 : []);
|
|
561
578
|
if (!feat) continue;
|
|
562
|
-
walk(feat.choices,
|
|
579
|
+
walk(feat.choices, site.read);
|
|
563
580
|
}
|
|
581
|
+
for (const site of memberSites) if (site.classIndex === i) walk(site.choices, site.read);
|
|
564
582
|
});
|
|
565
583
|
if (resolved.race) {
|
|
566
584
|
walk(resolved.race.choices, originRead("race"));
|
|
@@ -578,6 +596,10 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
578
596
|
const of = featBySlug.get(resolved.originFeatSlug);
|
|
579
597
|
if (of) walk(of.choices, (id) => oc[`background:feat:${id}`]);
|
|
580
598
|
}
|
|
599
|
+
for (const site of raceFeatSites(resolved.race, oc)) {
|
|
600
|
+
const rf = (_e = featBySlug.get(stripRef(site.slug))) != null ? _e : ((_d = resolved.feats) != null ? _d : []).find((f) => bareEntitySlug(f.slug) === bareEntitySlug(site.slug));
|
|
601
|
+
if (rf) walk(rf.choices, site.read);
|
|
602
|
+
}
|
|
581
603
|
}
|
|
582
604
|
var filterToPool = (vals, pool) => pool ? vals.map((v) => matchPool(v, pool)).filter((v) => !!v) : vals;
|
|
583
605
|
function collectChosenProficiencies(resolved) {
|
|
@@ -614,6 +636,14 @@ function proficiencyEntryFor(raw, vocab, origin, sources, expertise) {
|
|
|
614
636
|
return { value, label, sources, origin, ...expertise ? { expertise: true } : {} };
|
|
615
637
|
}
|
|
616
638
|
function computeEffectiveProficiencies(resolved) {
|
|
639
|
+
const c = composeLanguageToolProficiencies(resolved);
|
|
640
|
+
return { languages: c.languages.kept, tools: c.tools.kept };
|
|
641
|
+
}
|
|
642
|
+
function computeSuppressedProficiencies(resolved) {
|
|
643
|
+
const c = composeLanguageToolProficiencies(resolved);
|
|
644
|
+
return { languages: c.languages.suppressed, tools: c.tools.suppressed };
|
|
645
|
+
}
|
|
646
|
+
function composeLanguageToolProficiencies(resolved) {
|
|
617
647
|
const grants = collectProficiencyGrants(resolved);
|
|
618
648
|
const chosen = collectChosenProficiencies(resolved);
|
|
619
649
|
const build = (domain) => {
|
|
@@ -659,7 +689,9 @@ function computeEffectiveProficiencies(resolved) {
|
|
|
659
689
|
}
|
|
660
690
|
}
|
|
661
691
|
const suppressed = /* @__PURE__ */ new Set([...removes.map((r) => toProfSlug(r)), ...triSuppressed]);
|
|
662
|
-
|
|
692
|
+
const byLabel = (a, b) => a.label < b.label ? -1 : a.label > b.label ? 1 : 0;
|
|
693
|
+
const kept = [...byValue.values()].filter((e) => !suppressed.has(toProfSlug(e.value))).sort(byLabel);
|
|
694
|
+
return { kept, suppressed: [...byValue.values()].filter((e) => suppressed.has(toProfSlug(e.value))).sort(byLabel) };
|
|
663
695
|
};
|
|
664
696
|
return { languages: build("languages"), tools: build("tools") };
|
|
665
697
|
}
|
|
@@ -961,6 +993,28 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
961
993
|
});
|
|
962
994
|
}
|
|
963
995
|
for (const o of item.options) if (strandedSlugs.has(o.value)) o.stranded = true;
|
|
996
|
+
const memberChildren = [];
|
|
997
|
+
for (const entry of pool.selected) {
|
|
998
|
+
for (const ch of memberChoices(entry.entity)) {
|
|
999
|
+
const child = buildItem(
|
|
1000
|
+
ch,
|
|
1001
|
+
{ kind: "class", slug: entity.slug, level: pool.anchorLevel },
|
|
1002
|
+
pool.anchorLevel,
|
|
1003
|
+
entry.entity.name,
|
|
1004
|
+
readAt(pool.anchorLevel),
|
|
1005
|
+
ctx,
|
|
1006
|
+
ownerBare,
|
|
1007
|
+
effective,
|
|
1008
|
+
{ keyPrefix: `${pool.id}:${entry.key}:` }
|
|
1009
|
+
);
|
|
1010
|
+
child.parentLabel = entry.entity.name;
|
|
1011
|
+
memberChildren.push(child);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (memberChildren.length) {
|
|
1015
|
+
item.children = memberChildren;
|
|
1016
|
+
if (item.status === "resolved" && memberChildren.some((c2) => c2.status !== "resolved")) item.status = "partial";
|
|
1017
|
+
}
|
|
964
1018
|
push(pool.anchorLevel, item);
|
|
965
1019
|
}
|
|
966
1020
|
for (const entry of featProgressions) {
|
|
@@ -1124,7 +1178,7 @@ function resolveOriginFeat(entities, originFeatRef, ownerSlug) {
|
|
|
1124
1178
|
const baseSlug = base && base !== rawTail ? wikilinkTailSlug(`[[${base}]]`) : null;
|
|
1125
1179
|
const baseInner = baseSlug ? inner.slice(0, inner.length - rawTail.length) + base : null;
|
|
1126
1180
|
const prefix = (ownerSlug == null ? void 0 : ownerSlug.includes("_")) ? ownerSlug.slice(0, ownerSlug.indexOf("_")) : null;
|
|
1127
|
-
const feats = entities
|
|
1181
|
+
const feats = bucketOf(entities, "feat");
|
|
1128
1182
|
const byPath = (p) => feats.find((f) => f.filePath === `${p}.md` || f.filePath.endsWith(`/${p}.md`));
|
|
1129
1183
|
const sameCompendiumTail = (s) => prefix ? feats.find((f) => f.slug.startsWith(`${prefix}_feat_`) && f.slug.endsWith(`_${s}`)) : void 0;
|
|
1130
1184
|
const anyTail = (s) => feats.find((f) => f.slug.endsWith(`_${s}`));
|
|
@@ -1168,7 +1222,7 @@ var PCResolver = class {
|
|
|
1168
1222
|
return this.entities;
|
|
1169
1223
|
}
|
|
1170
1224
|
resolve(character) {
|
|
1171
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
1225
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1172
1226
|
const warnings = [];
|
|
1173
1227
|
const lookup = (rawRef, type) => {
|
|
1174
1228
|
const slug = stripSlug(rawRef);
|
|
@@ -1189,14 +1243,19 @@ var PCResolver = class {
|
|
|
1189
1243
|
subclass: lookup(c.subclass, "subclass"),
|
|
1190
1244
|
choices: c.choices
|
|
1191
1245
|
}));
|
|
1246
|
+
const memberSites = poolMemberSites(classes, this.entities);
|
|
1247
|
+
const classSlugOf = (i) => {
|
|
1248
|
+
var _a2, _b2, _c2, _d2, _e2;
|
|
1249
|
+
return (_e2 = (_b2 = (_a2 = classes[i]) == null ? void 0 : _a2.entity) == null ? void 0 : _b2.slug) != null ? _e2 : stripSlug((_d2 = (_c2 = character.class[i]) == null ? void 0 : _c2.name) != null ? _d2 : null);
|
|
1250
|
+
};
|
|
1251
|
+
const featSites = featPickSites(character.class, memberSites, classSlugOf);
|
|
1192
1252
|
const feats = [];
|
|
1193
1253
|
const featVia = /* @__PURE__ */ new Map();
|
|
1194
|
-
for (const
|
|
1195
|
-
const f = lookup(`[[${
|
|
1254
|
+
for (const site of featSites) {
|
|
1255
|
+
const f = lookup(`[[${site.slug}]]`, "feat");
|
|
1196
1256
|
if (!f) continue;
|
|
1197
|
-
feats.push(f);
|
|
1198
|
-
|
|
1199
|
-
if (classSlug && pick.level !== null && !featVia.has(f.slug)) featVia.set(f.slug, { kind: "class", slug: classSlug, level: pick.level });
|
|
1257
|
+
if (!feats.some((x) => x.slug === f.slug)) feats.push(f);
|
|
1258
|
+
if (site.via && !featVia.has(f.slug)) featVia.set(f.slug, site.via);
|
|
1200
1259
|
}
|
|
1201
1260
|
const originFeat = (background == null ? void 0 : background.origin_feat) ? resolveOriginFeat(this.entities, background.origin_feat, background.slug) : null;
|
|
1202
1261
|
const originFeatSlug = originFeat == null ? void 0 : originFeat.feat.slug;
|
|
@@ -1206,9 +1265,17 @@ var PCResolver = class {
|
|
|
1206
1265
|
if (originFeat && background && !featVia.has(originFeat.feat.slug)) {
|
|
1207
1266
|
featVia.set(originFeat.feat.slug, { kind: "background", slug: background.slug });
|
|
1208
1267
|
}
|
|
1268
|
+
const raceFeats = [];
|
|
1269
|
+
for (const site of raceFeatSites(race, character.origin_choices)) {
|
|
1270
|
+
const f = lookup(`[[${site.slug}]]`, "feat");
|
|
1271
|
+
if (!f) continue;
|
|
1272
|
+
raceFeats.push({ feat: f, read: site.read });
|
|
1273
|
+
if (!feats.some((x) => x.slug === f.slug)) feats.push(f);
|
|
1274
|
+
if (!featVia.has(f.slug)) featVia.set(f.slug, site.via);
|
|
1275
|
+
}
|
|
1209
1276
|
const totalLevel = classes.reduce((sum, c) => sum + c.level, 0);
|
|
1210
1277
|
const features = collectResolvedFeatures(race, classes, background, feats, featVia);
|
|
1211
|
-
const extraFeatures = collectChosenGrantedFeatures(character, classes, this.entities, race, background);
|
|
1278
|
+
const extraFeatures = collectChosenGrantedFeatures(character, classes, this.entities, race, background, memberSites);
|
|
1212
1279
|
features.push(...extraFeatures);
|
|
1213
1280
|
features.push(...collectAdditionalFeatures(character, this.entities, warnings));
|
|
1214
1281
|
const casters = [];
|
|
@@ -1218,7 +1285,7 @@ var PCResolver = class {
|
|
|
1218
1285
|
if (profile && classSlug != null) casters.push({ classSlug, spellList: profile.spellList });
|
|
1219
1286
|
});
|
|
1220
1287
|
const spells = [];
|
|
1221
|
-
for (const raw of (
|
|
1288
|
+
for (const raw of (_a = character.spells.known) != null ? _a : []) {
|
|
1222
1289
|
const n = normalizeKnownSpell(raw);
|
|
1223
1290
|
const reg = this.entities.getByTypeAndSlug("spell", n.slug);
|
|
1224
1291
|
if (!reg) {
|
|
@@ -1226,45 +1293,47 @@ var PCResolver = class {
|
|
|
1226
1293
|
continue;
|
|
1227
1294
|
}
|
|
1228
1295
|
const entity = mirrorSpellShapes(reg.data);
|
|
1229
|
-
const isCantrip = ((
|
|
1230
|
-
const classSlug = (
|
|
1231
|
-
const prep = isCantrip || n.alwaysPrepared ? true : (
|
|
1296
|
+
const isCantrip = ((_b = entity.level) != null ? _b : 0) === 0;
|
|
1297
|
+
const classSlug = (_c = n.classSlug) != null ? _c : attributeUnclassedSpell(entity.classes, casters, this.entities);
|
|
1298
|
+
const prep = isCantrip || n.alwaysPrepared ? true : (_d = n.preparedFlag) != null ? _d : false;
|
|
1232
1299
|
spells.push({ entity, slug: n.slug, classSlug, source: n.source, prepared: prep, alwaysPrepared: n.alwaysPrepared, persisted: true });
|
|
1233
1300
|
}
|
|
1234
|
-
const oc = (
|
|
1301
|
+
const oc = (_e = character.origin_choices) != null ? _e : {};
|
|
1235
1302
|
if (originFeat) {
|
|
1236
1303
|
const read = (childId) => oc[`background:feat:${childId}`];
|
|
1237
1304
|
spells.push(...collectFeatGrantedSpells(originFeat.feat, read, this.entities, warnings));
|
|
1238
1305
|
}
|
|
1239
|
-
for (const
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1306
|
+
for (const rf of raceFeats) spells.push(...collectFeatGrantedSpells(rf.feat, rf.read, this.entities, warnings));
|
|
1307
|
+
for (const site of featSites) {
|
|
1308
|
+
const reg = this.entities.getByTypeAndSlug("feat", site.slug);
|
|
1309
|
+
if (!reg) continue;
|
|
1310
|
+
const feat = reg.data;
|
|
1311
|
+
spells.push(...collectFeatGrantedSpells(feat, site.read, this.entities, warnings));
|
|
1312
|
+
}
|
|
1313
|
+
for (const site of memberSites) {
|
|
1314
|
+
const classSlug = stripSlug((_g = (_f = character.class[site.classIndex]) == null ? void 0 : _f.name) != null ? _g : null);
|
|
1315
|
+
for (const ch of site.choices) {
|
|
1316
|
+
if (ch.kind !== "select-entity" || ch.entity_type !== "spell" || isTargetChoice(ch)) continue;
|
|
1317
|
+
const v = site.read(ch.id);
|
|
1318
|
+
for (const ref of Array.isArray(v) ? v : typeof v === "string" ? [v] : []) {
|
|
1319
|
+
const slug = typeof ref === "string" ? stripSlug(ref) : null;
|
|
1320
|
+
if (!slug) continue;
|
|
1321
|
+
const reg = this.entities.getByTypeAndSlug("spell", slug);
|
|
1322
|
+
if (!reg) {
|
|
1323
|
+
warnings.push(`Spell [[${slug}]] not found in compendium.`);
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
const entity = mirrorSpellShapes(reg.data);
|
|
1327
|
+
spells.push({ entity, slug, classSlug, source: "class", prepared: true, alwaysPrepared: true });
|
|
1328
|
+
}
|
|
1250
1329
|
}
|
|
1251
1330
|
}
|
|
1252
|
-
const ownSpellcastingAbility = (
|
|
1331
|
+
const ownSpellcastingAbility = (_h = classes.map((c) => {
|
|
1253
1332
|
if (!c.entity) return null;
|
|
1254
1333
|
const p = resolveSpellcasting(c);
|
|
1255
1334
|
return p ? effectiveSpellcastingAbility(c.entity.slug, p.ability, character.overrides) : null;
|
|
1256
|
-
}).find((a) => a != null)) != null ?
|
|
1335
|
+
}).find((a) => a != null)) != null ? _h : null;
|
|
1257
1336
|
spells.push(...collectItemGrantedSpells(character, ownSpellcastingAbility, this.entities, warnings));
|
|
1258
|
-
spells.push(...collectAdditionalSpells({
|
|
1259
|
-
race,
|
|
1260
|
-
feats,
|
|
1261
|
-
classes,
|
|
1262
|
-
totalLevel,
|
|
1263
|
-
ownAbility: ownSpellcastingAbility,
|
|
1264
|
-
alreadyCollected: spells,
|
|
1265
|
-
entities: this.entities,
|
|
1266
|
-
warnings
|
|
1267
|
-
}));
|
|
1268
1337
|
const chosenMasteries = collectChosenWeaponMasteries(character);
|
|
1269
1338
|
if (chosenMasteries.full.length > 0) {
|
|
1270
1339
|
const target = features.find(
|
|
@@ -1296,14 +1365,29 @@ var PCResolver = class {
|
|
|
1296
1365
|
...originFeatSlug ? { originFeatSlug } : {},
|
|
1297
1366
|
totalLevel,
|
|
1298
1367
|
features,
|
|
1299
|
-
spells:
|
|
1368
|
+
spells: [],
|
|
1300
1369
|
pools: [],
|
|
1301
1370
|
resources: featureResources,
|
|
1302
1371
|
weaponMasteries: chosenMasteries.bare,
|
|
1303
1372
|
state: character.state
|
|
1304
1373
|
};
|
|
1305
1374
|
resolvedCharacter.pools = resolveAllPools(resolvedCharacter, this.entities, featureResources);
|
|
1375
|
+
spells.push(...collectAdditionalSpells({
|
|
1376
|
+
race,
|
|
1377
|
+
feats,
|
|
1378
|
+
classes,
|
|
1379
|
+
totalLevel,
|
|
1380
|
+
ownAbility: ownSpellcastingAbility,
|
|
1381
|
+
alreadyCollected: spells,
|
|
1382
|
+
entities: this.entities,
|
|
1383
|
+
warnings,
|
|
1384
|
+
// SRD-G T4: the race's lineage and spellcasting-ability picks select and qualify its spell blocks.
|
|
1385
|
+
raceChoice: (id) => oc[`race:${id}`],
|
|
1386
|
+
pools: resolvedCharacter.pools
|
|
1387
|
+
}));
|
|
1388
|
+
resolvedCharacter.spells = dedupeResolvedSpells(spells);
|
|
1306
1389
|
resolvedCharacter.resources = resolveResourceIndex(resolvedCharacter);
|
|
1390
|
+
resolvedCharacter.features = bindFeatureConsumers(resolvedCharacter.features, resolvedCharacter.resources, classes);
|
|
1307
1391
|
const infusions = buildInfusionContext(character, resolvedCharacter, this.entities);
|
|
1308
1392
|
if (infusions) resolvedCharacter.infusions = infusions;
|
|
1309
1393
|
return { character: resolvedCharacter, warnings };
|
|
@@ -1324,16 +1408,9 @@ function collectChosenWeaponMasteries(character) {
|
|
|
1324
1408
|
}
|
|
1325
1409
|
function collectFeatPicks(character) {
|
|
1326
1410
|
const picks = /* @__PURE__ */ new Map();
|
|
1327
|
-
character.class
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
if (typeof feat === "string") {
|
|
1331
|
-
const s = stripSlug(feat);
|
|
1332
|
-
const level = /^\d+$/.test(lvl) ? Number(lvl) : null;
|
|
1333
|
-
if (s && !picks.has(s)) picks.set(s, { slug: s, classIndex, level });
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
});
|
|
1411
|
+
for (const site of featPickSites(character.class, [], () => null)) {
|
|
1412
|
+
if (!picks.has(site.slug)) picks.set(site.slug, { slug: site.slug, classIndex: site.classIndex, level: site.level });
|
|
1413
|
+
}
|
|
1337
1414
|
return [...picks.values()];
|
|
1338
1415
|
}
|
|
1339
1416
|
function collectFeatGrantedSpells(feat, read, entities, warnings) {
|
|
@@ -1379,7 +1456,7 @@ function collectItemGrantedSpells(character, ownAbility, entities, warnings) {
|
|
|
1379
1456
|
function dedupeResolvedSpells(spells) {
|
|
1380
1457
|
const byKey = /* @__PURE__ */ new Map();
|
|
1381
1458
|
for (const s of spells) {
|
|
1382
|
-
const key = s.source === "item" ? `${s.slug}#${s.entryIndex}` : s.slug;
|
|
1459
|
+
const key = s.source === "item" ? `${s.slug}#${s.entryIndex}` : s.atWill ? `${s.slug}#atwill` : s.slug;
|
|
1383
1460
|
const existing = byKey.get(key);
|
|
1384
1461
|
if (!existing) {
|
|
1385
1462
|
byKey.set(key, s);
|
|
@@ -1410,11 +1487,21 @@ function collectSpellPickSlugs(choices, read, out) {
|
|
|
1410
1487
|
}
|
|
1411
1488
|
}
|
|
1412
1489
|
}
|
|
1413
|
-
function collectChosenGrantedFeatures(character, classes, registry, race = null, background = null) {
|
|
1414
|
-
var _a, _b;
|
|
1490
|
+
function collectChosenGrantedFeatures(character, classes, registry, race = null, background = null, memberSites = []) {
|
|
1491
|
+
var _a, _b, _c, _d;
|
|
1415
1492
|
const out = [];
|
|
1493
|
+
for (const site of memberSites) {
|
|
1494
|
+
const classSlug = (_b = (_a = classes[site.classIndex]) == null ? void 0 : _a.entity) == null ? void 0 : _b.slug;
|
|
1495
|
+
if (!classSlug) continue;
|
|
1496
|
+
const at = {};
|
|
1497
|
+
const grants = site.choices.filter((ch) => !isTargetChoice(ch));
|
|
1498
|
+
for (const ch of grants) at[ch.id] = site.read(ch.id);
|
|
1499
|
+
walkChoiceGrants(grants, at, (granted, suppress) => {
|
|
1500
|
+
out.push({ feature: granted, source: { kind: "class", slug: classSlug, level: site.level }, ...suppress ? { renderSuppressed: true } : {} });
|
|
1501
|
+
}, registry);
|
|
1502
|
+
}
|
|
1416
1503
|
classes.forEach((c, i) => {
|
|
1417
|
-
var _a2, _b2,
|
|
1504
|
+
var _a2, _b2, _c2, _d2;
|
|
1418
1505
|
if (!c.entity) return;
|
|
1419
1506
|
const entity = c.entity;
|
|
1420
1507
|
const entry = character.class[i];
|
|
@@ -1423,7 +1510,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1423
1510
|
const lvl = Number(lvlStr);
|
|
1424
1511
|
if (!Number.isFinite(lvl) || lvl > entry.level) continue;
|
|
1425
1512
|
const features = (_b2 = ((_a2 = entity.features_by_level) != null ? _a2 : {})[lvl]) != null ? _b2 : [];
|
|
1426
|
-
const subFeatures = c.subclass ? (
|
|
1513
|
+
const subFeatures = c.subclass ? (_d2 = ((_c2 = c.subclass.features_by_level) != null ? _c2 : {})[lvl]) != null ? _d2 : [] : [];
|
|
1427
1514
|
for (const feature of [...features, ...subFeatures]) {
|
|
1428
1515
|
walkChoiceGrants(feature.choices, atLevel, (granted, suppress) => {
|
|
1429
1516
|
out.push({
|
|
@@ -1435,7 +1522,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1435
1522
|
}
|
|
1436
1523
|
}
|
|
1437
1524
|
});
|
|
1438
|
-
const oc = (
|
|
1525
|
+
const oc = (_c = character.origin_choices) != null ? _c : {};
|
|
1439
1526
|
const originAt = (ns) => {
|
|
1440
1527
|
const at = {};
|
|
1441
1528
|
for (const [key, val] of Object.entries(oc)) {
|
|
@@ -1453,7 +1540,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1453
1540
|
});
|
|
1454
1541
|
};
|
|
1455
1542
|
walkChoiceGrants(race.choices, atRace, emitRace, registry);
|
|
1456
|
-
for (const trait of (
|
|
1543
|
+
for (const trait of (_d = race.traits) != null ? _d : []) {
|
|
1457
1544
|
walkChoiceGrants(trait.choices, atRace, emitRace, registry);
|
|
1458
1545
|
}
|
|
1459
1546
|
}
|
|
@@ -1745,6 +1832,7 @@ export {
|
|
|
1745
1832
|
__categoryToEntitySelectForTest,
|
|
1746
1833
|
collectChosenProficiencies,
|
|
1747
1834
|
computeEffectiveProficiencies,
|
|
1835
|
+
computeSuppressedProficiencies,
|
|
1748
1836
|
collectChosenAbilityPoints,
|
|
1749
1837
|
buildDecisionLedger
|
|
1750
1838
|
};
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-ZJXSXVFP.js";
|
|
5
5
|
import {
|
|
6
6
|
choiceSchema
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OOL4KMG2.js";
|
|
8
8
|
import {
|
|
9
9
|
featureEffectSchema
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JXWNXIIZ.js";
|
|
11
11
|
import {
|
|
12
12
|
additionalSpellsEntrySchema,
|
|
13
13
|
imageField,
|
|
@@ -4,9 +4,29 @@ var abilityEnum = z.enum(["str", "dex", "con", "int", "wis", "cha"]);
|
|
|
4
4
|
var subjectField = z.string().min(1).optional();
|
|
5
5
|
var conditionField = z.string().optional();
|
|
6
6
|
var weaponScopeEnum = z.enum(["weapon", "melee", "ranged", "unarmed", "finesse", "thrown"]);
|
|
7
|
+
var spellScopeSchema = z.object({
|
|
8
|
+
list: z.string().min(1).optional(),
|
|
9
|
+
level: z.number().int().min(0).max(9).optional(),
|
|
10
|
+
school: z.string().min(1).optional(),
|
|
11
|
+
damage_types: z.array(z.string().min(1)).min(1).optional(),
|
|
12
|
+
damage_type_pick: z.string().min(1).optional(),
|
|
13
|
+
spells: z.array(z.string().min(1)).min(1).optional(),
|
|
14
|
+
once: z.boolean().optional()
|
|
15
|
+
}).strict();
|
|
7
16
|
var featureEffectSchema = z.discriminatedUnion("kind", [
|
|
8
17
|
z.object({ kind: z.literal("initiative-bonus"), value: z.number().int(), condition: conditionField, subject: subjectField }),
|
|
9
18
|
z.object({ kind: z.literal("skill-bonus"), skills: z.array(z.string().min(1)).nonempty(), ability: abilityEnum, minimum: z.number().int().optional(), condition: conditionField, subject: subjectField }),
|
|
19
|
+
// SL (2026-09-27): the `skill-bonus` twin for saving throws (Aura of Protection). `saves` absent = every save; `inactive_while` turns
|
|
20
|
+
// the bonus off while the character is incapacitated (any condition that disables actions) or unconscious.
|
|
21
|
+
z.object({
|
|
22
|
+
kind: z.literal("save-bonus"),
|
|
23
|
+
ability: abilityEnum,
|
|
24
|
+
minimum: z.number().int().optional(),
|
|
25
|
+
saves: z.array(abilityEnum).nonempty().optional(),
|
|
26
|
+
inactive_while: z.enum(["incapacitated", "unconscious"]).optional(),
|
|
27
|
+
condition: conditionField,
|
|
28
|
+
subject: subjectField
|
|
29
|
+
}),
|
|
10
30
|
// Jack of All Trades / Remarkable Athlete: half the proficiency bonus, and ONLY on a skill the character is
|
|
11
31
|
// not already proficient in — the "doesn't otherwise use your Proficiency Bonus" clause is the whole mechanic,
|
|
12
32
|
// so it is the kind's semantics, not a field. `skills` omitted = every skill (Jack of All Trades); a list
|
|
@@ -72,6 +92,10 @@ var featureEffectSchema = z.discriminatedUnion("kind", [
|
|
|
72
92
|
// ART-c1 Task 9b: `spell` and `all` as before, or a weapon scope, one word or an any-of list, which the engine
|
|
73
93
|
// evaluates per attack row (pc.recalc.ts `riderReachesRow`). `weapon`, like an absent value, reaches every row.
|
|
74
94
|
applies_to: z.union([z.enum(["spell", "all"]), weaponScopeEnum, z.array(weaponScopeEnum).min(1)]).optional(),
|
|
95
|
+
// The spells a `spell` or `all` rider reaches (Potent Spellcasting's Cleric cantrips, Empowered Evocation's Wizard
|
|
96
|
+
// evocation spells); pc.recalc.ts `spellsInScope` reads it. A `spell` rider without one reaches only the spells its
|
|
97
|
+
// pool member's data names (Agonizing Blast's target pick); an `all` rider without one reaches every damaging spell.
|
|
98
|
+
spell_scope: spellScopeSchema.optional(),
|
|
75
99
|
condition: conditionField,
|
|
76
100
|
subject: subjectField
|
|
77
101
|
}),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/pc/spell-source.ts
|
|
2
|
+
var SPELL_SOURCE = {
|
|
3
|
+
class: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false },
|
|
4
|
+
feat: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
|
|
5
|
+
item: { ownAbility: false, section: "consumable", freeCastWhenNoSlot: false, showInPrepare: false, countsAsGranted: true },
|
|
6
|
+
race: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
|
|
7
|
+
domain: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false }
|
|
8
|
+
};
|
|
9
|
+
var spellSource = (s) => SPELL_SOURCE[s.source];
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
SPELL_SOURCE,
|
|
13
|
+
spellSource
|
|
14
|
+
};
|