@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,489 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CR_TO_XP,
|
|
3
|
+
getProficiencyBonus
|
|
4
|
+
} from "./chunk-6PXTNCBP.js";
|
|
5
|
+
import {
|
|
6
|
+
abilityModifier
|
|
7
|
+
} from "./chunk-PDJSUH24.js";
|
|
8
|
+
import {
|
|
9
|
+
ALL_SKILLS
|
|
10
|
+
} from "./chunk-WELIKLZF.js";
|
|
11
|
+
|
|
12
|
+
// src/monster/monster.format.ts
|
|
13
|
+
function capitalizeWords(str) {
|
|
14
|
+
return str.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
function capitalizeOutsideLinks(str) {
|
|
17
|
+
return str.replace(/\[\[([^\]|]+)(?:\|([^\]]*))?\]\]|([^[]+|\[)/g, (m, target, alias, plain) => {
|
|
18
|
+
if (target !== void 0) return alias !== void 0 ? `[[${target}|${capitalizeWords(alias)}]]` : `[[${target}]]`;
|
|
19
|
+
return capitalizeWords(plain != null ? plain : m);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
var SIZE_CODES = { T: "Tiny", S: "Small", M: "Medium", L: "Large", H: "Huge", G: "Gargantuan" };
|
|
23
|
+
function sizeWords(size) {
|
|
24
|
+
if (size === void 0) return [];
|
|
25
|
+
const arr = Array.isArray(size) ? size : [size];
|
|
26
|
+
return arr.map((s) => {
|
|
27
|
+
var _a;
|
|
28
|
+
return (_a = SIZE_CODES[s]) != null ? _a : capitalizeWords(s);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function joinOr(words) {
|
|
32
|
+
if (words.length <= 1) return words.join("");
|
|
33
|
+
if (words.length === 2) return `${words[0]} or ${words[1]}`;
|
|
34
|
+
return `${words.slice(0, -1).join(", ")}, or ${words[words.length - 1]}`;
|
|
35
|
+
}
|
|
36
|
+
function formatSize(size, note) {
|
|
37
|
+
const text = joinOr(sizeWords(size));
|
|
38
|
+
return note ? `${text} ${note}` : text;
|
|
39
|
+
}
|
|
40
|
+
function sizeWord(size) {
|
|
41
|
+
const first = sizeWords(size)[0];
|
|
42
|
+
return (first != null ? first : "Medium").toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
var ALIGNMENT_CODES = {
|
|
45
|
+
L: "lawful",
|
|
46
|
+
N: "neutral",
|
|
47
|
+
NX: "neutral",
|
|
48
|
+
NY: "neutral",
|
|
49
|
+
C: "chaotic",
|
|
50
|
+
G: "good",
|
|
51
|
+
E: "evil",
|
|
52
|
+
U: "unaligned",
|
|
53
|
+
A: "any alignment"
|
|
54
|
+
};
|
|
55
|
+
var ALIGNMENT_SETS = {
|
|
56
|
+
"C,E,L,NX,NY": "any non-good alignment",
|
|
57
|
+
"C,E,G,NX,NY": "any non-lawful alignment",
|
|
58
|
+
"C,E,L,NX": "any evil alignment",
|
|
59
|
+
"C,E,G,NY": "any chaotic alignment",
|
|
60
|
+
"N,NX,NY": "any neutral alignment"
|
|
61
|
+
};
|
|
62
|
+
function decodeCodes(codes) {
|
|
63
|
+
const key = [...codes].sort().join(",");
|
|
64
|
+
if (ALIGNMENT_SETS[key]) return ALIGNMENT_SETS[key];
|
|
65
|
+
return codes.map((c) => {
|
|
66
|
+
var _a;
|
|
67
|
+
return (_a = ALIGNMENT_CODES[c]) != null ? _a : c;
|
|
68
|
+
}).join(" ");
|
|
69
|
+
}
|
|
70
|
+
function alignmentText(alignment, prefix) {
|
|
71
|
+
if (alignment === void 0) return "";
|
|
72
|
+
let body;
|
|
73
|
+
if (typeof alignment === "string") body = alignment;
|
|
74
|
+
else if (alignment.every((a) => typeof a === "string")) body = decodeCodes(alignment);
|
|
75
|
+
else {
|
|
76
|
+
body = alignment.map((a) => {
|
|
77
|
+
var _a, _b;
|
|
78
|
+
if (typeof a === "string") return (_a = ALIGNMENT_CODES[a]) != null ? _a : a;
|
|
79
|
+
if (a.special) return a.special;
|
|
80
|
+
let t = decodeCodes((_b = a.alignment) != null ? _b : []);
|
|
81
|
+
if (a.chance !== void 0) t += ` (${a.chance}%)`;
|
|
82
|
+
if (a.note) t += ` (${a.note})`;
|
|
83
|
+
return t;
|
|
84
|
+
}).join(" or ");
|
|
85
|
+
}
|
|
86
|
+
return `${prefix != null ? prefix : ""}${body}`;
|
|
87
|
+
}
|
|
88
|
+
function formatAlignment(alignment, prefix) {
|
|
89
|
+
return capitalizeWords(alignmentText(alignment, prefix));
|
|
90
|
+
}
|
|
91
|
+
function alignmentWords(alignment) {
|
|
92
|
+
return alignmentText(alignment).toLowerCase();
|
|
93
|
+
}
|
|
94
|
+
var IRREGULAR_PLURALS = { fey: "fey", undead: "undead" };
|
|
95
|
+
function plural(word) {
|
|
96
|
+
var _a;
|
|
97
|
+
return (_a = IRREGULAR_PLURALS[word.toLowerCase()]) != null ? _a : `${word}s`;
|
|
98
|
+
}
|
|
99
|
+
function formatType(type, level) {
|
|
100
|
+
var _a, _b;
|
|
101
|
+
if (type === void 0) return "";
|
|
102
|
+
if (typeof type === "string") return capitalizeWords(type);
|
|
103
|
+
const baseText = typeof type.type === "string" ? capitalizeWords(type.type) : type.type.choose.map(capitalizeWords).join(" or ");
|
|
104
|
+
let text = type.swarm_size !== void 0 ? `Swarm of ${(_a = SIZE_CODES[type.swarm_size]) != null ? _a : capitalizeWords(type.swarm_size)} ${capitalizeWords(plural(typeof type.type === "string" ? type.type : type.type.choose.join(" or ")))}` : baseText;
|
|
105
|
+
const tags = ((_b = type.tags) != null ? _b : []).map((t) => typeof t === "string" ? t : t.prefix_hidden ? t.tag : `${t.prefix} ${t.tag}`);
|
|
106
|
+
if (tags.length > 0) text += ` (${tags.map(capitalizeWords).join(", ")})`;
|
|
107
|
+
if (type.sidekick_type && !type.sidekick_hidden) {
|
|
108
|
+
text += `, ${capitalizeWords(type.sidekick_type)} Sidekick`;
|
|
109
|
+
if (type.sidekick_tags && type.sidekick_tags.length > 0) text += ` (${type.sidekick_tags.map(capitalizeWords).join(", ")})`;
|
|
110
|
+
if (level !== void 0) text += ` (level ${level})`;
|
|
111
|
+
}
|
|
112
|
+
return text;
|
|
113
|
+
}
|
|
114
|
+
var CR_DECIMAL_KEYS = { "0.125": "1/8", "0.25": "1/4", "0.5": "1/2" };
|
|
115
|
+
function hasOwn(table, key) {
|
|
116
|
+
return Object.prototype.hasOwnProperty.call(table, key);
|
|
117
|
+
}
|
|
118
|
+
function crKey(text) {
|
|
119
|
+
return hasOwn(CR_DECIMAL_KEYS, text) ? CR_DECIMAL_KEYS[text] : text;
|
|
120
|
+
}
|
|
121
|
+
function xpFor(cr) {
|
|
122
|
+
const key = crKey(cr);
|
|
123
|
+
return hasOwn(CR_TO_XP, key) ? CR_TO_XP[key] : 0;
|
|
124
|
+
}
|
|
125
|
+
function formatCR(cr) {
|
|
126
|
+
var _a;
|
|
127
|
+
if (cr === void 0 || cr === null) return void 0;
|
|
128
|
+
const obj = typeof cr === "object" ? cr : { cr: String(cr) };
|
|
129
|
+
const text = String(obj.cr);
|
|
130
|
+
const key = crKey(text);
|
|
131
|
+
const tableMiss = !hasOwn(CR_TO_XP, key);
|
|
132
|
+
return {
|
|
133
|
+
crText: text,
|
|
134
|
+
xp: (_a = obj.xp) != null ? _a : xpFor(text),
|
|
135
|
+
pb: getProficiencyBonus(key),
|
|
136
|
+
tableMiss,
|
|
137
|
+
lair: obj.lair,
|
|
138
|
+
coven: obj.coven,
|
|
139
|
+
xpLair: obj.xp_lair,
|
|
140
|
+
xpOverride: obj.xp
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function formatXP(xp) {
|
|
144
|
+
return String(xp).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
145
|
+
}
|
|
146
|
+
function crString(cr) {
|
|
147
|
+
var _a;
|
|
148
|
+
return (_a = formatCR(cr)) == null ? void 0 : _a.crText;
|
|
149
|
+
}
|
|
150
|
+
function challengeLine(cr, pbNote) {
|
|
151
|
+
const f = formatCR(cr);
|
|
152
|
+
if (!f) return void 0;
|
|
153
|
+
const pbText = pbNote ? `PB ${pbNote}` : `PB +${f.pb}`;
|
|
154
|
+
if (f.tableMiss && f.xpOverride === void 0) return `${f.crText} (${pbText})`;
|
|
155
|
+
const xpText = `${formatXP(f.xp)} XP`;
|
|
156
|
+
if (f.xpLair !== void 0) return `${f.crText} (${xpText}, or ${formatXP(f.xpLair)} XP in its lair; ${pbText})`;
|
|
157
|
+
let line = `${f.crText} (${xpText}; ${pbText})`;
|
|
158
|
+
if (f.lair !== void 0) line += `, or ${f.lair} (${formatXP(xpFor(f.lair))} XP) in its lair`;
|
|
159
|
+
if (f.coven !== void 0) line += `, or ${f.coven} (${formatXP(xpFor(f.coven))} XP) as a coven`;
|
|
160
|
+
return line;
|
|
161
|
+
}
|
|
162
|
+
function formatAC(ac) {
|
|
163
|
+
const parts = [];
|
|
164
|
+
for (const entry of ac != null ? ac : []) {
|
|
165
|
+
if (entry.special !== void 0) {
|
|
166
|
+
parts.push({ text: entry.special, braced: false });
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (entry.ac === void 0) continue;
|
|
170
|
+
let text = String(entry.ac);
|
|
171
|
+
if (entry.from && entry.from.length > 0) text += ` (${entry.from.map(capitalizeOutsideLinks).join(", ")})`;
|
|
172
|
+
if (entry.condition) text += ` ${entry.condition}`;
|
|
173
|
+
parts.push(entry.braces ? { text: `(${text})`, braced: true } : { text, braced: false });
|
|
174
|
+
}
|
|
175
|
+
if (parts.length === 0) return "10";
|
|
176
|
+
return parts.reduce((acc, p, i) => i === 0 ? p.text : `${acc}${p.braced ? " " : ", "}${p.text}`, "");
|
|
177
|
+
}
|
|
178
|
+
function formatHP(hp) {
|
|
179
|
+
if (!hp) return { text: "0" };
|
|
180
|
+
if (hp.special !== void 0) return { text: hp.special };
|
|
181
|
+
if (hp.average === void 0) return { text: "0" };
|
|
182
|
+
return hp.formula ? { text: String(hp.average), formula: hp.formula } : { text: String(hp.average) };
|
|
183
|
+
}
|
|
184
|
+
var SPEED_MODES = ["walk", "fly", "swim", "climb", "burrow"];
|
|
185
|
+
function speedEntry(mode, value, hoverAppend) {
|
|
186
|
+
if (value === void 0 || value === null) return void 0;
|
|
187
|
+
const n = typeof value === "number" ? value : value.number;
|
|
188
|
+
if (!n) return void 0;
|
|
189
|
+
let text = `${capitalizeWords(mode)} ${n} ft.`;
|
|
190
|
+
const cond = typeof value === "number" ? void 0 : value.condition;
|
|
191
|
+
if (cond) text += ` ${cond}`;
|
|
192
|
+
if (hoverAppend && !(cond != null ? cond : "").toLowerCase().includes("hover")) text += " (hover)";
|
|
193
|
+
return text;
|
|
194
|
+
}
|
|
195
|
+
function formatSpeed(speed) {
|
|
196
|
+
var _a;
|
|
197
|
+
if (!speed) return "0 ft.";
|
|
198
|
+
const parts = [];
|
|
199
|
+
for (const mode of SPEED_MODES) {
|
|
200
|
+
const e = speedEntry(mode, speed[mode], mode === "fly" && speed.can_hover === true);
|
|
201
|
+
if (e) parts.push(e);
|
|
202
|
+
}
|
|
203
|
+
for (const [mode, entries] of Object.entries((_a = speed.alternate) != null ? _a : {})) {
|
|
204
|
+
for (const alt of entries) {
|
|
205
|
+
const e = speedEntry(mode, alt, false);
|
|
206
|
+
if (e) parts.push(e);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (speed.choose) {
|
|
210
|
+
let t = `${speed.choose.amount} ft. ${speed.choose.from.join(" or ")}`;
|
|
211
|
+
if (speed.choose.note) t += ` ${speed.choose.note}`;
|
|
212
|
+
parts.push(t);
|
|
213
|
+
}
|
|
214
|
+
return parts.join(", ");
|
|
215
|
+
}
|
|
216
|
+
function speedNumber(speed, mode) {
|
|
217
|
+
const v = speed == null ? void 0 : speed[mode];
|
|
218
|
+
if (v === void 0 || v === null) return 0;
|
|
219
|
+
return typeof v === "number" ? v : v.number;
|
|
220
|
+
}
|
|
221
|
+
function qualifierText(q) {
|
|
222
|
+
var _a;
|
|
223
|
+
if (typeof q === "string") return capitalizeWords(q);
|
|
224
|
+
if (q.special !== void 0) return q.special;
|
|
225
|
+
const inner = ((_a = q.types) != null ? _a : []).map(qualifierText).join(", ");
|
|
226
|
+
let text = inner;
|
|
227
|
+
if (q.pre_note) text = `${q.pre_note} ${text}`;
|
|
228
|
+
if (q.note) text = `${text} ${q.note}`;
|
|
229
|
+
return text;
|
|
230
|
+
}
|
|
231
|
+
function formatQualifiers(list) {
|
|
232
|
+
return (list != null ? list : []).map(qualifierText);
|
|
233
|
+
}
|
|
234
|
+
function qualifierStrings(list) {
|
|
235
|
+
return (list != null ? list : []).filter((q) => typeof q === "string");
|
|
236
|
+
}
|
|
237
|
+
var INITIATIVE_MODES = { advantage: "advantage", adv: "advantage", disadvantage: "disadvantage", dis: "disadvantage" };
|
|
238
|
+
function formatInitiative(initiative, abilities, pb) {
|
|
239
|
+
var _a;
|
|
240
|
+
if (initiative === void 0 || initiative === null) return void 0;
|
|
241
|
+
const dex = abilities ? abilityModifier(abilities.dex) : 0;
|
|
242
|
+
const bonus = typeof initiative === "number" ? initiative : dex + ((_a = initiative.proficiency) != null ? _a : 0) * pb;
|
|
243
|
+
const sign = bonus >= 0 ? `+${bonus}` : `${bonus}`;
|
|
244
|
+
let text = `${sign} (${10 + bonus})`;
|
|
245
|
+
const mode = typeof initiative === "number" ? void 0 : initiative.advantage_mode;
|
|
246
|
+
if (mode && INITIATIVE_MODES[mode]) text += ` (${INITIATIVE_MODES[mode]})`;
|
|
247
|
+
return text;
|
|
248
|
+
}
|
|
249
|
+
function itemName(uid) {
|
|
250
|
+
return capitalizeWords(uid.split("|")[0]);
|
|
251
|
+
}
|
|
252
|
+
function formatGear(gear) {
|
|
253
|
+
return (gear != null ? gear : []).map((g) => {
|
|
254
|
+
var _a;
|
|
255
|
+
if (typeof g === "string") return itemName(g);
|
|
256
|
+
const name = (_a = g.displayName) != null ? _a : itemName(g.item);
|
|
257
|
+
return g.quantity !== void 0 && g.quantity > 1 ? `${name} \xD7 ${g.quantity}` : name;
|
|
258
|
+
}).join(", ");
|
|
259
|
+
}
|
|
260
|
+
function formatLanguages(list) {
|
|
261
|
+
return (list != null ? list : []).map((entry) => entry.replace(/([\d,]*\d[\d,]*\s+)?\b(\w)/g, (m, amount, ch) => amount ? m : ch.toUpperCase())).join(", ");
|
|
262
|
+
}
|
|
263
|
+
var SKILL_DISPLAY = new Map(ALL_SKILLS.map((s) => [s.toLowerCase(), s]));
|
|
264
|
+
function skillDisplayName(key) {
|
|
265
|
+
var _a;
|
|
266
|
+
return (_a = SKILL_DISPLAY.get(key.replace(/[_-]+/g, " ").trim().toLowerCase())) != null ? _a : capitalizeWords(key);
|
|
267
|
+
}
|
|
268
|
+
function formatSkillsOther(list) {
|
|
269
|
+
if (!list || list.length === 0) return void 0;
|
|
270
|
+
const parts = [];
|
|
271
|
+
for (const entry of list) {
|
|
272
|
+
const oneOf = entry == null ? void 0 : entry.one_of;
|
|
273
|
+
if (!oneOf) continue;
|
|
274
|
+
parts.push(Object.entries(oneOf).map(([k, v]) => `${skillDisplayName(k)} ${String(v)}`).join(", "));
|
|
275
|
+
}
|
|
276
|
+
return parts.length > 0 ? `plus one of: ${parts.join("; ")}` : void 0;
|
|
277
|
+
}
|
|
278
|
+
function shortNameOfNamed(name) {
|
|
279
|
+
return name.includes(",") ? name.split(",")[0].trim() : name;
|
|
280
|
+
}
|
|
281
|
+
function legendaryIntro(m, count) {
|
|
282
|
+
const subject = m.is_named_creature ? typeof m.short_name === "string" ? m.short_name : m.short_name === void 0 ? shortNameOfNamed(m.name) : m.name : `the ${m.name.toLowerCase()}`;
|
|
283
|
+
const Subject = m.is_named_creature ? subject : `The ${m.name.toLowerCase()}`;
|
|
284
|
+
const lair = m.legendary_actions_lair_count !== void 0 ? ` (${m.legendary_actions_lair_count} in its lair)` : "";
|
|
285
|
+
return `${Subject} can take ${count} legendary actions${lair}, choosing from the options below. Only one legendary action option can be used at a time and only at the end of another creature's turn. ${Subject} regains spent legendary actions at the start of its turn.`;
|
|
286
|
+
}
|
|
287
|
+
function sectionHeader(m, section) {
|
|
288
|
+
var _a;
|
|
289
|
+
const entry = ((_a = m.section_headers) != null ? _a : []).find((h) => h.section === section);
|
|
290
|
+
if (entry) return entry.header;
|
|
291
|
+
if (section === "mythic" && m.mythic_header && m.mythic_header.length > 0) return m.mythic_header;
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
var DISPLAY_AS_SECTION = {
|
|
295
|
+
action: "actions",
|
|
296
|
+
bonus: "bonus_actions",
|
|
297
|
+
reaction: "reactions",
|
|
298
|
+
legendary: "legendary_actions"
|
|
299
|
+
};
|
|
300
|
+
function displayAsSection(displayAs) {
|
|
301
|
+
return displayAs !== void 0 && DISPLAY_AS_SECTION[displayAs] || "traits";
|
|
302
|
+
}
|
|
303
|
+
var GROUP_ORDER = ["will", "daily", "rest", "restLong", "recharge", "legendary", "charges", "ritual"];
|
|
304
|
+
var SPELLCASTING_LABELS = {
|
|
305
|
+
will: { plain: "At Will:" },
|
|
306
|
+
daily: { plain: "N/Day:", each: "N/Day Each:" },
|
|
307
|
+
rest: { plain: "N/Rest:", each: "N/Rest Each:" },
|
|
308
|
+
restLong: { plain: "N/Long Rest:", each: "N/Long Rest Each:" },
|
|
309
|
+
recharge: { plain: "Recharge N-6:", six: "Recharge 6:" },
|
|
310
|
+
legendary: { plain: "N/Legendary Action:", each: "N/Legendary Action Each:" },
|
|
311
|
+
charges: { plain: "N Charges", each: "N Charges Each" },
|
|
312
|
+
ritual: { plain: "Rituals:" }
|
|
313
|
+
};
|
|
314
|
+
function spellText(e) {
|
|
315
|
+
if (typeof e === "string") return e;
|
|
316
|
+
if (!e || typeof e !== "object") return void 0;
|
|
317
|
+
return e.hidden ? void 0 : e.entry;
|
|
318
|
+
}
|
|
319
|
+
function spellsOf(list) {
|
|
320
|
+
return (Array.isArray(list) ? list : []).map(spellText).filter((s) => s !== void 0).join(", ");
|
|
321
|
+
}
|
|
322
|
+
function sortedKeys(record) {
|
|
323
|
+
return Object.keys(record).sort((a, b) => {
|
|
324
|
+
const na = parseInt(a, 10), nb = parseInt(b, 10);
|
|
325
|
+
if (na !== nb) return nb - na;
|
|
326
|
+
return (a.endsWith("e") ? 1 : 0) - (b.endsWith("e") ? 1 : 0);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function ordinal(n) {
|
|
330
|
+
var _a, _b;
|
|
331
|
+
const s = ["th", "st", "nd", "rd"], v = n % 100;
|
|
332
|
+
return `${n}${(_b = (_a = s[(v - 20) % 10]) != null ? _a : s[v]) != null ? _b : s[0]}`;
|
|
333
|
+
}
|
|
334
|
+
function spellcastingLines(block) {
|
|
335
|
+
var _a, _b, _c, _d;
|
|
336
|
+
const hidden = new Set(Array.isArray(block.hidden) ? block.hidden : []);
|
|
337
|
+
const lines = Array.isArray(block.headerEntries) ? [...block.headerEntries] : [];
|
|
338
|
+
for (const group of GROUP_ORDER) {
|
|
339
|
+
if (hidden.has(group)) continue;
|
|
340
|
+
const label = SPELLCASTING_LABELS[group];
|
|
341
|
+
if (group === "will" || group === "ritual") {
|
|
342
|
+
const s = spellsOf(group === "will" ? block.will : block.ritual);
|
|
343
|
+
if (s) lines.push(`${label.plain} ${s}`);
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (group === "recharge") {
|
|
347
|
+
for (const k of sortedKeys((_a = block.recharge) != null ? _a : {})) {
|
|
348
|
+
const s = spellsOf(block.recharge[k]);
|
|
349
|
+
if (!s) continue;
|
|
350
|
+
lines.push(`${(k === "6" ? (_b = label.six) != null ? _b : label.plain : label.plain).replace("N", k)} ${s}`);
|
|
351
|
+
}
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const record = (_c = block[group]) != null ? _c : {};
|
|
355
|
+
for (const k of sortedKeys(record)) {
|
|
356
|
+
const s = spellsOf(record[k]);
|
|
357
|
+
if (!s) continue;
|
|
358
|
+
const text = (k.endsWith("e") ? (_d = label.each) != null ? _d : label.plain : label.plain).replace("N", String(parseInt(k, 10)));
|
|
359
|
+
lines.push(group === "charges" ? `${text}${block.chargesItem ? ` (${block.chargesItem})` : ""}: ${s}` : `${text} ${s}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (!hidden.has("spells") && block.spells) {
|
|
363
|
+
const levelKeys = Object.keys(block.spells).filter((k) => String(Number(k)) === k).sort((a, b) => Number(a) - Number(b));
|
|
364
|
+
for (const key of levelKeys) {
|
|
365
|
+
const level = block.spells[key];
|
|
366
|
+
if (!level || !Array.isArray(level.spells)) continue;
|
|
367
|
+
const lvl = Number(key);
|
|
368
|
+
const s = level.spells.join(", ");
|
|
369
|
+
if (!s) continue;
|
|
370
|
+
if (lvl === 0) {
|
|
371
|
+
lines.push(`Cantrips (At Will): ${s}`);
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const plural2 = level.slots === 1 ? "Slot" : "Slots";
|
|
375
|
+
const slots = level.slots !== void 0 ? level.lower !== void 0 ? `${level.slots} ${ordinal(level.lower)}-Level ${plural2}` : `${level.slots} ${plural2}` : void 0;
|
|
376
|
+
lines.push(`${ordinal(lvl)} Level${slots ? ` (${slots})` : ""}: ${s}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (Array.isArray(block.footerEntries)) lines.push(...block.footerEntries);
|
|
380
|
+
return lines;
|
|
381
|
+
}
|
|
382
|
+
function inline(v) {
|
|
383
|
+
if (typeof v === "string") return v;
|
|
384
|
+
if (Array.isArray(v)) return v.map(inline).filter(Boolean).join(" ");
|
|
385
|
+
if (v && typeof v === "object") {
|
|
386
|
+
const n = v;
|
|
387
|
+
const parts = [];
|
|
388
|
+
if (typeof n.name === "string") parts.push(`**${n.name}.**`);
|
|
389
|
+
if (n.entry !== void 0) parts.push(inline(n.entry));
|
|
390
|
+
if (n.entries !== void 0) parts.push(inline(n.entries));
|
|
391
|
+
if (n.items !== void 0) parts.push(inline(n.items));
|
|
392
|
+
return parts.join(" ");
|
|
393
|
+
}
|
|
394
|
+
return v === void 0 || v === null ? "" : String(v);
|
|
395
|
+
}
|
|
396
|
+
function blocksOf(v) {
|
|
397
|
+
if (typeof v === "string") return [v];
|
|
398
|
+
if (Array.isArray(v)) return v.flatMap(blocksOf);
|
|
399
|
+
if (!v || typeof v !== "object") return [];
|
|
400
|
+
const n = v;
|
|
401
|
+
const type = typeof n.type === "string" ? n.type : "entries";
|
|
402
|
+
switch (type) {
|
|
403
|
+
case "entries":
|
|
404
|
+
case "section": {
|
|
405
|
+
const body = blocksOf(n.entries);
|
|
406
|
+
if (typeof n.name === "string" && body.length > 0) body[0] = `**${n.name}.** ${body[0]}`;
|
|
407
|
+
else if (typeof n.name === "string") body.push(`**${n.name}.**`);
|
|
408
|
+
return body;
|
|
409
|
+
}
|
|
410
|
+
case "list": {
|
|
411
|
+
const items = Array.isArray(n.items) ? n.items : [];
|
|
412
|
+
return [items.map((it) => `- ${inline(it)}`).join("\n")];
|
|
413
|
+
}
|
|
414
|
+
case "item":
|
|
415
|
+
return [inline(n)];
|
|
416
|
+
case "table": {
|
|
417
|
+
const out = [];
|
|
418
|
+
if (typeof n.caption === "string") out.push(`**${n.caption}**`);
|
|
419
|
+
const cell = (v2) => inline(v2).replace(/\\?\|/g, "\\|");
|
|
420
|
+
const styles = Array.isArray(n.colStyles) ? n.colStyles.map((x) => String(x)) : [];
|
|
421
|
+
const alignment = (i) => {
|
|
422
|
+
var _a;
|
|
423
|
+
const s = (_a = styles[i]) != null ? _a : "";
|
|
424
|
+
if (/\btext-center\b/.test(s)) return ":---:";
|
|
425
|
+
if (/\btext-right\b/.test(s)) return "---:";
|
|
426
|
+
return "---";
|
|
427
|
+
};
|
|
428
|
+
const cols = Array.isArray(n.colLabels) ? n.colLabels.map(cell) : [];
|
|
429
|
+
const rows = Array.isArray(n.rows) ? n.rows : [];
|
|
430
|
+
const table = [`| ${cols.join(" | ")} |`, `| ${cols.map((_, i) => alignment(i)).join(" | ")} |`];
|
|
431
|
+
for (const r of rows) table.push(`| ${(Array.isArray(r) ? r : [r]).map(cell).join(" | ")} |`);
|
|
432
|
+
out.push(table.join("\n"));
|
|
433
|
+
return out;
|
|
434
|
+
}
|
|
435
|
+
case "inset":
|
|
436
|
+
case "variant":
|
|
437
|
+
case "variantInner":
|
|
438
|
+
case "variantSub": {
|
|
439
|
+
const body = blocksOf(n.entries).map((b) => b.split("\n").map((l) => `> ${l}`).join("\n"));
|
|
440
|
+
const head = typeof n.name === "string" ? [`> **${n.name}**`] : [];
|
|
441
|
+
return [[...head, ...body].join("\n>\n")];
|
|
442
|
+
}
|
|
443
|
+
case "spellcasting":
|
|
444
|
+
return [spellcastingLines(n).join("\n")];
|
|
445
|
+
default:
|
|
446
|
+
return [...blocksOf(n.entries), ...blocksOf(n.items), ...blocksOf(n.entry)];
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function entriesToMarkdown(tree) {
|
|
450
|
+
return blocksOf(tree).filter((b) => b.length > 0).join("\n\n");
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export {
|
|
454
|
+
capitalizeWords,
|
|
455
|
+
capitalizeOutsideLinks,
|
|
456
|
+
SIZE_CODES,
|
|
457
|
+
formatSize,
|
|
458
|
+
sizeWord,
|
|
459
|
+
ALIGNMENT_CODES,
|
|
460
|
+
ALIGNMENT_SETS,
|
|
461
|
+
formatAlignment,
|
|
462
|
+
alignmentWords,
|
|
463
|
+
IRREGULAR_PLURALS,
|
|
464
|
+
formatType,
|
|
465
|
+
formatCR,
|
|
466
|
+
formatXP,
|
|
467
|
+
crString,
|
|
468
|
+
challengeLine,
|
|
469
|
+
formatAC,
|
|
470
|
+
formatHP,
|
|
471
|
+
SPEED_MODES,
|
|
472
|
+
formatSpeed,
|
|
473
|
+
speedNumber,
|
|
474
|
+
formatQualifiers,
|
|
475
|
+
qualifierStrings,
|
|
476
|
+
INITIATIVE_MODES,
|
|
477
|
+
formatInitiative,
|
|
478
|
+
formatGear,
|
|
479
|
+
formatLanguages,
|
|
480
|
+
skillDisplayName,
|
|
481
|
+
formatSkillsOther,
|
|
482
|
+
legendaryIntro,
|
|
483
|
+
sectionHeader,
|
|
484
|
+
DISPLAY_AS_SECTION,
|
|
485
|
+
displayAsSection,
|
|
486
|
+
SPELLCASTING_LABELS,
|
|
487
|
+
spellcastingLines,
|
|
488
|
+
entriesToMarkdown
|
|
489
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {
|
|
2
|
+
durationSchema
|
|
3
|
+
} from "./chunk-WYGD2UGN.js";
|
|
4
|
+
import {
|
|
5
|
+
actionCostEnum,
|
|
6
|
+
resourceConsumptionSchema,
|
|
7
|
+
resourceSchema
|
|
8
|
+
} from "./chunk-YLL2QXY2.js";
|
|
9
|
+
import {
|
|
10
|
+
choiceSchema
|
|
11
|
+
} from "./chunk-T26ZVCL5.js";
|
|
12
|
+
import {
|
|
13
|
+
featureEffectSchema
|
|
14
|
+
} from "./chunk-WPWOHGPI.js";
|
|
15
|
+
|
|
16
|
+
// src/schemas/feature-schema.ts
|
|
17
|
+
import { z as z2 } from "zod";
|
|
18
|
+
|
|
19
|
+
// src/schemas/attack-schema.ts
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
var abilityEnum = z.enum(["str", "dex", "con", "int", "wis", "cha"]);
|
|
22
|
+
var attackSchema = z.object({
|
|
23
|
+
name: z.string().min(1),
|
|
24
|
+
type: z.enum(["melee", "ranged", "spell"]),
|
|
25
|
+
ability: z.union([abilityEnum, z.array(abilityEnum).nonempty()]).optional(),
|
|
26
|
+
damage: z.string().optional(),
|
|
27
|
+
damage_type: z.string().optional(),
|
|
28
|
+
action: z.enum(["action", "bonus-action", "reaction"]).optional(),
|
|
29
|
+
properties: z.array(z.string()).optional(),
|
|
30
|
+
range: z.object({
|
|
31
|
+
normal: z.number().int().nonnegative().optional(),
|
|
32
|
+
long: z.number().int().nonnegative().optional(),
|
|
33
|
+
reach: z.number().int().nonnegative().optional()
|
|
34
|
+
}).optional(),
|
|
35
|
+
condition: z.string().optional(),
|
|
36
|
+
// R4-G6 §5: declared on the `Attack` interface since the monster port, stripped by this schema until now.
|
|
37
|
+
// Monsters are the only carriers (8,176 bonuses, 1,796 extra-damage riders in the converter corpus).
|
|
38
|
+
bonus: z.number().optional(),
|
|
39
|
+
extra_damage: z.object({ dice: z.string(), type: z.string() }).optional()
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// src/schemas/feature-schema.ts
|
|
43
|
+
var companionSchema = z2.object({
|
|
44
|
+
statblock: z2.string().optional(),
|
|
45
|
+
statblock_wikilink: z2.string().nullable().optional(),
|
|
46
|
+
count: z2.string().optional(),
|
|
47
|
+
count_scaling: z2.array(z2.object({
|
|
48
|
+
level: z2.number().optional(),
|
|
49
|
+
count: z2.string().optional(),
|
|
50
|
+
source_quote: z2.string().optional()
|
|
51
|
+
})).optional(),
|
|
52
|
+
shares_action_economy: z2.boolean().optional(),
|
|
53
|
+
turn_order: z2.string().optional(),
|
|
54
|
+
turn_order_source_quote: z2.string().nullable().optional(),
|
|
55
|
+
proficiency_bonus_scaled: z2.array(z2.object({
|
|
56
|
+
stat: z2.string().optional(),
|
|
57
|
+
formula: z2.string().optional(),
|
|
58
|
+
source_quote: z2.string().optional()
|
|
59
|
+
})).optional(),
|
|
60
|
+
lifecycle: z2.object({
|
|
61
|
+
created_by: z2.string().optional(),
|
|
62
|
+
recreate_on: z2.string().nullable().optional(),
|
|
63
|
+
previous_instance_perishes: z2.boolean().nullable().optional(),
|
|
64
|
+
vanishes_if_owner_dies: z2.boolean().nullable().optional(),
|
|
65
|
+
vanishes_after: z2.string().nullable().optional(),
|
|
66
|
+
source_quote: z2.string().optional()
|
|
67
|
+
}).nullable().optional(),
|
|
68
|
+
autonomy: z2.object({
|
|
69
|
+
when: z2.string().optional(),
|
|
70
|
+
behaviour: z2.string().optional(),
|
|
71
|
+
source_quote: z2.string().optional()
|
|
72
|
+
}).nullable().optional(),
|
|
73
|
+
variants: z2.array(z2.object({
|
|
74
|
+
axis: z2.string().optional(),
|
|
75
|
+
choices: z2.array(z2.string()).optional(),
|
|
76
|
+
chosen_at: z2.string().optional(),
|
|
77
|
+
source_quote: z2.string().optional()
|
|
78
|
+
})).optional(),
|
|
79
|
+
base_statblock: z2.string().nullable().optional(),
|
|
80
|
+
overrides: z2.array(z2.object({
|
|
81
|
+
field: z2.string().optional(),
|
|
82
|
+
value: z2.string().optional(),
|
|
83
|
+
source_quote: z2.string().optional()
|
|
84
|
+
})).optional(),
|
|
85
|
+
source_quote: z2.string().optional()
|
|
86
|
+
});
|
|
87
|
+
var featureObjectSchema = z2.lazy(
|
|
88
|
+
() => z2.object({
|
|
89
|
+
id: z2.string().min(1).optional(),
|
|
90
|
+
name: z2.string().min(1),
|
|
91
|
+
description: z2.string().optional(),
|
|
92
|
+
entries: z2.array(z2.string()).optional(),
|
|
93
|
+
choices: z2.array(choiceSchema).optional(),
|
|
94
|
+
grants_resource: z2.string().optional(),
|
|
95
|
+
consumes: resourceConsumptionSchema.optional(),
|
|
96
|
+
attacks: z2.array(attackSchema).optional(),
|
|
97
|
+
action: z2.enum(["action", "bonus-action", "reaction", "free", "special"]).optional(),
|
|
98
|
+
trigger: z2.string().optional(),
|
|
99
|
+
dc_formula: z2.string().optional(),
|
|
100
|
+
effects: z2.array(featureEffectSchema).optional(),
|
|
101
|
+
sub_features: z2.array(featureSchemaTyped).optional(),
|
|
102
|
+
resources: z2.array(resourceSchema).optional(),
|
|
103
|
+
// Phase 3 activatable buffs: a feature flagged `activatable` folds its effects
|
|
104
|
+
// only while its id is present in state.active_buffs. `passive` renders a tag;
|
|
105
|
+
// `duration` is a static label (no live countdown this phase).
|
|
106
|
+
activatable: z2.boolean().optional(),
|
|
107
|
+
passive: z2.boolean().optional(),
|
|
108
|
+
duration: durationSchema.optional(),
|
|
109
|
+
// Converter feature-level keys (164 census strip rows, class 80 + subclass 84; counts per finding 2):
|
|
110
|
+
class_source: z2.string().min(1).optional(),
|
|
111
|
+
// class 646 + subclass 1616 leaves
|
|
112
|
+
rendering_hint: z2.string().optional(),
|
|
113
|
+
// always "" — NEVER .min(1)
|
|
114
|
+
subclass_short_name: z2.string().min(1).optional(),
|
|
115
|
+
// 1616
|
|
116
|
+
subclass_source: z2.string().min(1).optional(),
|
|
117
|
+
// 1616
|
|
118
|
+
header: z2.number().optional(),
|
|
119
|
+
// 1,237 carriers, ALL numbers
|
|
120
|
+
is_class_feature_variant: z2.boolean().optional(),
|
|
121
|
+
gain_subclass_feature: z2.boolean().optional(),
|
|
122
|
+
gain_subclass_feature_has_content: z2.boolean().optional(),
|
|
123
|
+
type: z2.string().min(1).optional(),
|
|
124
|
+
// values {"inset","item"}
|
|
125
|
+
recharge: z2.object({
|
|
126
|
+
// ONE class doc (UA Mystic), FOUR features, ALL
|
|
127
|
+
type: z2.enum(["recharge_on_roll", "per_day", "per_short_rest", "per_long_rest"]),
|
|
128
|
+
// {type:"per_day",param:1..4}
|
|
129
|
+
param: z2.number()
|
|
130
|
+
// tree-wide nested-recharge type census: exactly these
|
|
131
|
+
}).optional(),
|
|
132
|
+
// four members (gate1-r1 f9) = the EXISTING FeatureRecharge type
|
|
133
|
+
// SRD-BUNDLE-side keys (the converter emits NEITHER at feature level; finding 14 — our own
|
|
134
|
+
// generator emits them and featureSchema strips them, losing the SRD Dragonborn Breath Weapon's
|
|
135
|
+
// action cost and save DC). MAPPED since R4-G3a §10: `action_cost` is aliased onto `action` by
|
|
136
|
+
// the race / class / subclass parsers, and `save` renders as the feature card's Save line
|
|
137
|
+
// (`dc_formula` is echoed as TEXT, never evaluated).
|
|
138
|
+
action_cost: actionCostEnum.optional(),
|
|
139
|
+
// ONE vocabulary, imported from schemas/resource-schema
|
|
140
|
+
// (no cycle: resource-schema imports neither; two spellings of a closed enum is the G1a
|
|
141
|
+
// "fifth enum consumer" drift — gate1-r2 NEW-12)
|
|
142
|
+
save: z2.object({ ability: z2.string().min(1), dc_formula: z2.string().min(1) }).optional(),
|
|
143
|
+
// R4-G5 §7 (ruling G5-UR2): DECLARED so the class / subclass / race parsers stop stripping it on the day the
|
|
144
|
+
// G7 re-emit lands. The converter withholds it today (`P9_NOT_EMITTED_FIELDS`), so 0 converted and 0 bundle
|
|
145
|
+
// documents carry it and the census cannot see this key in either state (§12.1); the 47-block cache
|
|
146
|
+
// round-trip in `tests/feature-schema-widening.test.ts` is its instrument.
|
|
147
|
+
companion: companionSchema.optional()
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
var featureSchemaTyped = featureObjectSchema.refine(
|
|
151
|
+
(f) => f.description !== void 0 || f.entries !== void 0 && f.entries.length > 0,
|
|
152
|
+
{ message: "feature requires either description or non-empty entries" }
|
|
153
|
+
);
|
|
154
|
+
var featureSchema = featureSchemaTyped;
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
featureObjectSchema,
|
|
158
|
+
featureSchema
|
|
159
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/schemas/feature-alias.ts
|
|
2
|
+
function aliasFeatureActionCost(f) {
|
|
3
|
+
if (f.action === void 0 && typeof f.action_cost === "string") f.action = f.action_cost;
|
|
4
|
+
}
|
|
5
|
+
function aliasFeatureListActionCost(list) {
|
|
6
|
+
if (Array.isArray(list)) {
|
|
7
|
+
for (const f of list) if (f && typeof f === "object") aliasFeatureActionCost(f);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function aliasFeaturesByLevelActionCost(byLevel) {
|
|
11
|
+
if (byLevel && typeof byLevel === "object")
|
|
12
|
+
for (const list of Object.values(byLevel)) aliasFeatureListActionCost(list);
|
|
13
|
+
}
|
|
14
|
+
function withResolvedActionCost(f) {
|
|
15
|
+
return f.action === void 0 && typeof f.action_cost === "string" ? { ...f, action: f.action_cost } : f;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
aliasFeatureListActionCost,
|
|
20
|
+
aliasFeaturesByLevelActionCost,
|
|
21
|
+
withResolvedActionCost
|
|
22
|
+
};
|