@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
|
@@ -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
|
+
};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
featureSchema
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-W74BCA7V.js";
|
|
4
4
|
import {
|
|
5
5
|
choiceSchema
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IWRVOCT5.js";
|
|
7
|
+
import {
|
|
8
|
+
additionalSpellsEntrySchema,
|
|
9
|
+
imageField
|
|
10
|
+
} from "./chunk-UA5KS2PL.js";
|
|
7
11
|
|
|
8
12
|
// src/race/race.schema.ts
|
|
9
13
|
import { z } from "zod";
|
|
@@ -55,9 +59,31 @@ var raceEntitySchema = z.object({
|
|
|
55
59
|
variant_label: z.string().min(1),
|
|
56
60
|
traits: z.array(featureSchema),
|
|
57
61
|
choices: z.array(choiceSchema).optional(),
|
|
58
|
-
subspecies_of: z.string().regex(wikilinkRegex).optional()
|
|
62
|
+
subspecies_of: z.string().regex(wikilinkRegex).optional(),
|
|
63
|
+
rendering_hint: z.string().optional(),
|
|
64
|
+
has_fluff: z.boolean().optional(),
|
|
65
|
+
has_fluff_images: z.boolean().optional(),
|
|
66
|
+
creature_type: z.array(z.string().min(1)).optional(),
|
|
67
|
+
// guarded non-empty at the emitter (finding 24)
|
|
68
|
+
creature_type_tags: z.array(z.string().min(1)).optional(),
|
|
69
|
+
additional_spells: z.union([
|
|
70
|
+
z.array(additionalSpellsEntrySchema),
|
|
71
|
+
// converter form, 109 docs
|
|
72
|
+
additionalSpellsEntrySchema
|
|
73
|
+
// SHIPPED-BUNDLE bare-object form, 3 docs (§2.8)
|
|
74
|
+
]).optional(),
|
|
75
|
+
// The four RAW 5etools PASSTHROUGHS (race-mapper.ts D13 block copies them VERBATIM, no shape
|
|
76
|
+
// guard — finding 24): today's variant set is a snapshot, not a contract (lineage is already
|
|
77
|
+
// string|null|boolean), and NO G row ever reads them. Maximally loose by ruling; the guard
|
|
78
|
+
// test §9.5 pins today's variant classes since the census goes blind under z.unknown().
|
|
79
|
+
trait_tags: z.unknown().optional(),
|
|
80
|
+
lineage: z.unknown().optional(),
|
|
81
|
+
height_and_weight: z.unknown().optional(),
|
|
82
|
+
sound_clip: z.unknown().optional(),
|
|
83
|
+
image: imageField
|
|
59
84
|
});
|
|
60
85
|
|
|
61
86
|
export {
|
|
87
|
+
fixedAsiSchema,
|
|
62
88
|
raceEntitySchema
|
|
63
89
|
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
featureObjectSchema
|
|
3
|
+
} from "./chunk-W74BCA7V.js";
|
|
4
|
+
import {
|
|
5
|
+
imageField
|
|
6
|
+
} from "./chunk-UA5KS2PL.js";
|
|
7
|
+
|
|
8
|
+
// src/monster/monster.schema.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var str = z.string();
|
|
11
|
+
var num = z.number();
|
|
12
|
+
var bool = z.boolean();
|
|
13
|
+
var strArr = z.array(z.string());
|
|
14
|
+
var damageQualifierSchema = z.object({
|
|
15
|
+
get types() {
|
|
16
|
+
return z.array(z.union([str, damageQualifierSchema])).optional();
|
|
17
|
+
},
|
|
18
|
+
note: str.optional(),
|
|
19
|
+
pre_note: str.optional(),
|
|
20
|
+
cond: bool.optional(),
|
|
21
|
+
special: str.optional()
|
|
22
|
+
});
|
|
23
|
+
var qualifierList = z.array(z.union([str, damageQualifierSchema])).optional();
|
|
24
|
+
var speedValue = z.union([num, z.object({ number: num, condition: str.optional() })]);
|
|
25
|
+
var monsterSpeedSchema = z.object({
|
|
26
|
+
walk: speedValue.optional(),
|
|
27
|
+
fly: speedValue.optional(),
|
|
28
|
+
swim: speedValue.optional(),
|
|
29
|
+
climb: speedValue.optional(),
|
|
30
|
+
burrow: speedValue.optional(),
|
|
31
|
+
hover: bool.optional(),
|
|
32
|
+
can_hover: bool.optional(),
|
|
33
|
+
alternate: z.record(str, z.array(z.object({ number: num, condition: str.optional() }))).optional(),
|
|
34
|
+
choose: z.object({ from: strArr, amount: num, note: str.optional() }).optional()
|
|
35
|
+
});
|
|
36
|
+
var monsterTypeSchema = z.object({
|
|
37
|
+
type: z.union([str, z.object({ choose: strArr })]),
|
|
38
|
+
tags: z.array(z.union([str, z.object({ tag: str, prefix: str, prefix_hidden: bool.optional() })])).optional(),
|
|
39
|
+
sidekick_type: str.optional(),
|
|
40
|
+
sidekick_tags: strArr.optional(),
|
|
41
|
+
swarm_size: str.optional(),
|
|
42
|
+
sidekick_hidden: bool.optional()
|
|
43
|
+
});
|
|
44
|
+
var monsterCRSchema = z.object({ cr: str, lair: str.optional(), coven: str.optional(), xp: num.optional(), xp_lair: num.optional() });
|
|
45
|
+
var monsterACSchema = z.object({ ac: num.optional(), from: strArr.optional(), condition: str.optional(), braces: bool.optional(), special: str.optional() });
|
|
46
|
+
var monsterHPSchema = z.object({ average: num.optional(), formula: str.optional(), special: str.optional() });
|
|
47
|
+
var alignmentEntrySchema = z.object({ alignment: strArr.optional(), chance: num.optional(), note: str.optional(), special: str.optional() });
|
|
48
|
+
var spellEntry = z.union([str, z.object({ entry: str, hidden: bool.optional() })]);
|
|
49
|
+
var spellList = z.array(spellEntry);
|
|
50
|
+
var spellLevel = z.object({ slots: num.optional(), lower: num.optional(), spells: strArr });
|
|
51
|
+
var monsterSpellcastingSchema = z.object({
|
|
52
|
+
name: str.optional(),
|
|
53
|
+
type: str.optional(),
|
|
54
|
+
headerEntries: strArr.optional(),
|
|
55
|
+
footerEntries: strArr.optional(),
|
|
56
|
+
ability: str.optional(),
|
|
57
|
+
displayAs: str.optional(),
|
|
58
|
+
hidden: strArr.optional(),
|
|
59
|
+
spells: z.record(str, spellLevel).optional(),
|
|
60
|
+
will: spellList.optional(),
|
|
61
|
+
ritual: spellList.optional(),
|
|
62
|
+
daily: z.record(str, spellList).optional(),
|
|
63
|
+
rest: z.record(str, spellList).optional(),
|
|
64
|
+
restLong: z.record(str, spellList).optional(),
|
|
65
|
+
recharge: z.record(str, spellList).optional(),
|
|
66
|
+
legendary: z.record(str, spellList).optional(),
|
|
67
|
+
charges: z.record(str, spellList).optional(),
|
|
68
|
+
chargesItem: str.optional()
|
|
69
|
+
});
|
|
70
|
+
var initiativeSchema = z.union([num, z.object({ proficiency: num.optional(), advantage_mode: str.optional() })]);
|
|
71
|
+
var gearEntrySchema = z.union([str, z.object({ item: str, quantity: num.optional(), displayName: str.optional() })]);
|
|
72
|
+
var featureArr = z.array(featureObjectSchema).optional();
|
|
73
|
+
var monsterSchema = z.object({
|
|
74
|
+
name: str.min(1),
|
|
75
|
+
size: z.union([str, strArr]).optional(),
|
|
76
|
+
size_note: str.optional(),
|
|
77
|
+
type: z.union([str, monsterTypeSchema]).optional(),
|
|
78
|
+
subtype: str.optional(),
|
|
79
|
+
alignment: z.union([str, z.array(z.union([str, alignmentEntrySchema]))]).optional(),
|
|
80
|
+
alignment_prefix: str.optional(),
|
|
81
|
+
cr: z.union([str, monsterCRSchema]).optional(),
|
|
82
|
+
pb_note: str.optional(),
|
|
83
|
+
ac: z.array(monsterACSchema).optional(),
|
|
84
|
+
hp: monsterHPSchema.optional(),
|
|
85
|
+
speed: monsterSpeedSchema.optional(),
|
|
86
|
+
abilities: z.object({ str: num, dex: num, con: num, int: num, wis: num, cha: num }).optional(),
|
|
87
|
+
saves: z.record(str, num).optional(),
|
|
88
|
+
skills: z.record(str, num).optional(),
|
|
89
|
+
skills_other: z.array(z.unknown()).optional(),
|
|
90
|
+
senses: strArr.nullable().optional(),
|
|
91
|
+
passive_perception: num.optional(),
|
|
92
|
+
languages: strArr.nullable().optional(),
|
|
93
|
+
damage_vulnerabilities: qualifierList,
|
|
94
|
+
damage_resistances: qualifierList,
|
|
95
|
+
damage_immunities: qualifierList,
|
|
96
|
+
condition_immunities: qualifierList,
|
|
97
|
+
traits: featureArr,
|
|
98
|
+
actions: featureArr,
|
|
99
|
+
bonus_actions: featureArr,
|
|
100
|
+
reactions: featureArr,
|
|
101
|
+
legendary_actions: featureArr,
|
|
102
|
+
mythic: featureArr,
|
|
103
|
+
mythic_header: strArr.optional(),
|
|
104
|
+
legendary_action_uses: num.optional(),
|
|
105
|
+
legendary_resistance: num.optional(),
|
|
106
|
+
legendary_actions_lair_count: num.optional(),
|
|
107
|
+
section_headers: z.array(z.object({ section: str, header: strArr })).optional(),
|
|
108
|
+
action_note: str.optional(),
|
|
109
|
+
reaction_note: str.optional(),
|
|
110
|
+
spellcasting: z.array(monsterSpellcastingSchema).optional(),
|
|
111
|
+
legendary_group: z.object({ name: str, source: str }).optional(),
|
|
112
|
+
lair_actions: z.array(z.unknown()).optional(),
|
|
113
|
+
regional_actions: z.array(z.unknown()).optional(),
|
|
114
|
+
variant: z.array(z.unknown()).optional(),
|
|
115
|
+
initiative: initiativeSchema.optional(),
|
|
116
|
+
gear: z.array(gearEntrySchema).optional(),
|
|
117
|
+
is_named_creature: bool.optional(),
|
|
118
|
+
is_npc: bool.optional(),
|
|
119
|
+
familiar: bool.optional(),
|
|
120
|
+
short_name: z.union([str, bool]).optional(),
|
|
121
|
+
level: num.optional(),
|
|
122
|
+
dragon_age: str.optional(),
|
|
123
|
+
dragon_casting_color: str.optional(),
|
|
124
|
+
environment: strArr.optional(),
|
|
125
|
+
treasure: strArr.optional(),
|
|
126
|
+
attached_items: strArr.optional(),
|
|
127
|
+
group: strArr.nullable().optional(),
|
|
128
|
+
summoned_by_spell: str.optional(),
|
|
129
|
+
summoned_by_spell_level: num.optional(),
|
|
130
|
+
summoned_by_class: str.optional(),
|
|
131
|
+
trait_tags: strArr.optional(),
|
|
132
|
+
action_tags: strArr.optional(),
|
|
133
|
+
sense_tags: strArr.optional(),
|
|
134
|
+
language_tags: strArr.optional(),
|
|
135
|
+
spellcasting_tags: strArr.optional(),
|
|
136
|
+
misc_tags: strArr.optional(),
|
|
137
|
+
damage_tags: strArr.optional(),
|
|
138
|
+
damage_tags_spell: strArr.optional(),
|
|
139
|
+
damage_tags_legendary: strArr.optional(),
|
|
140
|
+
condition_inflict: strArr.optional(),
|
|
141
|
+
condition_inflict_spell: strArr.optional(),
|
|
142
|
+
condition_inflict_legendary: strArr.optional(),
|
|
143
|
+
saving_throw_forced: strArr.optional(),
|
|
144
|
+
saving_throw_forced_spell: strArr.optional(),
|
|
145
|
+
saving_throw_forced_legendary: strArr.optional(),
|
|
146
|
+
has_fluff: bool.optional(),
|
|
147
|
+
has_fluff_images: bool.optional(),
|
|
148
|
+
has_token: bool.optional(),
|
|
149
|
+
token_credit: str.optional(),
|
|
150
|
+
token_custom: bool.optional(),
|
|
151
|
+
foundry_token_scale: num.optional(),
|
|
152
|
+
sound_clip: z.object({ type: str, path: str }).optional(),
|
|
153
|
+
alt_art: z.array(z.object({ name: str, source: str.optional(), page: num.optional() })).optional(),
|
|
154
|
+
image: imageField,
|
|
155
|
+
thumbnail: imageField,
|
|
156
|
+
rendering_hint: str.optional(),
|
|
157
|
+
columns: num.optional(),
|
|
158
|
+
slug: str.optional(),
|
|
159
|
+
edition: str.optional(),
|
|
160
|
+
source: str.optional(),
|
|
161
|
+
raw: z.record(str, z.unknown()).optional()
|
|
162
|
+
});
|
|
163
|
+
var MONSTER_KNOWN_KEYS = new Set(Object.keys(monsterSchema.shape));
|
|
164
|
+
|
|
165
|
+
export {
|
|
166
|
+
damageQualifierSchema,
|
|
167
|
+
monsterSpeedSchema,
|
|
168
|
+
monsterTypeSchema,
|
|
169
|
+
monsterCRSchema,
|
|
170
|
+
monsterACSchema,
|
|
171
|
+
monsterHPSchema,
|
|
172
|
+
alignmentEntrySchema,
|
|
173
|
+
monsterSpellcastingSchema,
|
|
174
|
+
initiativeSchema,
|
|
175
|
+
gearEntrySchema,
|
|
176
|
+
monsterSchema,
|
|
177
|
+
MONSTER_KNOWN_KEYS
|
|
178
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MONSTER_KNOWN_KEYS,
|
|
3
|
+
monsterSchema
|
|
4
|
+
} from "./chunk-UQ3ZFCWD.js";
|
|
5
|
+
|
|
6
|
+
// src/monster/monster.parser.ts
|
|
7
|
+
import { parseYaml } from "@archivist-gg/core";
|
|
8
|
+
var VALID_RECHARGE_TYPES = /* @__PURE__ */ new Set([
|
|
9
|
+
"recharge_on_roll",
|
|
10
|
+
"per_day",
|
|
11
|
+
"per_short_rest",
|
|
12
|
+
"per_long_rest"
|
|
13
|
+
]);
|
|
14
|
+
var NUMERIC_STRING = /^[+-]?\d+(\.\d+)?$/;
|
|
15
|
+
var FEATURE_ARRAYS = ["traits", "actions", "reactions", "legendary_actions", "bonus_actions", "mythic"];
|
|
16
|
+
var SPEED_MODES = ["walk", "fly", "swim", "climb", "burrow"];
|
|
17
|
+
var ABILITY_KEYS = ["str", "dex", "con", "int", "wis", "cha"];
|
|
18
|
+
var NULL_KEPT = /* @__PURE__ */ new Set(["senses", "languages", "group"]);
|
|
19
|
+
function isRecord(v) {
|
|
20
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
21
|
+
}
|
|
22
|
+
function coerceNumeric(obj, key) {
|
|
23
|
+
const v = obj[key];
|
|
24
|
+
if (typeof v === "string" && NUMERIC_STRING.test(v.trim())) obj[key] = Number(v);
|
|
25
|
+
}
|
|
26
|
+
function scrubNulls(v, top) {
|
|
27
|
+
if (Array.isArray(v)) {
|
|
28
|
+
for (let i = v.length - 1; i >= 0; i--) {
|
|
29
|
+
if (v[i] === null) v.splice(i, 1);
|
|
30
|
+
else scrubNulls(v[i], false);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!isRecord(v)) return;
|
|
35
|
+
for (const [k, x] of Object.entries(v)) {
|
|
36
|
+
if (x === null) {
|
|
37
|
+
if (!(top && NULL_KEPT.has(k))) delete v[k];
|
|
38
|
+
} else scrubNulls(x, false);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function scrubNonFinite(v) {
|
|
42
|
+
if (Array.isArray(v)) {
|
|
43
|
+
for (const x of v) scrubNonFinite(x);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!isRecord(v)) return;
|
|
47
|
+
for (const [k, x] of Object.entries(v)) {
|
|
48
|
+
if (typeof x === "number" && !Number.isFinite(x)) delete v[k];
|
|
49
|
+
else scrubNonFinite(x);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function migrateLegacy(raw) {
|
|
53
|
+
scrubNulls(raw, true);
|
|
54
|
+
if (raw.legendary_actions != null && !Array.isArray(raw.legendary_actions) && typeof raw.legendary_actions !== "object") {
|
|
55
|
+
if (raw.legendary_action_uses == null) raw.legendary_action_uses = Number(raw.legendary_actions);
|
|
56
|
+
delete raw.legendary_actions;
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(raw.legendary_actions) && Array.isArray(raw.legendary)) raw.legendary_actions = raw.legendary;
|
|
59
|
+
delete raw.legendary;
|
|
60
|
+
if (typeof raw.ac === "number") raw.ac = [{ ac: raw.ac }];
|
|
61
|
+
if (Array.isArray(raw.ac)) raw.ac = raw.ac.map((e) => typeof e === "number" ? { ac: e } : e);
|
|
62
|
+
if (typeof raw.hp === "number") raw.hp = { average: raw.hp };
|
|
63
|
+
if (typeof raw.cr === "number") raw.cr = String(raw.cr);
|
|
64
|
+
for (const k of ["passive_perception", "legendary_action_uses", "legendary_resistance", "columns", "initiative"]) coerceNumeric(raw, k);
|
|
65
|
+
if (isRecord(raw.initiative)) coerceNumeric(raw.initiative, "proficiency");
|
|
66
|
+
for (const k of ["saves", "skills"]) {
|
|
67
|
+
const o = raw[k];
|
|
68
|
+
if (isRecord(o)) for (const m of Object.keys(o)) coerceNumeric(o, m);
|
|
69
|
+
}
|
|
70
|
+
if (isRecord(raw.hp)) coerceNumeric(raw.hp, "average");
|
|
71
|
+
if (Array.isArray(raw.ac)) {
|
|
72
|
+
for (const e of raw.ac) if (isRecord(e)) coerceNumeric(e, "ac");
|
|
73
|
+
}
|
|
74
|
+
if (isRecord(raw.abilities)) for (const k of ABILITY_KEYS) coerceNumeric(raw.abilities, k);
|
|
75
|
+
if (isRecord(raw.speed)) for (const k of SPEED_MODES) {
|
|
76
|
+
coerceNumeric(raw.speed, k);
|
|
77
|
+
const v = raw.speed[k];
|
|
78
|
+
if (isRecord(v)) coerceNumeric(v, "number");
|
|
79
|
+
}
|
|
80
|
+
scrubNonFinite(raw);
|
|
81
|
+
if (isRecord(raw.abilities)) {
|
|
82
|
+
for (const k of ABILITY_KEYS) if (raw.abilities[k] == null) raw.abilities[k] = 10;
|
|
83
|
+
}
|
|
84
|
+
if (typeof raw.senses === "string") raw.senses = [raw.senses];
|
|
85
|
+
if (typeof raw.languages === "string") raw.languages = [raw.languages];
|
|
86
|
+
for (const k of FEATURE_ARRAYS) {
|
|
87
|
+
const arr = raw[k];
|
|
88
|
+
if (!Array.isArray(arr)) continue;
|
|
89
|
+
for (const f of arr) {
|
|
90
|
+
if (!isRecord(f)) continue;
|
|
91
|
+
if (typeof f.desc === "string" && f.description === void 0 && !Array.isArray(f.entries)) {
|
|
92
|
+
f.description = f.desc;
|
|
93
|
+
delete f.desc;
|
|
94
|
+
}
|
|
95
|
+
const r = f.recharge;
|
|
96
|
+
if (r !== void 0 && !(isRecord(r) && typeof r.param === "number" && VALID_RECHARGE_TYPES.has(r.type))) delete f.recharge;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function parseMonster(source) {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
const result = parseYaml(source, ["name"]);
|
|
103
|
+
if (!result.success) return result;
|
|
104
|
+
const raw = result.data;
|
|
105
|
+
migrateLegacy(raw);
|
|
106
|
+
const parsed = monsterSchema.safeParse(raw);
|
|
107
|
+
if (!parsed.success) {
|
|
108
|
+
return { success: false, error: `monster schema validation failed: ${parsed.error.message}` };
|
|
109
|
+
}
|
|
110
|
+
const monster = parsed.data;
|
|
111
|
+
const extras = {};
|
|
112
|
+
for (const [k, v] of Object.entries(raw)) if (!MONSTER_KNOWN_KEYS.has(k)) extras[k] = v;
|
|
113
|
+
if (Object.keys(extras).length > 0) monster.raw = { ...(_a = monster.raw) != null ? _a : {}, ...extras };
|
|
114
|
+
if (!monster.legendary_resistance && monster.traits) {
|
|
115
|
+
const lrIndex = monster.traits.findIndex((t) => {
|
|
116
|
+
var _a2;
|
|
117
|
+
return /^Legendary Resistance\s*\(/i.test((_a2 = t.name) != null ? _a2 : "");
|
|
118
|
+
});
|
|
119
|
+
if (lrIndex !== -1) {
|
|
120
|
+
const match = (_b = monster.traits[lrIndex].name) == null ? void 0 : _b.match(/\((\d+)\/Day\)/i);
|
|
121
|
+
if (match) {
|
|
122
|
+
monster.legendary_resistance = parseInt(match[1], 10);
|
|
123
|
+
monster.traits.splice(lrIndex, 1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { success: true, data: monster };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
migrateLegacy,
|
|
132
|
+
parseMonster
|
|
133
|
+
};
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
classifyWeaponRange
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import {
|
|
5
|
-
normKey
|
|
6
|
-
} from "./chunk-O5EYMKFH.js";
|
|
3
|
+
} from "./chunk-UIRMA5KM.js";
|
|
7
4
|
import {
|
|
8
5
|
defaultSlotForType,
|
|
9
6
|
effectiveArmor,
|
|
10
7
|
isItemEntity,
|
|
11
8
|
isWeaponEntity,
|
|
12
9
|
resolveEntityForEntry
|
|
13
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UBBKSYBY.js";
|
|
11
|
+
import {
|
|
12
|
+
normKey
|
|
13
|
+
} from "./chunk-RLGQ5PZZ.js";
|
|
14
14
|
import {
|
|
15
15
|
readNumericBonus
|
|
16
16
|
} from "./chunk-LWFTHJIE.js";
|
|
17
17
|
import {
|
|
18
18
|
resolveBaseItem
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-WXWPK3LI.js";
|
|
20
20
|
import {
|
|
21
21
|
bareEntitySlug
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-6X4KUDMU.js";
|
|
23
23
|
|
|
24
24
|
// src/weapon/weapon-mastery.ts
|
|
25
25
|
var MASTERY = {
|
|
@@ -405,7 +405,7 @@ function magicBonusesForWeaponEntry(entry, registry, ctx) {
|
|
|
405
405
|
itemRiders = Array.isArray(entity.damage_riders) ? entity.damage_riders.filter((r) => {
|
|
406
406
|
var _a2;
|
|
407
407
|
return ((_a2 = r.applies_to) != null ? _a2 : "weapon") !== "spell";
|
|
408
|
-
}).map((r) => ({ amount: r.amount, damage_type: r.damage_type, source: entity.name })) : [];
|
|
408
|
+
}).map((r) => ({ amount: r.amount, damage_type: r.damage_type, source: entity.name, ...r.condition ? { condition: r.condition } : {} })) : [];
|
|
409
409
|
}
|
|
410
410
|
return {
|
|
411
411
|
atk: itemAttack + entryAttack,
|
|
@@ -482,6 +482,40 @@ function buildAttackRow(args) {
|
|
|
482
482
|
}
|
|
483
483
|
return row;
|
|
484
484
|
}
|
|
485
|
+
function buildUnarmedRow(mods, proficiencyBonus, spec) {
|
|
486
|
+
var _a;
|
|
487
|
+
const candidates = ["str", ...(_a = spec == null ? void 0 : spec.abilities) != null ? _a : []];
|
|
488
|
+
let ability = "str";
|
|
489
|
+
for (const ab of candidates) if (mods[ab] >= mods[ability]) ability = ab;
|
|
490
|
+
const abilityMod = mods[ability];
|
|
491
|
+
const toHit = abilityMod + proficiencyBonus;
|
|
492
|
+
const flat = `${abilityMod >= 0 ? "+" : ""}${abilityMod}`.replace(/^\+0$/, "");
|
|
493
|
+
const damageDice = (spec == null ? void 0 : spec.dice) ? `${spec.dice}${flat}` : String(Math.max(0, 1 + abilityMod));
|
|
494
|
+
const label = `${ability.toUpperCase()} modifier`;
|
|
495
|
+
return {
|
|
496
|
+
id: "unarmed-strike",
|
|
497
|
+
name: "Unarmed Strike",
|
|
498
|
+
unarmed: true,
|
|
499
|
+
range: "5 ft",
|
|
500
|
+
toHit,
|
|
501
|
+
damageDice,
|
|
502
|
+
damageType: "bludgeoning",
|
|
503
|
+
properties: [],
|
|
504
|
+
proficient: true,
|
|
505
|
+
breakdown: {
|
|
506
|
+
toHit: [
|
|
507
|
+
{ source: label, amount: abilityMod, kind: "ability" },
|
|
508
|
+
{ source: "Proficiency bonus", amount: proficiencyBonus, kind: "ability" }
|
|
509
|
+
],
|
|
510
|
+
damage: [
|
|
511
|
+
{ source: "Base damage", amount: 0, kind: "ability" },
|
|
512
|
+
{ source: label, amount: abilityMod, kind: "ability" }
|
|
513
|
+
]
|
|
514
|
+
},
|
|
515
|
+
subLabel: "Unarmed",
|
|
516
|
+
actionCost: "action"
|
|
517
|
+
};
|
|
518
|
+
}
|
|
485
519
|
function humanizeWeaponToken(s) {
|
|
486
520
|
return s.replace(/[-_]/g, " ").replace(/(^|[\s(])\w/g, (c) => c.toUpperCase());
|
|
487
521
|
}
|
|
@@ -571,7 +605,7 @@ function computeCarriedWeight(resolved, registry) {
|
|
|
571
605
|
}
|
|
572
606
|
return total;
|
|
573
607
|
}
|
|
574
|
-
function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, proficiencyBonus, weaponAbilities = [], weaponMasteries = []) {
|
|
608
|
+
function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, proficiencyBonus, weaponAbilities = [], weaponMasteries = [], attunementFloor = 0) {
|
|
575
609
|
var _a, _b, _c;
|
|
576
610
|
const equippedSlots = assignSlots(resolved, registry, warnings);
|
|
577
611
|
const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
|
|
@@ -587,12 +621,16 @@ function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, profi
|
|
|
587
621
|
carriedWeight: computeCarriedWeight(resolved, registry),
|
|
588
622
|
// Attunement is persistent: an attuned item still occupies a slot even when unequipped (SRD).
|
|
589
623
|
attunementUsed: ((_b = resolved.definition.equipment) != null ? _b : []).filter((e) => e.attuned).length,
|
|
590
|
-
|
|
624
|
+
// PRECEDENCE: an explicit character override wins outright (a number the player typed is intent);
|
|
625
|
+
// otherwise the baseline 3 is raised — never lowered — by whatever features granted.
|
|
626
|
+
attunementLimit: (_c = overrides.attunement_limit) != null ? _c : Math.max(3, attunementFloor)
|
|
591
627
|
};
|
|
592
628
|
}
|
|
593
629
|
|
|
594
630
|
export {
|
|
595
631
|
emptyAppliedBonuses,
|
|
596
632
|
computeAppliedBonuses,
|
|
633
|
+
isWeaponSlugProficient,
|
|
634
|
+
buildUnarmedRow,
|
|
597
635
|
computeSlotsAndAttacks
|
|
598
636
|
};
|