@archivist-gg/dnd5e 0.3.17 → 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-7QN7XSAK.js → chunk-3SFGWFVQ.js} +1 -1
- package/dist/{chunk-2UDSN6VW.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-TULQ4FFX.js → chunk-64VNLMSG.js} +31 -9
- package/dist/{chunk-JSM6JFZR.js → chunk-7XJHI5H5.js} +2 -2
- package/dist/{chunk-YD2VAHA6.js → chunk-B2QHP6UF.js} +2 -2
- package/dist/{chunk-AZRGFUSR.js → chunk-BJGOSM76.js} +1 -1
- package/dist/{chunk-JCMUVZIK.js → chunk-BJWSOQUC.js} +1 -1
- package/dist/{chunk-ONTGZR5T.js → chunk-EJD47JHL.js} +64 -32
- package/dist/{chunk-FANQVQ3D.js → chunk-FJYBLXV7.js} +2 -2
- package/dist/{chunk-PQZ4LM4Z.js → chunk-FMUD3LDV.js} +1 -1
- package/dist/{chunk-PKX6TGRE.js → chunk-FMYWORTP.js} +2 -2
- package/dist/{chunk-G6PBI2BU.js → chunk-FVXLP7P3.js} +1 -1
- package/dist/{chunk-MBX25B6D.js → chunk-GVWEFECG.js} +1 -1
- package/dist/{chunk-Y5VVP73C.js → chunk-HY2SRSVM.js} +1 -1
- package/dist/{chunk-2JSQE3DD.js → chunk-JXWNXIIZ.js} +13 -0
- package/dist/{chunk-VRV3NNTA.js → chunk-LICYHPI3.js} +81 -5
- package/dist/{chunk-LF5AGJA4.js → chunk-LNT64X7C.js} +1 -1
- package/dist/{chunk-6EI737IO.js → chunk-NKZMQV2C.js} +1 -1
- package/dist/{chunk-T6QIF5XR.js → chunk-NTU2DXNG.js} +9 -2
- package/dist/{chunk-3VZZDKRA.js → chunk-NXUY5XQN.js} +63 -15
- package/dist/{chunk-QZSWN2KT.js → chunk-NZO7M5GV.js} +1 -1
- package/dist/{chunk-5MXFW4O3.js → chunk-OOL4KMG2.js} +1 -1
- package/dist/{chunk-H5PTKYXL.js → chunk-QA3YCOML.js} +1 -1
- package/dist/{chunk-3MGQFFNE.js → chunk-QFWQKS3M.js} +1 -1
- package/dist/{chunk-HTYMW5CH.js → chunk-RD2MID3M.js} +67 -3
- package/dist/{chunk-PXVNAY7T.js → chunk-TRBGC4ZG.js} +29 -1
- package/dist/{chunk-UUBJCNQU.js → chunk-UJCK5IW4.js} +2 -2
- package/dist/{chunk-OFCSP6MT.js → chunk-UNYR5GLI.js} +1 -1
- package/dist/{chunk-DOXSFYLH.js → chunk-VN5DLURA.js} +2 -2
- package/dist/{chunk-7ATNGKBS.js → chunk-VP5TIXDK.js} +1 -1
- package/dist/{chunk-QH36K2PU.js → chunk-WOHX7YTH.js} +7 -0
- package/dist/{chunk-YKL6SHRJ.js → chunk-XTEFPUSN.js} +1 -1
- package/dist/{chunk-RYLXAYIQ.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.js +4 -4
- package/dist/dnd/amount-text.d.ts +4 -0
- package/dist/dnd/amount-text.js +3 -1
- 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 +9 -0
- package/dist/feat/feat.schema.js +3 -3
- package/dist/index.js +3720 -338
- 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 -5
- package/dist/optional-feature/optional-feature.parser.js +4 -4
- package/dist/optional-feature/optional-feature.schema.d.ts +9 -0
- package/dist/optional-feature/optional-feature.schema.js +3 -3
- package/dist/pc/pc.additional-spells.d.ts +16 -2
- package/dist/pc/pc.additional-spells.js +4 -1
- package/dist/pc/pc.amount-bindings.d.ts +11 -2
- package/dist/pc/pc.amount-bindings.js +6 -1
- package/dist/pc/pc.decision-engine.d.ts +8 -0
- package/dist/pc/pc.decision-engine.js +13 -10
- package/dist/pc/pc.entry-overrides.js +3 -2
- package/dist/pc/pc.equipment.js +5 -4
- package/dist/pc/pc.feature-effects.d.ts +9 -2
- package/dist/pc/pc.feature-effects.js +15 -2
- package/dist/pc/pc.infusions.js +3 -2
- package/dist/pc/pc.member-choices.d.ts +33 -1
- package/dist/pc/pc.member-choices.js +12 -5
- package/dist/pc/pc.parser.js +1 -1
- package/dist/pc/pc.pools.js +3 -2
- package/dist/pc/pc.proficiencies.d.ts +14 -0
- package/dist/pc/pc.proficiencies.js +68 -19
- 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 +1 -1
- package/dist/pc/pc.recalc.js +151 -55
- package/dist/pc/pc.resolver.d.ts +4 -1
- package/dist/pc/pc.resolver.js +10 -9
- package/dist/pc/pc.rest.js +3 -2
- package/dist/pc/pc.schema.d.ts +19 -0
- 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 +65 -4
- 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 +9 -0
- package/dist/schemas/feature-effect-schema.js +1 -1
- package/dist/schemas/feature-schema.js +3 -3
- 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 +2 -2
- package/dist/types/feature-effect.d.ts +18 -0
- package/dist/types/optional-feature.types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
warnOnce
|
|
6
6
|
} from "./chunk-LVQLWRCU.js";
|
|
7
|
+
import {
|
|
8
|
+
memoByRevision
|
|
9
|
+
} from "./chunk-4J6DS3EJ.js";
|
|
7
10
|
import {
|
|
8
11
|
slugify
|
|
9
12
|
} from "./chunk-ZCTUYGNV.js";
|
|
@@ -41,6 +44,10 @@ function normalizeSpellRef(ref) {
|
|
|
41
44
|
return out.length > 0 ? out : null;
|
|
42
45
|
}
|
|
43
46
|
function buildSpellNameIndex(entities) {
|
|
47
|
+
return memoByRevision(SPELL_NAME_INDEX, entities, () => spellNameIndexOf(entities));
|
|
48
|
+
}
|
|
49
|
+
var SPELL_NAME_INDEX = /* @__PURE__ */ new WeakMap();
|
|
50
|
+
function spellNameIndexOf(entities) {
|
|
44
51
|
var _a;
|
|
45
52
|
const byName = /* @__PURE__ */ new Map();
|
|
46
53
|
for (const e of entities.search("", "spell", Number.POSITIVE_INFINITY)) {
|
|
@@ -95,20 +102,78 @@ var entryHasInSliceLeaf = (e, comparand, own) => readAbility(e.ability, own) !==
|
|
|
95
102
|
const lv = e[b];
|
|
96
103
|
return !!lv && typeof lv === "object" && !Array.isArray(lv) && Object.entries(lv).some(([k, v]) => (k === "_" || Number(k) <= comparand) && Array.isArray(v) && v.some((x) => typeof x === "string"));
|
|
97
104
|
});
|
|
105
|
+
function chosenRaceOptionKeys(race, read) {
|
|
106
|
+
var _a;
|
|
107
|
+
const out = /* @__PURE__ */ new Set();
|
|
108
|
+
const r = race;
|
|
109
|
+
const lists = [r.choices, ...((_a = r.traits) != null ? _a : []).map((t) => t == null ? void 0 : t.choices)];
|
|
110
|
+
for (const list of lists) {
|
|
111
|
+
for (const c of Array.isArray(list) ? list : []) {
|
|
112
|
+
if ((c == null ? void 0 : c.kind) !== "select-inline" || typeof c.id !== "string" || RACE_STRUCTURAL_PSEUDO.has(c.id)) continue;
|
|
113
|
+
const v = read(c.id);
|
|
114
|
+
for (const value of Array.isArray(v) ? v : typeof v === "string" ? [v] : []) {
|
|
115
|
+
if (typeof value !== "string") continue;
|
|
116
|
+
out.add(slugify(value));
|
|
117
|
+
const opt = (Array.isArray(c.options) ? c.options : []).find((o) => (o == null ? void 0 : o.value) === value);
|
|
118
|
+
if (typeof (opt == null ? void 0 : opt.label) === "string") out.add(slugify(opt.label));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function innateLeaves(innate, comparand) {
|
|
125
|
+
if (!innate || typeof innate !== "object" || Array.isArray(innate)) return [];
|
|
126
|
+
const strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : v && typeof v === "object" ? Object.values(v).flatMap(strings) : [];
|
|
127
|
+
return Object.entries(innate).filter(([k]) => k === "_" || Number(k) <= comparand).flatMap(([, v]) => strings(v));
|
|
128
|
+
}
|
|
129
|
+
function memberAtWillLeaves(innate, comparand, slug) {
|
|
130
|
+
if (!innate || typeof innate !== "object" || Array.isArray(innate)) return [];
|
|
131
|
+
const out = [];
|
|
132
|
+
for (const [k, v] of Object.entries(innate)) {
|
|
133
|
+
if (!(k === "_" || Number(k) <= comparand)) continue;
|
|
134
|
+
if (Array.isArray(v)) {
|
|
135
|
+
out.push(...v);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
for (const [usage, list] of v && typeof v === "object" ? Object.entries(v) : []) {
|
|
139
|
+
if (usage === "will" && Array.isArray(list)) out.push(...list);
|
|
140
|
+
else warnOnce(`addspells:usage:${slug}:innate:${k}:${usage}`, `archivist: additional_spells on "${slug}" innate.${k}.${usage} is a usage economy (skipped; G8)`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
98
145
|
function collectAdditionalSpells(args) {
|
|
146
|
+
var _a, _b;
|
|
99
147
|
const { race, feats, classes, totalLevel, ownAbility, alreadyCollected, entities, warnings } = args;
|
|
148
|
+
const raceChoice = (_a = args.raceChoice) != null ? _a : (() => void 0);
|
|
100
149
|
let index = null;
|
|
101
150
|
const indexOf = () => index != null ? index : index = buildSpellNameIndex(entities);
|
|
102
151
|
const out = [];
|
|
103
152
|
const carriers = [];
|
|
104
153
|
const asRaw = (x) => x == null ? void 0 : x.additional_spells;
|
|
105
154
|
if (race && raceIsUngated(race)) carriers.push({ root: "race", slug: race.slug, edition: editionOf(race), entries: entriesOf(asRaw(race)), comparand: totalLevel, classSlug: null });
|
|
155
|
+
else if (race) {
|
|
156
|
+
const chosen = chosenRaceOptionKeys(race, raceChoice);
|
|
157
|
+
for (const e of entriesOf(asRaw(race))) {
|
|
158
|
+
if (typeof e.name === "string" && chosen.has(slugify(e.name))) {
|
|
159
|
+
carriers.push({ root: "race", slug: race.slug, edition: editionOf(race), entries: [e], comparand: totalLevel, classSlug: null });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
106
163
|
for (const f of feats) carriers.push({ root: "feat", slug: f.slug, edition: editionOf(f), entries: entriesOf(asRaw(f)), comparand: totalLevel, classSlug: null });
|
|
107
164
|
for (const c of classes) {
|
|
108
165
|
if (!c.entity) continue;
|
|
109
166
|
carriers.push({ root: "class", slug: c.entity.slug, edition: editionOf(c.entity), entries: entriesOf(asRaw(c.entity)), comparand: c.level, classSlug: c.entity.slug });
|
|
110
167
|
if (c.subclass) carriers.push({ root: "subclass", slug: c.subclass.slug, edition: editionOf(c.subclass), entries: entriesOf(asRaw(c.subclass)), comparand: c.level, classSlug: c.entity.slug });
|
|
111
168
|
}
|
|
169
|
+
for (const pool of (_b = args.pools) != null ? _b : []) {
|
|
170
|
+
const c = classes[pool.classIndex];
|
|
171
|
+
if (!(c == null ? void 0 : c.entity)) continue;
|
|
172
|
+
for (const m of [...pool.selected, ...pool.grants]) {
|
|
173
|
+
if (m.itemBound === true) continue;
|
|
174
|
+
carriers.push({ root: "member", slug: m.slug, edition: editionOf(m.entity), entries: entriesOf(asRaw(m.entity)), comparand: c.level, classSlug: c.entity.slug });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
112
177
|
for (const car of carriers) {
|
|
113
178
|
if (car.entries.length === 0) continue;
|
|
114
179
|
if (car.entries.length > 1) {
|
|
@@ -116,12 +181,21 @@ function collectAdditionalSpells(args) {
|
|
|
116
181
|
continue;
|
|
117
182
|
}
|
|
118
183
|
const entry = car.entries[0];
|
|
119
|
-
|
|
184
|
+
let ability = readAbility(entry.ability, ownAbility);
|
|
185
|
+
if (ability === "choose" && car.root === "race") {
|
|
186
|
+
const pick = raceChoice("spellcasting-ability");
|
|
187
|
+
const allowed = entry.ability.choose;
|
|
188
|
+
ability = typeof pick === "string" && Array.isArray(allowed) && allowed.includes(pick) ? pick : "choose";
|
|
189
|
+
}
|
|
120
190
|
if (ability === "choose") continue;
|
|
121
|
-
|
|
191
|
+
const buckets = ["known", "prepared"].map((bucket) => {
|
|
122
192
|
const levels = entry[bucket];
|
|
123
|
-
|
|
124
|
-
|
|
193
|
+
return [bucket, !levels || typeof levels !== "object" || Array.isArray(levels) ? [] : Object.entries(levels)];
|
|
194
|
+
});
|
|
195
|
+
if (car.root === "race") buckets.push(["innate", [["_", innateLeaves(entry.innate, car.comparand)]]]);
|
|
196
|
+
if (car.root === "member") buckets.push(["at-will", [["_", memberAtWillLeaves(entry.innate, car.comparand, car.slug)]]]);
|
|
197
|
+
for (const [bucket, levelEntries] of buckets) {
|
|
198
|
+
for (const [k, v] of levelEntries) {
|
|
125
199
|
if (!(k === "_" || Number(k) <= car.comparand)) continue;
|
|
126
200
|
if (!Array.isArray(v)) {
|
|
127
201
|
warnOnce(`addspells:usage:${car.slug}:${bucket}:${k}`, `archivist: additional_spells on "${car.slug}" ${bucket}.${k} is a usage economy (skipped; G8)`);
|
|
@@ -142,7 +216,8 @@ function collectAdditionalSpells(args) {
|
|
|
142
216
|
source: car.root === "race" ? "race" : car.root === "feat" ? "feat" : "class",
|
|
143
217
|
prepared: true,
|
|
144
218
|
alwaysPrepared: true,
|
|
145
|
-
...ability ? { ability } : {}
|
|
219
|
+
...ability ? { ability } : {},
|
|
220
|
+
...bucket === "at-will" ? { atWill: true } : {}
|
|
146
221
|
});
|
|
147
222
|
}
|
|
148
223
|
}
|
|
@@ -157,5 +232,6 @@ export {
|
|
|
157
232
|
buildSpellNameIndex,
|
|
158
233
|
resolveSpellByName,
|
|
159
234
|
raceIsUngated,
|
|
235
|
+
chosenRaceOptionKeys,
|
|
160
236
|
collectAdditionalSpells
|
|
161
237
|
};
|
|
@@ -143,13 +143,16 @@ var characterOverridesShape = z.object({
|
|
|
143
143
|
* `toProfSlug` output with the apostrophe RETAINED ("thieves'-tools"), matching the engine's
|
|
144
144
|
* own tool vocabulary in types/choice.ts. The READER is wider: `computeEffectiveProficiencies`
|
|
145
145
|
* normalises each key with `toProfSlug` on read, so a hand-typed "Thieves' Tools" also
|
|
146
|
-
* matches; and the plugin's two writers (`CharacterEditState.
|
|
146
|
+
* matches; and the plugin's two writers (`CharacterEditState.setToolExpertise` and the
|
|
147
147
|
* `addProficiency` clearance) match an existing key by slug too, so a key the note ALREADY
|
|
148
148
|
* carries is written THROUGH in its own spelling rather than duplicated · nothing here
|
|
149
149
|
* re-spells it (review M-4: "repaired in place" read as "normalised", which it is not).
|
|
150
150
|
* `languages` gets no such sibling: languages have no tri (§9.3). */
|
|
151
151
|
proficiency: z.record(z.string(), proficiencyTri).optional()
|
|
152
152
|
}).optional(),
|
|
153
|
+
/** D4 A: weapon and armor proficiency edits, the `languages` shape. Same no-defaults rule. */
|
|
154
|
+
weapons: z.object({ add: z.array(z.string()).optional(), remove: z.array(z.string()).optional() }).optional(),
|
|
155
|
+
armor: z.object({ add: z.array(z.string()).optional(), remove: z.array(z.string()).optional() }).optional(),
|
|
153
156
|
/** Manual defense edits. SUPPRESSION-ONLY, and the missing `add` channel is a DELIBERATE
|
|
154
157
|
* asymmetry with `languages`/`tools` above · do not "complete the pattern". The additive
|
|
155
158
|
* store is `character.defenses.*`, which already exists and works; a second additive
|
|
@@ -261,7 +264,11 @@ var sheetPoolViewSchema = z.object({
|
|
|
261
264
|
folded: z.array(z.string().min(1)).optional()
|
|
262
265
|
});
|
|
263
266
|
var sheetStateSchema = z.object({
|
|
264
|
-
|
|
267
|
+
// D13 (D3-A): `body: wide` is the wide three-column sheet (it draws the saves as a section, like `saves: section`).
|
|
268
|
+
layout: z.object({
|
|
269
|
+
saves: z.enum(["section"]).optional().catch(void 0),
|
|
270
|
+
body: z.enum(["wide"]).optional().catch(void 0)
|
|
271
|
+
}).optional(),
|
|
265
272
|
favorites: z.array(z.string().min(1)).optional(),
|
|
266
273
|
filters: z.object({ actions: sheetViewFilterSchema.optional(), passive: sheetViewFilterSchema.optional() }).optional(),
|
|
267
274
|
pools: z.record(z.string(), sheetPoolViewSchema).optional()
|
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
readTableColumn
|
|
9
9
|
} from "./chunk-IUAAXXNO.js";
|
|
10
|
+
import {
|
|
11
|
+
findItemAction,
|
|
12
|
+
resolveItemAction
|
|
13
|
+
} from "./chunk-ZUQW5VBZ.js";
|
|
10
14
|
import {
|
|
11
15
|
requiresAttunement
|
|
12
16
|
} from "./chunk-IHE6KVC3.js";
|
|
@@ -18,10 +22,6 @@ import {
|
|
|
18
22
|
resolveEntityForEntry,
|
|
19
23
|
slotAcTerms
|
|
20
24
|
} from "./chunk-LHZXYFBU.js";
|
|
21
|
-
import {
|
|
22
|
-
findItemAction,
|
|
23
|
-
resolveItemAction
|
|
24
|
-
} from "./chunk-ZUQW5VBZ.js";
|
|
25
25
|
import {
|
|
26
26
|
warnOnce
|
|
27
27
|
} from "./chunk-LVQLWRCU.js";
|
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
keptSlugFor,
|
|
30
30
|
resolveBaseItem
|
|
31
31
|
} from "./chunk-CM5CWO4K.js";
|
|
32
|
+
import {
|
|
33
|
+
bucketOf,
|
|
34
|
+
memoByRevision
|
|
35
|
+
} from "./chunk-4J6DS3EJ.js";
|
|
32
36
|
import {
|
|
33
37
|
bareEntitySlug,
|
|
34
38
|
slugify,
|
|
@@ -102,6 +106,11 @@ function bindFeatureConsumers(features, index, classes) {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
// src/pc/pc.pools.ts
|
|
109
|
+
var SORTED_OPTIONAL_FEATURES = /* @__PURE__ */ new WeakMap();
|
|
110
|
+
function sortedOptionalFeatures(registry) {
|
|
111
|
+
return memoByRevision(SORTED_OPTIONAL_FEATURES, registry, () => bucketOf(registry, "optional-feature").slice().sort((a, b) => a.name.localeCompare(b.name) || a.slug.localeCompare(b.slug)));
|
|
112
|
+
}
|
|
113
|
+
var SRD_OWNER_PREFIXES = /* @__PURE__ */ new Set(["srd-5e", "srd-2024"]);
|
|
105
114
|
function levelPrereqMax(d) {
|
|
106
115
|
var _a;
|
|
107
116
|
return ((_a = d.prerequisites) != null ? _a : []).filter((p) => p.kind === "level").reduce((m, p) => Math.max(m, p.min), 0);
|
|
@@ -125,6 +134,7 @@ function resolvePool(rc, classIndex, pool, registry, index, edition) {
|
|
|
125
134
|
const level = rc.level;
|
|
126
135
|
const ownerBare = bareEntitySlug(entity.slug);
|
|
127
136
|
const ownerPrefix = entity.slug.split("_")[0];
|
|
137
|
+
const ownEdition = SRD_OWNER_PREFIXES.has(ownerPrefix) ? entity.edition : void 0;
|
|
128
138
|
const col = pool.count.column;
|
|
129
139
|
const count = (_a = readTableColumn(entity.table, level, [col])) != null ? _a : 0;
|
|
130
140
|
const { anchorLevel, columnSeen } = poolAnchorLevel(entity, pool);
|
|
@@ -135,7 +145,7 @@ function resolvePool(rc, classIndex, pool, registry, index, edition) {
|
|
|
135
145
|
);
|
|
136
146
|
}
|
|
137
147
|
const ft = pool.source.where.feature_type;
|
|
138
|
-
const all = registry
|
|
148
|
+
const all = sortedOptionalFeatures(registry);
|
|
139
149
|
const entryOf = (slug, entity2, compendium) => ({ slug, entity: entity2, ...compendium ? { compendium } : {}, key: slug, param: null, itemBound: isItemBound(entity2) });
|
|
140
150
|
const byBare = /* @__PURE__ */ new Map();
|
|
141
151
|
const candidates = /* @__PURE__ */ new Map();
|
|
@@ -147,6 +157,7 @@ function resolvePool(rc, classIndex, pool, registry, index, edition) {
|
|
|
147
157
|
if (d.feature_type !== ft) continue;
|
|
148
158
|
if (!((_b = d.available_to) != null ? _b : []).some((l) => wikilinkTailSlug(l) === ownerBare)) continue;
|
|
149
159
|
if (levelPrereqMax(d) > level) continue;
|
|
160
|
+
if (ownEdition && d.edition && d.edition !== ownEdition) continue;
|
|
150
161
|
const group = candidates.get(bare);
|
|
151
162
|
if (group) group.push(entry);
|
|
152
163
|
else candidates.set(bare, [entry]);
|
|
@@ -353,13 +364,49 @@ function rowMatches(row, it) {
|
|
|
353
364
|
if (c.variant) return c.variant.candidates.some((l) => bareEntitySlug(linkSlug(l)) === bareEntitySlug(it.slug));
|
|
354
365
|
return !!c.filter && matchesFilter(it.data, c.filter);
|
|
355
366
|
}
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
function buildItemIndex(items) {
|
|
368
|
+
const lcType = [], lcRarity = [];
|
|
369
|
+
const byLcName = /* @__PURE__ */ new Map(), bySlug = /* @__PURE__ */ new Map(), byBare = /* @__PURE__ */ new Map();
|
|
370
|
+
const push = (m, k, i) => {
|
|
371
|
+
const l = m.get(k);
|
|
372
|
+
if (l) l.push(i);
|
|
373
|
+
else m.set(k, [i]);
|
|
374
|
+
};
|
|
375
|
+
items.forEach((it, i) => {
|
|
376
|
+
const data = it.data;
|
|
377
|
+
lcType.push(lc(data.type));
|
|
378
|
+
lcRarity.push(lc(data.rarity));
|
|
379
|
+
push(byLcName, lc(it.name), i);
|
|
380
|
+
if (!bySlug.has(it.slug)) bySlug.set(it.slug, i);
|
|
381
|
+
push(byBare, bareEntitySlug(it.slug), i);
|
|
382
|
+
});
|
|
383
|
+
return { items, lcType, lcRarity, byLcName, bySlug, byBare };
|
|
384
|
+
}
|
|
385
|
+
var ITEM_INDEX = /* @__PURE__ */ new WeakMap();
|
|
386
|
+
var itemIndexOf = (registry) => memoByRevision(ITEM_INDEX, registry, () => buildItemIndex(itemsOf(registry)));
|
|
387
|
+
var inBucketOrder = (ix, hits) => [...hits].sort((a, b) => a - b).map((i) => ix.items[i]);
|
|
388
|
+
function rowInstalledIn(row, ix) {
|
|
389
|
+
var _a, _b, _c;
|
|
390
|
+
const c = row.creates;
|
|
391
|
+
if (c.item) {
|
|
392
|
+
const hits = new Set((_a = ix.byLcName.get(lc(row.name))) != null ? _a : []);
|
|
393
|
+
const own = ix.bySlug.get(linkSlug(c.item));
|
|
394
|
+
if (own !== void 0) hits.add(own);
|
|
395
|
+
return inBucketOrder(ix, hits);
|
|
396
|
+
}
|
|
397
|
+
if (c.variant) {
|
|
398
|
+
const hits = /* @__PURE__ */ new Set();
|
|
399
|
+
for (const l of c.variant.candidates) for (const i of (_b = ix.byBare.get(bareEntitySlug(linkSlug(l)))) != null ? _b : []) hits.add(i);
|
|
400
|
+
return inBucketOrder(ix, hits);
|
|
401
|
+
}
|
|
402
|
+
const f = c.filter;
|
|
403
|
+
if (!f) return [];
|
|
404
|
+
const rarities = new Set(f.rarity.map(lc));
|
|
405
|
+
const types = f.types ? new Set(f.types.map(lc)) : null;
|
|
406
|
+
const excluded = new Set(((_c = f.exclude_types) != null ? _c : []).map(lc));
|
|
407
|
+
return ix.items.filter((it, i) => rarities.has(ix.lcRarity[i]) && (!types || types.has(ix.lcType[i])) && !excluded.has(ix.lcType[i]) && !(f.cursed === false && it.data.cursed === true));
|
|
408
|
+
}
|
|
409
|
+
var rowInstalled = (row, registry) => rowInstalledIn(row, itemIndexOf(registry));
|
|
363
410
|
function candidateOrder(edition) {
|
|
364
411
|
return (a, b) => {
|
|
365
412
|
const ea = edition && lc(a.data.edition) === edition ? 0 : 1;
|
|
@@ -393,9 +440,10 @@ function candidatesFrom(installed, registry, opts) {
|
|
|
393
440
|
}
|
|
394
441
|
function resolveOptionRows(note, registry, opts = {}) {
|
|
395
442
|
var _a;
|
|
396
|
-
const
|
|
443
|
+
const ix = itemIndexOf(registry);
|
|
397
444
|
return ((_a = note.options) != null ? _a : []).map((row) => {
|
|
398
|
-
|
|
445
|
+
var _a2;
|
|
446
|
+
const rowItems = rowInstalledIn(row, ix);
|
|
399
447
|
const candidates = candidatesFrom(rowItems, registry, opts);
|
|
400
448
|
const anyVisible = candidates.length > 0 || candidatesFrom(rowItems, registry, { ...opts, exclude: [] }).length > 0;
|
|
401
449
|
const installed = rowItems.length > 0;
|
|
@@ -407,7 +455,7 @@ function resolveOptionRows(note, registry, opts = {}) {
|
|
|
407
455
|
arm: row.creates.item ? "item" : row.creates.variant ? "variant" : "filter",
|
|
408
456
|
candidates,
|
|
409
457
|
availability: anyVisible ? "installed" : installed ? "hidden-only" : "not-installed",
|
|
410
|
-
...rowItemWords(row, candidates[0] ?
|
|
458
|
+
...rowItemWords(row, candidates[0] ? ix.items[(_a2 = ix.bySlug.get(candidates[0])) != null ? _a2 : -1] : rowItems[0])
|
|
411
459
|
};
|
|
412
460
|
});
|
|
413
461
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parsePickKey,
|
|
3
3
|
poolAnchorLevel
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NXUY5XQN.js";
|
|
5
5
|
import {
|
|
6
6
|
featProgressionCategory
|
|
7
7
|
} from "./chunk-YBLDE5CG.js";
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
warnOnce
|
|
10
10
|
} from "./chunk-LVQLWRCU.js";
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
bucketOf
|
|
13
|
+
} from "./chunk-4J6DS3EJ.js";
|
|
14
|
+
import {
|
|
15
|
+
bareEntitySlug,
|
|
16
|
+
wikilinkTailSlug
|
|
13
17
|
} from "./chunk-ZCTUYGNV.js";
|
|
14
18
|
|
|
15
19
|
// src/pc/pc.member-choices.ts
|
|
@@ -104,6 +108,46 @@ function memberChoices(entity) {
|
|
|
104
108
|
}
|
|
105
109
|
return out;
|
|
106
110
|
}
|
|
111
|
+
function memberSpellTargets(member, read) {
|
|
112
|
+
var _a;
|
|
113
|
+
const refs = [];
|
|
114
|
+
const open = [];
|
|
115
|
+
for (const ch of memberChoices(member)) {
|
|
116
|
+
if (ch.kind !== "select-entity" || !isTargetChoice(ch) || ch.entity_type !== "spell") continue;
|
|
117
|
+
const v = read(ch.id);
|
|
118
|
+
const picked = (Array.isArray(v) ? v : [v]).filter((x) => typeof x === "string" && x.trim() !== "");
|
|
119
|
+
if (picked.length) refs.push(...picked);
|
|
120
|
+
else if (ch.where) open.push(ch.where);
|
|
121
|
+
}
|
|
122
|
+
for (const pre of (_a = member.prerequisites) != null ? _a : []) if (pre.kind === "spell-known") refs.push(pre.spell);
|
|
123
|
+
return refs.length || open.length ? { refs, open } : null;
|
|
124
|
+
}
|
|
125
|
+
function spellMatchesFilter(d, where) {
|
|
126
|
+
var _a, _b;
|
|
127
|
+
if (where.list && !((_a = d.classes) != null ? _a : []).includes(where.list)) return false;
|
|
128
|
+
if (where.level !== void 0 && ((_b = d.level) != null ? _b : 0) !== where.level) return false;
|
|
129
|
+
if (where.edition && d.edition !== where.edition) return false;
|
|
130
|
+
if (where.ritual && d.ritual !== true) return false;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
function spellsReached(targets, spells) {
|
|
134
|
+
if (!targets) return [];
|
|
135
|
+
const hit = /* @__PURE__ */ new Set();
|
|
136
|
+
for (const ref of targets.refs) {
|
|
137
|
+
const full = stripRef(ref);
|
|
138
|
+
const exact = spells.filter((s) => s.slug === full);
|
|
139
|
+
const bare = wikilinkTailSlug(ref);
|
|
140
|
+
for (const s of exact.length ? exact : spells.filter((s2) => bareEntitySlug(s2.slug) === bare)) hit.add(s.slug);
|
|
141
|
+
}
|
|
142
|
+
for (const where of targets.open) {
|
|
143
|
+
const legal = new Set(spells.filter((s) => {
|
|
144
|
+
var _a;
|
|
145
|
+
return spellMatchesFilter(s.entity, where) && !!((_a = s.entity.damage_roll) == null ? void 0 : _a.trim());
|
|
146
|
+
}).map((s) => s.slug));
|
|
147
|
+
if (legal.size === 1) hit.add([...legal][0]);
|
|
148
|
+
}
|
|
149
|
+
return [...new Set(spells.map((s) => s.slug))].filter((slug) => hit.has(slug));
|
|
150
|
+
}
|
|
107
151
|
function siteOf(classIndex, level, poolId, pickKey, member, memberSlug, block) {
|
|
108
152
|
const choices = memberChoices(member);
|
|
109
153
|
if (!choices.length) return null;
|
|
@@ -115,7 +159,7 @@ function poolMemberSites(classes, registry) {
|
|
|
115
159
|
let byBare = null;
|
|
116
160
|
let all = null;
|
|
117
161
|
const lookup = (s, ownerPrefix) => {
|
|
118
|
-
all != null ? all : all = registry
|
|
162
|
+
all != null ? all : all = bucketOf(registry, "optional-feature");
|
|
119
163
|
const bare = bareEntitySlug(s);
|
|
120
164
|
const owned = all.find((e) => bareEntitySlug(e.slug) === bare && e.slug.split("_")[0] === ownerPrefix);
|
|
121
165
|
if (owned) return owned;
|
|
@@ -204,6 +248,23 @@ function featPickSites(classEntries, memberSites, classSlugOf) {
|
|
|
204
248
|
}
|
|
205
249
|
return out;
|
|
206
250
|
}
|
|
251
|
+
function raceFeatSites(race, originChoices) {
|
|
252
|
+
var _a;
|
|
253
|
+
if (!race) return [];
|
|
254
|
+
const oc = originChoices != null ? originChoices : {};
|
|
255
|
+
const out = [];
|
|
256
|
+
for (const list of [race.choices, ...((_a = race.traits) != null ? _a : []).map((t) => t == null ? void 0 : t.choices)]) {
|
|
257
|
+
for (const ch of Array.isArray(list) ? list : []) {
|
|
258
|
+
if ((ch == null ? void 0 : ch.kind) !== "select-entity" || ch.entity_type !== "feat") continue;
|
|
259
|
+
const v = oc[`race:${ch.id}`];
|
|
260
|
+
for (const ref of Array.isArray(v) ? v : typeof v === "string" ? [v] : []) {
|
|
261
|
+
const slug = typeof ref === "string" ? stripRef(ref) : "";
|
|
262
|
+
if (slug) out.push({ slug, via: { kind: "race", slug: race.slug }, read: (id) => oc[`race:feat:${id}`] });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
207
268
|
function featOfSite(site, feats) {
|
|
208
269
|
var _a;
|
|
209
270
|
return (_a = feats.find((f) => f.slug === site.slug)) != null ? _a : feats.find((f) => bareEntitySlug(f.slug) === bareEntitySlug(site.slug));
|
|
@@ -220,9 +281,12 @@ function nestedPickKeysToPrune(block, key, next) {
|
|
|
220
281
|
export {
|
|
221
282
|
isTargetChoice,
|
|
222
283
|
memberChoices,
|
|
284
|
+
memberSpellTargets,
|
|
285
|
+
spellsReached,
|
|
223
286
|
poolMemberSites,
|
|
224
287
|
poolMemberSitesOf,
|
|
225
288
|
featPickSites,
|
|
289
|
+
raceFeatSites,
|
|
226
290
|
featOfSite,
|
|
227
291
|
nestedPickKeysToPrune
|
|
228
292
|
};
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
resourceLevelFor
|
|
6
6
|
} from "./chunk-KSTV7J2U.js";
|
|
7
|
+
import {
|
|
8
|
+
addToRoll
|
|
9
|
+
} from "./chunk-WOHX7YTH.js";
|
|
7
10
|
import {
|
|
8
11
|
baseClassName
|
|
9
12
|
} from "./chunk-VTTA2ALZ.js";
|
|
@@ -74,11 +77,36 @@ function spellRollBonus(spell) {
|
|
|
74
77
|
const re = new RegExp(`(?<![\\w])${esc}\`?\\s*(?:plus|\\+)\\s*your\\s+spellcasting\\s+(?:ability\\s+)?modifier`, "i");
|
|
75
78
|
return re.test(text) ? "{spell_mod}" : null;
|
|
76
79
|
}
|
|
80
|
+
function foldsIntoRoll(rider, spell) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
const own = ((_b = (_a = spell.entity.damage) == null ? void 0 : _a.types) != null ? _b : []).map((t) => t.toLowerCase());
|
|
83
|
+
return !rider.condition && (!rider.damage_type || own.includes(rider.damage_type.toLowerCase()));
|
|
84
|
+
}
|
|
85
|
+
var reaching = (spell, derived) => {
|
|
86
|
+
var _a;
|
|
87
|
+
return ((_a = derived.spellDamageRiders) != null ? _a : []).filter((r) => {
|
|
88
|
+
var _a2;
|
|
89
|
+
return (_a2 = r.spells) == null ? void 0 : _a2.includes(spell.slug);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
function addSpellDamageRiders(roll, spell, derived) {
|
|
93
|
+
return addToRoll(roll, reaching(spell, derived).filter((r) => foldsIntoRoll(r, spell)).map((r) => r.amount));
|
|
94
|
+
}
|
|
95
|
+
function spellDamageRiderLines(spell, derived) {
|
|
96
|
+
return reaching(spell, derived).filter((r) => !foldsIntoRoll(r, spell)).map((r) => ({
|
|
97
|
+
amount: r.amount,
|
|
98
|
+
...r.damage_type ? { damage_type: r.damage_type } : {},
|
|
99
|
+
...r.source ? { source: r.source } : {},
|
|
100
|
+
...r.condition ? { condition: r.condition } : {}
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
77
103
|
|
|
78
104
|
export {
|
|
79
105
|
ownerClassSlug,
|
|
80
106
|
amountBindingsFor,
|
|
81
107
|
spellcastingFor,
|
|
82
108
|
spellAmountBindings,
|
|
83
|
-
spellRollBonus
|
|
109
|
+
spellRollBonus,
|
|
110
|
+
addSpellDamageRiders,
|
|
111
|
+
spellDamageRiderLines
|
|
84
112
|
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-CJYCVNW2.js";
|
|
9
9
|
import {
|
|
10
10
|
featureSchema
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-B2QHP6UF.js";
|
|
12
12
|
import {
|
|
13
13
|
resourceSchema
|
|
14
14
|
} from "./chunk-ZJXSXVFP.js";
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "./chunk-IN4M4X7P.js";
|
|
19
19
|
import {
|
|
20
20
|
choiceSchema
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-OOL4KMG2.js";
|
|
22
22
|
import {
|
|
23
23
|
additionalSpellsEntrySchema,
|
|
24
24
|
imageField,
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
} from "./chunk-ZJXSXVFP.js";
|
|
9
9
|
import {
|
|
10
10
|
choiceSchema
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-OOL4KMG2.js";
|
|
12
12
|
import {
|
|
13
13
|
featureEffectSchema
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JXWNXIIZ.js";
|
|
15
15
|
import {
|
|
16
16
|
additionalSpellsEntrySchema,
|
|
17
17
|
imageField,
|
|
@@ -141,6 +141,12 @@ function resolveAmountText(text, b) {
|
|
|
141
141
|
if (/\b(?:floor|ceil|max|min)\(/.test(display)) return text;
|
|
142
142
|
return display;
|
|
143
143
|
}
|
|
144
|
+
function addToRoll(roll, amounts) {
|
|
145
|
+
var _a;
|
|
146
|
+
if (!amounts.length) return roll;
|
|
147
|
+
const text = tidySigns([roll, ...amounts].join(" + "));
|
|
148
|
+
return (_a = foldDice(text)) != null ? _a : text;
|
|
149
|
+
}
|
|
144
150
|
function diceRollOf(resolved) {
|
|
145
151
|
var _a, _b;
|
|
146
152
|
return (_b = (_a = diceRollPrefix(resolved)) == null ? void 0 : _a.notation) != null ? _b : null;
|
|
@@ -153,6 +159,7 @@ function diceRollPrefix(text) {
|
|
|
153
159
|
export {
|
|
154
160
|
normalizeAmountPhrases,
|
|
155
161
|
resolveAmountText,
|
|
162
|
+
addToRoll,
|
|
156
163
|
diceRollOf,
|
|
157
164
|
diceRollPrefix
|
|
158
165
|
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
classCodec
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-GVWEFECG.js";
|
|
4
|
+
import "../chunk-XTEFPUSN.js";
|
|
5
5
|
import "../chunk-4U55VNC7.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-UJCK5IW4.js";
|
|
7
7
|
import "../chunk-G6MHJDVT.js";
|
|
8
8
|
import "../chunk-CJYCVNW2.js";
|
|
9
|
-
import "../chunk-
|
|
9
|
+
import "../chunk-B2QHP6UF.js";
|
|
10
10
|
import "../chunk-WYGD2UGN.js";
|
|
11
11
|
import "../chunk-ZJXSXVFP.js";
|
|
12
12
|
import "../chunk-IN4M4X7P.js";
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-OOL4KMG2.js";
|
|
14
|
+
import "../chunk-JXWNXIIZ.js";
|
|
15
15
|
import "../chunk-UA5KS2PL.js";
|
|
16
16
|
export {
|
|
17
17
|
classCodec
|