@archivist-gg/dnd5e 0.3.1 → 0.3.5
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 +25 -6
- package/dist/armor/armor.codec.js +4 -3
- package/dist/armor/armor.parser.js +3 -2
- package/dist/armor/armor.schema.d.ts +4 -0
- package/dist/armor/armor.schema.js +2 -1
- package/dist/armor/armor.types.d.ts +8 -0
- package/dist/background/background.codec.js +7 -6
- package/dist/background/background.parser.js +6 -5
- package/dist/background/background.schema.d.ts +26 -0
- package/dist/background/background.schema.js +5 -4
- package/dist/background/background.types.d.ts +22 -0
- package/dist/{chunk-4TIJKN6O.js → chunk-23LZLBJK.js} +1 -1
- package/dist/{chunk-AFKTJXRA.js → chunk-2DFENQIJ.js} +18 -0
- package/dist/chunk-2FRUSVZS.js +489 -0
- package/dist/chunk-2VDTW7QO.js +1580 -0
- package/dist/{chunk-ZZGEVJKX.js → chunk-3JOTQW7A.js} +1 -1
- package/dist/{chunk-5ZBE4CWV.js → chunk-3PZHBLFG.js} +1 -1
- package/dist/chunk-4U55VNC7.js +22 -0
- package/dist/{chunk-4JHOHWBI.js → chunk-4XTNPNQB.js} +1 -1
- package/dist/{chunk-HCP3GMHS.js → chunk-5N2GW72F.js} +15 -2
- package/dist/{chunk-42Y5IJKT.js → chunk-5RKLL2AD.js} +5 -1
- package/dist/{chunk-SE7AZDR3.js → chunk-63XQXPZL.js} +29 -3
- package/dist/{chunk-4F6AIZ36.js → chunk-6BFWZW6T.js} +1 -1
- package/dist/{chunk-GJOI2GHP.js → chunk-6GNXYAYP.js} +1 -1
- package/dist/{chunk-66XXW2Z2.js → chunk-6PXTNCBP.js} +2 -2
- package/dist/chunk-6X2NV665.js +33 -0
- package/dist/{chunk-LV4SNWZQ.js → chunk-6X4KUDMU.js} +8 -1
- package/dist/{chunk-ZMR77DDL.js → chunk-AW3EHF3L.js} +1 -1
- package/dist/{chunk-TLYDBT5F.js → chunk-CGRLQ34U.js} +64 -7
- package/dist/chunk-CJYCVNW2.js +7 -0
- package/dist/{chunk-XLSVNUTK.js → chunk-CV5XDJKU.js} +1 -1
- package/dist/{chunk-RAWJTA45.js → chunk-DEEHHLAP.js} +1 -1
- package/dist/{chunk-6IRYTM5V.js → chunk-DPUJDOKV.js} +119 -28
- package/dist/{chunk-GE4TLPWM.js → chunk-EHDATXP7.js} +1 -1
- package/dist/chunk-EVMUJYUD.js +195 -0
- package/dist/{chunk-K6Q5OUGK.js → chunk-GFZ7PITJ.js} +86 -10
- package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
- package/dist/{chunk-TN6ZLTNU.js → chunk-I2NDWFDD.js} +51 -4
- package/dist/{chunk-3DZ74AKK.js → chunk-IN4M4X7P.js} +8 -2
- package/dist/chunk-IUAAXXNO.js +58 -0
- package/dist/{chunk-NXSWH3AE.js → chunk-IWRVOCT5.js} +1 -1
- package/dist/{chunk-XJNECUPT.js → chunk-JC5UNIVM.js} +19 -0
- package/dist/{chunk-24GFQU7T.js → chunk-JSZ4H6AQ.js} +1 -1
- package/dist/{chunk-XTIQWSFM.js → chunk-KADJZGZY.js} +1 -1
- package/dist/{chunk-L7E2UT5A.js → chunk-KK33PIDN.js} +5 -1
- package/dist/chunk-KPEJMNRD.js +302 -0
- package/dist/chunk-KU3YLF6D.js +106 -0
- package/dist/{chunk-5INR4NSL.js → chunk-LDDCNPHD.js} +1 -1
- package/dist/chunk-LVQLWRCU.js +15 -0
- package/dist/chunk-MI7P3NX3.js +161 -0
- package/dist/{chunk-PHQRGDRQ.js → chunk-N3A5ICBO.js} +5 -1
- package/dist/chunk-O4SRD3J5.js +165 -0
- package/dist/chunk-OAXWSVJB.js +81 -0
- package/dist/chunk-OZP6JFGT.js +162 -0
- package/dist/{chunk-NAEPSZAM.js → chunk-PDJSUH24.js} +24 -2
- package/dist/chunk-PP2UHLBA.js +50 -0
- package/dist/chunk-PVCEA4HZ.js +6 -0
- package/dist/{chunk-RSDRMH54.js → chunk-RF4TYCA2.js} +1 -1
- package/dist/chunk-RLGQ5PZZ.js +16 -0
- package/dist/chunk-RVXC6ZHY.js +89 -0
- package/dist/chunk-S7REMWW4.js +21 -0
- package/dist/{chunk-7VJ6BOA5.js → chunk-SMLXZUBH.js} +9 -1
- package/dist/chunk-TOM66P2P.js +38 -0
- package/dist/chunk-UA5KS2PL.js +26 -0
- package/dist/{chunk-N6N74K6X.js → chunk-UBBKSYBY.js} +1 -1
- package/dist/{chunk-353WXS6S.js → chunk-UIRMA5KM.js} +1 -1
- package/dist/{chunk-BIK4DFWK.js → chunk-ULCQ73LA.js} +1 -1
- package/dist/{chunk-2BWAID3Y.js → chunk-UMWIPLLM.js} +29 -3
- package/dist/chunk-UQ3ZFCWD.js +178 -0
- package/dist/chunk-UXPGW4TI.js +101 -0
- package/dist/chunk-V2MJE6NC.js +133 -0
- package/dist/{chunk-D3CLOBE3.js → chunk-V373TRJE.js} +48 -10
- package/dist/chunk-VQAXTIBW.js +100 -0
- package/dist/chunk-W74BCA7V.js +159 -0
- package/dist/{chunk-WP2CX2JO.js → chunk-WELIKLZF.js} +22 -1
- package/dist/{chunk-MDEJHMKK.js → chunk-WHVLNFTG.js} +26 -5
- package/dist/{chunk-GZ46OVGZ.js → chunk-WSVMLNTO.js} +1 -1
- package/dist/{chunk-4LZJXJJS.js → chunk-WXWPK3LI.js} +6 -2
- package/dist/chunk-X3D6LXUU.js +185 -0
- package/dist/chunk-XJ2F2WO6.js +8 -0
- package/dist/{chunk-73HOFQQ5.js → chunk-Y4AGLCY6.js} +1 -1
- package/dist/chunk-YBLDE5CG.js +42 -0
- package/dist/{chunk-JEYQU3JT.js → chunk-YHYTW5QA.js} +2 -18
- package/dist/{chunk-PZOWBI3B.js → chunk-YLL2QXY2.js} +7 -2
- package/dist/class/class.codec.js +12 -9
- package/dist/class/class.parser.js +11 -8
- package/dist/class/class.schema.d.ts +55 -3
- package/dist/class/class.schema.js +9 -7
- package/dist/class/class.types.d.ts +48 -3
- package/dist/condition/condition.codec.d.ts +9 -0
- package/dist/condition/condition.entity-type.d.ts +2 -0
- package/dist/condition/condition.parser.d.ts +13 -0
- package/dist/condition/condition.parser.js +7 -0
- package/dist/condition/condition.schema.d.ts +29 -0
- package/dist/condition/condition.types.d.ts +15 -0
- package/dist/condition/condition.types.js +0 -0
- package/dist/dnd/constants.d.ts +22 -0
- package/dist/dnd/constants.js +9 -3
- package/dist/dnd/formula-tags.js +2 -2
- package/dist/dnd/math.d.ts +26 -0
- package/dist/dnd/math.js +12 -2
- package/dist/dnd/prose-tags.js +1 -1
- package/dist/dnd/resource-formula.d.ts +36 -10
- package/dist/dnd/resource-formula.js +10 -155
- package/dist/dnd/srd-tag-converter.js +3 -3
- package/dist/dnd/tag-grammar.js +1 -1
- package/dist/dnd/warn-once.d.ts +2 -0
- package/dist/dnd/warn-once.js +8 -0
- package/dist/entities/base-item-resolver.js +2 -2
- package/dist/entities/slug.d.ts +13 -0
- package/dist/entities/slug.js +5 -3
- package/dist/entities/wikilink-display.d.ts +3 -0
- package/dist/entities/wikilink-display.js +10 -0
- package/dist/feat/feat.category-codes.d.ts +32 -0
- package/dist/feat/feat.category-codes.js +14 -0
- package/dist/feat/feat.codec.js +7 -5
- package/dist/feat/feat.parser.js +6 -4
- package/dist/feat/feat.schema.d.ts +239 -0
- package/dist/feat/feat.schema.js +5 -3
- package/dist/feat/feat.types.d.ts +37 -1
- package/dist/index.js +2033 -6907
- package/dist/item/item.codec.js +4 -3
- package/dist/item/item.enrichment.js +4 -4
- package/dist/item/item.parser.js +3 -2
- package/dist/item/item.schema.d.ts +69 -3
- package/dist/item/item.schema.js +2 -1
- package/dist/item/item.types.d.ts +69 -3
- package/dist/monster/monster.codec.d.ts +7 -6
- package/dist/monster/monster.enrichment.js +4 -4
- package/dist/monster/monster.format.d.ts +135 -0
- package/dist/monster/monster.format.js +78 -0
- package/dist/monster/monster.parser.d.ts +6 -1
- package/dist/monster/monster.parser.js +10 -1
- package/dist/monster/monster.schema.d.ts +369 -0
- package/dist/monster/monster.schema.js +34 -0
- package/dist/monster/monster.types.d.ts +200 -14
- package/dist/optional-feature/optional-feature.codec.js +6 -5
- package/dist/optional-feature/optional-feature.parser.js +5 -4
- package/dist/optional-feature/optional-feature.schema.d.ts +185 -0
- package/dist/optional-feature/optional-feature.schema.js +4 -3
- package/dist/pack.d.ts +1 -1
- package/dist/pc/conditions.constants.d.ts +0 -1
- package/dist/pc/conditions.constants.js +1 -3
- package/dist/pc/decision-recognizer.js +1 -1
- package/dist/pc/pc.additional-spells.d.ts +47 -0
- package/dist/pc/pc.additional-spells.js +23 -0
- package/dist/pc/pc.asi-flatten.d.ts +18 -0
- package/dist/pc/pc.decision-engine.d.ts +105 -17
- package/dist/pc/pc.decision-engine.js +28 -12
- package/dist/pc/pc.defense-normalize.d.ts +11 -0
- package/dist/pc/pc.defense-normalize.js +6 -0
- package/dist/pc/pc.equipment.d.ts +31 -2
- package/dist/pc/pc.equipment.js +12 -8
- package/dist/pc/pc.feature-effects.d.ts +234 -11
- package/dist/pc/pc.feature-effects.js +21 -5
- package/dist/pc/pc.parser.js +2 -2
- package/dist/pc/pc.pools.d.ts +11 -3
- package/dist/pc/pc.pools.js +9 -13
- package/dist/pc/pc.proficiencies.d.ts +54 -29
- package/dist/pc/pc.proficiencies.js +74 -95
- package/dist/pc/pc.proficiency-grants.d.ts +58 -0
- package/dist/pc/pc.proficiency-normalize.d.ts +24 -0
- package/dist/pc/pc.proficiency-normalize.js +12 -0
- package/dist/pc/pc.proficiency-query.d.ts +13 -0
- package/dist/pc/pc.proficiency-query.js +1 -1
- package/dist/pc/pc.recalc.d.ts +69 -14
- package/dist/pc/pc.recalc.js +261 -122
- package/dist/pc/pc.resolver.d.ts +34 -8
- package/dist/pc/pc.resolver.js +27 -12
- package/dist/pc/pc.resource-seed.d.ts +3 -2
- package/dist/pc/pc.resource-seed.js +19 -17
- package/dist/pc/pc.resources.d.ts +87 -0
- package/dist/pc/pc.resources.js +21 -0
- package/dist/pc/pc.rest.d.ts +10 -1
- package/dist/pc/pc.rest.js +66 -12
- package/dist/pc/pc.schema.d.ts +139 -3
- package/dist/pc/pc.schema.js +4 -2
- package/dist/pc/pc.slotting.js +3 -3
- package/dist/pc/pc.spellcasting.d.ts +75 -6
- package/dist/pc/pc.spellcasting.js +16 -6
- package/dist/pc/pc.table-column.d.ts +23 -0
- package/dist/pc/pc.table-column.js +13 -3
- package/dist/pc/pc.types.d.ts +251 -12
- package/dist/pc/pool-layout.d.ts +47 -0
- package/dist/pc/pool-layout.js +16 -0
- package/dist/pc/roll-scope.d.ts +2 -0
- package/dist/pc/roll-scope.js +8 -0
- package/dist/pc/roll-tag-labels.d.ts +40 -0
- package/dist/pc/roll-tag-labels.js +17 -0
- package/dist/pc/spell-source.d.ts +21 -0
- package/dist/pc/spell-source.js +13 -0
- package/dist/race/race.codec.js +9 -7
- package/dist/race/race.parser.js +8 -6
- package/dist/race/race.schema.d.ts +51 -1
- package/dist/race/race.schema.js +8 -5
- package/dist/race/race.structural.d.ts +7 -0
- package/dist/race/race.structural.js +6 -0
- package/dist/race/race.types.d.ts +20 -0
- package/dist/schemas/attack-schema.d.ts +5 -0
- package/dist/schemas/caster-type-schema.d.ts +14 -0
- package/dist/schemas/caster-type-schema.js +6 -0
- package/dist/schemas/choice-schema.js +2 -2
- package/dist/schemas/entity-extras-schema.d.ts +53 -0
- package/dist/schemas/entity-extras-schema.js +10 -0
- package/dist/schemas/equipment-grant-schema.d.ts +2 -0
- package/dist/schemas/equipment-grant-schema.js +1 -1
- package/dist/schemas/feature-alias.d.ts +34 -0
- package/dist/schemas/feature-effect-schema.d.ts +133 -0
- package/dist/schemas/feature-effect-schema.js +1 -1
- package/dist/schemas/feature-schema.d.ts +8 -0
- package/dist/schemas/feature-schema.js +6 -4
- package/dist/schemas/resource-schema.d.ts +43 -0
- package/dist/schemas/resource-schema.js +1 -1
- package/dist/schemas/selection-pool-schema.d.ts +2 -0
- package/dist/schemas/selection-pool-schema.js +1 -1
- package/dist/spell/spell.access.js +23 -3
- package/dist/spell/spell.codec.js +4 -3
- package/dist/spell/spell.enrichment.js +4 -4
- package/dist/spell/spell.parser.d.ts +30 -0
- package/dist/spell/spell.parser.js +9 -2
- package/dist/spell/spell.scaling.d.ts +27 -6
- package/dist/spell/spell.scaling.js +25 -6
- package/dist/spell/spell.schema.d.ts +44 -2
- package/dist/spell/spell.schema.js +2 -1
- package/dist/spell/spell.types.d.ts +14 -0
- package/dist/subclass/subclass.codec.d.ts +1 -1
- package/dist/subclass/subclass.codec.js +11 -8
- package/dist/subclass/subclass.parser.js +10 -7
- package/dist/subclass/subclass.schema.d.ts +54 -7
- package/dist/subclass/subclass.schema.js +8 -6
- package/dist/subclass/subclass.types.d.ts +20 -2
- package/dist/types/choice.d.ts +53 -2
- package/dist/types/choice.js +13 -1
- package/dist/types/equipment-grant.d.ts +8 -1
- package/dist/types/feature-effect.d.ts +85 -23
- package/dist/types/feature.d.ts +70 -1
- package/dist/types/optional-feature.types.d.ts +28 -0
- package/dist/types/resource.d.ts +21 -1
- package/dist/types/selection-pool.d.ts +17 -2
- package/dist/weapon/weapon.classify.js +2 -2
- package/dist/weapon/weapon.codec.js +4 -3
- package/dist/weapon/weapon.parser.js +3 -2
- package/dist/weapon/weapon.schema.d.ts +4 -0
- package/dist/weapon/weapon.schema.js +2 -1
- package/dist/weapon/weapon.types.d.ts +8 -0
- package/package.json +2 -2
- package/dist/chunk-5XUXXAQJ.js +0 -30
- package/dist/chunk-7P65Q426.js +0 -158
- package/dist/chunk-7TEK5KK7.js +0 -49
- package/dist/chunk-AIRFC5NQ.js +0 -143
- package/dist/chunk-CZPMTQOY.js +0 -68
- package/dist/chunk-N2JE7BWL.js +0 -81
- package/dist/chunk-NXR3BD2V.js +0 -90
- package/dist/chunk-O5EYMKFH.js +0 -6
- package/dist/chunk-Q5K6LWBZ.js +0 -45
- package/dist/chunk-TNUFPIXI.js +0 -1110
- package/dist/chunk-TZK36BU7.js +0 -38
- package/dist/chunk-W7HWMMBF.js +0 -46
- package/dist/chunk-Y4I74YEG.js +0 -33
|
@@ -1,118 +1,97 @@
|
|
|
1
1
|
import {
|
|
2
2
|
collectChosenProficiencies,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
3
|
+
collectProficiencyGrants,
|
|
4
|
+
computeEffectiveProficiencies
|
|
5
|
+
} from "../chunk-2VDTW7QO.js";
|
|
6
|
+
import "../chunk-UXPGW4TI.js";
|
|
7
|
+
import "../chunk-DPUJDOKV.js";
|
|
8
|
+
import "../chunk-O4SRD3J5.js";
|
|
9
|
+
import "../chunk-PP2UHLBA.js";
|
|
10
|
+
import "../chunk-IUAAXXNO.js";
|
|
11
|
+
import "../chunk-YHYTW5QA.js";
|
|
12
|
+
import "../chunk-MI7P3NX3.js";
|
|
13
|
+
import "../chunk-PVCEA4HZ.js";
|
|
14
|
+
import "../chunk-UBBKSYBY.js";
|
|
15
|
+
import "../chunk-KPEJMNRD.js";
|
|
16
|
+
import "../chunk-TOM66P2P.js";
|
|
17
|
+
import "../chunk-KU3YLF6D.js";
|
|
18
|
+
import {
|
|
19
|
+
proficiencyLabel,
|
|
20
|
+
toProfSlug
|
|
21
|
+
} from "../chunk-RLGQ5PZZ.js";
|
|
22
|
+
import "../chunk-LVQLWRCU.js";
|
|
23
|
+
import "../chunk-WXWPK3LI.js";
|
|
24
|
+
import "../chunk-6X4KUDMU.js";
|
|
25
|
+
import "../chunk-YBLDE5CG.js";
|
|
26
|
+
import "../chunk-EVMUJYUD.js";
|
|
12
27
|
import "../chunk-VTTA2ALZ.js";
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
28
|
+
import "../chunk-OZP6JFGT.js";
|
|
29
|
+
import "../chunk-VQAXTIBW.js";
|
|
30
|
+
import "../chunk-PDJSUH24.js";
|
|
31
|
+
import "../chunk-WELIKLZF.js";
|
|
32
|
+
import "../chunk-4U55VNC7.js";
|
|
33
|
+
import "../chunk-UA5KS2PL.js";
|
|
15
34
|
|
|
16
35
|
// src/pc/pc.proficiencies.ts
|
|
17
36
|
function collectProficiencySources(resolved) {
|
|
18
|
-
|
|
19
|
-
const classArmor = [];
|
|
20
|
-
const classWeaponFixed = [];
|
|
21
|
-
const classWeaponCategories = [];
|
|
22
|
-
const classToolFixed = [];
|
|
23
|
-
for (const c of resolved.classes) {
|
|
24
|
-
const prof = (_a = c.entity) == null ? void 0 : _a.proficiencies;
|
|
25
|
-
if (!prof) continue;
|
|
26
|
-
for (const a of (_b = prof.armor) != null ? _b : []) classArmor.push(a);
|
|
27
|
-
for (const w of (_d = (_c = prof.weapons) == null ? void 0 : _c.fixed) != null ? _d : []) classWeaponFixed.push(w);
|
|
28
|
-
for (const w of (_f = (_e = prof.weapons) == null ? void 0 : _e.categories) != null ? _f : []) classWeaponCategories.push(w);
|
|
29
|
-
for (const t of (_h = (_g = prof.tools) == null ? void 0 : _g.fixed) != null ? _h : []) classToolFixed.push(t);
|
|
30
|
-
}
|
|
31
|
-
const raceLangFixed = [...(_k = (_j = (_i = resolved.race) == null ? void 0 : _i.languages) == null ? void 0 : _j.fixed) != null ? _k : []];
|
|
32
|
-
const bgToolFixed = [];
|
|
33
|
-
const bgLangFixed = [];
|
|
34
|
-
const bg = resolved.background;
|
|
35
|
-
if (bg) {
|
|
36
|
-
for (const entry of (_l = bg.tool_proficiencies) != null ? _l : []) {
|
|
37
|
-
if (entry.kind === "fixed") bgToolFixed.push(...entry.items);
|
|
38
|
-
}
|
|
39
|
-
for (const entry of (_m = bg.language_proficiencies) != null ? _m : []) {
|
|
40
|
-
if (entry.kind === "fixed") bgLangFixed.push(...entry.languages);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const featArmor = [];
|
|
44
|
-
const featWeapons = [];
|
|
45
|
-
const featTools = [];
|
|
46
|
-
const featLanguages = [];
|
|
47
|
-
for (const f of resolved.feats) {
|
|
48
|
-
const featView = f;
|
|
49
|
-
const grants = featView.proficiencies;
|
|
50
|
-
if (!grants) continue;
|
|
51
|
-
featArmor.push(...(_n = grants.armor) != null ? _n : []);
|
|
52
|
-
featWeapons.push(...(_o = grants.weapons) != null ? _o : []);
|
|
53
|
-
featTools.push(...(_p = grants.tools) != null ? _p : []);
|
|
54
|
-
featLanguages.push(...(_q = grants.languages) != null ? _q : []);
|
|
55
|
-
}
|
|
37
|
+
const g = collectProficiencyGrants(resolved);
|
|
56
38
|
const chosen = collectChosenProficiencies(resolved);
|
|
57
|
-
const status = collectLanguageToolChoiceStatus(resolved);
|
|
58
39
|
return {
|
|
59
|
-
|
|
60
|
-
classWeaponFixed,
|
|
61
|
-
classWeaponCategories,
|
|
62
|
-
classToolFixed,
|
|
63
|
-
raceLangFixed,
|
|
64
|
-
bgToolFixed,
|
|
65
|
-
bgLangFixed,
|
|
66
|
-
featArmor,
|
|
67
|
-
featWeapons,
|
|
68
|
-
featTools,
|
|
69
|
-
featLanguages,
|
|
40
|
+
...g,
|
|
70
41
|
chosenLanguages: chosen.languages,
|
|
71
42
|
chosenTools: chosen.tools,
|
|
72
|
-
|
|
73
|
-
toolChoices: status.tools
|
|
43
|
+
chosenWeapons: chosen.weapons
|
|
74
44
|
};
|
|
75
45
|
}
|
|
76
46
|
function aggregateProficiencies(resolved) {
|
|
77
47
|
const src = collectProficiencySources(resolved);
|
|
78
|
-
const
|
|
79
|
-
const weapons = /* @__PURE__ */ new Set();
|
|
80
|
-
const tools = /* @__PURE__ */ new Set();
|
|
81
|
-
const languages = /* @__PURE__ */ new Set();
|
|
82
|
-
for (const a of src.classArmor) armor.add(prettyName(a));
|
|
83
|
-
for (const w of src.classWeaponFixed) weapons.add(prettyName(w));
|
|
84
|
-
for (const w of src.classWeaponCategories) weapons.add(prettyName(w));
|
|
85
|
-
for (const t of src.classToolFixed) tools.add(prettyName(t));
|
|
86
|
-
for (const l of src.raceLangFixed) languages.add(prettyName(l));
|
|
87
|
-
for (const t of src.bgToolFixed) tools.add(prettyName(t));
|
|
88
|
-
for (const l of src.bgLangFixed) languages.add(prettyName(l));
|
|
89
|
-
for (const a of src.featArmor) armor.add(prettyName(a));
|
|
90
|
-
for (const w of src.featWeapons) weapons.add(prettyName(w));
|
|
91
|
-
for (const t of src.featTools) tools.add(prettyName(t));
|
|
92
|
-
for (const l of src.featLanguages) languages.add(prettyName(l));
|
|
93
|
-
for (const l of src.chosenLanguages) languages.add(prettyName(l));
|
|
94
|
-
for (const t of src.chosenTools) tools.add(prettyName(t));
|
|
48
|
+
const effective = computeEffectiveProficiencies(resolved);
|
|
95
49
|
return {
|
|
96
|
-
|
|
97
|
-
weapons
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
50
|
+
// Walk order defines `sources` order (spec §4.1): class before feats, and
|
|
51
|
+
// for weapons the class `fixed` names before the class categories, matching
|
|
52
|
+
// the insertion order of the bucket this replaced, exactly.
|
|
53
|
+
//
|
|
54
|
+
// Effect buckets go LAST: first-seen wins the dedupe key, so an existing
|
|
55
|
+
// class or feat grant keeps its shipped spelling and label and the effect
|
|
56
|
+
// only appends its source name. Reordering these silently relabels rows.
|
|
57
|
+
//
|
|
58
|
+
// The chosen weapon PICKS are the second argument, so they are seeded after
|
|
59
|
+
// every grant bucket: a weapon both granted and picked stays ONE row that
|
|
60
|
+
// keeps origin `grant` and its granting source(s) (R4-G3b §7 F5 · the same
|
|
61
|
+
// grants-then-picks order computeEffectiveProficiencies uses for the
|
|
62
|
+
// language and tool buckets). Armor passes none.
|
|
63
|
+
armor: composeGrantEntries([src.classArmor, src.featArmor, src.effectArmor]),
|
|
64
|
+
weapons: composeGrantEntries([src.classWeaponFixed, src.classWeaponCategories, src.featWeapons, src.effectWeapons], src.chosenWeapons),
|
|
65
|
+
tools: effective.tools,
|
|
66
|
+
languages: effective.languages
|
|
104
67
|
};
|
|
105
68
|
}
|
|
106
|
-
function
|
|
107
|
-
const
|
|
108
|
-
for (const
|
|
109
|
-
const
|
|
110
|
-
|
|
69
|
+
function composeGrantEntries(buckets, picks = []) {
|
|
70
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const bucket of buckets) {
|
|
72
|
+
for (const g of bucket) {
|
|
73
|
+
const key = toProfSlug(g.value);
|
|
74
|
+
const existing = byKey.get(key);
|
|
75
|
+
if (!existing) {
|
|
76
|
+
byKey.set(key, {
|
|
77
|
+
value: g.value,
|
|
78
|
+
label: prettyName(g.value),
|
|
79
|
+
sources: [g.source],
|
|
80
|
+
origin: "grant"
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (!existing.sources.includes(g.source)) existing.sources.push(g.source);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const v of picks) {
|
|
88
|
+
const k = toProfSlug(v);
|
|
89
|
+
if (!byKey.has(k)) byKey.set(k, { value: v, label: prettyName(v), sources: [], origin: "pick" });
|
|
111
90
|
}
|
|
112
|
-
return
|
|
91
|
+
return [...byKey.values()].sort((a, b) => a.label < b.label ? -1 : a.label > b.label ? 1 : 0);
|
|
113
92
|
}
|
|
114
93
|
function prettyName(slug) {
|
|
115
|
-
return slug
|
|
94
|
+
return proficiencyLabel(slug);
|
|
116
95
|
}
|
|
117
96
|
export {
|
|
118
97
|
aggregateProficiencies,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ResolvedCharacter } from "./pc.types.js";
|
|
2
|
+
export type ProficiencyOrigin = "grant" | "pick" | "manual" | "custom";
|
|
3
|
+
export interface ProficiencyEntry {
|
|
4
|
+
/** Canonical slug when the value lands on the domain vocabulary, else the raw string. Spec §3.3. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Display form. Spec §3.3's first code block (languages/tools) or second (armor/weapons). */
|
|
7
|
+
label: string;
|
|
8
|
+
/** EVERY granting entity's display name, in walk order: class, race,
|
|
9
|
+
* background, feats, then feature EFFECTS last (R4-P3c · both composers order
|
|
10
|
+
* the effect bucket last so a first-seen entity grant keeps its own label). */
|
|
11
|
+
sources: string[];
|
|
12
|
+
origin: ProficiencyOrigin;
|
|
13
|
+
/** R4-G4 §9: tool expertise rides the grant channel (the ONE channel the panel
|
|
14
|
+
* and the modal read); the manual tri `overrides.tools.proficiency` (spec §9.3,
|
|
15
|
+
* Tier B) is its second writer, applied in `computeEffectiveProficiencies`.
|
|
16
|
+
* ABSENT rather than `false` on a plain entry. */
|
|
17
|
+
expertise?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** One granted value plus the display name of the entity that granted it.
|
|
20
|
+
* `expertise` is present (and `true`) only when the granting effect authored it
|
|
21
|
+
* (R4-G4 §9.2), so a plain grant keeps the exact two-key shape every pre-phase
|
|
22
|
+
* reader was written against. */
|
|
23
|
+
export interface ProficiencyGrant {
|
|
24
|
+
value: string;
|
|
25
|
+
source: string;
|
|
26
|
+
expertise?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface ProficiencyGrants {
|
|
29
|
+
classArmor: ProficiencyGrant[];
|
|
30
|
+
classWeaponFixed: ProficiencyGrant[];
|
|
31
|
+
classWeaponCategories: ProficiencyGrant[];
|
|
32
|
+
classToolFixed: ProficiencyGrant[];
|
|
33
|
+
raceLangFixed: ProficiencyGrant[];
|
|
34
|
+
bgToolFixed: ProficiencyGrant[];
|
|
35
|
+
bgLangFixed: ProficiencyGrant[];
|
|
36
|
+
featArmor: ProficiencyGrant[];
|
|
37
|
+
featWeapons: ProficiencyGrant[];
|
|
38
|
+
featTools: ProficiencyGrant[];
|
|
39
|
+
featLanguages: ProficiencyGrant[];
|
|
40
|
+
effectArmor: ProficiencyGrant[];
|
|
41
|
+
effectWeapons: ProficiencyGrant[];
|
|
42
|
+
effectTools: ProficiencyGrant[];
|
|
43
|
+
effectLanguages: ProficiencyGrant[];
|
|
44
|
+
}
|
|
45
|
+
/** Every FIXED proficiency/language a character's entities grant, each paired
|
|
46
|
+
* with the display name of the entity that granted it. Walk order is
|
|
47
|
+
* class → race → background → feats, and that order defines `sources` ordering
|
|
48
|
+
* downstream (spec §4.1).
|
|
49
|
+
*
|
|
50
|
+
* This module is a LEAF on purpose: it must import nothing from the decision
|
|
51
|
+
* engine module, so that the engine can import it without a cycle. NOT enforced
|
|
52
|
+
* by any test or lint rule · a previous comment claimed a grep guard that has
|
|
53
|
+
* never existed. It is a convention, and this phase adds a feature-effects
|
|
54
|
+
* import that is cycle-free by inspection, not by tooling.
|
|
55
|
+
* The walk returns raw `{value, source}` buckets and nothing else · no
|
|
56
|
+
* humanizing, no sorting, no dedupe. Label composition stays with the
|
|
57
|
+
* module-private `prettyName` in `pc.proficiencies.ts` (spec §7.1). */
|
|
58
|
+
export declare function collectProficiencyGrants(resolved: ResolvedCharacter): ProficiencyGrants;
|
|
@@ -3,3 +3,27 @@
|
|
|
3
3
|
* collision-free across the SRD weapon set. Strip-"s" singularizer does not handle
|
|
4
4
|
* irregular plurals; no SRD weapon triggers that. */
|
|
5
5
|
export declare const normKey: (s: string) => string;
|
|
6
|
+
/** Canonical proficiency slug: lowercase, curly apostrophe folded to ASCII,
|
|
7
|
+
* whitespace collapsed to hyphens. Universally idempotent (one pass removes all
|
|
8
|
+
* whitespace) and the IDENTITY over ALL_SKILL_SLUGS / ALL_LANGUAGES / ALL_TOOLS,
|
|
9
|
+
* which are already canonical. The fold list is deliberately U+2019-only: no SRD
|
|
10
|
+
* tool name contains any other non-ASCII character. */
|
|
11
|
+
export declare const toProfSlug: (s: string) => string;
|
|
12
|
+
/** Apostrophe-safe title case: capitalizes only at start-of-string or after
|
|
13
|
+
* whitespace, never after `'` (so "smith's-tools" reads "Smith's Tools", not
|
|
14
|
+
* "Smith'S Tools"). Intentionally the same body as the plugin's humanizeSlug.
|
|
15
|
+
* The divergence that matters is one level up: prettyName is
|
|
16
|
+
* humanizeProficiency(toProfSlug(x)), and the U+2019 fold lives in toProfSlug.
|
|
17
|
+
* Do NOT "simplify" prettyName to a bare humanizer call · that reintroduces
|
|
18
|
+
* the duplicate-row defect (one proficiency rendering as two rows). */
|
|
19
|
+
export declare const humanizeProficiency: (s: string) => string;
|
|
20
|
+
/** The display label for one AUTHORED proficiency value that no vocabulary canonicalizes (R4-G7 T8 RIDER-14).
|
|
21
|
+
* The rule reads the value's SHAPE, never a word list:
|
|
22
|
+
* - a value with no whitespace is a slug ("thieves'-tools", "heavy"), and a phrase with no uppercase letter
|
|
23
|
+
* ("hand crossbows") carries no authored casing and shares its slug's `toProfSlug` key: both keep today's
|
|
24
|
+
* `humanizeProficiency(toProfSlug(raw))` (the fold and the apostrophe rule of the composition above);
|
|
25
|
+
* - a phrase that carries authored uppercase is PROSE ("Martial weapons that have the Light property",
|
|
26
|
+
* "... the 2H or H property") and prints as authored: U+2019 folded to ASCII, whitespace trimmed and collapsed,
|
|
27
|
+
* the first character capitalised, every other letter untouched. Title-casing it word by word lower-cased
|
|
28
|
+
* `2H` to `2h` and read "That Have The Light Property". */
|
|
29
|
+
export declare const proficiencyLabel: (raw: string) => string;
|
|
@@ -6,6 +6,19 @@ interface ProficienciesForQuery {
|
|
|
6
6
|
weapons: ProficiencySet;
|
|
7
7
|
tools: ProficiencySet;
|
|
8
8
|
}
|
|
9
|
+
/** NOT the live weapon gate · that is `isWeaponSlugProficient` in
|
|
10
|
+
* `pc.equipment.ts`, reached from `computeAttacks`. The two are near-twins,
|
|
11
|
+
* NOT aliases: that function's docblock records where their matching diverges,
|
|
12
|
+
* so anything asserting runtime behaviour must call it, not this one. */
|
|
9
13
|
export declare function isProficientWithWeapon(weapon: WeaponEntity, profs: ProficienciesForQuery): boolean;
|
|
14
|
+
/** No live armor gate exists at all · nothing in the product gates on armor
|
|
15
|
+
* proficiency today (`computeAppliedBonuses` takes `_profs` and ignores it),
|
|
16
|
+
* so this has no production caller either. Do NOT read that as "the
|
|
17
|
+
* `.specific` branch is dead": `normalizeArmorProf` in `pc.recalc.ts` routes
|
|
18
|
+
* an authored `armor: { specific: [...] }` block straight into it. No SRD
|
|
19
|
+
* entity uses that object form for armor yet, but `weapons:` and `tools:`
|
|
20
|
+
* already do in the same `proficiencies:` block, so it is one plausible
|
|
21
|
+
* keystroke away · and the function is published API besides. Trimming that
|
|
22
|
+
* branch could silently regress either. */
|
|
10
23
|
export declare function isProficientWithArmor(armor: ArmorEntity, profs: ProficienciesForQuery): boolean;
|
|
11
24
|
export {};
|
package/dist/pc/pc.recalc.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { Ability } from "@archivist-gg/dnd5e";
|
|
|
2
2
|
import type { FeatEntity } from "@archivist-gg/dnd5e/feat/feat.types";
|
|
3
3
|
import type { RaceEntity } from "@archivist-gg/dnd5e/race/race.types";
|
|
4
4
|
import type { EntityRegistry } from "@archivist-gg/core";
|
|
5
|
+
import { type UnarmedStrikeSpec } from "./pc.equipment.js";
|
|
6
|
+
import { type FeatureEffectTotals } from "./pc.feature-effects.js";
|
|
5
7
|
import type { ACTerm, DerivedStats, ProficiencySet, ResolvedCharacter, ResolvedClass, CharacterOverrides } from "./pc.types.js";
|
|
6
8
|
/**
|
|
7
9
|
* PHB "fixed average" value per hit die (per level beyond first). Called
|
|
@@ -28,18 +30,26 @@ export declare function flattenRaceAsi(race: RaceEntity | null): Partial<Record<
|
|
|
28
30
|
* `abilityBonusBreakdown`'s `class` bucket so the two reads can never drift.
|
|
29
31
|
*
|
|
30
32
|
* Disjoint from chosen-feat ability-points (`choices[lvl]["feat:<id>"]`) and from
|
|
31
|
-
* origin ability-points
|
|
33
|
+
* origin ability-points · no source double-counts.
|
|
34
|
+
*
|
|
35
|
+
* Since R4-P4 Decision B an `asi` that SHARES a level with a string `feat` key is
|
|
36
|
+
* discarded as an orphan rather than folded: that level took the feat branch, and
|
|
37
|
+
* the `asi` beside it is residue the picker never cleared on a branch switch.
|
|
38
|
+
* Folding both paid the same slot twice (Volker.md drew FOUR points from one L4).
|
|
32
39
|
*/
|
|
33
40
|
export declare function collectClassAsiBranch(resolved: ResolvedCharacter): Partial<Record<Ability, number>>;
|
|
34
41
|
/** Per-ability bonus provenance for the builder's obelisk captions:
|
|
35
42
|
* species = fixed race ASI + subrace fixed ASI + race ability-points choices;
|
|
36
43
|
* background = background ability-points choices;
|
|
37
|
-
* class = legacy class ASI-BRANCH allocations (the L4 asi-or-feat → asi path)
|
|
44
|
+
* class = legacy class ASI-BRANCH allocations (the L4 asi-or-feat → asi path),
|
|
45
|
+
* MINUS any `asi` sharing a level with a string `feat` key, which
|
|
46
|
+
* collectClassAsiBranch discards as branch-switch residue (R4-P4 Dec. B),
|
|
47
|
+
* + the flat capstone fold when the caller threads the effect totals (R4-G3b §4);
|
|
38
48
|
* feat = class chosen-feat ability-points (the L4 asi-or-feat → feat path) +
|
|
39
49
|
* flat feat ability_bonuses (e.g. Athlete +1 STR). All already fold into
|
|
40
50
|
* computeAbilityScores totals, so the caption must account for them or a
|
|
41
51
|
* tile reads higher than the named sources explain (smoke r1/r5c). */
|
|
42
|
-
export declare function abilityBonusBreakdown(resolved: ResolvedCharacter): Record<Ability, {
|
|
52
|
+
export declare function abilityBonusBreakdown(resolved: ResolvedCharacter, featureEffects?: FeatureEffectTotals): Record<Ability, {
|
|
43
53
|
species: number;
|
|
44
54
|
background: number;
|
|
45
55
|
class: number;
|
|
@@ -60,21 +70,41 @@ export declare function hpLevelCount(classes: ResolvedClass[]): number;
|
|
|
60
70
|
*/
|
|
61
71
|
export declare function multiclassMaxHP(classes: ResolvedClass[], conMod: number): number;
|
|
62
72
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
73
|
+
* The BEST APPLICABLE unarmoured formula (R4-G7 T6a, spec §4): the plain 10 + DEX mod, against every
|
|
74
|
+
* `unarmored-ac` effect that folds right now (its `base ?? 10` plus the modifier of every ability its
|
|
75
|
+
* OWN `abilities` list names), highest total winning. A class feature carrying an "Unarmored
|
|
76
|
+
* Defense"-style structured flag, or only the feature NAME (matched SILENTLY since R4-G6b §5.7), is the
|
|
77
|
+
* FALLBACK for a document that authors no effect at all (Monk: +WIS; Barbarian: +CON). `warnings` is
|
|
78
|
+
* retained for the exported signature and is no longer written to by this function or by
|
|
79
|
+
* `unarmoredACBreakdown`.
|
|
67
80
|
*/
|
|
68
81
|
export declare function unarmoredAC(resolved: ResolvedCharacter, mods: Record<Ability, number>, warnings: string[]): number;
|
|
69
82
|
/**
|
|
70
|
-
* Same
|
|
71
|
-
*
|
|
72
|
-
* Used by recalc to assemble a richer acBreakdown when no armor is equipped.
|
|
83
|
+
* Same rule as `unarmoredAC` but also returns the WINNING formula's structured terms (its base, then one
|
|
84
|
+
* term per ability its `abilities` list names, in that list's order) and whether that formula admits a
|
|
85
|
+
* shield. Used by recalc to assemble a richer acBreakdown when no armor is equipped.
|
|
86
|
+
*
|
|
87
|
+
* `shieldBonus` is the equipped shield's contribution, read for the COMPARISON only: it is NOT part of
|
|
88
|
+
* the returned `total` or `terms`, because the shield is one of the additive terms recalc merges on the
|
|
89
|
+
* unarmoured path, and `shieldAllowed` is what tells that caller to keep it. A shield counts on a
|
|
90
|
+
* candidate only where its effect declares `allow_shield === true` (absent is NOT true: the SRD Monk
|
|
91
|
+
* omits the key and RAW allows the Monk no shield), and always on the plain 10 + DEX candidate, which is
|
|
92
|
+
* unarmoured-with-a-shield. Both fallback arms keep the shipped answer, shield included.
|
|
73
93
|
*/
|
|
74
|
-
export declare function unarmoredACBreakdown(resolved: ResolvedCharacter, mods: Record<Ability, number>, warnings: string[]): {
|
|
94
|
+
export declare function unarmoredACBreakdown(resolved: ResolvedCharacter, mods: Record<Ability, number>, warnings: string[], shieldBonus?: number): {
|
|
75
95
|
total: number;
|
|
76
96
|
terms: ACTerm[];
|
|
97
|
+
shieldAllowed: boolean;
|
|
77
98
|
};
|
|
99
|
+
/** R4-G6b §5.4: the die and ability set for the always-present Unarmed Strike row. Authored `unarmed-strike` effects
|
|
100
|
+
* first (a `{ column }` die is read from the GRANTING class's table at that class's level); then the SILENT synthetic:
|
|
101
|
+
* a class-sourced feature whose id slug `unarmedDieColumnFor` knows (`martial-arts`) with NO authored effect, on a
|
|
102
|
+
* class whose table carries that column with a dice value, contributes that die with DEX. The SHAPE is
|
|
103
|
+
* `decision-recognizer.ts`'s (a table-driven synthetic mirroring an overlay entry, retired when the data is
|
|
104
|
+
* authored: the G7 booking gives `overlay.schema.ts`'s class arm `effects` + `.strict()` and authors both Monks);
|
|
105
|
+
* the PLACEMENT is here because the builder ledger never feeds `derived.attacks`. Merge: the die with the highest
|
|
106
|
+
* average wins; the abilities are the union. Nothing writes onto a registry object. */
|
|
107
|
+
export declare function resolveUnarmedStrike(resolved: ResolvedCharacter): UnarmedStrikeSpec;
|
|
78
108
|
/** Initiative = DEX mod + Alert (+5 in 2014). Extendable via feat flags. */
|
|
79
109
|
export declare function initiativeBonus(dexMod: number, feats: FeatEntity[], edition: "2014" | "2024"): number;
|
|
80
110
|
/** Speed = race.speed.walk + flat bonuses from feats (e.g., Mobile +10). */
|
|
@@ -83,14 +113,38 @@ export declare function speedFromRace(resolved: ResolvedCharacter): number;
|
|
|
83
113
|
* Folds class-level CHOSEN-FEAT ability-points into per-ability totals.
|
|
84
114
|
*
|
|
85
115
|
* When the L4-style "asi or feat" decision resolves to a feat that carries
|
|
86
|
-
* `ability-points` choices (e.g. Ability Score Improvement, the
|
|
87
|
-
*
|
|
116
|
+
* `ability-points` choices (e.g. Ability Score Improvement), the picker
|
|
117
|
+
* persists the allocation under the namespaced key
|
|
88
118
|
* `choices[lvl]["feat:" + choice.id]` (the engine's `buildItem` surfaces those
|
|
89
119
|
* children; see pc.decision-engine.ts). This is disjoint from both the legacy
|
|
90
120
|
* asi-BRANCH key (`choices[lvl].asi`) and origin ability-points, so no source
|
|
91
121
|
* double-counts. The chosen feat entity is resolved from `resolved.feats`
|
|
92
122
|
* (already looked up by the resolver) — no registry needed here.
|
|
93
123
|
*
|
|
124
|
+
* The L19 Epic Boon folds through this SAME path, but only as of R4-P4's
|
|
125
|
+
* re-key (live in the SRD data from that phase's regeneration). This docblock
|
|
126
|
+
* earlier cited it as an existing example, which it was not. EVERY reader OF THE
|
|
127
|
+
* FEAT PICK keys on the LITERAL string `feat`, and there are THREE of them, not
|
|
128
|
+
* the two the R4-P4 spec §2.3 and task brief enumerate: this function
|
|
129
|
+
* (`block.feat`, below), `collectFeatPicks` (pc.resolver.ts) and
|
|
130
|
+
* `PCResolver.resolve`'s feat-to-spell application pass, the two
|
|
131
|
+
* `collectFeatGrantedSpells` calls (pc.resolver.ts), the one that
|
|
132
|
+
* makes a SPELL-granting boon work. Note the qualifier: this is NOT a claim that
|
|
133
|
+
* every reader of a saved class choice block keys on `feat`. Others read the very
|
|
134
|
+
* same block by OTHER keys · `collectClassAsiBranch` (above) reads the literal
|
|
135
|
+
* `.asi`, while `resolvePool` (pc.pools.ts) and `resolveChosenInline`
|
|
136
|
+
* (pc.resolver.ts) read by a DYNAMIC pool/choice id. As of R4-P4 Decision B
|
|
137
|
+
* `collectClassAsiBranch` also tests `block.feat`, but only to DETECT the feat
|
|
138
|
+
* branch, not to consume the pick. pc.decision-engine.ts is NOT a fourth:
|
|
139
|
+
* it reads generically by `choice.id`, which is exactly why re-keying works at
|
|
140
|
+
* all. srd-2024.yaml authored the boon's pick `id: epic-boon`, so an L19
|
|
141
|
+
* selection persisted under `choices[19]["epic-boon"]`, which no reader looks
|
|
142
|
+
* at: the boon resolved to no feat, granted no spells, and contributed no
|
|
143
|
+
* ability points at all. Re-keying the authored pick to `id: feat` is what
|
|
144
|
+
* makes it fold. No persisted GRANDCHILD key moved with it ·
|
|
145
|
+
* pc.decision-engine.ts builds `feat:<childId>` off a hardcoded prefix,
|
|
146
|
+
* independent of the parent choice's own id.
|
|
147
|
+
*
|
|
94
148
|
* Clamps defensively (per-ability max_per, then stops at the points total in
|
|
95
149
|
* ABILITY_KEYS order), mirroring collectChosenAbilityPoints.
|
|
96
150
|
*/
|
|
@@ -99,7 +153,8 @@ export declare function collectClassFeatAbilityPoints(resolved: ResolvedCharacte
|
|
|
99
153
|
* Combines racial ASI (from race.ability_score_increases), feat ASI,
|
|
100
154
|
* class-choice ASI (from classes[i].choices[lvl].asi), chosen-feat ASI
|
|
101
155
|
* (from classes[i].choices[lvl]["feat:<id>"]), and user overrides.
|
|
102
|
-
* Overrides win; ASI sources sum unconditionally.
|
|
156
|
+
* Overrides win; ASI sources sum unconditionally. The flat capstone fold is added
|
|
157
|
+
* in recalc's bonus loop, not here (R4-G3b §4).
|
|
103
158
|
*/
|
|
104
159
|
export declare function computeAbilityScores(resolved: ResolvedCharacter, overrides: CharacterOverrides): Record<Ability, number>;
|
|
105
160
|
export declare function computeProficiencies(resolved: ResolvedCharacter): {
|