@archivist-gg/dnd5e 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background/background.codec.js +4 -4
- package/dist/background/background.parser.js +3 -3
- package/dist/background/background.schema.js +2 -2
- package/dist/{chunk-FFULAF2P.js → chunk-2BWAID3Y.js} +2 -2
- package/dist/chunk-353WXS6S.js +25 -0
- package/dist/{chunk-FUK7QSN5.js → chunk-42Y5IJKT.js} +1 -1
- package/dist/{chunk-TPZSPU4L.js → chunk-4JHOHWBI.js} +1 -1
- package/dist/{chunk-DC74TZNA.js → chunk-4LZJXJJS.js} +7 -2
- package/dist/chunk-5MZSB6OM.js +1089 -0
- package/dist/{chunk-FEOB24KP.js → chunk-73HOFQQ5.js} +1 -1
- package/dist/{chunk-YDPWD2T7.js → chunk-7VJ6BOA5.js} +4 -1
- package/dist/{chunk-ZLG6FQFB.js → chunk-A4WENOUQ.js} +21 -2
- package/dist/{chunk-GEJSJP6E.js → chunk-AIRFC5NQ.js} +3 -1
- package/dist/{chunk-DABBCYTT.js → chunk-CZPMTQOY.js} +1 -1
- package/dist/{chunk-DRNZJNJP.js → chunk-DZXSWSBP.js} +1 -1
- package/dist/{chunk-ADLTSHOR.js → chunk-EMOORSQ7.js} +59 -30
- package/dist/{chunk-RVYYKYFL.js → chunk-GE4TLPWM.js} +1 -1
- package/dist/{chunk-VLKIB33F.js → chunk-K6Q5OUGK.js} +6 -0
- package/dist/{chunk-PMADYMUI.js → chunk-L7E2UT5A.js} +1 -1
- package/dist/{chunk-3TRGRSCH.js → chunk-LV4SNWZQ.js} +7 -1
- package/dist/{chunk-IXZXFFFW.js → chunk-M2EMFD6S.js} +1 -1
- package/dist/{chunk-UC4FE5X3.js → chunk-N6N74K6X.js} +1 -1
- package/dist/{chunk-CDW7R2QT.js → chunk-NXSWH3AE.js} +4 -1
- package/dist/{chunk-IDTDACM6.js → chunk-PHQRGDRQ.js} +1 -1
- package/dist/{chunk-BAXWWGFJ.js → chunk-Q5K6LWBZ.js} +1 -1
- package/dist/{chunk-Z6GXV2GO.js → chunk-TLYDBT5F.js} +1 -1
- package/dist/{chunk-A7T5L7SS.js → chunk-TUIFSVLI.js} +1 -1
- package/dist/{chunk-J2RYSZMQ.js → chunk-VTTA2ALZ.js} +2 -2
- package/dist/{chunk-Z4TL2V7S.js → chunk-VTYUBINW.js} +1 -1
- package/dist/{chunk-B7UXKNLD.js → chunk-W7HWMMBF.js} +1 -1
- package/dist/{chunk-SSXBYF3P.js → chunk-XLSVNUTK.js} +1 -1
- package/dist/{chunk-GIOH5JB5.js → chunk-XTIQWSFM.js} +1 -1
- package/dist/{chunk-PKC77VZP.js → chunk-ZZGEVJKX.js} +1 -1
- package/dist/class/class.codec.js +5 -5
- package/dist/class/class.parser.js +4 -4
- package/dist/class/class.schema.js +3 -3
- package/dist/class/class.slug.d.ts +7 -5
- package/dist/class/class.slug.js +1 -1
- package/dist/entities/base-item-resolver.d.ts +9 -0
- package/dist/entities/base-item-resolver.js +6 -4
- package/dist/entities/slug.d.ts +7 -0
- package/dist/entities/slug.js +3 -1
- package/dist/feat/feat.codec.js +4 -4
- package/dist/feat/feat.parser.js +3 -3
- package/dist/feat/feat.schema.js +2 -2
- package/dist/index.js +4116 -3662
- package/dist/item/item.actions-map.d.ts +18 -10
- package/dist/item/item.actions-map.js +16 -12
- package/dist/item/item.codec.js +3 -3
- package/dist/item/item.parser.js +2 -2
- package/dist/item/item.schema.d.ts +3 -0
- package/dist/item/item.schema.js +1 -1
- package/dist/item/item.types.d.ts +8 -0
- package/dist/pc/pc.decision-engine.d.ts +0 -3
- package/dist/pc/pc.decision-engine.js +8 -3
- package/dist/pc/pc.equipment.js +5 -8
- package/dist/pc/pc.feature-effects.d.ts +5 -0
- package/dist/pc/pc.feature-effects.js +2 -4
- package/dist/pc/pc.parser.js +1 -1
- package/dist/pc/pc.pools.js +8 -3
- package/dist/pc/pc.recalc.d.ts +7 -0
- package/dist/pc/pc.recalc.js +94 -40
- package/dist/pc/pc.resolver.d.ts +59 -1
- package/dist/pc/pc.resolver.js +21 -343
- package/dist/pc/pc.rest.d.ts +1 -1
- package/dist/pc/pc.rest.js +20 -11
- package/dist/pc/pc.schema.d.ts +23 -0
- package/dist/pc/pc.schema.js +1 -1
- package/dist/pc/pc.slotting.js +3 -3
- package/dist/pc/pc.spellcasting.js +2 -2
- package/dist/pc/pc.types.d.ts +65 -5
- package/dist/race/race.codec.js +5 -5
- package/dist/race/race.parser.js +4 -4
- package/dist/race/race.schema.js +3 -3
- package/dist/schemas/choice-schema.js +1 -1
- package/dist/schemas/feature-schema.js +2 -2
- package/dist/spell/spell.access.js +1 -1
- package/dist/subclass/subclass.codec.js +5 -5
- package/dist/subclass/subclass.parser.js +4 -4
- package/dist/subclass/subclass.schema.js +3 -3
- package/dist/types/choice.d.ts +5 -0
- package/dist/weapon/weapon-mastery.d.ts +3 -0
- package/dist/weapon/weapon.classify.d.ts +21 -0
- package/dist/weapon/weapon.classify.js +7 -0
- package/package.json +1 -1
- package/dist/chunk-6PXE7T7C.js +0 -79
- package/dist/chunk-TJCNX6UZ.js +0 -521
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
itemEntitySchema
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-K6Q5OUGK.js";
|
|
4
4
|
|
|
5
5
|
// src/item/item.parser.ts
|
|
6
6
|
import { parseYaml } from "@archivist-gg/core";
|
|
@@ -38,6 +38,9 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
|
38
38
|
"effects",
|
|
39
39
|
"damage_riders",
|
|
40
40
|
"raw",
|
|
41
|
+
"scroll_level",
|
|
42
|
+
"unidentified",
|
|
43
|
+
"masked_category",
|
|
41
44
|
// Legacy fields kept (removed in Slice 7 after grep verifies no consumer)
|
|
42
45
|
"damage_dice",
|
|
43
46
|
"damage_type",
|
|
@@ -35,7 +35,19 @@ var equipmentEntryOverridesSchema = z.object({
|
|
|
35
35
|
extra_damage: z.string().optional(),
|
|
36
36
|
ac_bonus: z.number().int().optional(),
|
|
37
37
|
action: z.enum(["action", "bonus-action", "reaction", "free", "special"]).optional(),
|
|
38
|
-
range: z.string().optional()
|
|
38
|
+
range: z.string().optional(),
|
|
39
|
+
// Per-instance defense arrays. The EquipmentEntryOverrides type declares
|
|
40
|
+
// these and pc.equipment reads them into defenses, but the strict schema
|
|
41
|
+
// used to omit them, so a file carrying one failed the WHOLE parse. Admitted
|
|
42
|
+
// here so a per-instance resist/immune/vulnerable/condition_immune loads.
|
|
43
|
+
resist: z.array(z.string()).optional(),
|
|
44
|
+
immune: z.array(z.string()).optional(),
|
|
45
|
+
vulnerable: z.array(z.string()).optional(),
|
|
46
|
+
condition_immune: z.array(z.string()).optional(),
|
|
47
|
+
// Scroll authoring: a per-instance spell payload (e.g. a Spell Scroll's spell)
|
|
48
|
+
// plus the ability that governs its save DC / attack when cast from the scroll.
|
|
49
|
+
spell: z.string().optional(),
|
|
50
|
+
spell_ability: abilityEnum.optional()
|
|
39
51
|
}).strict();
|
|
40
52
|
var equipmentEntryStateSchema = z.object({
|
|
41
53
|
charges: z.object({
|
|
@@ -82,7 +94,11 @@ var characterOverridesSchema = z.object({
|
|
|
82
94
|
investigation: z.number().int().optional(),
|
|
83
95
|
insight: z.number().int().optional()
|
|
84
96
|
}).partial().optional(),
|
|
85
|
-
hp: z.object({
|
|
97
|
+
hp: z.object({
|
|
98
|
+
max: z.number().int().positive().optional(),
|
|
99
|
+
rolled: z.number().int().positive().optional(),
|
|
100
|
+
modifier: z.number().int().optional()
|
|
101
|
+
}).optional(),
|
|
86
102
|
ac: z.number().int().optional(),
|
|
87
103
|
speed: z.number().int().optional(),
|
|
88
104
|
initiative: z.number().int().optional(),
|
|
@@ -90,6 +106,9 @@ var characterOverridesSchema = z.object({
|
|
|
90
106
|
saveDC: z.number().int().optional(),
|
|
91
107
|
attackBonus: z.number().int().optional()
|
|
92
108
|
}).optional(),
|
|
109
|
+
// Character-level DC-ability fallback for own-ability-less spells (e.g. a Spell
|
|
110
|
+
// Scroll cast by a non-caster). Same ability enum as the per-instance spell_ability.
|
|
111
|
+
spellcasting_ability: abilityEnum.optional(),
|
|
93
112
|
spell_slots: z.record(z.coerce.number().int(), z.number().int().nonnegative()).optional(),
|
|
94
113
|
attunement_limit: z.number().int().nonnegative().optional()
|
|
95
114
|
}).default({});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
bareEntitySlug
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LV4SNWZQ.js";
|
|
4
4
|
import {
|
|
5
5
|
ABILITY_KEYS
|
|
6
6
|
} from "./chunk-WP2CX2JO.js";
|
|
@@ -10,6 +10,7 @@ function emptyFeatureEffectTotals() {
|
|
|
10
10
|
return {
|
|
11
11
|
initiative_bonus: 0,
|
|
12
12
|
hp_per_level_bonus: 0,
|
|
13
|
+
hp_per_level_terms: [],
|
|
13
14
|
speed_walk_bonus: 0,
|
|
14
15
|
speed_walk_set: 0,
|
|
15
16
|
senses: { darkvision: 0, blindsight: 0, tremorsense: 0, truesight: 0 },
|
|
@@ -66,6 +67,7 @@ function applyEffect(out, eff, label) {
|
|
|
66
67
|
break;
|
|
67
68
|
case "hp-per-level-bonus":
|
|
68
69
|
out.hp_per_level_bonus += eff.value;
|
|
70
|
+
out.hp_per_level_terms.push({ label, value: eff.value });
|
|
69
71
|
break;
|
|
70
72
|
case "speed-bonus":
|
|
71
73
|
if (eff.mode === "walk") {
|
|
@@ -1,31 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyWeaponRange
|
|
3
|
+
} from "./chunk-353WXS6S.js";
|
|
1
4
|
import {
|
|
2
5
|
defaultSlotForType,
|
|
3
6
|
effectiveArmor,
|
|
4
7
|
isItemEntity,
|
|
5
8
|
isWeaponEntity,
|
|
6
9
|
resolveEntityForEntry
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
bareEntitySlug
|
|
10
|
-
} from "./chunk-TJCNX6UZ.js";
|
|
10
|
+
} from "./chunk-N6N74K6X.js";
|
|
11
11
|
import {
|
|
12
12
|
readNumericBonus
|
|
13
13
|
} from "./chunk-LWFTHJIE.js";
|
|
14
14
|
import {
|
|
15
15
|
resolveBaseItem
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-4LZJXJJS.js";
|
|
17
|
+
import {
|
|
18
|
+
bareEntitySlug
|
|
19
|
+
} from "./chunk-LV4SNWZQ.js";
|
|
17
20
|
|
|
18
21
|
// src/weapon/weapon-mastery.ts
|
|
19
22
|
var MASTERY = {
|
|
20
|
-
cleave: { label: "Cleave", description: "If you hit a creature with a melee attack roll using this weapon, you can make an attack roll with the weapon against a second creature within 5 feet of the first that is also within your reach. On a hit, the second creature takes the weapon's damage, but don't add your ability modifier to that damage unless it is negative. You can make this extra attack only once per turn." },
|
|
21
|
-
graze: { label: "Graze", description: "If your attack roll with this weapon misses a creature, you can deal damage to that creature equal to the ability modifier you used to make the attack roll. This damage is the same type dealt by the weapon, and the damage can be increased only by increasing the ability modifier." },
|
|
22
|
-
nick: { label: "Nick", description: "When you make the extra attack of the Light property, you can make it as part of the Attack action instead of as a Bonus Action. You can make this extra attack only once per turn." },
|
|
23
|
-
push: { label: "Push", description: "If you hit a creature with this weapon, you can push the creature up to 10 feet straight away from yourself if it is Large or smaller." },
|
|
24
|
-
sap: { label: "Sap", description: "If you hit a creature with this weapon, that creature has Disadvantage on its next attack roll before the start of your next turn." },
|
|
25
|
-
slow: { label: "Slow", description: "If you hit a creature with this weapon and deal damage, you can reduce its Speed by 10 feet until the start of your next turn. If the creature is hit more than once by weapons that have this property, the Speed reduction doesn't exceed 10 feet." },
|
|
26
|
-
topple: { label: "Topple", description: "If you hit a creature with this weapon, you can force the creature to make a Constitution saving throw (DC 8 plus the ability modifier used to make the attack roll and your Proficiency Bonus). On a failed save, the creature has the Prone condition." },
|
|
27
|
-
vex: { label: "Vex", description: "If you hit a creature with this weapon and deal damage, you have Advantage on your next attack roll against that creature before the end of your next turn." }
|
|
23
|
+
cleave: { label: "Cleave", description: "If you hit a creature with a melee attack roll using this weapon, you can make an attack roll with the weapon against a second creature within 5 feet of the first that is also within your reach. On a hit, the second creature takes the weapon's damage, but don't add your ability modifier to that damage unless it is negative. You can make this extra attack only once per turn.", gist: "hit a 2nd creature in reach" },
|
|
24
|
+
graze: { label: "Graze", description: "If your attack roll with this weapon misses a creature, you can deal damage to that creature equal to the ability modifier you used to make the attack roll. This damage is the same type dealt by the weapon, and the damage can be increased only by increasing the ability modifier.", gist: "on miss: ability-mod damage" },
|
|
25
|
+
nick: { label: "Nick", description: "When you make the extra attack of the Light property, you can make it as part of the Attack action instead of as a Bonus Action. You can make this extra attack only once per turn.", gist: "extra Light attack (no Bonus Action)" },
|
|
26
|
+
push: { label: "Push", description: "If you hit a creature with this weapon, you can push the creature up to 10 feet straight away from yourself if it is Large or smaller.", gist: "on hit: pushed 10 ft" },
|
|
27
|
+
sap: { label: "Sap", description: "If you hit a creature with this weapon, that creature has Disadvantage on its next attack roll before the start of your next turn.", gist: "on hit: target Disadvantage" },
|
|
28
|
+
slow: { label: "Slow", description: "If you hit a creature with this weapon and deal damage, you can reduce its Speed by 10 feet until the start of your next turn. If the creature is hit more than once by weapons that have this property, the Speed reduction doesn't exceed 10 feet.", gist: "on hit: -10 ft Speed" },
|
|
29
|
+
topple: { label: "Topple", description: "If you hit a creature with this weapon, you can force the creature to make a Constitution saving throw (DC 8 plus the ability modifier used to make the attack roll and your Proficiency Bonus). On a failed save, the creature has the Prone condition.", gist: "on fail: Prone" },
|
|
30
|
+
vex: { label: "Vex", description: "If you hit a creature with this weapon and deal damage, you have Advantage on your next attack roll against that creature before the end of your next turn.", gist: "on hit: you gain Advantage next" }
|
|
28
31
|
};
|
|
32
|
+
function masteryGist(slug) {
|
|
33
|
+
var _a;
|
|
34
|
+
return (_a = MASTERY[slug]) == null ? void 0 : _a.gist;
|
|
35
|
+
}
|
|
29
36
|
function masteryDerived(slug, abilityMod, proficiencyBonus) {
|
|
30
37
|
if (slug === "topple") return { label: "Save DC", value: 8 + proficiencyBonus + abilityMod };
|
|
31
38
|
if (slug === "graze") return { label: "On miss", value: abilityMod };
|
|
@@ -241,7 +248,14 @@ function assignSlots(resolved, registry, warnings) {
|
|
|
241
248
|
const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
|
|
242
249
|
if (!entity || !entityType) continue;
|
|
243
250
|
const defaultSlot = defaultSlotForType(entityType, entity, registry);
|
|
244
|
-
if (!defaultSlot)
|
|
251
|
+
if (!defaultSlot) {
|
|
252
|
+
if (isItemEntity(entity) && typeof entity.base_item === "string" && entity.base_item.length > 0) {
|
|
253
|
+
warnings.push(
|
|
254
|
+
`Magic item "${entity.name}" base_item ${entity.base_item} did not resolve to a base weapon or armor; not slotted (AC/attack not applied).`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
245
259
|
const placed = { index: i, entity, entityType, entry };
|
|
246
260
|
if (defaultSlot === "mainhand") {
|
|
247
261
|
if (!slots.mainhand) slots.mainhand = placed;
|
|
@@ -261,12 +275,17 @@ function assignSlots(resolved, registry, warnings) {
|
|
|
261
275
|
}
|
|
262
276
|
return slots;
|
|
263
277
|
}
|
|
264
|
-
function computeAC(equippedSlots, resolved, mods, registry) {
|
|
278
|
+
function computeAC(equippedSlots, resolved, mods, registry, warnings) {
|
|
265
279
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
266
280
|
const breakdown = [];
|
|
267
281
|
const armorSlot = equippedSlots.armor;
|
|
268
282
|
const armorEntity = (_a = armorSlot == null ? void 0 : armorSlot.entity) != null ? _a : null;
|
|
269
283
|
const armor = effectiveArmor(armorEntity, registry);
|
|
284
|
+
if (isItemEntity(armorEntity) && typeof armorEntity.base_item === "string" && !armor) {
|
|
285
|
+
warnings.push(
|
|
286
|
+
`Magic armor "${armorEntity.name}" base_item ${armorEntity.base_item} did not resolve to a base armor; AC not applied.`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
270
289
|
let ac = 10;
|
|
271
290
|
if (armor) {
|
|
272
291
|
const armorBase = armor.ac.base + ((_b = armor.ac.flat) != null ? _b : 0);
|
|
@@ -325,8 +344,9 @@ function hasProperty(weapon, prop) {
|
|
|
325
344
|
return weapon.properties.some((p) => p === prop);
|
|
326
345
|
}
|
|
327
346
|
function attackAbility(weapon, mods, weaponAbilities) {
|
|
328
|
-
const
|
|
329
|
-
|
|
347
|
+
const modes = classifyWeaponRange(weapon);
|
|
348
|
+
const finesse = hasProperty(weapon, "finesse");
|
|
349
|
+
if (modes.melee) {
|
|
330
350
|
const scoped = weaponAbilities.find((o2) => {
|
|
331
351
|
var _a;
|
|
332
352
|
return (_a = o2.weaponSlugs) == null ? void 0 : _a.includes(bareEntitySlug(weapon.slug));
|
|
@@ -334,10 +354,10 @@ function attackAbility(weapon, mods, weaponAbilities) {
|
|
|
334
354
|
const glob = weaponAbilities.find((o2) => !o2.weaponSlugs);
|
|
335
355
|
const o = scoped != null ? scoped : glob;
|
|
336
356
|
if (o) return o.ability;
|
|
357
|
+
if (finesse) return mods.dex >= mods.str ? "dex" : "str";
|
|
358
|
+
return "str";
|
|
337
359
|
}
|
|
338
|
-
|
|
339
|
-
if (hasProperty(weapon, "finesse")) return mods.dex >= mods.str ? "dex" : "str";
|
|
340
|
-
return "str";
|
|
360
|
+
return finesse && mods.str > mods.dex ? "str" : "dex";
|
|
341
361
|
}
|
|
342
362
|
function isWeaponSlugProficient(weapon, weaponSlug, profs) {
|
|
343
363
|
const wp = profs.weapons;
|
|
@@ -416,8 +436,10 @@ function buildAttackRow(args) {
|
|
|
416
436
|
{ source: `${ability.toUpperCase()} modifier`, amount: abilityMod, kind: "ability" },
|
|
417
437
|
{ source: magicSource, amount: magic.dmg, kind: "item" }
|
|
418
438
|
];
|
|
419
|
-
const
|
|
420
|
-
const
|
|
439
|
+
const modes = classifyWeaponRange(weapon);
|
|
440
|
+
const fmtRanged = (r) => `${r.normal}/${r.long} ft`;
|
|
441
|
+
const range = modes.melee ? `${modes.melee.reach} ft` : modes.ranged ? fmtRanged(modes.ranged) : void 0;
|
|
442
|
+
const thrownRange = modes.melee && modes.ranged ? fmtRanged(modes.ranged) : void 0;
|
|
421
443
|
const stringProps = weapon.properties.filter(
|
|
422
444
|
(p) => typeof p === "string"
|
|
423
445
|
);
|
|
@@ -425,7 +447,8 @@ function buildAttackRow(args) {
|
|
|
425
447
|
const row = {
|
|
426
448
|
id,
|
|
427
449
|
name,
|
|
428
|
-
range,
|
|
450
|
+
...range !== void 0 ? { range } : {},
|
|
451
|
+
...thrownRange !== void 0 ? { thrownRange } : {},
|
|
429
452
|
toHit,
|
|
430
453
|
damageDice,
|
|
431
454
|
damageType: (_b = magic.damageTypeOverride) != null ? _b : weapon.damage.type,
|
|
@@ -442,7 +465,7 @@ function buildAttackRow(args) {
|
|
|
442
465
|
breakdown: { toHit: toHitBreakdown, damage: damageBreakdown },
|
|
443
466
|
informational: args.magic.informational.length > 0 ? args.magic.informational : void 0,
|
|
444
467
|
slotKey: args.slotKey,
|
|
445
|
-
subLabel: formatWeaponSubLabel(weapon, finalProps),
|
|
468
|
+
subLabel: formatWeaponSubLabel(weapon, finalProps, modes),
|
|
446
469
|
actionCost: args.actionCost,
|
|
447
470
|
versatile: args.versatileDice ? { damageDice: formatDice(args.versatileDice) } : void 0
|
|
448
471
|
};
|
|
@@ -451,15 +474,21 @@ function buildAttackRow(args) {
|
|
|
451
474
|
const g = MASTERY[mSlug];
|
|
452
475
|
if (g) {
|
|
453
476
|
const derived = masteryDerived(mSlug, mods[ability], proficiencyBonus);
|
|
454
|
-
row.mastery = { slug: mSlug, label: g.label, description: g.description, ...derived ? { derived } : {} };
|
|
477
|
+
row.mastery = { slug: mSlug, label: g.label, description: g.description, gist: masteryGist(mSlug), ...derived ? { derived } : {} };
|
|
455
478
|
}
|
|
456
479
|
}
|
|
457
480
|
return row;
|
|
458
481
|
}
|
|
459
|
-
function
|
|
482
|
+
function humanizeWeaponToken(s) {
|
|
483
|
+
return s.replace(/[-_]/g, " ").replace(/(^|[\s(])\w/g, (c) => c.toUpperCase());
|
|
484
|
+
}
|
|
485
|
+
function formatWeaponSubLabel(weapon, properties, modes) {
|
|
460
486
|
const parts = [];
|
|
461
|
-
if (weapon.category)
|
|
462
|
-
|
|
487
|
+
if (weapon.category) {
|
|
488
|
+
const cat = modes.melee && /ranged/.test(weapon.category) ? weapon.category.replace("ranged", "melee") : weapon.category;
|
|
489
|
+
parts.push(humanizeWeaponToken(cat));
|
|
490
|
+
}
|
|
491
|
+
if (properties.length > 0) parts.push(properties.map(humanizeWeaponToken).join(", "));
|
|
463
492
|
return parts.join(" \xB7 ");
|
|
464
493
|
}
|
|
465
494
|
function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities = []) {
|
|
@@ -482,7 +511,7 @@ function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficie
|
|
|
482
511
|
if (found && found.entityType === "weapon" && isWeaponEntity(found.data)) {
|
|
483
512
|
weapon = found.data;
|
|
484
513
|
} else {
|
|
485
|
-
warnings.push(`Magic weapon ${entity.name} references missing base_item
|
|
514
|
+
warnings.push(`Magic weapon ${entity.name} references missing base_item ${baseSlug}.`);
|
|
486
515
|
continue;
|
|
487
516
|
}
|
|
488
517
|
} else {
|
|
@@ -543,7 +572,7 @@ function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, profi
|
|
|
543
572
|
var _a, _b, _c;
|
|
544
573
|
const equippedSlots = assignSlots(resolved, registry, warnings);
|
|
545
574
|
const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
|
|
546
|
-
const acOut = computeAC(equippedSlots, resolved, mods, registry);
|
|
575
|
+
const acOut = computeAC(equippedSlots, resolved, mods, registry, warnings);
|
|
547
576
|
const ctx = buildConditionContext(resolved, equippedSlots);
|
|
548
577
|
const attacks = computeAttacks(equippedSlots, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities);
|
|
549
578
|
return {
|
|
@@ -176,6 +176,12 @@ var itemEntitySchema = z.object({
|
|
|
176
176
|
applies_to: z.enum(["weapon", "spell", "all"]).optional(),
|
|
177
177
|
condition: z.string().optional()
|
|
178
178
|
})).optional(),
|
|
179
|
+
// Scroll & unidentified-item markers (Phase 4). Declared here so they survive
|
|
180
|
+
// parse (the schema strips undeclared keys) and are ALSO listed in the
|
|
181
|
+
// parser's KNOWN_KEYS so they are not additionally copied into `raw`.
|
|
182
|
+
scroll_level: z.number().optional(),
|
|
183
|
+
unidentified: z.boolean().optional(),
|
|
184
|
+
masked_category: z.string().optional(),
|
|
179
185
|
raw: z.record(z.string(), z.unknown()).optional(),
|
|
180
186
|
// Legacy fields preserved
|
|
181
187
|
damage_dice: z.string().optional(),
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
function slugify(name) {
|
|
3
3
|
return name.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/[\s]+/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
4
4
|
}
|
|
5
|
+
function bareEntitySlug(slug) {
|
|
6
|
+
if (!slug) return "";
|
|
7
|
+
const p = slug.split("_");
|
|
8
|
+
return p.length >= 3 ? p.slice(2).join("_") : p[p.length - 1];
|
|
9
|
+
}
|
|
5
10
|
|
|
6
11
|
export {
|
|
7
|
-
slugify
|
|
12
|
+
slugify,
|
|
13
|
+
bareEntitySlug
|
|
8
14
|
};
|
|
@@ -11,7 +11,10 @@ var entityFilterSchema = z.object({
|
|
|
11
11
|
parent_class: z.literal("self").optional(),
|
|
12
12
|
available_to: z.literal("self").optional(),
|
|
13
13
|
weapon_category: z.enum(["simple", "martial"]).optional(),
|
|
14
|
-
armor_category: z.enum(["light", "medium", "heavy", "shield"]).optional()
|
|
14
|
+
armor_category: z.enum(["light", "medium", "heavy", "shield"]).optional(),
|
|
15
|
+
list: z.string().min(1).optional(),
|
|
16
|
+
level: z.number().int().min(0).max(9).optional(),
|
|
17
|
+
edition: z.string().min(1).optional()
|
|
15
18
|
}).strict();
|
|
16
19
|
var inlineOptionSchema = z.lazy(() => z.object({
|
|
17
20
|
value: z.string().min(1),
|
|
@@ -6,8 +6,8 @@ function bareSlug(ref) {
|
|
|
6
6
|
}
|
|
7
7
|
function baseClassName(ref) {
|
|
8
8
|
const bare = bareSlug(ref);
|
|
9
|
-
const
|
|
10
|
-
return
|
|
9
|
+
const p = bare.split("_");
|
|
10
|
+
return p.length >= 3 ? p.slice(2).join("_") : p[p.length - 1];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
classCodec
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-GE4TLPWM.js";
|
|
4
|
+
import "../chunk-42Y5IJKT.js";
|
|
5
|
+
import "../chunk-TLYDBT5F.js";
|
|
6
6
|
import "../chunk-4TIJKN6O.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-CZPMTQOY.js";
|
|
8
8
|
import "../chunk-WYGD2UGN.js";
|
|
9
9
|
import "../chunk-PZOWBI3B.js";
|
|
10
10
|
import "../chunk-3DZ74AKK.js";
|
|
11
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-NXSWH3AE.js";
|
|
12
12
|
import "../chunk-NXR3BD2V.js";
|
|
13
13
|
export {
|
|
14
14
|
classCodec
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseClass
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-42Y5IJKT.js";
|
|
4
|
+
import "../chunk-TLYDBT5F.js";
|
|
5
5
|
import "../chunk-4TIJKN6O.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-CZPMTQOY.js";
|
|
7
7
|
import "../chunk-WYGD2UGN.js";
|
|
8
8
|
import "../chunk-PZOWBI3B.js";
|
|
9
9
|
import "../chunk-3DZ74AKK.js";
|
|
10
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-NXSWH3AE.js";
|
|
11
11
|
import "../chunk-NXR3BD2V.js";
|
|
12
12
|
export {
|
|
13
13
|
parseClass
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
classEntitySchema
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-TLYDBT5F.js";
|
|
4
4
|
import "../chunk-4TIJKN6O.js";
|
|
5
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-CZPMTQOY.js";
|
|
6
6
|
import "../chunk-WYGD2UGN.js";
|
|
7
7
|
import "../chunk-PZOWBI3B.js";
|
|
8
8
|
import "../chunk-3DZ74AKK.js";
|
|
9
|
-
import "../chunk-
|
|
9
|
+
import "../chunk-NXSWH3AE.js";
|
|
10
10
|
import "../chunk-NXR3BD2V.js";
|
|
11
11
|
export {
|
|
12
12
|
classEntitySchema
|
|
@@ -2,10 +2,12 @@ export declare function bareSlug(ref: string): string;
|
|
|
2
2
|
/**
|
|
3
3
|
* Bare class name for profile / spell-`classes` lookups.
|
|
4
4
|
*
|
|
5
|
-
* Compendium-qualified slugs are `<compendium>_<name>`
|
|
6
|
-
* `srd-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Compendium-qualified slugs are `<compendium>_<type>_<name>` (3-part, e.g.
|
|
6
|
+
* `srd-2024_class_wizard`) or the legacy `<compendium>_<name>` (2-part, e.g.
|
|
7
|
+
* `srd-5e_wizard`); compendium/type segments are hyphen-cased, so `_` only ever
|
|
8
|
+
* separates the structural parts from the entity name. Strip that prefix to get
|
|
9
|
+
* the canonical class key (`wizard`). Name-slugs never contain `_`, so a 3-part
|
|
10
|
+
* slug's name is `parts.slice(2).join("_")`. Hand-written/test slugs without a
|
|
11
|
+
* `_` pass through unchanged (`wizard` → `wizard`).
|
|
10
12
|
*/
|
|
11
13
|
export declare function baseClassName(ref: string): string;
|
package/dist/class/class.slug.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { EntityRegistry, RegisteredEntity } from "@archivist-gg/core";
|
|
2
|
+
/**
|
|
3
|
+
* Convert a vault-path target (e.g. `SRD 5e/Weapons/Longsword`) to a
|
|
4
|
+
* registry-compatible slug (`srd-5e_weapon_longsword`). The middle Type folder
|
|
5
|
+
* (`segments[length-2]`) supplies the entity-type token so the slug matches
|
|
6
|
+
* the now type-namespaced registry key. For a bare basename without any `/`,
|
|
7
|
+
* returns the slugified basename - which lets legacy wikilinks like
|
|
8
|
+
* `[[longsword]]` continue to resolve when registered under that bare slug.
|
|
9
|
+
*/
|
|
10
|
+
export declare function vaultPathToSlug(target: string): string;
|
|
2
11
|
/**
|
|
3
12
|
* Public: take a `base_item` string (vault-path wikilink, alias-form
|
|
4
13
|
* wikilink, bare-slug wikilink, or bare slug) and return the matching
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveBaseItem,
|
|
3
|
-
resolveBaseItemOfType
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
resolveBaseItemOfType,
|
|
4
|
+
vaultPathToSlug
|
|
5
|
+
} from "../chunk-4LZJXJJS.js";
|
|
6
|
+
import "../chunk-LV4SNWZQ.js";
|
|
6
7
|
export {
|
|
7
8
|
resolveBaseItem,
|
|
8
|
-
resolveBaseItemOfType
|
|
9
|
+
resolveBaseItemOfType,
|
|
10
|
+
vaultPathToSlug
|
|
9
11
|
};
|
package/dist/entities/slug.d.ts
CHANGED
|
@@ -3,3 +3,10 @@
|
|
|
3
3
|
* "Ancient Red Dragon" -> "ancient-red-dragon"
|
|
4
4
|
*/
|
|
5
5
|
export declare function slugify(name: string): string;
|
|
6
|
+
/** "srd-2024_fighter" → "fighter", "srd-2024_background_acolyte" → "acolyte".
|
|
7
|
+
* Arity-robust: strips a `<prefix>_<type>_<name>` (3-part) or legacy `<prefix>_<name>`
|
|
8
|
+
* (2-part) slug down to the bare NAME, and passes a bare slug through unchanged.
|
|
9
|
+
* Name-slugs never contain `_`, so for a 3-part-or-longer slug the name is
|
|
10
|
+
* `parts.slice(2).join("_")`. Tolerates a nullish slug (degrades to "") so a
|
|
11
|
+
* malformed entity can't hard-crash the builder; the resolver backfills real slugs. */
|
|
12
|
+
export declare function bareEntitySlug(slug: string | null | undefined): string;
|
package/dist/entities/slug.js
CHANGED
package/dist/feat/feat.codec.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
featCodec
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-73HOFQQ5.js";
|
|
4
|
+
import "../chunk-XTIQWSFM.js";
|
|
5
|
+
import "../chunk-Q5K6LWBZ.js";
|
|
6
|
+
import "../chunk-NXSWH3AE.js";
|
|
7
7
|
import "../chunk-NXR3BD2V.js";
|
|
8
8
|
export {
|
|
9
9
|
featCodec
|