@archivist-gg/dnd5e 0.3.1 → 0.3.4
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-4FWNK4FD.js +159 -0
- 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-5U5FFFA3.js} +5 -1
- package/dist/{chunk-4F6AIZ36.js → chunk-5XMQPTHD.js} +1 -1
- package/dist/{chunk-GJOI2GHP.js → chunk-6GNXYAYP.js} +1 -1
- package/dist/chunk-6PKV5V2H.js +178 -0
- 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-CJYCVNW2.js +7 -0
- package/dist/chunk-COEOOQX2.js +133 -0
- package/dist/{chunk-XTIQWSFM.js → chunk-D5U7GMPX.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-73HOFQQ5.js → chunk-ESS46GR4.js} +1 -1
- package/dist/chunk-EVMUJYUD.js +195 -0
- package/dist/{chunk-2BWAID3Y.js → chunk-FDBWYMZK.js} +29 -3
- package/dist/{chunk-K6Q5OUGK.js → chunk-GFZ7PITJ.js} +86 -10
- package/dist/chunk-H7KBLR4X.js +81 -0
- package/dist/{chunk-L7E2UT5A.js → chunk-HB7XZXDK.js} +5 -1
- package/dist/{chunk-BIK4DFWK.js → chunk-HJ5EEZ47.js} +1 -1
- package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
- package/dist/{chunk-TN6ZLTNU.js → chunk-I2NDWFDD.js} +51 -4
- package/dist/{chunk-RSDRMH54.js → chunk-IMZFOOVL.js} +1 -1
- package/dist/{chunk-3DZ74AKK.js → chunk-IN4M4X7P.js} +8 -2
- package/dist/chunk-IUAAXXNO.js +58 -0
- package/dist/{chunk-XJNECUPT.js → chunk-JC5UNIVM.js} +19 -0
- package/dist/chunk-JJ46T5XX.js +297 -0
- package/dist/{chunk-SE7AZDR3.js → chunk-JRDPUDT5.js} +29 -3
- package/dist/{chunk-24GFQU7T.js → chunk-JSZ4H6AQ.js} +1 -1
- package/dist/chunk-KU3YLF6D.js +106 -0
- package/dist/{chunk-5INR4NSL.js → chunk-LDDCNPHD.js} +1 -1
- package/dist/{chunk-5ZBE4CWV.js → chunk-LMBAEIP6.js} +1 -1
- package/dist/chunk-LVQLWRCU.js +15 -0
- package/dist/chunk-MI7P3NX3.js +161 -0
- package/dist/chunk-O4SRD3J5.js +165 -0
- package/dist/{chunk-D3CLOBE3.js → chunk-OSQFPGLM.js} +44 -8
- 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-XLSVNUTK.js → chunk-R3VAKWKW.js} +1 -1
- package/dist/chunk-RIXI5D3R.js +89 -0
- package/dist/chunk-RLGQ5PZZ.js +16 -0
- package/dist/chunk-S7REMWW4.js +21 -0
- package/dist/{chunk-7VJ6BOA5.js → chunk-SMLXZUBH.js} +9 -1
- package/dist/{chunk-NXSWH3AE.js → chunk-T26ZVCL5.js} +1 -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-GE4TLPWM.js → chunk-US5IKYCW.js} +1 -1
- package/dist/chunk-UXPGW4TI.js +101 -0
- package/dist/chunk-VQAXTIBW.js +100 -0
- package/dist/{chunk-WP2CX2JO.js → chunk-WELIKLZF.js} +22 -1
- package/dist/chunk-WPWOHGPI.js +172 -0
- package/dist/{chunk-GZ46OVGZ.js → chunk-WSVMLNTO.js} +1 -1
- package/dist/{chunk-4LZJXJJS.js → chunk-WXWPK3LI.js} +6 -2
- package/dist/{chunk-ZZGEVJKX.js → chunk-XBQMCEI2.js} +1 -1
- package/dist/{chunk-PHQRGDRQ.js → chunk-XGOFP7AQ.js} +5 -1
- package/dist/chunk-XJ2F2WO6.js +8 -0
- package/dist/chunk-XQCSGNXE.js +1580 -0
- package/dist/chunk-YBLDE5CG.js +42 -0
- package/dist/{chunk-JEYQU3JT.js → chunk-YHYTW5QA.js} +2 -18
- package/dist/{chunk-TLYDBT5F.js → chunk-YJJTISBN.js} +64 -7
- package/dist/{chunk-PZOWBI3B.js → chunk-YLL2QXY2.js} +7 -2
- package/dist/{chunk-MDEJHMKK.js → chunk-ZONJ66NE.js} +26 -5
- 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 +230 -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 +176 -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 +30 -1
- package/dist/pc/pc.equipment.js +12 -8
- package/dist/pc/pc.feature-effects.d.ts +225 -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 +124 -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 +78 -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
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
spellEntitySchema
|
|
3
|
+
} from "./chunk-VQAXTIBW.js";
|
|
4
|
+
|
|
5
|
+
// src/spell/spell.parser.ts
|
|
6
|
+
import { parseYaml, toStringSafe } from "@archivist-gg/core";
|
|
7
|
+
var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
8
|
+
"name",
|
|
9
|
+
"level",
|
|
10
|
+
"school",
|
|
11
|
+
"casting_time",
|
|
12
|
+
"range",
|
|
13
|
+
"components",
|
|
14
|
+
"duration",
|
|
15
|
+
"concentration",
|
|
16
|
+
"ritual",
|
|
17
|
+
"classes",
|
|
18
|
+
"description",
|
|
19
|
+
"at_higher_levels",
|
|
20
|
+
"damage",
|
|
21
|
+
"saving_throw",
|
|
22
|
+
"casting_options",
|
|
23
|
+
// §2 · the fourteen converter keys. This gate and `spellEntitySchema` are independent: a key
|
|
24
|
+
// missing here is refused BEFORE zod ever sees it, so both must learn every new key.
|
|
25
|
+
"rendering_hint",
|
|
26
|
+
"misc_tags",
|
|
27
|
+
"area_tags",
|
|
28
|
+
"condition_inflict",
|
|
29
|
+
"affects_creature_type",
|
|
30
|
+
"spell_attack",
|
|
31
|
+
"ability_check",
|
|
32
|
+
"damage_resist",
|
|
33
|
+
"damage_immune",
|
|
34
|
+
"condition_immune",
|
|
35
|
+
"damage_vulnerable",
|
|
36
|
+
"has_fluff",
|
|
37
|
+
"image",
|
|
38
|
+
"has_fluff_images",
|
|
39
|
+
// Body-only metadata that's emitted to YAML but ignored at runtime — accept silently.
|
|
40
|
+
"slug",
|
|
41
|
+
"edition",
|
|
42
|
+
"source"
|
|
43
|
+
]);
|
|
44
|
+
var DURATION_END_WORDS = { dispel: "dispelled", trigger: "triggered" };
|
|
45
|
+
function normalizeSpellComponents(value) {
|
|
46
|
+
if (typeof value === "string") return value;
|
|
47
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) return toStringSafe(value);
|
|
48
|
+
const c = value;
|
|
49
|
+
const parts = [];
|
|
50
|
+
if (c.v === true) parts.push("V");
|
|
51
|
+
if (c.s === true) parts.push("S");
|
|
52
|
+
if (typeof c.m === "string") parts.push(`M (${c.m})`);
|
|
53
|
+
else if (c.m === true) parts.push("M");
|
|
54
|
+
else if (c.m != null && typeof c.m === "object") {
|
|
55
|
+
const text = c.m.text;
|
|
56
|
+
parts.push(typeof text === "string" ? `M (${text})` : "M");
|
|
57
|
+
}
|
|
58
|
+
if (c.r === true) parts.push("R");
|
|
59
|
+
return parts.join(", ");
|
|
60
|
+
}
|
|
61
|
+
function normalizeSpellDurationEntry(entry) {
|
|
62
|
+
if (entry == null || typeof entry !== "object") return toStringSafe(entry);
|
|
63
|
+
const e = entry;
|
|
64
|
+
if (e.type === "permanent" && Array.isArray(e.ends)) {
|
|
65
|
+
return "until " + e.ends.map((w) => {
|
|
66
|
+
var _a;
|
|
67
|
+
return (_a = DURATION_END_WORDS[String(w)]) != null ? _a : String(w);
|
|
68
|
+
}).join(" or ");
|
|
69
|
+
}
|
|
70
|
+
if (e.type === "timed" && e.duration != null) {
|
|
71
|
+
const unit = e.duration.type;
|
|
72
|
+
const amount = e.duration.amount;
|
|
73
|
+
if (typeof unit === "string" && typeof amount === "number") {
|
|
74
|
+
const prefix = e.duration.up_to === true ? "up to " : "";
|
|
75
|
+
return `${prefix}${amount} ${unit}${amount > 1 ? "s" : ""}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return toStringSafe(entry);
|
|
79
|
+
}
|
|
80
|
+
function normalizeSpellDuration(value) {
|
|
81
|
+
if (typeof value === "string") return value;
|
|
82
|
+
if (!Array.isArray(value)) return toStringSafe(value);
|
|
83
|
+
return value.map((entry) => normalizeSpellDurationEntry(entry)).join("; ");
|
|
84
|
+
}
|
|
85
|
+
function mirrorSpellShapes(entity) {
|
|
86
|
+
return {
|
|
87
|
+
...entity,
|
|
88
|
+
...entity.components != null ? { components: normalizeSpellComponents(entity.components) } : {},
|
|
89
|
+
...entity.duration != null ? { duration: normalizeSpellDuration(entity.duration) } : {}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseSpell(source) {
|
|
93
|
+
const result = parseYaml(source, ["name"]);
|
|
94
|
+
if (!result.success) return result;
|
|
95
|
+
const meta = {};
|
|
96
|
+
if (typeof result.data.source === "string") meta.source = result.data.source;
|
|
97
|
+
if (typeof result.data.edition === "string") meta.edition = result.data.edition;
|
|
98
|
+
const filtered = {};
|
|
99
|
+
for (const [k, v] of Object.entries(result.data)) {
|
|
100
|
+
if (k === "slug" || k === "edition" || k === "source") continue;
|
|
101
|
+
if (!KNOWN_KEYS.has(k)) {
|
|
102
|
+
return { success: false, error: `Unknown spell field: ${k}` };
|
|
103
|
+
}
|
|
104
|
+
filtered[k] = v;
|
|
105
|
+
}
|
|
106
|
+
const parsed = spellEntitySchema.safeParse(filtered);
|
|
107
|
+
if (!parsed.success) {
|
|
108
|
+
return { success: false, error: `spell schema validation failed: ${parsed.error.message}` };
|
|
109
|
+
}
|
|
110
|
+
const raw = parsed.data;
|
|
111
|
+
const spell = { name: raw.name };
|
|
112
|
+
if (raw.level != null) spell.level = raw.level;
|
|
113
|
+
if (raw.school != null) spell.school = toStringSafe(raw.school);
|
|
114
|
+
if (raw.casting_time != null) spell.casting_time = toStringSafe(raw.casting_time);
|
|
115
|
+
if (raw.range != null) spell.range = toStringSafe(raw.range);
|
|
116
|
+
if (raw.components != null) spell.components = normalizeSpellComponents(raw.components);
|
|
117
|
+
if (raw.duration != null) spell.duration = normalizeSpellDuration(raw.duration);
|
|
118
|
+
if (raw.concentration != null) spell.concentration = Boolean(raw.concentration);
|
|
119
|
+
if (raw.ritual != null) spell.ritual = Boolean(raw.ritual);
|
|
120
|
+
if (raw.classes) spell.classes = raw.classes.map(String);
|
|
121
|
+
if (raw.description) spell.description = raw.description;
|
|
122
|
+
if (raw.at_higher_levels) spell.at_higher_levels = raw.at_higher_levels.map(String);
|
|
123
|
+
if (raw.damage) spell.damage = { types: raw.damage.types.map(String) };
|
|
124
|
+
if (raw.saving_throw) spell.saving_throw = { ability: raw.saving_throw.ability };
|
|
125
|
+
if (raw.casting_options) {
|
|
126
|
+
spell.casting_options = raw.casting_options.map((opt) => {
|
|
127
|
+
const co = { type: opt.type };
|
|
128
|
+
if (opt.damage_roll !== void 0) co.damage_roll = opt.damage_roll;
|
|
129
|
+
if (opt.target_count !== void 0) co.target_count = opt.target_count;
|
|
130
|
+
if (opt.duration !== void 0) co.duration = opt.duration;
|
|
131
|
+
if (opt.range !== void 0) co.range = opt.range;
|
|
132
|
+
if (opt.concentration !== void 0) co.concentration = opt.concentration;
|
|
133
|
+
if (opt.shape_size !== void 0) co.shape_size = opt.shape_size;
|
|
134
|
+
if (opt.desc !== void 0) co.desc = opt.desc;
|
|
135
|
+
return co;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (raw.rendering_hint != null) spell.rendering_hint = raw.rendering_hint;
|
|
139
|
+
if (raw.misc_tags != null) spell.misc_tags = raw.misc_tags;
|
|
140
|
+
if (raw.area_tags != null) spell.area_tags = raw.area_tags;
|
|
141
|
+
if (raw.condition_inflict != null) spell.condition_inflict = raw.condition_inflict;
|
|
142
|
+
if (raw.affects_creature_type != null) spell.affects_creature_type = raw.affects_creature_type;
|
|
143
|
+
if (raw.spell_attack != null) spell.spell_attack = raw.spell_attack;
|
|
144
|
+
if (raw.ability_check != null) spell.ability_check = raw.ability_check;
|
|
145
|
+
if (raw.damage_resist != null) spell.damage_resist = raw.damage_resist;
|
|
146
|
+
if (raw.damage_immune != null) spell.damage_immune = raw.damage_immune;
|
|
147
|
+
if (raw.condition_immune != null) spell.condition_immune = raw.condition_immune;
|
|
148
|
+
if (raw.damage_vulnerable != null) spell.damage_vulnerable = raw.damage_vulnerable;
|
|
149
|
+
if (raw.has_fluff != null) spell.has_fluff = raw.has_fluff;
|
|
150
|
+
if (raw.image != null) spell.image = raw.image;
|
|
151
|
+
if (raw.has_fluff_images != null) spell.has_fluff_images = raw.has_fluff_images;
|
|
152
|
+
if (meta.source) spell.source = meta.source;
|
|
153
|
+
if (meta.edition) spell.edition = meta.edition;
|
|
154
|
+
return { success: true, data: spell };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export {
|
|
158
|
+
normalizeSpellComponents,
|
|
159
|
+
normalizeSpellDuration,
|
|
160
|
+
mirrorSpellShapes,
|
|
161
|
+
parseSpell
|
|
162
|
+
};
|
|
@@ -2,8 +2,9 @@ import {
|
|
|
2
2
|
ABILITY_KEYS,
|
|
3
3
|
CR_PROFICIENCY,
|
|
4
4
|
CR_XP,
|
|
5
|
+
DAMAGE_TYPES,
|
|
5
6
|
SIZE_HIT_DICE
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WELIKLZF.js";
|
|
7
8
|
|
|
8
9
|
// src/dnd/math.ts
|
|
9
10
|
function abilityModifier(score) {
|
|
@@ -68,6 +69,22 @@ function abilityNameToKey(name) {
|
|
|
68
69
|
}
|
|
69
70
|
return null;
|
|
70
71
|
}
|
|
72
|
+
var CANONICAL_DAMAGE_TYPES = new Set(DAMAGE_TYPES.map((t) => t.toLowerCase()));
|
|
73
|
+
function isCanonicalDamageType(type) {
|
|
74
|
+
return CANONICAL_DAMAGE_TYPES.has(type.trim().toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
var CHOSEN_DAMAGE_TYPE = "chosen";
|
|
77
|
+
var CHOSEN_DAMAGE_TYPE_NOTE = "damage type of your choice";
|
|
78
|
+
function isChosenDamageType(type) {
|
|
79
|
+
return type !== void 0 && type.trim().toLowerCase() === CHOSEN_DAMAGE_TYPE;
|
|
80
|
+
}
|
|
81
|
+
function isRenderableDamageText(text) {
|
|
82
|
+
var _a;
|
|
83
|
+
const m = /^(?:\d*d\d+(?:\s*[+-]\s*\d+)?|[+-]?\d+)(?:\s+(.*))?$/i.exec(text.trim());
|
|
84
|
+
if (!m) return false;
|
|
85
|
+
const type = ((_a = m[1]) != null ? _a : "").trim();
|
|
86
|
+
return type === "" || isCanonicalDamageType(type);
|
|
87
|
+
}
|
|
71
88
|
|
|
72
89
|
export {
|
|
73
90
|
abilityModifier,
|
|
@@ -84,5 +101,10 @@ export {
|
|
|
84
101
|
passivePerception,
|
|
85
102
|
attackBonus,
|
|
86
103
|
saveDC,
|
|
87
|
-
abilityNameToKey
|
|
104
|
+
abilityNameToKey,
|
|
105
|
+
isCanonicalDamageType,
|
|
106
|
+
CHOSEN_DAMAGE_TYPE,
|
|
107
|
+
CHOSEN_DAMAGE_TYPE_NOTE,
|
|
108
|
+
isChosenDamageType,
|
|
109
|
+
isRenderableDamageText
|
|
88
110
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/pc/pool-layout.ts
|
|
2
|
+
var RENDERING_HINT_LAYOUT = {
|
|
3
|
+
"dice-pool": "dice-pool",
|
|
4
|
+
"point-pool": "point-pool"
|
|
5
|
+
};
|
|
6
|
+
function derivePoolLayout(entries) {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
const votes = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const e of entries) {
|
|
10
|
+
const hint = (_a = e.entity.rendering_hint) != null ? _a : "";
|
|
11
|
+
if (!Object.prototype.hasOwnProperty.call(RENDERING_HINT_LAYOUT, hint)) continue;
|
|
12
|
+
const layout = RENDERING_HINT_LAYOUT[hint];
|
|
13
|
+
votes.set(layout, ((_b = votes.get(layout)) != null ? _b : 0) + 1);
|
|
14
|
+
}
|
|
15
|
+
let best;
|
|
16
|
+
let bestN = 0;
|
|
17
|
+
let tied = false;
|
|
18
|
+
for (const [layout, n] of votes) {
|
|
19
|
+
if (n > bestN) {
|
|
20
|
+
best = layout;
|
|
21
|
+
bestN = n;
|
|
22
|
+
tied = false;
|
|
23
|
+
} else if (n === bestN) tied = true;
|
|
24
|
+
}
|
|
25
|
+
return tied ? void 0 : best;
|
|
26
|
+
}
|
|
27
|
+
var RENDERING_HINT_AFFORDANCE = {
|
|
28
|
+
"granted-die-to-ally": "granted-die"
|
|
29
|
+
};
|
|
30
|
+
function deriveEntryAffordance(entity) {
|
|
31
|
+
var _a;
|
|
32
|
+
const hint = (_a = entity.rendering_hint) != null ? _a : "";
|
|
33
|
+
if (!Object.prototype.hasOwnProperty.call(RENDERING_HINT_AFFORDANCE, hint)) return void 0;
|
|
34
|
+
return RENDERING_HINT_AFFORDANCE[hint];
|
|
35
|
+
}
|
|
36
|
+
var AFFORDANCE_CAPTIONS = {
|
|
37
|
+
"granted-die": "{amount}{die} to an ally"
|
|
38
|
+
};
|
|
39
|
+
function formatAffordanceCaption(affordance, values) {
|
|
40
|
+
return AFFORDANCE_CAPTIONS[affordance].replace(/\{(\w+)\}/g, (whole, key) => Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : whole);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
RENDERING_HINT_LAYOUT,
|
|
45
|
+
derivePoolLayout,
|
|
46
|
+
RENDERING_HINT_AFFORDANCE,
|
|
47
|
+
deriveEntryAffordance,
|
|
48
|
+
AFFORDANCE_CAPTIONS,
|
|
49
|
+
formatAffordanceCaption
|
|
50
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
actionCostEnum,
|
|
3
|
+
resourceSchema
|
|
4
|
+
} from "./chunk-YLL2QXY2.js";
|
|
5
|
+
import {
|
|
6
|
+
choiceSchema
|
|
7
|
+
} from "./chunk-T26ZVCL5.js";
|
|
8
|
+
import {
|
|
9
|
+
featureEffectSchema
|
|
10
|
+
} from "./chunk-WPWOHGPI.js";
|
|
11
|
+
import {
|
|
12
|
+
additionalSpellsEntrySchema,
|
|
13
|
+
imageField,
|
|
14
|
+
progressionSchema
|
|
15
|
+
} from "./chunk-UA5KS2PL.js";
|
|
16
|
+
|
|
17
|
+
// src/feat/feat.schema.ts
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
var abilityEnum = z.enum(["str", "dex", "con", "int", "wis", "cha"]);
|
|
20
|
+
var editionEnum = z.enum(["2014", "2024"]);
|
|
21
|
+
var categoryEnum = z.enum(["origin", "general", "fighting-style", "epic-boon"]);
|
|
22
|
+
var prerequisiteSchema = z.discriminatedUnion("kind", [
|
|
23
|
+
z.object({ kind: z.literal("ability"), ability: abilityEnum, min: z.number().int().positive() }),
|
|
24
|
+
z.object({ kind: z.literal("level"), min: z.number().int().positive() }),
|
|
25
|
+
z.object({ kind: z.literal("spellcaster") }),
|
|
26
|
+
z.object({
|
|
27
|
+
kind: z.literal("proficiency"),
|
|
28
|
+
proficiency_type: z.enum(["armor", "weapon", "tool", "skill", "saving-throw"]),
|
|
29
|
+
value: z.string().min(1)
|
|
30
|
+
}),
|
|
31
|
+
z.object({ kind: z.literal("race"), slug: z.string().min(1) }),
|
|
32
|
+
z.object({ kind: z.literal("class"), slug: z.string().min(1) }),
|
|
33
|
+
// The exclusive-feat-category and feat-category arms carry a raw 5etools category code, not a
|
|
34
|
+
// slug; featCategoryLabel names it. The rest carry slugs the renderer humanizes, except other,
|
|
35
|
+
// which carries free prose that prereqText returns verbatim.
|
|
36
|
+
z.object({ kind: z.literal("feat"), slug: z.string().min(1) }),
|
|
37
|
+
z.object({ kind: z.literal("campaign"), slug: z.string().min(1) }),
|
|
38
|
+
z.object({ kind: z.literal("exclusive-feat-category"), slug: z.string().min(1) }),
|
|
39
|
+
z.object({ kind: z.literal("feature"), slug: z.string().min(1) }),
|
|
40
|
+
z.object({ kind: z.literal("other"), detail: z.string().min(1) }),
|
|
41
|
+
z.object({ kind: z.literal("feat-category"), slug: z.string().min(1) }),
|
|
42
|
+
z.object({ kind: z.literal("background"), slug: z.string().min(1) })
|
|
43
|
+
]);
|
|
44
|
+
var featEntitySchema = z.object({
|
|
45
|
+
slug: z.string().min(1),
|
|
46
|
+
name: z.string().min(1),
|
|
47
|
+
edition: editionEnum,
|
|
48
|
+
source: z.string().min(1),
|
|
49
|
+
category: categoryEnum,
|
|
50
|
+
description: z.string(),
|
|
51
|
+
prerequisites: z.array(prerequisiteSchema),
|
|
52
|
+
benefits: z.array(z.string()),
|
|
53
|
+
effects: z.array(featureEffectSchema),
|
|
54
|
+
grants_asi: z.object({
|
|
55
|
+
amount: z.number().int().positive(),
|
|
56
|
+
pool: z.array(abilityEnum).optional()
|
|
57
|
+
}).nullable(),
|
|
58
|
+
repeatable: z.boolean(),
|
|
59
|
+
choices: z.array(choiceSchema),
|
|
60
|
+
rendering_hint: z.string().optional(),
|
|
61
|
+
additional_spells: z.array(additionalSpellsEntrySchema).optional(),
|
|
62
|
+
// 71
|
|
63
|
+
has_fluff: z.boolean().optional(),
|
|
64
|
+
// 0 carriers — symmetry, §9.4
|
|
65
|
+
has_fluff_images: z.boolean().optional(),
|
|
66
|
+
// 41
|
|
67
|
+
trait_tags: z.unknown().optional(),
|
|
68
|
+
// 7, nullable measured — same passthrough family
|
|
69
|
+
optionalfeature_progression: z.array(progressionSchema).optional(),
|
|
70
|
+
// 4
|
|
71
|
+
resources: z.array(resourceSchema).optional(),
|
|
72
|
+
// closes the feat.types.ts `Feat.resources` schema/type asymmetry (C);
|
|
73
|
+
// ZERO converter/bundle carriers (no census row) — the only behaviour delta is AUTHORED feats,
|
|
74
|
+
// where the type has promised the field all along. Import resourceSchema.
|
|
75
|
+
action_cost: actionCostEnum.optional(),
|
|
76
|
+
// ruling R-G1b-5 (gate1-r1 f1): a TOP-LEVEL bundle key on ONE
|
|
77
|
+
// feat (`SRD 2024/Feats/Boon of the Night Spirit.md`, `action_cost: bonus-action` at entity top
|
|
78
|
+
// level) — the ninth SRD-control non-kept row: top-level on the ENTITY, not featureSchema-shaped
|
|
79
|
+
// (finding 14's nine rows split 4 featureSchema / 4 §2.8-arity / this one, which needed its own
|
|
80
|
+
// declaration — gate1-r4 R4-1). `actionCostEnum` is exported from
|
|
81
|
+
// `schemas/resource-schema.ts` (optionalFeatureEntitySchema already imports it). MAPPED since
|
|
82
|
+
// R4-G3a §10.2.3: the resolver aliases it onto the resolved feature's `action`, which is what
|
|
83
|
+
// draws the feat note's Action line and files the row under that economy.
|
|
84
|
+
image: imageField
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
featEntitySchema
|
|
89
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/pc/pc.proficiency-normalize.ts
|
|
2
|
+
var normKey = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim().split(/\s+/).filter(Boolean).map((w) => w.endsWith("s") ? w.slice(0, -1) : w).sort().join(" ");
|
|
3
|
+
var toProfSlug = (s) => s.toLowerCase().replace(/’/g, "'").trim().replace(/\s+/g, "-");
|
|
4
|
+
var humanizeProficiency = (s) => s.replace(/-/g, " ").replace(/(^|\s)\w/g, (c) => c.toUpperCase());
|
|
5
|
+
var proficiencyLabel = (raw) => {
|
|
6
|
+
const text = raw.replace(/’/g, "'").trim().replace(/\s+/g, " ");
|
|
7
|
+
if (!/\s/.test(text) || text === text.toLowerCase()) return humanizeProficiency(toProfSlug(raw));
|
|
8
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
normKey,
|
|
13
|
+
toProfSlug,
|
|
14
|
+
humanizeProficiency,
|
|
15
|
+
proficiencyLabel
|
|
16
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/pc/conditions.constants.ts
|
|
2
|
+
var CONDITION_SLUGS = [
|
|
3
|
+
"blinded",
|
|
4
|
+
"charmed",
|
|
5
|
+
"deafened",
|
|
6
|
+
"frightened",
|
|
7
|
+
"grappled",
|
|
8
|
+
"incapacitated",
|
|
9
|
+
"invisible",
|
|
10
|
+
"paralyzed",
|
|
11
|
+
"petrified",
|
|
12
|
+
"poisoned",
|
|
13
|
+
"prone",
|
|
14
|
+
"restrained",
|
|
15
|
+
"stunned",
|
|
16
|
+
"unconscious"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
CONDITION_SLUGS
|
|
21
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
itemEntitySchema
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GFZ7PITJ.js";
|
|
4
4
|
|
|
5
5
|
// src/item/item.parser.ts
|
|
6
6
|
import { parseYaml } from "@archivist-gg/core";
|
|
@@ -41,6 +41,14 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
41
41
|
"scroll_level",
|
|
42
42
|
"unidentified",
|
|
43
43
|
"masked_category",
|
|
44
|
+
// Modelled top-level converter keys (spec §4). The schema declaring them is NOT
|
|
45
|
+
// enough: this set is the second, independent gate — a key missing here is
|
|
46
|
+
// copied into `raw` as well, so the two lists must move together.
|
|
47
|
+
"modify_speed",
|
|
48
|
+
"rendering_hint",
|
|
49
|
+
"has_fluff",
|
|
50
|
+
"has_fluff_images",
|
|
51
|
+
"image",
|
|
44
52
|
// Legacy fields kept (removed in Slice 7 after grep verifies no consumer)
|
|
45
53
|
"damage_dice",
|
|
46
54
|
"damage_type",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_SKILL_SLUGS
|
|
3
|
+
} from "./chunk-KU3YLF6D.js";
|
|
4
|
+
import {
|
|
5
|
+
normalizeAbility
|
|
6
|
+
} from "./chunk-WELIKLZF.js";
|
|
7
|
+
|
|
8
|
+
// src/pc/roll-scope.ts
|
|
9
|
+
var NOUNS = /\b(saving throws?|saves?|ability checks?|checks?|attack rolls?)\b/gi;
|
|
10
|
+
var QUANTIFIERS = /\b(all|any|other|the next|you make|that you make)\b/gi;
|
|
11
|
+
var slug = (s) => s.toLowerCase().trim().replace(/[^a-z]+/g, "-").replace(/(^-|-$)/g, "");
|
|
12
|
+
function normalizeRollScope(raw, _roll) {
|
|
13
|
+
if (raw == null) return void 0;
|
|
14
|
+
const cleaned = raw.replace(NOUNS, " ").replace(QUANTIFIERS, " ").replace(/\s+/g, " ").trim();
|
|
15
|
+
const parts = cleaned.split(/\s*(?:,|\/|\band\b|\bor\b)\s*/i).map((p) => p.trim()).filter(Boolean);
|
|
16
|
+
if (parts.length === 0 || parts.length > 3) return void 0;
|
|
17
|
+
const out = [];
|
|
18
|
+
for (let p of parts) {
|
|
19
|
+
const m = p.match(/^(?:[a-z]+\s*)?\(\s*([a-z -]+)\s*\)$/i);
|
|
20
|
+
if (m) p = m[1];
|
|
21
|
+
const s = slug(p);
|
|
22
|
+
if (ALL_SKILL_SLUGS.includes(s)) {
|
|
23
|
+
out.push(s);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const ab = normalizeAbility(p);
|
|
27
|
+
if (ab) {
|
|
28
|
+
out.push(ab);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
normalizeRollScope
|
|
38
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/schemas/entity-extras-schema.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var imageField = z.union([z.string().min(1), z.array(z.string().min(1))]).optional();
|
|
4
|
+
var additionalSpellsEntrySchema = z.object({
|
|
5
|
+
name: z.string().min(1).optional(),
|
|
6
|
+
ability: z.union([z.string().min(1), z.object({ choose: z.array(z.string().min(1)) })]).optional(),
|
|
7
|
+
known: z.unknown().optional(),
|
|
8
|
+
innate: z.unknown().optional(),
|
|
9
|
+
prepared: z.unknown().optional(),
|
|
10
|
+
expanded: z.unknown().optional(),
|
|
11
|
+
resourceName: z.string().min(1).optional()
|
|
12
|
+
});
|
|
13
|
+
var progressionSchema = z.object({
|
|
14
|
+
name: z.string().min(1),
|
|
15
|
+
progression: z.union([z.record(z.string(), z.number()), z.array(z.number())]),
|
|
16
|
+
feature_type: z.array(z.string().min(1)).optional(),
|
|
17
|
+
featureType: z.array(z.string().min(1)).optional(),
|
|
18
|
+
category: z.array(z.string().min(1)).optional(),
|
|
19
|
+
required: z.record(z.string(), z.array(z.string())).optional()
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
imageField,
|
|
24
|
+
additionalSpellsEntrySchema,
|
|
25
|
+
progressionSchema
|
|
26
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveSpellcasting
|
|
3
|
+
} from "./chunk-DPUJDOKV.js";
|
|
4
|
+
import {
|
|
5
|
+
warnOnce
|
|
6
|
+
} from "./chunk-LVQLWRCU.js";
|
|
7
|
+
import {
|
|
8
|
+
isValidMaxFormula
|
|
9
|
+
} from "./chunk-EVMUJYUD.js";
|
|
10
|
+
|
|
11
|
+
// src/pc/pc.resources.ts
|
|
12
|
+
function resourceLevelFor(source, resolved) {
|
|
13
|
+
var _a, _b, _c, _d;
|
|
14
|
+
if (source.kind === "class") {
|
|
15
|
+
return (_b = (_a = resolved.classes.find((c) => {
|
|
16
|
+
var _a2;
|
|
17
|
+
return ((_a2 = c.entity) == null ? void 0 : _a2.slug) === source.slug;
|
|
18
|
+
})) == null ? void 0 : _a.level) != null ? _b : resolved.totalLevel;
|
|
19
|
+
}
|
|
20
|
+
if (source.kind === "subclass") {
|
|
21
|
+
return (_d = (_c = resolved.classes.find((c) => {
|
|
22
|
+
var _a2;
|
|
23
|
+
return ((_a2 = c.subclass) == null ? void 0 : _a2.slug) === source.slug;
|
|
24
|
+
})) == null ? void 0 : _c.level) != null ? _d : resolved.totalLevel;
|
|
25
|
+
}
|
|
26
|
+
return resolved.totalLevel;
|
|
27
|
+
}
|
|
28
|
+
function resolveRecovery(entry) {
|
|
29
|
+
var _a;
|
|
30
|
+
const kind = (_a = entry.restores) != null ? _a : "uses";
|
|
31
|
+
const restTriggered = (entry.reset === "short-rest" || entry.reset === "long-rest") && !entry.action;
|
|
32
|
+
const flavour = kind === "spell-slots" ? "manual" : restTriggered ? "rest" : "manual";
|
|
33
|
+
return { entry, kind, flavour };
|
|
34
|
+
}
|
|
35
|
+
function toResolvedResource(r, fallbackName, owner) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
return {
|
|
38
|
+
id: r.id,
|
|
39
|
+
name: (_a = r.name) != null ? _a : fallbackName,
|
|
40
|
+
reset: r.reset,
|
|
41
|
+
maxFormula: r.max_formula,
|
|
42
|
+
...r.die ? { die: r.die } : {},
|
|
43
|
+
...r.scales_at ? { scalesAt: r.scales_at } : {},
|
|
44
|
+
...((_b = r.recovery) == null ? void 0 : _b.length) ? { recovery: r.recovery.map(resolveRecovery) } : {},
|
|
45
|
+
owner
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function resolveFeatureResources(features) {
|
|
49
|
+
var _a, _b;
|
|
50
|
+
const out = /* @__PURE__ */ new Map();
|
|
51
|
+
for (const rf of features) {
|
|
52
|
+
for (const r of (_a = rf.feature.resources) != null ? _a : []) {
|
|
53
|
+
if (out.has(r.id)) continue;
|
|
54
|
+
const owner = { kind: "feature", featureId: (_b = rf.feature.id) != null ? _b : rf.feature.name, featureName: rf.feature.name, source: rf.source };
|
|
55
|
+
out.set(r.id, toResolvedResource(r, rf.feature.name, owner));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function resolveResourceIndex(resolved) {
|
|
61
|
+
var _a, _b, _c, _d, _e;
|
|
62
|
+
const out = new Map(resolveFeatureResources((_a = resolved.features) != null ? _a : []));
|
|
63
|
+
for (const pool of (_b = resolved.pools) != null ? _b : []) {
|
|
64
|
+
const rc = resolved.classes[pool.classIndex];
|
|
65
|
+
const classSlug = (_c = rc == null ? void 0 : rc.entity) == null ? void 0 : _c.slug;
|
|
66
|
+
if (!classSlug) continue;
|
|
67
|
+
for (const entry of [...(_d = pool.selected) != null ? _d : [], ...(_e = pool.grants) != null ? _e : []]) {
|
|
68
|
+
const uses = entry.entity.uses;
|
|
69
|
+
if (!uses || out.has(entry.slug)) continue;
|
|
70
|
+
const maxFormula = String(uses.max);
|
|
71
|
+
if (!isValidMaxFormula(maxFormula)) {
|
|
72
|
+
warnOnce(`pool-uses:${entry.slug}`, `optional feature "${entry.slug}" has a prose uses.max (${JSON.stringify(uses.max)}); no tracker`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
out.set(entry.slug, {
|
|
76
|
+
id: entry.slug,
|
|
77
|
+
name: entry.entity.name,
|
|
78
|
+
reset: uses.recharge,
|
|
79
|
+
maxFormula,
|
|
80
|
+
owner: { kind: "pool", poolId: pool.id, poolLabel: pool.label, source: { kind: "class", slug: classSlug, level: pool.anchorLevel } }
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function poolSaveDC(resolved, derived, pool) {
|
|
87
|
+
var _a, _b;
|
|
88
|
+
const rc = resolved.classes[pool.classIndex];
|
|
89
|
+
const ability = (_b = (_a = rc == null ? void 0 : rc.subclass) == null ? void 0 : _a.spellcasting) == null ? void 0 : _b.ability;
|
|
90
|
+
if (!rc || !ability) return null;
|
|
91
|
+
if (resolveSpellcasting(rc) !== null) return null;
|
|
92
|
+
return 8 + derived.proficiencyBonus + derived.mods[ability];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
resourceLevelFor,
|
|
97
|
+
resolveRecovery,
|
|
98
|
+
resolveFeatureResources,
|
|
99
|
+
resolveResourceIndex,
|
|
100
|
+
poolSaveDC
|
|
101
|
+
};
|