@archivist-gg/dnd5e 0.3.13 → 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/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-ZMJQUZQH.js → chunk-2JSQE3DD.js} +11 -0
- package/dist/{chunk-Q6UOHCCT.js → chunk-2UDSN6VW.js} +1 -1
- package/dist/chunk-3LWMFYKS.js +57 -0
- package/dist/{chunk-MUIU7RZ3.js → chunk-3MGQFFNE.js} +1 -1
- package/dist/{chunk-T5GZBKIQ.js → chunk-3VZZDKRA.js} +114 -27
- package/dist/{chunk-BRGLDWUP.js → chunk-5MXFW4O3.js} +7 -3
- package/dist/{chunk-RQNJXADQ.js → chunk-6EI737IO.js} +1 -1
- package/dist/{chunk-EL6QPF6I.js → chunk-7ATNGKBS.js} +1 -1
- package/dist/{chunk-XY6X2APM.js → chunk-7Q2VPKCD.js} +17 -0
- package/dist/{chunk-4SLOJXJ4.js → chunk-7QN7XSAK.js} +1 -1
- package/dist/{chunk-MC5YJ4PB.js → chunk-AZRGFUSR.js} +1 -1
- package/dist/{chunk-HJQNK3J5.js → chunk-B3DP42OM.js} +1 -4
- package/dist/{chunk-JNNNBEUH.js → chunk-DOXSFYLH.js} +7 -2
- package/dist/{chunk-X7VZY4ON.js → chunk-FANQVQ3D.js} +2 -2
- package/dist/{chunk-PX25R3DK.js → chunk-G6PBI2BU.js} +1 -1
- package/dist/chunk-HTYMW5CH.js +228 -0
- package/dist/{chunk-VDPRBUU5.js → chunk-JCMUVZIK.js} +1 -1
- package/dist/{chunk-Q5XTEYHD.js → chunk-JSM6JFZR.js} +15 -8
- package/dist/chunk-KR6JF3BF.js +14 -0
- package/dist/{chunk-J53ERF6K.js → chunk-LF5AGJA4.js} +1 -1
- package/dist/{chunk-XJRNEQPD.js → chunk-MBX25B6D.js} +1 -1
- package/dist/{chunk-5KGV6TF7.js → chunk-OFCSP6MT.js} +1 -1
- package/dist/{chunk-QEO7LYTG.js → chunk-ONTGZR5T.js} +127 -71
- package/dist/{chunk-MWCCGPG3.js → chunk-OOSRUJBI.js} +3 -2
- package/dist/{chunk-LVX6TQ3R.js → chunk-PKX6TGRE.js} +2 -2
- package/dist/{chunk-QSBJ6NEM.js → chunk-PQZ4LM4Z.js} +1 -1
- package/dist/chunk-PXVNAY7T.js +84 -0
- package/dist/chunk-QH36K2PU.js +158 -0
- package/dist/{chunk-M2OWVAZG.js → chunk-QZSWN2KT.js} +1 -1
- package/dist/{chunk-6ZY3U6BQ.js → chunk-RYLXAYIQ.js} +1 -1
- package/dist/{chunk-UE6LKRXQ.js → chunk-T6QIF5XR.js} +16 -0
- package/dist/{chunk-4BZ47YJ4.js → chunk-TULQ4FFX.js} +32 -11
- package/dist/{chunk-PLOSP4XQ.js → chunk-UUBJCNQU.js} +11 -2
- package/dist/{chunk-DPM6V7YX.js → chunk-VRV3NNTA.js} +1 -1
- package/dist/{chunk-R2V5LN3I.js → chunk-Y5VVP73C.js} +1 -1
- package/dist/{chunk-FPGXFD2M.js → chunk-YD2VAHA6.js} +2 -2
- package/dist/{chunk-G7ED5H2G.js → chunk-YKL6SHRJ.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 +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/feat/feat.codec.js +5 -5
- package/dist/feat/feat.parser.js +4 -4
- package/dist/feat/feat.schema.d.ts +25 -0
- package/dist/feat/feat.schema.js +3 -3
- package/dist/index.js +332 -70
- 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 +26 -0
- package/dist/optional-feature/optional-feature.schema.js +3 -2
- package/dist/pc/pc.additional-spells.js +2 -2
- package/dist/pc/pc.amount-bindings.d.ts +32 -0
- package/dist/pc/pc.amount-bindings.js +23 -0
- package/dist/pc/pc.decision-engine.d.ts +3 -0
- package/dist/pc/pc.decision-engine.js +14 -13
- package/dist/pc/pc.entry-overrides.js +3 -3
- package/dist/pc/pc.equipment.js +6 -5
- package/dist/pc/pc.feature-effects.d.ts +12 -0
- package/dist/pc/pc.feature-effects.js +1 -1
- package/dist/pc/pc.infusions.d.ts +9 -1
- package/dist/pc/pc.infusions.js +3 -3
- 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 +1 -1
- package/dist/pc/pc.pools.d.ts +7 -0
- package/dist/pc/pc.pools.js +5 -3
- package/dist/pc/pc.proficiencies.js +13 -12
- package/dist/pc/pc.proficiency-query.js +6 -0
- package/dist/pc/pc.recalc.js +75 -58
- package/dist/pc/pc.resolver.d.ts +2 -1
- package/dist/pc/pc.resolver.js +13 -12
- package/dist/pc/pc.rest.js +4 -4
- package/dist/pc/pc.schema.d.ts +29 -2
- package/dist/pc/pc.schema.js +1 -1
- package/dist/pc/pc.types.d.ts +45 -2
- 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 +25 -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 +5 -0
- package/dist/types/feature-effect.d.ts +6 -0
- package/dist/types/optional-feature.types.d.ts +5 -0
- package/dist/types/selection-pool.d.ts +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parsePickKey,
|
|
3
|
+
poolAnchorLevel
|
|
4
|
+
} from "./chunk-3VZZDKRA.js";
|
|
5
|
+
import {
|
|
6
|
+
featProgressionCategory
|
|
7
|
+
} from "./chunk-YBLDE5CG.js";
|
|
8
|
+
import {
|
|
9
|
+
warnOnce
|
|
10
|
+
} from "./chunk-LVQLWRCU.js";
|
|
11
|
+
import {
|
|
12
|
+
bareEntitySlug
|
|
13
|
+
} from "./chunk-ZCTUYGNV.js";
|
|
14
|
+
|
|
15
|
+
// src/pc/pc.member-choices.ts
|
|
16
|
+
var OPTIONAL_FEATURE_TYPE_CODE = {
|
|
17
|
+
"MV:B": "maneuver",
|
|
18
|
+
MV: "maneuver",
|
|
19
|
+
EI: "invocation",
|
|
20
|
+
MM: "metamagic",
|
|
21
|
+
"FS:F": "fighting_style"
|
|
22
|
+
};
|
|
23
|
+
function spellFilter(choose, edition) {
|
|
24
|
+
const where = { edition };
|
|
25
|
+
for (const part of choose.split("|")) {
|
|
26
|
+
const [rawKey, rawValue = ""] = part.split("=");
|
|
27
|
+
const key = rawKey.trim().toLowerCase();
|
|
28
|
+
const value = rawValue.trim();
|
|
29
|
+
if (key === "level") {
|
|
30
|
+
const n = Number(value.split(";")[0]);
|
|
31
|
+
if (!Number.isInteger(n)) return null;
|
|
32
|
+
where.level = n;
|
|
33
|
+
} else if (key === "class") where.list = value.toLowerCase();
|
|
34
|
+
else if (key === "components & miscellaneous" && /ritual/i.test(value)) where.ritual = true;
|
|
35
|
+
}
|
|
36
|
+
return where;
|
|
37
|
+
}
|
|
38
|
+
function isTargetChoice(ch) {
|
|
39
|
+
return ch.kind === "select-entity" && ch.target === true;
|
|
40
|
+
}
|
|
41
|
+
function progressionCount(p) {
|
|
42
|
+
var _a;
|
|
43
|
+
if (Array.isArray(p)) return 0;
|
|
44
|
+
return (_a = p["*"]) != null ? _a : Math.max(0, ...Object.values(p));
|
|
45
|
+
}
|
|
46
|
+
function spellChoices(entity, used) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const block of (_a = entity.additional_spells) != null ? _a : []) {
|
|
50
|
+
for (const bucket of ["known", "prepared"]) {
|
|
51
|
+
const byLevel = block[bucket];
|
|
52
|
+
if (!byLevel || typeof byLevel !== "object") continue;
|
|
53
|
+
for (const rows of Object.values(byLevel)) {
|
|
54
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
55
|
+
const r = row;
|
|
56
|
+
if (typeof r.choose !== "string") continue;
|
|
57
|
+
const where = spellFilter(r.choose, entity.edition);
|
|
58
|
+
if (!where) continue;
|
|
59
|
+
const base = where.ritual ? "rituals" : where.level === 0 ? "cantrips" : `spells-${(_b = where.level) != null ? _b : "any"}`;
|
|
60
|
+
const label = where.ritual ? "Rituals" : where.level === 0 ? "Cantrips" : `Level ${where.level} spells`;
|
|
61
|
+
let id = base;
|
|
62
|
+
for (let i = 2; used.has(id); i++) id = `${base}-${i}`;
|
|
63
|
+
used.add(id);
|
|
64
|
+
out.push({ kind: "select-entity", id, label, count: typeof r.count === "number" ? r.count : 1, entity_type: "spell", where });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
function memberChoices(entity) {
|
|
72
|
+
var _a, _b, _c, _d, _e, _f;
|
|
73
|
+
if (!entity) return [];
|
|
74
|
+
if ((_a = entity.choices) == null ? void 0 : _a.length) return entity.choices;
|
|
75
|
+
const out = [];
|
|
76
|
+
const used = /* @__PURE__ */ new Set();
|
|
77
|
+
for (const fp of (_b = entity.feat_progression) != null ? _b : []) {
|
|
78
|
+
const category = featProgressionCategory(fp.category);
|
|
79
|
+
const count = progressionCount(fp.progression);
|
|
80
|
+
if (!category || count < 1) continue;
|
|
81
|
+
const id = used.has("feat") ? `feat-${used.size}` : "feat";
|
|
82
|
+
used.add(id);
|
|
83
|
+
out.push({ kind: "select-entity", id, label: fp.name, count, entity_type: "feat", where: { category, edition: entity.edition } });
|
|
84
|
+
}
|
|
85
|
+
for (const op of (_c = entity.optionalfeature_progression) != null ? _c : []) {
|
|
86
|
+
const codes = (_e = (_d = op.feature_type) != null ? _d : op.featureType) != null ? _e : [];
|
|
87
|
+
const featureType = codes.map((c) => OPTIONAL_FEATURE_TYPE_CODE[c]).find((t) => !!t);
|
|
88
|
+
const count = progressionCount(op.progression);
|
|
89
|
+
if (!featureType || count < 1) {
|
|
90
|
+
if (!featureType) warnOnce(`member-of-code:${entity.slug}`, `Archivist: "${entity.slug}" asks for optional features of type ${codes.join(", ")}, which this engine does not map; no pick is offered`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const id = op.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "option";
|
|
94
|
+
used.add(id);
|
|
95
|
+
out.push({ kind: "select-entity", id, label: op.name, count, entity_type: "optional-feature", where: { feature_type: featureType, edition: entity.edition } });
|
|
96
|
+
}
|
|
97
|
+
out.push(...spellChoices(entity, used));
|
|
98
|
+
for (const pre of (_f = entity.prerequisites) != null ? _f : []) {
|
|
99
|
+
if (pre.kind !== "spell-choose") continue;
|
|
100
|
+
const where = spellFilter(pre.choose, entity.edition);
|
|
101
|
+
if (!where || used.has("cantrip")) continue;
|
|
102
|
+
used.add("cantrip");
|
|
103
|
+
out.push({ kind: "select-entity", id: "cantrip", label: where.level === 0 ? "Cantrip" : "Spell", count: 1, entity_type: "spell", where, target: true });
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
function siteOf(classIndex, level, poolId, pickKey, member, memberSlug, block) {
|
|
108
|
+
const choices = memberChoices(member);
|
|
109
|
+
if (!choices.length) return null;
|
|
110
|
+
const prefix = `${poolId}:${pickKey}:`;
|
|
111
|
+
return { classIndex, level, poolId, pickKey, member, memberSlug, choices, prefix, block, read: (id) => block[`${prefix}${id}`] };
|
|
112
|
+
}
|
|
113
|
+
function poolMemberSites(classes, registry) {
|
|
114
|
+
const out = [];
|
|
115
|
+
let byBare = null;
|
|
116
|
+
let all = null;
|
|
117
|
+
const lookup = (s, ownerPrefix) => {
|
|
118
|
+
all != null ? all : all = registry.search("", "optional-feature", Number.POSITIVE_INFINITY);
|
|
119
|
+
const bare = bareEntitySlug(s);
|
|
120
|
+
const owned = all.find((e) => bareEntitySlug(e.slug) === bare && e.slug.split("_")[0] === ownerPrefix);
|
|
121
|
+
if (owned) return owned;
|
|
122
|
+
const direct = registry.getByTypeAndSlug("optional-feature", s);
|
|
123
|
+
if (direct) return direct;
|
|
124
|
+
byBare != null ? byBare : byBare = new Map(all.map((e) => [bareEntitySlug(e.slug), e]));
|
|
125
|
+
return byBare.get(bare);
|
|
126
|
+
};
|
|
127
|
+
classes.forEach((rc, classIndex) => {
|
|
128
|
+
var _a, _b, _c, _d, _e;
|
|
129
|
+
if (!rc.entity) return;
|
|
130
|
+
const seen = /* @__PURE__ */ new Set();
|
|
131
|
+
for (const pool of [...(_a = rc.entity.selection_pools) != null ? _a : [], ...(_c = (_b = rc.subclass) == null ? void 0 : _b.selection_pools) != null ? _c : []]) {
|
|
132
|
+
if (seen.has(pool.id)) continue;
|
|
133
|
+
seen.add(pool.id);
|
|
134
|
+
const { anchorLevel } = poolAnchorLevel(rc.entity, pool);
|
|
135
|
+
const block = (_e = (_d = rc.choices) == null ? void 0 : _d[anchorLevel]) != null ? _e : {};
|
|
136
|
+
const raw = block[pool.id];
|
|
137
|
+
const picks = Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
|
|
138
|
+
for (const s of picks) {
|
|
139
|
+
if (typeof s !== "string") continue;
|
|
140
|
+
const { slugPart, param } = parsePickKey(s);
|
|
141
|
+
const reg = lookup(slugPart, rc.entity.slug.split("_")[0]);
|
|
142
|
+
if (!reg) continue;
|
|
143
|
+
const member = reg.data;
|
|
144
|
+
const key = member.repeatable === true || param !== null ? s : reg.slug;
|
|
145
|
+
const site = siteOf(classIndex, anchorLevel, pool.id, key, member, reg.slug, block);
|
|
146
|
+
if (site) out.push(site);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
function poolMemberSitesOf(resolved) {
|
|
153
|
+
var _a, _b, _c, _d, _e, _f;
|
|
154
|
+
const out = [];
|
|
155
|
+
for (const pool of (_a = resolved.pools) != null ? _a : []) {
|
|
156
|
+
const block = (_e = (_d = (_c = (_b = resolved.classes) == null ? void 0 : _b[pool.classIndex]) == null ? void 0 : _c.choices) == null ? void 0 : _d[pool.anchorLevel]) != null ? _e : {};
|
|
157
|
+
for (const e of (_f = pool.selected) != null ? _f : []) {
|
|
158
|
+
const site = siteOf(pool.classIndex, pool.anchorLevel, pool.id, e.key, e.entity, e.slug, block);
|
|
159
|
+
if (site) out.push(site);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
var stripRef = (ref) => ref.replace(/^\[\[/, "").replace(/\]\]$/, "");
|
|
165
|
+
function featPickSites(classEntries, memberSites, classSlugOf) {
|
|
166
|
+
const out = [];
|
|
167
|
+
(classEntries != null ? classEntries : []).forEach((c, classIndex) => {
|
|
168
|
+
var _a;
|
|
169
|
+
for (const [lvl, choiceBlock] of Object.entries((_a = c.choices) != null ? _a : {})) {
|
|
170
|
+
const block = choiceBlock;
|
|
171
|
+
const feat = block == null ? void 0 : block.feat;
|
|
172
|
+
if (!block || typeof feat !== "string") continue;
|
|
173
|
+
const slug = stripRef(feat);
|
|
174
|
+
if (!slug) continue;
|
|
175
|
+
const level = /^\d+$/.test(lvl) ? Number(lvl) : null;
|
|
176
|
+
const cls = classSlugOf(classIndex);
|
|
177
|
+
out.push({
|
|
178
|
+
slug,
|
|
179
|
+
classIndex,
|
|
180
|
+
level,
|
|
181
|
+
via: cls && level !== null ? { kind: "class", slug: cls, level } : null,
|
|
182
|
+
read: (id) => block[`feat:${id}`]
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
for (const site of memberSites) {
|
|
187
|
+
for (const ch of site.choices) {
|
|
188
|
+
if (ch.kind !== "select-entity" || ch.entity_type !== "feat" || ch.target === true) continue;
|
|
189
|
+
const v = site.read(ch.id);
|
|
190
|
+
for (const ref of Array.isArray(v) ? v : typeof v === "string" ? [v] : []) {
|
|
191
|
+
if (typeof ref !== "string") continue;
|
|
192
|
+
const slug = stripRef(ref);
|
|
193
|
+
if (!slug) continue;
|
|
194
|
+
const cls = classSlugOf(site.classIndex);
|
|
195
|
+
out.push({
|
|
196
|
+
slug,
|
|
197
|
+
classIndex: site.classIndex,
|
|
198
|
+
level: site.level,
|
|
199
|
+
via: cls ? { kind: "pool", slug: site.memberSlug, name: site.member.name, classSlug: cls, level: site.level } : null,
|
|
200
|
+
read: (id) => site.block[`${site.prefix}feat:${id}`]
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
function featOfSite(site, feats) {
|
|
208
|
+
var _a;
|
|
209
|
+
return (_a = feats.find((f) => f.slug === site.slug)) != null ? _a : feats.find((f) => bareEntitySlug(f.slug) === bareEntitySlug(site.slug));
|
|
210
|
+
}
|
|
211
|
+
function nestedPickKeysToPrune(block, key, next) {
|
|
212
|
+
const prev = block == null ? void 0 : block[key];
|
|
213
|
+
if (!block || !Array.isArray(prev)) return [];
|
|
214
|
+
const keep = new Set(next);
|
|
215
|
+
const gone = prev.filter((k) => typeof k === "string" && !keep.has(k));
|
|
216
|
+
if (!gone.length) return [];
|
|
217
|
+
return Object.keys(block).filter((k) => gone.some((g) => k.startsWith(`${key}:${g}:`)));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export {
|
|
221
|
+
isTargetChoice,
|
|
222
|
+
memberChoices,
|
|
223
|
+
poolMemberSites,
|
|
224
|
+
poolMemberSitesOf,
|
|
225
|
+
featPickSites,
|
|
226
|
+
featOfSite,
|
|
227
|
+
nestedPickKeysToPrune
|
|
228
|
+
};
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
qualifiedGrantCovers
|
|
3
|
+
} from "./chunk-3LWMFYKS.js";
|
|
1
4
|
import {
|
|
2
5
|
classifyWeaponRange
|
|
3
6
|
} from "./chunk-YDGMBMYI.js";
|
|
7
|
+
import {
|
|
8
|
+
resolveContainment
|
|
9
|
+
} from "./chunk-EJP263OP.js";
|
|
4
10
|
import {
|
|
5
11
|
normKey
|
|
6
12
|
} from "./chunk-RLGQ5PZZ.js";
|
|
7
13
|
import {
|
|
8
14
|
WEAPON_DEFAULT_ACTION_COST,
|
|
9
15
|
resolveEntryEntity
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import {
|
|
12
|
-
resolveContainment
|
|
13
|
-
} from "./chunk-EJP263OP.js";
|
|
16
|
+
} from "./chunk-3VZZDKRA.js";
|
|
14
17
|
import {
|
|
15
18
|
readNumericBonus
|
|
16
19
|
} from "./chunk-HHBD4SQ6.js";
|
|
@@ -61,6 +64,7 @@ function emptyAppliedBonuses() {
|
|
|
61
64
|
ability_bonuses: {},
|
|
62
65
|
ability_statics: {},
|
|
63
66
|
save_bonus: 0,
|
|
67
|
+
save_terms: [],
|
|
64
68
|
speed_bonuses: { walk: 0, fly: null, swim: 0, climb: 0 },
|
|
65
69
|
spell_attack: 0,
|
|
66
70
|
spell_save_dc: 0,
|
|
@@ -103,7 +107,7 @@ function pushApply(outcome, field, source, pool, onApply) {
|
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
function computeAppliedBonuses(resolved, _profs, registry, warnings) {
|
|
106
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
110
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
|
|
107
111
|
const out = emptyAppliedBonuses();
|
|
108
112
|
const equipment = (_a = resolved.definition.equipment) != null ? _a : [];
|
|
109
113
|
const ctx = buildConditionContext(resolved, {}, registry);
|
|
@@ -135,13 +139,15 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
|
|
|
135
139
|
}
|
|
136
140
|
const b = item.bonuses;
|
|
137
141
|
if (!b) continue;
|
|
142
|
+
const saveSource = (_q = (_p = entry.overrides) == null ? void 0 : _p.name) != null ? _q : item.name;
|
|
138
143
|
pushApply(
|
|
139
144
|
readNumericBonus(b.saving_throws, ctx),
|
|
140
145
|
"saving_throws",
|
|
141
|
-
|
|
146
|
+
saveSource,
|
|
142
147
|
out.informational,
|
|
143
148
|
(v) => {
|
|
144
149
|
out.save_bonus += v;
|
|
150
|
+
out.save_terms.push({ source: saveSource, amount: v });
|
|
145
151
|
}
|
|
146
152
|
);
|
|
147
153
|
pushApply(
|
|
@@ -162,7 +168,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
|
|
|
162
168
|
out.spell_save_dc += v;
|
|
163
169
|
}
|
|
164
170
|
);
|
|
165
|
-
if ((
|
|
171
|
+
if ((_r = b.ability_scores) == null ? void 0 : _r.bonus) {
|
|
166
172
|
for (const [k, v] of Object.entries(b.ability_scores.bonus)) {
|
|
167
173
|
if (!isAbilityKey(k)) continue;
|
|
168
174
|
pushApply(
|
|
@@ -177,7 +183,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
|
|
|
177
183
|
);
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
|
-
if ((
|
|
186
|
+
if ((_s = b.ability_scores) == null ? void 0 : _s.static) {
|
|
181
187
|
for (const [k, n] of Object.entries(b.ability_scores.static)) {
|
|
182
188
|
if (!isAbilityKey(k) || typeof n !== "number") continue;
|
|
183
189
|
const prev = out.ability_statics[k];
|
|
@@ -411,6 +417,7 @@ function attackAbility(weapon, mods, weaponAbilities) {
|
|
|
411
417
|
function isWeaponSlugProficient(weapon, weaponSlug, profs) {
|
|
412
418
|
const wp = profs.weapons;
|
|
413
419
|
if (wp.specific.some((e) => e === weaponSlug || normKey(e) === normKey(weapon.name))) return true;
|
|
420
|
+
if (wp.specific.some((e) => qualifiedGrantCovers(e, weapon))) return true;
|
|
414
421
|
const cat = weapon.category;
|
|
415
422
|
if (typeof cat === "string") {
|
|
416
423
|
if (/^simple\b/.test(cat) && wp.categories.includes("simple")) return true;
|
|
@@ -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
|
+
};
|