@archivist-gg/dnd5e 0.3.11 → 0.3.17
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/LICENSES/SRD.md +38 -3
- package/dist/armor/armor.codec.js +3 -3
- package/dist/armor/armor.parser.js +2 -2
- package/dist/armor/armor.schema.d.ts +1 -0
- package/dist/armor/armor.schema.js +1 -1
- package/dist/armor/armor.types.d.ts +2 -0
- 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-XTRDCSJB.js → chunk-2JSQE3DD.js} +15 -1
- package/dist/chunk-2LULMQTF.js +14 -0
- package/dist/{chunk-MAH6DCRI.js → chunk-2UDSN6VW.js} +1 -1
- package/dist/chunk-3LWMFYKS.js +57 -0
- package/dist/{chunk-JCEV7KYN.js → chunk-3MGQFFNE.js} +1 -1
- package/dist/chunk-3VZZDKRA.js +1014 -0
- package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
- package/dist/{chunk-2M34FLAY.js → chunk-5MXFW4O3.js} +9 -3
- package/dist/{chunk-4DOMDEBZ.js → chunk-6EI737IO.js} +1 -1
- package/dist/{chunk-G247QXWW.js → chunk-7ATNGKBS.js} +1 -1
- package/dist/{chunk-XY6X2APM.js → chunk-7Q2VPKCD.js} +17 -0
- package/dist/{chunk-T2SNEJOE.js → chunk-7QN7XSAK.js} +1 -1
- package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
- package/dist/{chunk-7YU4NPKR.js → chunk-AZRGFUSR.js} +1 -1
- package/dist/{chunk-PP2UHLBA.js → chunk-B3DP42OM.js} +5 -0
- package/dist/chunk-CM5CWO4K.js +735 -0
- package/dist/{chunk-MQ747UCR.js → chunk-DOXSFYLH.js} +70 -2
- package/dist/chunk-EJP263OP.js +186 -0
- package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
- package/dist/{chunk-V6LJFP4R.js → chunk-FANQVQ3D.js} +2 -2
- package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
- package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
- package/dist/{chunk-JANNRGJC.js → chunk-G6PBI2BU.js} +1 -1
- package/dist/chunk-H5PTKYXL.js +101 -0
- package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
- package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
- package/dist/chunk-HTYMW5CH.js +228 -0
- package/dist/chunk-IHE6KVC3.js +13 -0
- package/dist/{chunk-QHMWA3SZ.js → chunk-JCMUVZIK.js} +1 -1
- package/dist/{chunk-V373TRJE.js → chunk-JSM6JFZR.js} +198 -125
- package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
- package/dist/chunk-KR6JF3BF.js +14 -0
- package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
- package/dist/chunk-LBEXLN6I.js +91 -0
- package/dist/{chunk-BLRW2UU6.js → chunk-LF5AGJA4.js} +2 -2
- package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
- package/dist/{chunk-BIA32MQ5.js → chunk-MBX25B6D.js} +1 -1
- package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
- package/dist/{chunk-J77CKYV3.js → chunk-OFCSP6MT.js} +1 -1
- package/dist/{chunk-2INMRR3Q.js → chunk-ONTGZR5T.js} +326 -149
- package/dist/{chunk-MWCCGPG3.js → chunk-OOSRUJBI.js} +3 -2
- package/dist/{chunk-U3BABVJF.js → chunk-PKX6TGRE.js} +2 -2
- package/dist/{chunk-PJMG5XV3.js → chunk-PQZ4LM4Z.js} +1 -1
- package/dist/chunk-PXVNAY7T.js +84 -0
- package/dist/chunk-QH36K2PU.js +158 -0
- package/dist/{chunk-R747YKS7.js → chunk-QZSWN2KT.js} +1 -1
- package/dist/{chunk-CHUALUIX.js → chunk-RYLXAYIQ.js} +1 -1
- package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
- package/dist/{chunk-PZCE7DJM.js → chunk-T6QIF5XR.js} +31 -1
- package/dist/{chunk-CBEKVAX4.js → chunk-TULQ4FFX.js} +41 -13
- package/dist/{chunk-S56D6B6C.js → chunk-UUBJCNQU.js} +12 -3
- package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
- package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
- package/dist/{chunk-3HX5VLWP.js → chunk-VRV3NNTA.js} +2 -2
- package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
- package/dist/{chunk-BL3VELKP.js → chunk-Y5VVP73C.js} +1 -1
- package/dist/{chunk-PI4LLJG4.js → chunk-YD2VAHA6.js} +2 -2
- package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
- package/dist/{chunk-NWDF5HG3.js → chunk-YKL6SHRJ.js} +1 -1
- package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
- package/dist/chunk-ZUQW5VBZ.js +89 -0
- package/dist/class/class.codec.js +7 -7
- package/dist/class/class.parser.js +6 -6
- package/dist/class/class.schema.d.ts +18 -0
- package/dist/class/class.schema.js +5 -5
- 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 +38 -0
- package/dist/dnd/amount-text.js +13 -0
- package/dist/dnd/resource-words.d.ts +4 -0
- package/dist/dnd/resource-words.js +30 -0
- package/dist/entities/base-item-resolver.js +2 -2
- package/dist/entities/slug.d.ts +18 -8
- package/dist/entities/slug.js +3 -1
- package/dist/feat/feat.codec.js +5 -5
- package/dist/feat/feat.parser.js +4 -4
- package/dist/feat/feat.schema.d.ts +41 -3
- package/dist/feat/feat.schema.js +3 -3
- package/dist/index.js +7513 -4177
- package/dist/item/item.actions-map.d.ts +40 -5
- package/dist/item/item.actions-map.js +5 -84
- package/dist/item/item.attunement.js +3 -9
- package/dist/item/item.bonuses.js +5 -2
- package/dist/item/item.codec.js +3 -3
- package/dist/item/item.conditions.js +4 -1
- package/dist/item/item.conditions.types.d.ts +4 -0
- package/dist/item/item.cost.d.ts +3 -0
- package/dist/item/item.cost.js +29 -0
- package/dist/item/item.icon.d.ts +15 -0
- package/dist/item/item.icon.js +211 -0
- package/dist/item/item.parser.js +2 -2
- package/dist/item/item.schema.d.ts +16 -1
- package/dist/item/item.schema.js +3 -1
- package/dist/item/item.types.d.ts +9 -2
- 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 +255 -3
- package/dist/optional-feature/optional-feature.schema.js +7 -2
- package/dist/pc/pc.additional-spells.js +3 -3
- package/dist/pc/pc.amount-bindings.d.ts +32 -0
- package/dist/pc/pc.amount-bindings.js +23 -0
- package/dist/pc/pc.asi-flatten.d.ts +62 -1
- package/dist/pc/pc.asi-flatten.js +16 -0
- package/dist/pc/pc.conditions.js +1 -1
- package/dist/pc/pc.containment.d.ts +45 -0
- package/dist/pc/pc.containment.js +24 -0
- package/dist/pc/pc.decision-engine.d.ts +24 -3
- package/dist/pc/pc.decision-engine.js +26 -16
- package/dist/pc/pc.entry-overrides.d.ts +79 -0
- package/dist/pc/pc.entry-overrides.js +40 -0
- package/dist/pc/pc.equipment.d.ts +2 -2
- package/dist/pc/pc.equipment.js +19 -7
- package/dist/pc/pc.feature-effects.d.ts +12 -0
- package/dist/pc/pc.feature-effects.js +2 -2
- package/dist/pc/pc.infusions.d.ts +228 -0
- package/dist/pc/pc.infusions.js +64 -0
- package/dist/pc/pc.member-choices.d.ts +90 -0
- package/dist/pc/pc.member-choices.js +32 -0
- package/dist/pc/pc.parser.js +18 -1
- package/dist/pc/pc.pools.d.ts +8 -1
- package/dist/pc/pc.pools.js +13 -3
- package/dist/pc/pc.proficiencies.js +23 -15
- package/dist/pc/pc.proficiency-query.js +6 -0
- package/dist/pc/pc.recalc.d.ts +39 -36
- package/dist/pc/pc.recalc.js +115 -70
- package/dist/pc/pc.resolver.d.ts +2 -1
- package/dist/pc/pc.resolver.js +22 -14
- package/dist/pc/pc.resource-seed.js +1 -1
- package/dist/pc/pc.resources.d.ts +6 -1
- package/dist/pc/pc.resources.js +3 -1
- package/dist/pc/pc.rest.d.ts +21 -1
- package/dist/pc/pc.rest.js +52 -19
- package/dist/pc/pc.schema.d.ts +43 -2
- package/dist/pc/pc.schema.js +1 -1
- package/dist/pc/pc.slotting.d.ts +36 -3
- package/dist/pc/pc.slotting.js +13 -5
- package/dist/pc/pc.tool-picks.d.ts +51 -0
- package/dist/pc/pc.tool-picks.js +18 -0
- package/dist/pc/pc.types.d.ts +115 -14
- package/dist/pc/pc.weapon-grant.d.ts +15 -0
- package/dist/pc/pool-layout.d.ts +8 -0
- package/dist/pc/pool-layout.js +5 -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/attack-schema.d.ts +1 -1
- package/dist/schemas/choice-schema.js +2 -2
- package/dist/schemas/feature-effect-schema.d.ts +41 -3
- package/dist/schemas/feature-effect-schema.js +1 -1
- package/dist/schemas/feature-schema.js +3 -3
- package/dist/schemas/selection-pool-schema.d.ts +10 -0
- package/dist/schemas/selection-pool-schema.js +1 -1
- 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/srd/retired-items.d.ts +14 -0
- package/dist/srd/retired-items.js +11 -0
- package/dist/subclass/subclass.codec.js +7 -7
- package/dist/subclass/subclass.parser.js +6 -6
- package/dist/subclass/subclass.schema.d.ts +10 -0
- package/dist/subclass/subclass.schema.js +5 -5
- package/dist/types/choice.d.ts +13 -0
- package/dist/types/equipment-grant.d.ts +18 -1
- package/dist/types/equipment-grant.js +12 -0
- package/dist/types/feature-effect.d.ts +12 -1
- package/dist/types/optional-feature.types.d.ts +84 -1
- package/dist/types/selection-pool.d.ts +18 -3
- package/dist/weapon/weapon.classify.d.ts +10 -8
- package/dist/weapon/weapon.classify.js +2 -2
- package/dist/weapon/weapon.codec.js +3 -3
- package/dist/weapon/weapon.parser.js +2 -2
- package/dist/weapon/weapon.schema.d.ts +1 -0
- package/dist/weapon/weapon.schema.js +1 -1
- package/dist/weapon/weapon.types.d.ts +2 -0
- package/package.json +1 -1
- package/dist/chunk-O4SRD3J5.js +0 -165
- package/dist/chunk-WXWPK3LI.js +0 -55
|
@@ -1,7 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
equipmentCategoryKey,
|
|
3
|
+
isCategoryGrant
|
|
4
|
+
} from "./chunk-2LULMQTF.js";
|
|
5
|
+
import {
|
|
6
|
+
TOOL_CATEGORIES,
|
|
7
|
+
backgroundToolPicks,
|
|
8
|
+
categoryWords,
|
|
9
|
+
classToolPicks,
|
|
10
|
+
expandToolPool,
|
|
11
|
+
toolCategoriesOf
|
|
12
|
+
} from "./chunk-H5PTKYXL.js";
|
|
13
|
+
import {
|
|
14
|
+
assembleEffectFeatures,
|
|
15
|
+
collectProficiencyEffectGrants
|
|
16
|
+
} from "./chunk-TULQ4FFX.js";
|
|
17
|
+
import {
|
|
18
|
+
ALL_LANGUAGES,
|
|
19
|
+
ALL_SKILL_SLUGS,
|
|
20
|
+
ALL_TOOLS
|
|
21
|
+
} from "./chunk-KU3YLF6D.js";
|
|
22
|
+
import {
|
|
23
|
+
featOfSite,
|
|
24
|
+
featPickSites,
|
|
25
|
+
isTargetChoice,
|
|
26
|
+
memberChoices,
|
|
27
|
+
poolMemberSites,
|
|
28
|
+
poolMemberSitesOf
|
|
29
|
+
} from "./chunk-HTYMW5CH.js";
|
|
1
30
|
import {
|
|
2
31
|
resolveFeatureResources,
|
|
3
32
|
resolveResourceIndex
|
|
4
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-KSTV7J2U.js";
|
|
5
34
|
import {
|
|
6
35
|
attributeUnclassedSpell,
|
|
7
36
|
effectiveSpellcastingAbility,
|
|
@@ -9,9 +38,22 @@ import {
|
|
|
9
38
|
resolveSpellcasting
|
|
10
39
|
} from "./chunk-DPUJDOKV.js";
|
|
11
40
|
import {
|
|
41
|
+
convertibleLegacyAsi,
|
|
42
|
+
flattenAsiOrFeat,
|
|
43
|
+
resolveLegacyAsiFeat
|
|
44
|
+
} from "./chunk-LBEXLN6I.js";
|
|
45
|
+
import {
|
|
46
|
+
humanizeProficiency,
|
|
47
|
+
proficiencyLabel,
|
|
48
|
+
toProfSlug
|
|
49
|
+
} from "./chunk-RLGQ5PZZ.js";
|
|
50
|
+
import {
|
|
51
|
+
bindFeatureConsumers,
|
|
52
|
+
buildInfusionContext,
|
|
12
53
|
resolveAllPools,
|
|
54
|
+
resolveOptionRows,
|
|
13
55
|
strandedPicks
|
|
14
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-3VZZDKRA.js";
|
|
15
57
|
import {
|
|
16
58
|
countColumnsFor,
|
|
17
59
|
readTableColumn
|
|
@@ -21,42 +63,28 @@ import {
|
|
|
21
63
|
} from "./chunk-YHYTW5QA.js";
|
|
22
64
|
import {
|
|
23
65
|
collectAdditionalSpells
|
|
24
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-VRV3NNTA.js";
|
|
25
67
|
import {
|
|
26
68
|
isItemEntity,
|
|
27
69
|
resolveEntityForEntry
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import {
|
|
30
|
-
assembleEffectFeatures,
|
|
31
|
-
collectProficiencyEffectGrants
|
|
32
|
-
} from "./chunk-CBEKVAX4.js";
|
|
33
|
-
import {
|
|
34
|
-
ALL_LANGUAGES,
|
|
35
|
-
ALL_SKILL_SLUGS,
|
|
36
|
-
ALL_TOOLS
|
|
37
|
-
} from "./chunk-KU3YLF6D.js";
|
|
38
|
-
import {
|
|
39
|
-
humanizeProficiency,
|
|
40
|
-
proficiencyLabel,
|
|
41
|
-
toProfSlug
|
|
42
|
-
} from "./chunk-RLGQ5PZZ.js";
|
|
43
|
-
import {
|
|
44
|
-
warnOnce
|
|
45
|
-
} from "./chunk-LVQLWRCU.js";
|
|
46
|
-
import {
|
|
47
|
-
bareEntitySlug,
|
|
48
|
-
wikilinkTailSlug
|
|
49
|
-
} from "./chunk-6X4KUDMU.js";
|
|
70
|
+
} from "./chunk-LHZXYFBU.js";
|
|
50
71
|
import {
|
|
51
72
|
FEATURE_TYPE_FOR_CATEGORY,
|
|
52
73
|
featProgressionCategory
|
|
53
74
|
} from "./chunk-YBLDE5CG.js";
|
|
75
|
+
import {
|
|
76
|
+
warnOnce
|
|
77
|
+
} from "./chunk-LVQLWRCU.js";
|
|
54
78
|
import {
|
|
55
79
|
isValidMaxFormula
|
|
56
80
|
} from "./chunk-EVMUJYUD.js";
|
|
81
|
+
import {
|
|
82
|
+
bareEntitySlug,
|
|
83
|
+
wikilinkTailSlug
|
|
84
|
+
} from "./chunk-ZCTUYGNV.js";
|
|
57
85
|
import {
|
|
58
86
|
mirrorSpellShapes
|
|
59
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-7Q2VPKCD.js";
|
|
60
88
|
import {
|
|
61
89
|
ABILITY_KEYS
|
|
62
90
|
} from "./chunk-WELIKLZF.js";
|
|
@@ -80,6 +108,7 @@ function collectProficiencyGrants(resolved) {
|
|
|
80
108
|
for (const w of (_f = (_e = prof.weapons) == null ? void 0 : _e.fixed) != null ? _f : []) classWeaponFixed.push({ value: w, source });
|
|
81
109
|
for (const w of (_h = (_g = prof.weapons) == null ? void 0 : _g.categories) != null ? _h : []) classWeaponCategories.push({ value: w, source });
|
|
82
110
|
for (const t of (_j = (_i = prof.tools) == null ? void 0 : _i.fixed) != null ? _j : []) classToolFixed.push({ value: t, source });
|
|
111
|
+
for (const t of classToolPicks(c.entity).grants) classToolFixed.push({ value: t, source });
|
|
83
112
|
}
|
|
84
113
|
const raceSource = (_l = (_k = resolved.race) == null ? void 0 : _k.name) != null ? _l : UNKNOWN_SOURCE;
|
|
85
114
|
const raceLangFixed = ((_o = (_n = (_m = resolved.race) == null ? void 0 : _m.languages) == null ? void 0 : _n.fixed) != null ? _o : []).map(
|
|
@@ -95,6 +124,7 @@ function collectProficiencyGrants(resolved) {
|
|
|
95
124
|
for (const t of entry.items) bgToolFixed.push({ value: t, source });
|
|
96
125
|
}
|
|
97
126
|
}
|
|
127
|
+
for (const t of backgroundToolPicks(bg).grants) bgToolFixed.push({ value: t, source });
|
|
98
128
|
for (const entry of (_r = bg.language_proficiencies) != null ? _r : []) {
|
|
99
129
|
if (entry.kind === "fixed") {
|
|
100
130
|
for (const l of entry.languages) bgLangFixed.push({ value: l, source });
|
|
@@ -164,25 +194,18 @@ function collectProficiencyGrants(resolved) {
|
|
|
164
194
|
};
|
|
165
195
|
}
|
|
166
196
|
|
|
167
|
-
// src/pc/pc.asi-flatten.ts
|
|
168
|
-
function flattenAsiOrFeat(choice) {
|
|
169
|
-
var _a;
|
|
170
|
-
if (choice.kind !== "select-inline" || choice.id !== "asi-or-feat") return choice;
|
|
171
|
-
const featBranches = choice.options.filter((o) => {
|
|
172
|
-
var _a2;
|
|
173
|
-
return ((_a2 = o.choices) != null ? _a2 : []).some((c) => c.kind === "select-entity" && c.entity_type === "feat");
|
|
174
|
-
});
|
|
175
|
-
if (featBranches.length !== 1) return choice;
|
|
176
|
-
const inner = (_a = featBranches[0].choices) != null ? _a : [];
|
|
177
|
-
if (inner.length !== 1) return choice;
|
|
178
|
-
const only = inner[0];
|
|
179
|
-
if (only.kind !== "select-entity" || only.entity_type !== "feat") return choice;
|
|
180
|
-
return only;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
197
|
// src/pc/pc.decision-engine.ts
|
|
184
198
|
var warnedDegradedEquipment = /* @__PURE__ */ new Set();
|
|
185
199
|
var warnedAmbiguousBare = /* @__PURE__ */ new Set();
|
|
200
|
+
var foldedTypeMemo = /* @__PURE__ */ new Map();
|
|
201
|
+
function foldedType(s) {
|
|
202
|
+
let v = foldedTypeMemo.get(s);
|
|
203
|
+
if (v === void 0) {
|
|
204
|
+
v = categoryWords(s).join(" ");
|
|
205
|
+
foldedTypeMemo.set(s, v);
|
|
206
|
+
}
|
|
207
|
+
return v;
|
|
208
|
+
}
|
|
186
209
|
function matchesFilter(e, where, ownerBare) {
|
|
187
210
|
var _a, _b, _c, _d, _e;
|
|
188
211
|
const d = e.data;
|
|
@@ -191,6 +214,7 @@ function matchesFilter(e, where, ownerBare) {
|
|
|
191
214
|
if (where.list && !((_a = d.classes) != null ? _a : []).includes(where.list)) return false;
|
|
192
215
|
if (where.level !== void 0 && ((_b = d.level) != null ? _b : 0) !== where.level) return false;
|
|
193
216
|
if (where.edition && d.edition !== where.edition) return false;
|
|
217
|
+
if (where.ritual && d.ritual !== true) return false;
|
|
194
218
|
if (where.weapon_category) {
|
|
195
219
|
const cat = ((_c = d.category) != null ? _c : "").toLowerCase();
|
|
196
220
|
if (!cat.startsWith(`${where.weapon_category}-`) && cat !== where.weapon_category) return false;
|
|
@@ -198,6 +222,14 @@ function matchesFilter(e, where, ownerBare) {
|
|
|
198
222
|
if (where.armor_category) {
|
|
199
223
|
if (((_d = d.category) != null ? _d : "").toLowerCase() !== where.armor_category) return false;
|
|
200
224
|
}
|
|
225
|
+
if (where.item_type) {
|
|
226
|
+
const t = foldedType(typeof d.type === "string" ? d.type : "");
|
|
227
|
+
if (!t || !where.item_type.some((x) => foldedType(x) === t)) return false;
|
|
228
|
+
}
|
|
229
|
+
if (where.mundane) {
|
|
230
|
+
const r = typeof d.rarity === "string" ? d.rarity.trim().toLowerCase() : "";
|
|
231
|
+
if (r && r !== "none" && r !== "mundane") return false;
|
|
232
|
+
}
|
|
201
233
|
if (where.parent_class === "self") {
|
|
202
234
|
if (!d.parent_class || wikilinkTailSlug(d.parent_class) !== ownerBare) return false;
|
|
203
235
|
}
|
|
@@ -208,17 +240,94 @@ function matchesFilter(e, where, ownerBare) {
|
|
|
208
240
|
return true;
|
|
209
241
|
}
|
|
210
242
|
var __matchesFilterForTest = matchesFilter;
|
|
243
|
+
function parseEquipmentCategory(category) {
|
|
244
|
+
const tools = toolCategoriesOf(category);
|
|
245
|
+
if (tools) return { kind: "tool", tools };
|
|
246
|
+
const words = categoryWords(category).filter((w) => w !== "any");
|
|
247
|
+
const has = (w) => words.includes(w);
|
|
248
|
+
const only = (allowed) => words.every((w) => allowed.includes(w));
|
|
249
|
+
if (words.length === 1 && has("shield")) return { kind: "shield" };
|
|
250
|
+
if (has("armor") && only(["armor", "light", "medium", "heavy"]) && words.length <= 2) {
|
|
251
|
+
const armor = ["light", "medium", "heavy"].find((k) => has(k));
|
|
252
|
+
return { kind: "armor", armor };
|
|
253
|
+
}
|
|
254
|
+
if (has("weapon") && only(["weapon", "simple", "martial", "melee", "ranged"])) {
|
|
255
|
+
const klass = ["simple", "martial"].filter((k) => has(k));
|
|
256
|
+
const range = ["melee", "ranged"].filter((k) => has(k));
|
|
257
|
+
if (klass.length === 1 && range.length <= 1 && words.length === 2 + range.length) {
|
|
258
|
+
return { kind: "weapon", weapon: klass[0], range: range[0] };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return void 0;
|
|
262
|
+
}
|
|
211
263
|
function categoryToEntitySelect(category, id) {
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
264
|
+
const spec = parseEquipmentCategory(category);
|
|
265
|
+
const pick = { kind: "select-entity", id, count: 1 };
|
|
266
|
+
switch (spec == null ? void 0 : spec.kind) {
|
|
267
|
+
case "shield":
|
|
268
|
+
return { ...pick, label: "Choose a shield", entity_type: "armor", where: { armor_category: "shield" } };
|
|
269
|
+
case "armor":
|
|
270
|
+
return spec.armor ? { ...pick, label: `Choose ${spec.armor} armor`, entity_type: "armor", where: { armor_category: spec.armor } } : { ...pick, label: "Choose armor", entity_type: "armor" };
|
|
271
|
+
case "weapon":
|
|
272
|
+
return {
|
|
273
|
+
...pick,
|
|
274
|
+
label: `Choose a ${spec.weapon}${spec.range ? ` ${spec.range}` : ""} weapon`,
|
|
275
|
+
entity_type: "weapon",
|
|
276
|
+
where: { weapon_category: spec.weapon }
|
|
277
|
+
};
|
|
278
|
+
case "tool":
|
|
279
|
+
return {
|
|
280
|
+
...pick,
|
|
281
|
+
label: `Choose ${spec.tools.map((t) => TOOL_CATEGORIES[t].label).join(" or ")}`,
|
|
282
|
+
entity_type: "item",
|
|
283
|
+
where: { item_type: spec.tools.map((t) => TOOL_CATEGORIES[t].itemType), mundane: true }
|
|
284
|
+
};
|
|
285
|
+
default:
|
|
286
|
+
warnOnce(
|
|
287
|
+
`equipment-category:${category}`,
|
|
288
|
+
`Archivist: starting-equipment category "${category}" is not a known item category; its pick offers no options.`
|
|
289
|
+
);
|
|
290
|
+
return { ...pick, label: `Choose a ${category.replace(/[-_]+/g, " ")}`, entity_type: "item", from: [] };
|
|
215
291
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
292
|
+
}
|
|
293
|
+
var __categoryToEntitySelectForTest = categoryToEntitySelect;
|
|
294
|
+
function equipmentDecisions(entries, ownerSlug) {
|
|
295
|
+
const out = [];
|
|
296
|
+
let degraded = false;
|
|
297
|
+
(entries != null ? entries : []).forEach((eq, i) => {
|
|
298
|
+
var _a;
|
|
299
|
+
if ((eq == null ? void 0 : eq.kind) !== "choice") return;
|
|
300
|
+
const options = (_a = eq.options) != null ? _a : [];
|
|
301
|
+
out.push({
|
|
302
|
+
kind: "select-inline",
|
|
303
|
+
id: `equipment-${i}`,
|
|
304
|
+
label: "Starting Equipment",
|
|
305
|
+
count: 1,
|
|
306
|
+
options: options.map((opt, j) => {
|
|
307
|
+
var _a2;
|
|
308
|
+
const label = typeof opt === "string" ? opt : (_a2 = opt == null ? void 0 : opt.label) != null ? _a2 : "";
|
|
309
|
+
const wellFormed = !!opt && typeof opt === "object" && Array.isArray(opt.grants);
|
|
310
|
+
if (!wellFormed) degraded = true;
|
|
311
|
+
const grants = wellFormed ? opt.grants : [];
|
|
312
|
+
return {
|
|
313
|
+
value: `option-${j}`,
|
|
314
|
+
label,
|
|
315
|
+
choices: grants.flatMap((g, k) => isCategoryGrant(g) ? [categoryToEntitySelect(g.category, equipmentCategoryKey(i, j, k))] : [])
|
|
316
|
+
};
|
|
317
|
+
})
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
if (degraded && !warnedDegradedEquipment.has(ownerSlug)) {
|
|
321
|
+
warnedDegradedEquipment.add(ownerSlug);
|
|
322
|
+
console.warn(
|
|
323
|
+
`[archivist] Starting equipment for "${ownerSlug}" is in an outdated/unstructured format; its nested picks and seeding are skipped. Re-sync the compendium (delete _compendium.md and reload) to fix.`
|
|
324
|
+
);
|
|
219
325
|
}
|
|
220
|
-
|
|
221
|
-
|
|
326
|
+
return out;
|
|
327
|
+
}
|
|
328
|
+
function authoredProficiencyPool(choice) {
|
|
329
|
+
if (!choice.from) return void 0;
|
|
330
|
+
return choice.domain === "tool" ? expandToolPool(choice.from) : choice.from;
|
|
222
331
|
}
|
|
223
332
|
function enumerateOptions(choice, ctx, ownerBare) {
|
|
224
333
|
var _a, _b;
|
|
@@ -260,7 +369,7 @@ function enumerateOptions(choice, ctx, ownerBare) {
|
|
|
260
369
|
return filtered.map((e) => ({ value: e.slug, label: e.name, entity: e }));
|
|
261
370
|
}
|
|
262
371
|
case "select-proficiency": {
|
|
263
|
-
const pool = (_a = choice
|
|
372
|
+
const pool = (_a = authoredProficiencyPool(choice)) != null ? _a : choice.domain === "skill" ? [...ALL_SKILL_SLUGS] : choice.domain === "language" ? [...ALL_LANGUAGES] : choice.domain === "tool" ? [...ALL_TOOLS] : [];
|
|
264
373
|
return pool.map((v) => ({ value: v, label: humanizeProficiency(v) }));
|
|
265
374
|
}
|
|
266
375
|
case "ability-points": {
|
|
@@ -284,6 +393,12 @@ function requiredCount(choice) {
|
|
|
284
393
|
if (choice.kind === "select-proficiency") return choice.count;
|
|
285
394
|
return (_a = choice.count) != null ? _a : 1;
|
|
286
395
|
}
|
|
396
|
+
function capAtCount(choice, value) {
|
|
397
|
+
const folds = choice.kind === "select-proficiency" || choice.kind === "select-entity" && choice.entity_type === "weapon" && choice.id !== "weapon-mastery";
|
|
398
|
+
if (!folds || !Array.isArray(value)) return value;
|
|
399
|
+
const n = requiredCount(choice);
|
|
400
|
+
return value.length > n ? value.slice(0, n) : value;
|
|
401
|
+
}
|
|
287
402
|
function statusOf(choice, selected, satisfied) {
|
|
288
403
|
const n = selectionCount(choice, selected);
|
|
289
404
|
const need = requiredCount(choice);
|
|
@@ -317,7 +432,7 @@ function buildItem(inputChoice, source, level, featureName, readValue, ctx, owne
|
|
|
317
432
|
const keyPrefix = (_a = opts == null ? void 0 : opts.keyPrefix) != null ? _a : "";
|
|
318
433
|
const expandFeatChildren = (_b = opts == null ? void 0 : opts.expandFeatChildren) != null ? _b : true;
|
|
319
434
|
const key = keyPrefix + choice.id;
|
|
320
|
-
const raw = readValue(key);
|
|
435
|
+
const raw = capAtCount(choice, readValue(key));
|
|
321
436
|
const preExclusionOptions = enumerateOptions(choice, ctx, ownerBare);
|
|
322
437
|
let options = preExclusionOptions;
|
|
323
438
|
const mine = new Set(
|
|
@@ -422,8 +537,13 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
422
537
|
const originRead = (ns) => (id) => oc[`${ns}:${id}`];
|
|
423
538
|
const stripRef = (ref) => ref.replace(/^\[\[/, "").replace(/\]\]$/, "");
|
|
424
539
|
const featBySlug = new Map(((_b = resolved.feats) != null ? _b : []).map((f) => [f.slug, f]));
|
|
425
|
-
|
|
540
|
+
const memberSites = poolMemberSitesOf(resolved);
|
|
541
|
+
const featSites = featPickSites(resolved.classes, memberSites, (ci) => {
|
|
426
542
|
var _a2, _b2, _c2, _d;
|
|
543
|
+
return (_d = (_c2 = (_b2 = (_a2 = resolved.classes) == null ? void 0 : _a2[ci]) == null ? void 0 : _b2.entity) == null ? void 0 : _c2.slug) != null ? _d : null;
|
|
544
|
+
});
|
|
545
|
+
resolved.classes.forEach((c, i) => {
|
|
546
|
+
var _a2, _b2, _c2, _d, _e;
|
|
427
547
|
if (!c.entity) return;
|
|
428
548
|
const entity = c.entity;
|
|
429
549
|
const readAt = (lvl) => (id) => {
|
|
@@ -440,6 +560,7 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
440
560
|
}, readAt(1)("skills"));
|
|
441
561
|
}
|
|
442
562
|
if (i === 0) walk(entity.choices, readAt(1));
|
|
563
|
+
if (i === 0) walk(classToolPicks(entity).decisions, readAt(1));
|
|
443
564
|
for (const rf of resolved.features) {
|
|
444
565
|
if (rf.source.kind !== "class" && rf.source.kind !== "subclass") continue;
|
|
445
566
|
const belongs = rf.source.kind === "class" ? rf.source.slug === entity.slug : c.subclass != null && rf.source.slug === c.subclass.slug;
|
|
@@ -447,14 +568,13 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
447
568
|
for (const copy of (_c2 = rf.foldedFrom) != null ? _c2 : []) walk(copy.choices, readAt(copy.level));
|
|
448
569
|
walk(rf.feature.choices, readAt(rf.source.level));
|
|
449
570
|
}
|
|
450
|
-
for (const
|
|
451
|
-
|
|
452
|
-
const
|
|
453
|
-
if (!block || typeof featRef !== "string") continue;
|
|
454
|
-
const feat = featBySlug.get(stripRef(featRef));
|
|
571
|
+
for (const site of featSites) {
|
|
572
|
+
if (site.classIndex !== i) continue;
|
|
573
|
+
const feat = (_e = featBySlug.get(stripRef(site.slug))) != null ? _e : featOfSite(site, (_d = resolved.feats) != null ? _d : []);
|
|
455
574
|
if (!feat) continue;
|
|
456
|
-
walk(feat.choices,
|
|
575
|
+
walk(feat.choices, site.read);
|
|
457
576
|
}
|
|
577
|
+
for (const site of memberSites) if (site.classIndex === i) walk(site.choices, site.read);
|
|
458
578
|
});
|
|
459
579
|
if (resolved.race) {
|
|
460
580
|
walk(resolved.race.choices, originRead("race"));
|
|
@@ -462,6 +582,7 @@ function visitProficiencyChoices(resolved, visit) {
|
|
|
462
582
|
}
|
|
463
583
|
if (resolved.background) {
|
|
464
584
|
walk(resolved.background.choices, originRead("background"));
|
|
585
|
+
walk(backgroundToolPicks(resolved.background).decisions, originRead("background"));
|
|
465
586
|
if (resolved.background.feature) {
|
|
466
587
|
const feature = resolved.background.feature;
|
|
467
588
|
walk(feature.choices, originRead("background"));
|
|
@@ -476,7 +597,8 @@ var filterToPool = (vals, pool) => pool ? vals.map((v) => matchPool(v, pool)).fi
|
|
|
476
597
|
function collectChosenProficiencies(resolved) {
|
|
477
598
|
const out = { skills: [], expertise: [], languages: [], tools: [], weapons: [], saves: [] };
|
|
478
599
|
const isAbility = (v) => ABILITY_KEYS.includes(v);
|
|
479
|
-
visitProficiencyChoices(resolved, (choice,
|
|
600
|
+
visitProficiencyChoices(resolved, (choice, stored) => {
|
|
601
|
+
const selected = capAtCount(choice, stored);
|
|
480
602
|
const vals = Array.isArray(selected) ? selected : typeof selected === "string" ? [selected] : [];
|
|
481
603
|
if (choice.kind === "select-entity" && choice.entity_type === "weapon") {
|
|
482
604
|
if (choice.id === "weapon-mastery") return;
|
|
@@ -487,7 +609,7 @@ function collectChosenProficiencies(resolved) {
|
|
|
487
609
|
return;
|
|
488
610
|
}
|
|
489
611
|
if (choice.kind !== "select-proficiency") return;
|
|
490
|
-
const valid = filterToPool(vals, choice
|
|
612
|
+
const valid = filterToPool(vals, authoredProficiencyPool(choice));
|
|
491
613
|
if (choice.domain === "save") {
|
|
492
614
|
for (const v of valid) if (isAbility(v) && !out.saves.includes(v)) out.saves.push(v);
|
|
493
615
|
return;
|
|
@@ -589,7 +711,7 @@ function collectChosenAbilityPoints(resolved) {
|
|
|
589
711
|
return out;
|
|
590
712
|
}
|
|
591
713
|
function buildDecisionLedger(resolved, ctx) {
|
|
592
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
714
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
593
715
|
const eff = computeEffectiveProficiencies(resolved);
|
|
594
716
|
const chosen = collectChosenProficiencies(resolved);
|
|
595
717
|
const { features, activeBuffs } = assembleEffectFeatures(resolved);
|
|
@@ -614,7 +736,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
614
736
|
};
|
|
615
737
|
const classes = [];
|
|
616
738
|
resolved.classes.forEach((c, classIndex) => {
|
|
617
|
-
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2,
|
|
739
|
+
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o;
|
|
618
740
|
if (!c.entity) return;
|
|
619
741
|
const entity = c.entity;
|
|
620
742
|
const ownerBare = bareEntitySlug(entity.slug);
|
|
@@ -629,6 +751,19 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
629
751
|
var _a3;
|
|
630
752
|
return (_a3 = c.choices[lvl]) == null ? void 0 : _a3[id];
|
|
631
753
|
};
|
|
754
|
+
let legacyAsiFeat;
|
|
755
|
+
const legacyAsiReader = (choice, lvl) => {
|
|
756
|
+
const alloc = convertibleLegacyAsi(c.choices[lvl]);
|
|
757
|
+
if (!alloc) return null;
|
|
758
|
+
const flat = flattenAsiOrFeat(choice);
|
|
759
|
+
if (flat.kind !== "select-entity" || flat.entity_type !== "feat" || flat.from || flat.where) return null;
|
|
760
|
+
if (legacyAsiFeat === void 0) legacyAsiFeat = resolveLegacyAsiFeat(ctx.registry, entity);
|
|
761
|
+
const asi = legacyAsiFeat;
|
|
762
|
+
if (!asi) return null;
|
|
763
|
+
const raw = readAt(lvl);
|
|
764
|
+
const childKey = `feat:${asi.childId}`;
|
|
765
|
+
return (id) => id === "feat" ? asi.slug : id === childKey ? alloc : raw(id);
|
|
766
|
+
};
|
|
632
767
|
const featProgressions = [...(_a2 = entity.feat_progression) != null ? _a2 : [], ...(_c2 = (_b2 = c.subclass) == null ? void 0 : _b2.feat_progression) != null ? _c2 : []];
|
|
633
768
|
const suppressedFeatureTypes = /* @__PURE__ */ new Set();
|
|
634
769
|
for (const decl of [...(_d2 = entity.selection_pools) != null ? _d2 : [], ...(_f2 = (_e2 = c.subclass) == null ? void 0 : _e2.selection_pools) != null ? _f2 : []]) {
|
|
@@ -661,7 +796,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
661
796
|
));
|
|
662
797
|
}
|
|
663
798
|
if (classIndex === 0) {
|
|
664
|
-
for (const ch of (_i2 = entity.choices) != null ? _i2 : []) {
|
|
799
|
+
for (const ch of [...(_i2 = entity.choices) != null ? _i2 : [], ...classToolPicks(entity).decisions]) {
|
|
665
800
|
push(1, buildItem(
|
|
666
801
|
ch,
|
|
667
802
|
{ kind: "class", slug: entity.slug, level: 1 },
|
|
@@ -675,36 +810,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
675
810
|
}
|
|
676
811
|
}
|
|
677
812
|
if (classIndex === 0) {
|
|
678
|
-
(
|
|
679
|
-
var _a3;
|
|
680
|
-
if (eq.kind !== "choice") return;
|
|
681
|
-
const options = (_a3 = eq.options) != null ? _a3 : [];
|
|
682
|
-
let degraded = false;
|
|
683
|
-
const ch = {
|
|
684
|
-
kind: "select-inline",
|
|
685
|
-
id: `equipment-${i}`,
|
|
686
|
-
label: "Starting Equipment",
|
|
687
|
-
count: 1,
|
|
688
|
-
options: options.map((opt, j) => {
|
|
689
|
-
var _a4;
|
|
690
|
-
const label = typeof opt === "string" ? opt : (_a4 = opt == null ? void 0 : opt.label) != null ? _a4 : "";
|
|
691
|
-
const grants = opt && typeof opt === "object" && Array.isArray(opt.grants) ? opt.grants : [];
|
|
692
|
-
if (typeof opt === "string" || !(opt && typeof opt === "object" && Array.isArray(opt.grants))) {
|
|
693
|
-
degraded = true;
|
|
694
|
-
}
|
|
695
|
-
return {
|
|
696
|
-
value: `option-${j}`,
|
|
697
|
-
label,
|
|
698
|
-
choices: grants.flatMap((g, k) => g && typeof g === "object" && "category" in g && g.category ? [categoryToEntitySelect(g.category, `equipment-${i}-opt-${j}-cat-${k}`)] : [])
|
|
699
|
-
};
|
|
700
|
-
})
|
|
701
|
-
};
|
|
702
|
-
if (degraded && !warnedDegradedEquipment.has(entity.slug)) {
|
|
703
|
-
warnedDegradedEquipment.add(entity.slug);
|
|
704
|
-
console.warn(
|
|
705
|
-
`[archivist] Starting equipment for "${entity.slug}" is in an outdated/unstructured format; its nested picks and seeding are skipped. Re-sync the compendium (delete _compendium.md and reload) to fix.`
|
|
706
|
-
);
|
|
707
|
-
}
|
|
813
|
+
for (const ch of equipmentDecisions(entity.starting_equipment, entity.slug)) {
|
|
708
814
|
push(1, buildItem(
|
|
709
815
|
ch,
|
|
710
816
|
{ kind: "class", slug: entity.slug, level: 1 },
|
|
@@ -715,7 +821,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
715
821
|
ownerBare,
|
|
716
822
|
effective
|
|
717
823
|
));
|
|
718
|
-
}
|
|
824
|
+
}
|
|
719
825
|
}
|
|
720
826
|
let sawAuthoredSubclass = false;
|
|
721
827
|
const staged = [];
|
|
@@ -735,7 +841,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
735
841
|
staged.push({ level: atLvl, item, rank: authoredRank(src.kind, atLvl, rf.feature), seq: staged.length });
|
|
736
842
|
};
|
|
737
843
|
const emitChoices = (list, atLvl, name, description) => {
|
|
738
|
-
var _a3;
|
|
844
|
+
var _a3, _b3;
|
|
739
845
|
for (const ch of list) {
|
|
740
846
|
if (ch.kind === "select-entity" && ch.entity_type === "subclass") {
|
|
741
847
|
sawAuthoredSubclass = true;
|
|
@@ -753,7 +859,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
753
859
|
src,
|
|
754
860
|
atLvl,
|
|
755
861
|
name,
|
|
756
|
-
readAt(atLvl),
|
|
862
|
+
(_b3 = legacyAsiReader(emitted, atLvl)) != null ? _b3 : readAt(atLvl),
|
|
757
863
|
ctx,
|
|
758
864
|
ownerBare,
|
|
759
865
|
effective,
|
|
@@ -800,22 +906,22 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
800
906
|
}
|
|
801
907
|
emitChoices(list, copy.level, copy.name, copy.description);
|
|
802
908
|
};
|
|
803
|
-
for (const copy of (
|
|
909
|
+
for (const copy of (_j2 = rf.foldedFrom) != null ? _j2 : []) emitCopy({ ...copy, prose: copy.description });
|
|
804
910
|
emitCopy({
|
|
805
911
|
level: lvl,
|
|
806
912
|
name: rf.feature.name,
|
|
807
913
|
description: rf.feature.description,
|
|
808
914
|
// The card prose: the description, else the entries joined. `||`, not `??`, so an EMPTY description
|
|
809
915
|
// falls through to the entries the way this branch's own guard always did.
|
|
810
|
-
prose: rf.feature.description || (((
|
|
916
|
+
prose: rf.feature.description || (((_k2 = rf.feature.entries) == null ? void 0 : _k2.length) ? rf.feature.entries.join("\n\n") : void 0),
|
|
811
917
|
choices: rf.feature.choices
|
|
812
918
|
});
|
|
813
919
|
}
|
|
814
920
|
staged.sort((a, b) => a.rank - b.rank || a.seq - b.seq);
|
|
815
921
|
for (const s of staged) push(s.level, s.item);
|
|
816
|
-
const subclassLevel = (
|
|
922
|
+
const subclassLevel = (_l2 = entity.subclass_level) != null ? _l2 : null;
|
|
817
923
|
if (subclassLevel != null && subclassLevel <= c.level && !sawAuthoredSubclass) {
|
|
818
|
-
const featureName = (
|
|
924
|
+
const featureName = (_m2 = entity.subclass_feature_name) != null ? _m2 : "Subclass";
|
|
819
925
|
const synthChoice = {
|
|
820
926
|
kind: "select-entity",
|
|
821
927
|
id: "subclass",
|
|
@@ -851,13 +957,46 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
851
957
|
{ kind: "class", slug: entity.slug, level: pool.anchorLevel },
|
|
852
958
|
pool.anchorLevel,
|
|
853
959
|
pool.label,
|
|
854
|
-
() => pool.selected.map((e) => e.
|
|
960
|
+
() => pool.selected.map((e) => e.key),
|
|
855
961
|
ctx,
|
|
856
962
|
ownerBare,
|
|
857
963
|
effective
|
|
858
964
|
);
|
|
859
965
|
item.pool = { id: pool.id, anchorLevel: pool.anchorLevel };
|
|
966
|
+
const repeatables = pool.available.filter((e) => e.entity.repeatable === true);
|
|
967
|
+
if (repeatables.length > 0) {
|
|
968
|
+
item.repeatable = repeatables.map((e) => {
|
|
969
|
+
var _a3, _b3;
|
|
970
|
+
return {
|
|
971
|
+
noteSlug: e.slug,
|
|
972
|
+
itemChoice: (_a3 = e.entity.item_choice) != null ? _a3 : "learn",
|
|
973
|
+
rows: resolveOptionRows(e.entity, ctx.registry, { edition: resolved.definition.edition, isEntityVisible: (_b3 = ctx.isEntityVisible) == null ? void 0 : _b3.bind(ctx) })
|
|
974
|
+
};
|
|
975
|
+
});
|
|
976
|
+
}
|
|
860
977
|
for (const o of item.options) if (strandedSlugs.has(o.value)) o.stranded = true;
|
|
978
|
+
const memberChildren = [];
|
|
979
|
+
for (const entry of pool.selected) {
|
|
980
|
+
for (const ch of memberChoices(entry.entity)) {
|
|
981
|
+
const child = buildItem(
|
|
982
|
+
ch,
|
|
983
|
+
{ kind: "class", slug: entity.slug, level: pool.anchorLevel },
|
|
984
|
+
pool.anchorLevel,
|
|
985
|
+
entry.entity.name,
|
|
986
|
+
readAt(pool.anchorLevel),
|
|
987
|
+
ctx,
|
|
988
|
+
ownerBare,
|
|
989
|
+
effective,
|
|
990
|
+
{ keyPrefix: `${pool.id}:${entry.key}:` }
|
|
991
|
+
);
|
|
992
|
+
child.parentLabel = entry.entity.name;
|
|
993
|
+
memberChildren.push(child);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (memberChildren.length) {
|
|
997
|
+
item.children = memberChildren;
|
|
998
|
+
if (item.status === "resolved" && memberChildren.some((c2) => c2.status !== "resolved")) item.status = "partial";
|
|
999
|
+
}
|
|
861
1000
|
push(pool.anchorLevel, item);
|
|
862
1001
|
}
|
|
863
1002
|
for (const entry of featProgressions) {
|
|
@@ -865,7 +1004,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
865
1004
|
if (!category) {
|
|
866
1005
|
warnOnce(
|
|
867
1006
|
`feat-progression-category:${entity.slug}:${entry.name}`,
|
|
868
|
-
`Archivist: feat_progression "${entry.name}" on "${entity.slug}" carries no category this engine maps (${((
|
|
1007
|
+
`Archivist: feat_progression "${entry.name}" on "${entity.slug}" carries no category this engine maps (${((_n2 = entry.category) != null ? _n2 : []).join(", ")}); no decision is offered`
|
|
869
1008
|
);
|
|
870
1009
|
continue;
|
|
871
1010
|
}
|
|
@@ -875,7 +1014,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
875
1014
|
const lvl = Number.parseInt(key, 10);
|
|
876
1015
|
if (!Number.isInteger(lvl) || String(lvl) !== key) continue;
|
|
877
1016
|
if (lvl > c.level) continue;
|
|
878
|
-
if (((
|
|
1017
|
+
if (((_o = byLevel.get(lvl)) != null ? _o : []).some((i) => i.key === "feat")) {
|
|
879
1018
|
warnOnce(
|
|
880
1019
|
`feat-progression-collision:${entity.slug}:${lvl}`,
|
|
881
1020
|
`Archivist: "${entry.name}" on "${entity.slug}" would add a second feat pick at level ${lvl}, where one already exists; skipping`
|
|
@@ -947,10 +1086,10 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
947
1086
|
if (resolved.background) {
|
|
948
1087
|
const bare = bareEntitySlug(resolved.background.slug);
|
|
949
1088
|
pushOrigin(
|
|
950
|
-
resolved.background.choices,
|
|
1089
|
+
[...(_l = resolved.background.choices) != null ? _l : [], ...backgroundToolPicks(resolved.background).decisions],
|
|
951
1090
|
"background",
|
|
952
1091
|
{ kind: "background", slug: resolved.background.slug },
|
|
953
|
-
(
|
|
1092
|
+
(_m = resolved.background.name) != null ? _m : "Background",
|
|
954
1093
|
bare,
|
|
955
1094
|
resolved.background.description
|
|
956
1095
|
);
|
|
@@ -973,7 +1112,7 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
973
1112
|
if (originFeat) {
|
|
974
1113
|
const featSource = { kind: "feat", slug: originFeat.feat.slug };
|
|
975
1114
|
const featBare = bareEntitySlug(originFeat.feat.slug);
|
|
976
|
-
for (const ch of (
|
|
1115
|
+
for (const ch of (_n = originFeat.feat.choices) != null ? _n : []) {
|
|
977
1116
|
origin.push(buildItem(
|
|
978
1117
|
ch,
|
|
979
1118
|
featSource,
|
|
@@ -988,6 +1127,18 @@ function buildDecisionLedger(resolved, ctx) {
|
|
|
988
1127
|
}
|
|
989
1128
|
}
|
|
990
1129
|
}
|
|
1130
|
+
for (const ch of equipmentDecisions(resolved.background.equipment, resolved.background.slug)) {
|
|
1131
|
+
origin.push(buildItem(
|
|
1132
|
+
ch,
|
|
1133
|
+
{ kind: "background", slug: resolved.background.slug },
|
|
1134
|
+
0,
|
|
1135
|
+
"Starting Equipment",
|
|
1136
|
+
originRead("background"),
|
|
1137
|
+
ctx,
|
|
1138
|
+
bare,
|
|
1139
|
+
effective
|
|
1140
|
+
));
|
|
1141
|
+
}
|
|
991
1142
|
}
|
|
992
1143
|
return { classes, origin };
|
|
993
1144
|
}
|
|
@@ -1014,7 +1165,10 @@ function resolveOriginFeat(entities, originFeatRef, ownerSlug) {
|
|
|
1014
1165
|
const sameCompendiumTail = (s) => prefix ? feats.find((f) => f.slug.startsWith(`${prefix}_feat_`) && f.slug.endsWith(`_${s}`)) : void 0;
|
|
1015
1166
|
const anyTail = (s) => feats.find((f) => f.slug.endsWith(`_${s}`));
|
|
1016
1167
|
const tiers = [
|
|
1017
|
-
() =>
|
|
1168
|
+
() => {
|
|
1169
|
+
var _a2;
|
|
1170
|
+
return (_a2 = feats.find((f) => f.slug === inner)) != null ? _a2 : feats.find((f) => f.slug === slug);
|
|
1171
|
+
},
|
|
1018
1172
|
// 1 exact slug
|
|
1019
1173
|
() => byPath(inner),
|
|
1020
1174
|
// 2 PATH
|
|
@@ -1050,7 +1204,7 @@ var PCResolver = class {
|
|
|
1050
1204
|
return this.entities;
|
|
1051
1205
|
}
|
|
1052
1206
|
resolve(character) {
|
|
1053
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
1207
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1054
1208
|
const warnings = [];
|
|
1055
1209
|
const lookup = (rawRef, type) => {
|
|
1056
1210
|
const slug = stripSlug(rawRef);
|
|
@@ -1071,14 +1225,19 @@ var PCResolver = class {
|
|
|
1071
1225
|
subclass: lookup(c.subclass, "subclass"),
|
|
1072
1226
|
choices: c.choices
|
|
1073
1227
|
}));
|
|
1228
|
+
const memberSites = poolMemberSites(classes, this.entities);
|
|
1229
|
+
const classSlugOf = (i) => {
|
|
1230
|
+
var _a2, _b2, _c2, _d2, _e2;
|
|
1231
|
+
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);
|
|
1232
|
+
};
|
|
1233
|
+
const featSites = featPickSites(character.class, memberSites, classSlugOf);
|
|
1074
1234
|
const feats = [];
|
|
1075
1235
|
const featVia = /* @__PURE__ */ new Map();
|
|
1076
|
-
for (const
|
|
1077
|
-
const f = lookup(`[[${
|
|
1236
|
+
for (const site of featSites) {
|
|
1237
|
+
const f = lookup(`[[${site.slug}]]`, "feat");
|
|
1078
1238
|
if (!f) continue;
|
|
1079
|
-
feats.push(f);
|
|
1080
|
-
|
|
1081
|
-
if (classSlug && pick.level !== null && !featVia.has(f.slug)) featVia.set(f.slug, { kind: "class", slug: classSlug, level: pick.level });
|
|
1239
|
+
if (!feats.some((x) => x.slug === f.slug)) feats.push(f);
|
|
1240
|
+
if (site.via && !featVia.has(f.slug)) featVia.set(f.slug, site.via);
|
|
1082
1241
|
}
|
|
1083
1242
|
const originFeat = (background == null ? void 0 : background.origin_feat) ? resolveOriginFeat(this.entities, background.origin_feat, background.slug) : null;
|
|
1084
1243
|
const originFeatSlug = originFeat == null ? void 0 : originFeat.feat.slug;
|
|
@@ -1090,7 +1249,7 @@ var PCResolver = class {
|
|
|
1090
1249
|
}
|
|
1091
1250
|
const totalLevel = classes.reduce((sum, c) => sum + c.level, 0);
|
|
1092
1251
|
const features = collectResolvedFeatures(race, classes, background, feats, featVia);
|
|
1093
|
-
const extraFeatures = collectChosenGrantedFeatures(character, classes, this.entities, race, background);
|
|
1252
|
+
const extraFeatures = collectChosenGrantedFeatures(character, classes, this.entities, race, background, memberSites);
|
|
1094
1253
|
features.push(...extraFeatures);
|
|
1095
1254
|
features.push(...collectAdditionalFeatures(character, this.entities, warnings));
|
|
1096
1255
|
const casters = [];
|
|
@@ -1100,7 +1259,7 @@ var PCResolver = class {
|
|
|
1100
1259
|
if (profile && classSlug != null) casters.push({ classSlug, spellList: profile.spellList });
|
|
1101
1260
|
});
|
|
1102
1261
|
const spells = [];
|
|
1103
|
-
for (const raw of (
|
|
1262
|
+
for (const raw of (_a = character.spells.known) != null ? _a : []) {
|
|
1104
1263
|
const n = normalizeKnownSpell(raw);
|
|
1105
1264
|
const reg = this.entities.getByTypeAndSlug("spell", n.slug);
|
|
1106
1265
|
if (!reg) {
|
|
@@ -1108,34 +1267,45 @@ var PCResolver = class {
|
|
|
1108
1267
|
continue;
|
|
1109
1268
|
}
|
|
1110
1269
|
const entity = mirrorSpellShapes(reg.data);
|
|
1111
|
-
const isCantrip = ((
|
|
1112
|
-
const classSlug = (
|
|
1113
|
-
const prep = isCantrip || n.alwaysPrepared ? true : (
|
|
1270
|
+
const isCantrip = ((_b = entity.level) != null ? _b : 0) === 0;
|
|
1271
|
+
const classSlug = (_c = n.classSlug) != null ? _c : attributeUnclassedSpell(entity.classes, casters, this.entities);
|
|
1272
|
+
const prep = isCantrip || n.alwaysPrepared ? true : (_d = n.preparedFlag) != null ? _d : false;
|
|
1114
1273
|
spells.push({ entity, slug: n.slug, classSlug, source: n.source, prepared: prep, alwaysPrepared: n.alwaysPrepared, persisted: true });
|
|
1115
1274
|
}
|
|
1116
|
-
const oc = (
|
|
1275
|
+
const oc = (_e = character.origin_choices) != null ? _e : {};
|
|
1117
1276
|
if (originFeat) {
|
|
1118
1277
|
const read = (childId) => oc[`background:feat:${childId}`];
|
|
1119
1278
|
spells.push(...collectFeatGrantedSpells(originFeat.feat, read, this.entities, warnings));
|
|
1120
1279
|
}
|
|
1121
|
-
for (const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1280
|
+
for (const site of featSites) {
|
|
1281
|
+
const reg = this.entities.getByTypeAndSlug("feat", site.slug);
|
|
1282
|
+
if (!reg) continue;
|
|
1283
|
+
const feat = reg.data;
|
|
1284
|
+
spells.push(...collectFeatGrantedSpells(feat, site.read, this.entities, warnings));
|
|
1285
|
+
}
|
|
1286
|
+
for (const site of memberSites) {
|
|
1287
|
+
const classSlug = stripSlug((_g = (_f = character.class[site.classIndex]) == null ? void 0 : _f.name) != null ? _g : null);
|
|
1288
|
+
for (const ch of site.choices) {
|
|
1289
|
+
if (ch.kind !== "select-entity" || ch.entity_type !== "spell" || isTargetChoice(ch)) continue;
|
|
1290
|
+
const v = site.read(ch.id);
|
|
1291
|
+
for (const ref of Array.isArray(v) ? v : typeof v === "string" ? [v] : []) {
|
|
1292
|
+
const slug = typeof ref === "string" ? stripSlug(ref) : null;
|
|
1293
|
+
if (!slug) continue;
|
|
1294
|
+
const reg = this.entities.getByTypeAndSlug("spell", slug);
|
|
1295
|
+
if (!reg) {
|
|
1296
|
+
warnings.push(`Spell [[${slug}]] not found in compendium.`);
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
const entity = mirrorSpellShapes(reg.data);
|
|
1300
|
+
spells.push({ entity, slug, classSlug, source: "class", prepared: true, alwaysPrepared: true });
|
|
1301
|
+
}
|
|
1132
1302
|
}
|
|
1133
1303
|
}
|
|
1134
|
-
const ownSpellcastingAbility = (
|
|
1304
|
+
const ownSpellcastingAbility = (_h = classes.map((c) => {
|
|
1135
1305
|
if (!c.entity) return null;
|
|
1136
1306
|
const p = resolveSpellcasting(c);
|
|
1137
1307
|
return p ? effectiveSpellcastingAbility(c.entity.slug, p.ability, character.overrides) : null;
|
|
1138
|
-
}).find((a) => a != null)) != null ?
|
|
1308
|
+
}).find((a) => a != null)) != null ? _h : null;
|
|
1139
1309
|
spells.push(...collectItemGrantedSpells(character, ownSpellcastingAbility, this.entities, warnings));
|
|
1140
1310
|
spells.push(...collectAdditionalSpells({
|
|
1141
1311
|
race,
|
|
@@ -1186,6 +1356,9 @@ var PCResolver = class {
|
|
|
1186
1356
|
};
|
|
1187
1357
|
resolvedCharacter.pools = resolveAllPools(resolvedCharacter, this.entities, featureResources);
|
|
1188
1358
|
resolvedCharacter.resources = resolveResourceIndex(resolvedCharacter);
|
|
1359
|
+
resolvedCharacter.features = bindFeatureConsumers(resolvedCharacter.features, resolvedCharacter.resources, classes);
|
|
1360
|
+
const infusions = buildInfusionContext(character, resolvedCharacter, this.entities);
|
|
1361
|
+
if (infusions) resolvedCharacter.infusions = infusions;
|
|
1189
1362
|
return { character: resolvedCharacter, warnings };
|
|
1190
1363
|
}
|
|
1191
1364
|
};
|
|
@@ -1204,16 +1377,9 @@ function collectChosenWeaponMasteries(character) {
|
|
|
1204
1377
|
}
|
|
1205
1378
|
function collectFeatPicks(character) {
|
|
1206
1379
|
const picks = /* @__PURE__ */ new Map();
|
|
1207
|
-
character.class
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
if (typeof feat === "string") {
|
|
1211
|
-
const s = stripSlug(feat);
|
|
1212
|
-
const level = /^\d+$/.test(lvl) ? Number(lvl) : null;
|
|
1213
|
-
if (s && !picks.has(s)) picks.set(s, { slug: s, classIndex, level });
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
});
|
|
1380
|
+
for (const site of featPickSites(character.class, [], () => null)) {
|
|
1381
|
+
if (!picks.has(site.slug)) picks.set(site.slug, { slug: site.slug, classIndex: site.classIndex, level: site.level });
|
|
1382
|
+
}
|
|
1217
1383
|
return [...picks.values()];
|
|
1218
1384
|
}
|
|
1219
1385
|
function collectFeatGrantedSpells(feat, read, entities, warnings) {
|
|
@@ -1290,11 +1456,21 @@ function collectSpellPickSlugs(choices, read, out) {
|
|
|
1290
1456
|
}
|
|
1291
1457
|
}
|
|
1292
1458
|
}
|
|
1293
|
-
function collectChosenGrantedFeatures(character, classes, registry, race = null, background = null) {
|
|
1294
|
-
var _a, _b;
|
|
1459
|
+
function collectChosenGrantedFeatures(character, classes, registry, race = null, background = null, memberSites = []) {
|
|
1460
|
+
var _a, _b, _c, _d;
|
|
1295
1461
|
const out = [];
|
|
1462
|
+
for (const site of memberSites) {
|
|
1463
|
+
const classSlug = (_b = (_a = classes[site.classIndex]) == null ? void 0 : _a.entity) == null ? void 0 : _b.slug;
|
|
1464
|
+
if (!classSlug) continue;
|
|
1465
|
+
const at = {};
|
|
1466
|
+
const grants = site.choices.filter((ch) => !isTargetChoice(ch));
|
|
1467
|
+
for (const ch of grants) at[ch.id] = site.read(ch.id);
|
|
1468
|
+
walkChoiceGrants(grants, at, (granted, suppress) => {
|
|
1469
|
+
out.push({ feature: granted, source: { kind: "class", slug: classSlug, level: site.level }, ...suppress ? { renderSuppressed: true } : {} });
|
|
1470
|
+
}, registry);
|
|
1471
|
+
}
|
|
1296
1472
|
classes.forEach((c, i) => {
|
|
1297
|
-
var _a2, _b2,
|
|
1473
|
+
var _a2, _b2, _c2, _d2;
|
|
1298
1474
|
if (!c.entity) return;
|
|
1299
1475
|
const entity = c.entity;
|
|
1300
1476
|
const entry = character.class[i];
|
|
@@ -1303,7 +1479,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1303
1479
|
const lvl = Number(lvlStr);
|
|
1304
1480
|
if (!Number.isFinite(lvl) || lvl > entry.level) continue;
|
|
1305
1481
|
const features = (_b2 = ((_a2 = entity.features_by_level) != null ? _a2 : {})[lvl]) != null ? _b2 : [];
|
|
1306
|
-
const subFeatures = c.subclass ? (
|
|
1482
|
+
const subFeatures = c.subclass ? (_d2 = ((_c2 = c.subclass.features_by_level) != null ? _c2 : {})[lvl]) != null ? _d2 : [] : [];
|
|
1307
1483
|
for (const feature of [...features, ...subFeatures]) {
|
|
1308
1484
|
walkChoiceGrants(feature.choices, atLevel, (granted, suppress) => {
|
|
1309
1485
|
out.push({
|
|
@@ -1315,7 +1491,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1315
1491
|
}
|
|
1316
1492
|
}
|
|
1317
1493
|
});
|
|
1318
|
-
const oc = (
|
|
1494
|
+
const oc = (_c = character.origin_choices) != null ? _c : {};
|
|
1319
1495
|
const originAt = (ns) => {
|
|
1320
1496
|
const at = {};
|
|
1321
1497
|
for (const [key, val] of Object.entries(oc)) {
|
|
@@ -1333,7 +1509,7 @@ function collectChosenGrantedFeatures(character, classes, registry, race = null,
|
|
|
1333
1509
|
});
|
|
1334
1510
|
};
|
|
1335
1511
|
walkChoiceGrants(race.choices, atRace, emitRace, registry);
|
|
1336
|
-
for (const trait of (
|
|
1512
|
+
for (const trait of (_d = race.traits) != null ? _d : []) {
|
|
1337
1513
|
walkChoiceGrants(trait.choices, atRace, emitRace, registry);
|
|
1338
1514
|
}
|
|
1339
1515
|
}
|
|
@@ -1622,6 +1798,7 @@ export {
|
|
|
1622
1798
|
collectResolvedFeatures,
|
|
1623
1799
|
collectProficiencyGrants,
|
|
1624
1800
|
__matchesFilterForTest,
|
|
1801
|
+
__categoryToEntitySelectForTest,
|
|
1625
1802
|
collectChosenProficiencies,
|
|
1626
1803
|
computeEffectiveProficiencies,
|
|
1627
1804
|
collectChosenAbilityPoints,
|