@archivist-gg/dnd5e 0.3.11 → 0.3.13

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.
Files changed (164) hide show
  1. package/LICENSES/SRD.md +38 -3
  2. package/dist/armor/armor.codec.js +3 -3
  3. package/dist/armor/armor.parser.js +2 -2
  4. package/dist/armor/armor.schema.d.ts +1 -0
  5. package/dist/armor/armor.schema.js +1 -1
  6. package/dist/armor/armor.types.d.ts +2 -0
  7. package/dist/background/background.codec.js +5 -5
  8. package/dist/background/background.parser.js +4 -4
  9. package/dist/background/background.schema.js +3 -3
  10. package/dist/chunk-2LULMQTF.js +14 -0
  11. package/dist/{chunk-CBEKVAX4.js → chunk-4BZ47YJ4.js} +10 -3
  12. package/dist/{chunk-T2SNEJOE.js → chunk-4SLOJXJ4.js} +1 -1
  13. package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
  14. package/dist/{chunk-J77CKYV3.js → chunk-5KGV6TF7.js} +1 -1
  15. package/dist/{chunk-CHUALUIX.js → chunk-6ZY3U6BQ.js} +1 -1
  16. package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
  17. package/dist/{chunk-2M34FLAY.js → chunk-BRGLDWUP.js} +3 -1
  18. package/dist/chunk-CM5CWO4K.js +735 -0
  19. package/dist/{chunk-3HX5VLWP.js → chunk-DPM6V7YX.js} +1 -1
  20. package/dist/chunk-EJP263OP.js +186 -0
  21. package/dist/{chunk-G247QXWW.js → chunk-EL6QPF6I.js} +1 -1
  22. package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
  23. package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
  24. package/dist/{chunk-PI4LLJG4.js → chunk-FPGXFD2M.js} +2 -2
  25. package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
  26. package/dist/{chunk-NWDF5HG3.js → chunk-G7ED5H2G.js} +1 -1
  27. package/dist/chunk-H5PTKYXL.js +101 -0
  28. package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
  29. package/dist/{chunk-PP2UHLBA.js → chunk-HJQNK3J5.js} +8 -0
  30. package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
  31. package/dist/chunk-IHE6KVC3.js +13 -0
  32. package/dist/{chunk-BLRW2UU6.js → chunk-J53ERF6K.js} +2 -2
  33. package/dist/{chunk-MQ747UCR.js → chunk-JNNNBEUH.js} +65 -2
  34. package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
  35. package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
  36. package/dist/chunk-LBEXLN6I.js +91 -0
  37. package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
  38. package/dist/{chunk-U3BABVJF.js → chunk-LVX6TQ3R.js} +2 -2
  39. package/dist/{chunk-R747YKS7.js → chunk-M2OWVAZG.js} +1 -1
  40. package/dist/{chunk-7YU4NPKR.js → chunk-MC5YJ4PB.js} +1 -1
  41. package/dist/{chunk-JCEV7KYN.js → chunk-MUIU7RZ3.js} +1 -1
  42. package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
  43. package/dist/{chunk-S56D6B6C.js → chunk-PLOSP4XQ.js} +3 -3
  44. package/dist/{chunk-JANNRGJC.js → chunk-PX25R3DK.js} +1 -1
  45. package/dist/{chunk-V373TRJE.js → chunk-Q5XTEYHD.js} +191 -125
  46. package/dist/{chunk-MAH6DCRI.js → chunk-Q6UOHCCT.js} +1 -1
  47. package/dist/{chunk-2INMRR3Q.js → chunk-QEO7LYTG.js} +215 -94
  48. package/dist/{chunk-PJMG5XV3.js → chunk-QSBJ6NEM.js} +1 -1
  49. package/dist/{chunk-BL3VELKP.js → chunk-R2V5LN3I.js} +1 -1
  50. package/dist/{chunk-4DOMDEBZ.js → chunk-RQNJXADQ.js} +1 -1
  51. package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
  52. package/dist/chunk-T5GZBKIQ.js +927 -0
  53. package/dist/{chunk-PZCE7DJM.js → chunk-UE6LKRXQ.js} +15 -1
  54. package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
  55. package/dist/{chunk-QHMWA3SZ.js → chunk-VDPRBUU5.js} +1 -1
  56. package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
  57. package/dist/{chunk-V6LJFP4R.js → chunk-X7VZY4ON.js} +2 -2
  58. package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
  59. package/dist/{chunk-BIA32MQ5.js → chunk-XJRNEQPD.js} +1 -1
  60. package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
  61. package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
  62. package/dist/{chunk-XTRDCSJB.js → chunk-ZMJQUZQH.js} +4 -1
  63. package/dist/chunk-ZUQW5VBZ.js +89 -0
  64. package/dist/class/class.codec.js +7 -7
  65. package/dist/class/class.parser.js +6 -6
  66. package/dist/class/class.schema.d.ts +10 -0
  67. package/dist/class/class.schema.js +5 -5
  68. package/dist/entities/base-item-resolver.js +2 -2
  69. package/dist/entities/slug.d.ts +18 -8
  70. package/dist/entities/slug.js +3 -1
  71. package/dist/feat/feat.codec.js +5 -5
  72. package/dist/feat/feat.parser.js +4 -4
  73. package/dist/feat/feat.schema.d.ts +16 -3
  74. package/dist/feat/feat.schema.js +3 -3
  75. package/dist/index.js +7190 -4116
  76. package/dist/item/item.actions-map.d.ts +40 -5
  77. package/dist/item/item.actions-map.js +5 -84
  78. package/dist/item/item.attunement.js +3 -9
  79. package/dist/item/item.bonuses.js +5 -2
  80. package/dist/item/item.codec.js +3 -3
  81. package/dist/item/item.conditions.js +4 -1
  82. package/dist/item/item.conditions.types.d.ts +4 -0
  83. package/dist/item/item.cost.d.ts +3 -0
  84. package/dist/item/item.cost.js +29 -0
  85. package/dist/item/item.icon.d.ts +15 -0
  86. package/dist/item/item.icon.js +211 -0
  87. package/dist/item/item.parser.js +2 -2
  88. package/dist/item/item.schema.d.ts +16 -1
  89. package/dist/item/item.schema.js +3 -1
  90. package/dist/item/item.types.d.ts +9 -2
  91. package/dist/monster/monster.parser.js +5 -5
  92. package/dist/monster/monster.schema.js +4 -4
  93. package/dist/optional-feature/optional-feature.codec.js +4 -4
  94. package/dist/optional-feature/optional-feature.parser.js +3 -3
  95. package/dist/optional-feature/optional-feature.schema.d.ts +229 -3
  96. package/dist/optional-feature/optional-feature.schema.js +6 -2
  97. package/dist/pc/pc.additional-spells.js +2 -2
  98. package/dist/pc/pc.asi-flatten.d.ts +62 -1
  99. package/dist/pc/pc.asi-flatten.js +16 -0
  100. package/dist/pc/pc.conditions.js +1 -1
  101. package/dist/pc/pc.containment.d.ts +45 -0
  102. package/dist/pc/pc.containment.js +24 -0
  103. package/dist/pc/pc.decision-engine.d.ts +21 -3
  104. package/dist/pc/pc.decision-engine.js +21 -12
  105. package/dist/pc/pc.entry-overrides.d.ts +79 -0
  106. package/dist/pc/pc.entry-overrides.js +40 -0
  107. package/dist/pc/pc.equipment.d.ts +2 -2
  108. package/dist/pc/pc.equipment.js +18 -7
  109. package/dist/pc/pc.feature-effects.js +2 -2
  110. package/dist/pc/pc.infusions.d.ts +220 -0
  111. package/dist/pc/pc.infusions.js +64 -0
  112. package/dist/pc/pc.parser.js +18 -1
  113. package/dist/pc/pc.pools.d.ts +1 -1
  114. package/dist/pc/pc.pools.js +11 -3
  115. package/dist/pc/pc.proficiencies.js +19 -12
  116. package/dist/pc/pc.recalc.d.ts +39 -36
  117. package/dist/pc/pc.recalc.js +58 -30
  118. package/dist/pc/pc.resolver.js +19 -12
  119. package/dist/pc/pc.resource-seed.js +1 -1
  120. package/dist/pc/pc.resources.d.ts +6 -1
  121. package/dist/pc/pc.resources.js +3 -1
  122. package/dist/pc/pc.rest.d.ts +21 -1
  123. package/dist/pc/pc.rest.js +52 -19
  124. package/dist/pc/pc.schema.d.ts +14 -0
  125. package/dist/pc/pc.schema.js +1 -1
  126. package/dist/pc/pc.slotting.d.ts +36 -3
  127. package/dist/pc/pc.slotting.js +13 -5
  128. package/dist/pc/pc.tool-picks.d.ts +51 -0
  129. package/dist/pc/pc.tool-picks.js +18 -0
  130. package/dist/pc/pc.types.d.ts +70 -12
  131. package/dist/pc/pool-layout.d.ts +14 -0
  132. package/dist/pc/pool-layout.js +7 -3
  133. package/dist/race/race.codec.js +6 -6
  134. package/dist/race/race.parser.js +5 -5
  135. package/dist/race/race.schema.js +4 -4
  136. package/dist/schemas/attack-schema.d.ts +1 -1
  137. package/dist/schemas/choice-schema.js +2 -2
  138. package/dist/schemas/feature-effect-schema.d.ts +16 -3
  139. package/dist/schemas/feature-effect-schema.js +1 -1
  140. package/dist/schemas/feature-schema.js +3 -3
  141. package/dist/schemas/selection-pool-schema.d.ts +10 -0
  142. package/dist/schemas/selection-pool-schema.js +1 -1
  143. package/dist/srd/retired-items.d.ts +14 -0
  144. package/dist/srd/retired-items.js +11 -0
  145. package/dist/subclass/subclass.codec.js +7 -7
  146. package/dist/subclass/subclass.parser.js +6 -6
  147. package/dist/subclass/subclass.schema.d.ts +10 -0
  148. package/dist/subclass/subclass.schema.js +5 -5
  149. package/dist/types/choice.d.ts +8 -0
  150. package/dist/types/equipment-grant.d.ts +18 -1
  151. package/dist/types/equipment-grant.js +12 -0
  152. package/dist/types/feature-effect.d.ts +6 -1
  153. package/dist/types/optional-feature.types.d.ts +79 -1
  154. package/dist/types/selection-pool.d.ts +16 -1
  155. package/dist/weapon/weapon.classify.d.ts +10 -8
  156. package/dist/weapon/weapon.classify.js +2 -2
  157. package/dist/weapon/weapon.codec.js +3 -3
  158. package/dist/weapon/weapon.parser.js +2 -2
  159. package/dist/weapon/weapon.schema.d.ts +1 -0
  160. package/dist/weapon/weapon.schema.js +1 -1
  161. package/dist/weapon/weapon.types.d.ts +2 -0
  162. package/package.json +1 -1
  163. package/dist/chunk-O4SRD3J5.js +0 -165
  164. package/dist/chunk-WXWPK3LI.js +0 -55
@@ -1,4 +1,5 @@
1
1
  import type { EquipmentEntry } from "../pc/pc.types.js";
2
+ import type { EntryView } from "../pc/pc.infusions.js";
2
3
  export type ActionCost = "action" | "bonus-action" | "reaction" | "free" | "special";
3
4
  export interface ItemAction {
4
5
  cost: ActionCost;
@@ -8,7 +9,15 @@ export interface ItemAction {
8
9
  amount: string;
9
10
  reset: "dawn" | "short" | "long" | "special";
10
11
  };
12
+ /** Consumed on use (T17 rider C fold, user ruling 2026-09-24): using one spends the entry's QUANTITY, never a
13
+ * charge, so the item carries no `max_charges` or `recovery` and the sheet shows its quantity only. Read through
14
+ * `isConsumedOnUse` (`pc/pc.entry-overrides.ts`), which also answers by the entity's own type. */
15
+ consumed?: true;
11
16
  }
17
+ /** What `resolveItemAction` hands the Actions items row: its cost and range, nothing else. The curated charges and
18
+ * recovery are NOT on it: the charge pair is `effectiveItemCharges` and the rule `effectiveItemRecovery`
19
+ * (`pc/pc.entry-overrides.ts`), so no reader can take the curated max over a stored pair. */
20
+ export type ResolvedItemAction = Pick<ItemAction, "cost" | "range">;
12
21
  /**
13
22
  * Curated map of canonical SRD chargeable / activated items.
14
23
  * Slugs match the SRD compendium slug format. Augmenter reads this map
@@ -34,16 +43,42 @@ export declare const ITEM_ACTIONS: Record<string, ItemAction>;
34
43
  export declare function findItemAction(slug: string): ItemAction | undefined;
35
44
  /**
36
45
  * Resolve the ItemAction for an equipped entry.
37
- * Priority: per-instance override > curated map > `itemType==="potion"`
38
- * bonus-action default > null.
46
+ * Priority: per-instance override > the entry view's `action` > curated map >
47
+ * the type default (`itemType==="potion"`: bonus-action; `itemType==="scroll"`:
48
+ * its spell's cost, else action) > null.
39
49
  *
40
50
  * `itemType` is the entity's `data.type` (from the registry, statically
41
51
  * `unknown`); per the 2024 SRD, drinking/administering a potion is a Bonus
42
52
  * Action, so an uncurated `type==="potion"` item still surfaces (curated oils
43
53
  * mis-typed `"potion"` are pinned to "action" so this default cannot mislabel
44
- * them). Returns null when no source supplies a cost (non-potion uncurated with
45
- * no override).
54
+ * them). A spell scroll's use is its cast, so an uncurated `type==="scroll"` item
55
+ * costs what its spell's casting time costs: `opts.spellCost`, which the caller
56
+ * that holds the registry resolves (`scrollSpellCost`, pc/pc.entry-overrides.ts),
57
+ * else Action (no spell set or resolved, or a minute or hour cast). It keys on the
58
+ * type, never on a `scroll_level` marker alone, which every Enspelled weapon and
59
+ * armour also carries. Returns null when no source supplies a cost (an uncurated
60
+ * item that is neither a potion nor a scroll, with no override).
46
61
  *
47
62
  * Accepts both bare and compendium-prefixed slugs (see `findItemAction`).
63
+ *
64
+ * `opts.weaponLike`: the entry is a weapon or an item whose `base_item` is a
65
+ * weapon, so its `overrides.action` belongs to its ATTACK row (pc.equipment.ts)
66
+ * and is ignored here, as is its `overrides.range`, which no row reads (the
67
+ * attack row's range is the weapon's own, and `customizableOverrideKeys` offers
68
+ * no Range for it); only a curated activation (e.g. Sun Blade's) still
69
+ * resolves, and an uncurated weapon-like item with only an override resolves
70
+ * null. Omitted, the override wins as before.
71
+ *
72
+ * `opts.view` (ART-a, spec §5.4, Gate 1 I4): the entry's view. Its RULE
73
+ * entity's `action` (an infusion overlay's, e.g. Mind Sharpener's reaction)
74
+ * comes before the curated map, which is keyed by the base's slug and knows
75
+ * nothing of the infusion.
76
+ *
77
+ * `opts.spellCost`: a spell scroll's spell's cost (see above); read only for an
78
+ * item typed `scroll`.
48
79
  */
49
- export declare function resolveItemAction(slug: string, entry: EquipmentEntry, itemType?: unknown): ItemAction | null;
80
+ export declare function resolveItemAction(slug: string, entry: EquipmentEntry, itemType?: unknown, opts?: {
81
+ weaponLike?: boolean;
82
+ view?: EntryView | null;
83
+ spellCost?: ActionCost;
84
+ }): ResolvedItemAction | null;
@@ -1,87 +1,8 @@
1
- // src/item/item.actions-map.ts
2
- var ITEM_ACTIONS = {
3
- // Wands and rods
4
- "wand-of-fireballs": { cost: "action", range: "150 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
5
- "wand-of-magic-missiles": { cost: "action", range: "120 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
6
- "wand-of-lightning-bolts": { cost: "action", range: "100 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
7
- "wand-of-paralysis": { cost: "action", range: "60 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
8
- "wand-of-fear": { cost: "action", range: "self", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
9
- "wand-of-binding": { cost: "action", range: "self", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
10
- "wand-of-secrets": { cost: "action", range: "30 ft.", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
11
- "wand-of-web": { cost: "action", range: "60 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
12
- "wand-of-wonder": { cost: "action", range: "120 ft.", max_charges: 7, recovery: { amount: "1d6+1", reset: "dawn" } },
13
- // Activatable wondrous items
14
- "boots-of-speed": { cost: "bonus-action", range: "self", max_charges: 1, recovery: { amount: "1", reset: "long" } },
15
- "boots-of-levitation": { cost: "action", range: "self" },
16
- "boots-of-striding-and-springing": { cost: "free", range: "self" },
17
- "broom-of-flying": { cost: "action", range: "touch" },
18
- "cloak-of-displacement": { cost: "free", range: "self" },
19
- "cloak-of-the-bat": { cost: "action", range: "self", max_charges: 1, recovery: { amount: "1", reset: "long" } },
20
- "decanter-of-endless-water": { cost: "action", range: "touch" },
21
- "drum-of-panic": { cost: "action", range: "120 ft.", max_charges: 1, recovery: { amount: "1", reset: "long" } },
22
- "eyes-of-charming": { cost: "action", range: "30 ft.", max_charges: 3, recovery: { amount: "3", reset: "dawn" } },
23
- // Rings
24
- "ring-of-three-wishes": { cost: "action", range: "self", max_charges: 3, recovery: { amount: "0", reset: "special" } },
25
- "ring-of-shooting-stars": { cost: "action", range: "60 ft.", max_charges: 6, recovery: { amount: "1d6", reset: "dawn" } },
26
- "ring-of-the-ram": { cost: "action", range: "60 ft.", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
27
- "ring-of-spell-storing": { cost: "action", range: "self", max_charges: 5 },
28
- "ring-of-animal-influence": { cost: "action", range: "self", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
29
- "ring-of-elemental-command": { cost: "action", range: "self", max_charges: 5, recovery: { amount: "1d4+1", reset: "dawn" } },
30
- "ring-of-evasion": { cost: "reaction", range: "self", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
31
- // Necklaces
32
- "necklace-of-fireballs": { cost: "action", range: "60 ft.", max_charges: 9 },
33
- // Gems
34
- "gem-of-brightness": { cost: "action", range: "60 ft.", max_charges: 50 },
35
- "gem-of-seeing": { cost: "action", range: "self", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
36
- // Helms
37
- "helm-of-teleportation": { cost: "action", range: "self", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
38
- // Medallions
39
- "medallion-of-thoughts": { cost: "action", range: "30 ft.", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
40
- // Pipes
41
- "pipes-of-haunting": { cost: "action", range: "30 ft.", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
42
- "pipes-of-the-sewers": { cost: "action", range: "self", max_charges: 3, recovery: { amount: "1d3", reset: "dawn" } },
43
- // Cubes / chimes
44
- "cube-of-force": { cost: "action", range: "self", max_charges: 36, recovery: { amount: "1d20", reset: "dawn" } },
45
- "chime-of-opening": { cost: "action", range: "120 ft.", max_charges: 10 },
46
- // Magic weapons with activation actions (surface in items table only via override; weapons table is primary)
47
- "sun-blade": { cost: "free", range: "self" },
48
- // Potions / consumables
49
- // 2024 healing potions are a Bonus Action to drink/administer (curation still
50
- // carries range/max_charges/recovery; the type=potion default covers uncurated ones).
51
- "potion-of-healing": { cost: "bonus-action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
52
- "potion-of-greater-healing": { cost: "bonus-action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
53
- "potion-of-superior-healing": { cost: "bonus-action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
54
- "potion-of-supreme-healing": { cost: "bonus-action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
55
- "alchemists-fire": { cost: "action", range: "20 ft.", max_charges: 1, recovery: { amount: "0", reset: "special" } },
56
- "holy-water": { cost: "action", range: "20 ft.", max_charges: 1, recovery: { amount: "0", reset: "special" } },
57
- // Oils are APPLIED (minutes), not drunk: curated to "action" so the blanket
58
- // type=potion → bonus-action default never mislabels these mis-typed items.
59
- "oil-of-sharpness": { cost: "action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
60
- "oil-of-etherealness": { cost: "action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
61
- "oil-of-slipperiness": { cost: "action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } },
62
- "dust-of-disappearance": { cost: "action", range: "self", max_charges: 1, recovery: { amount: "0", reset: "special" } }
63
- };
64
- function findItemAction(slug) {
65
- if (slug in ITEM_ACTIONS) return ITEM_ACTIONS[slug];
66
- const p = slug.split("_");
67
- const bare = p.length >= 3 ? p.slice(2).join("_") : p[p.length - 1];
68
- return bare === slug ? void 0 : ITEM_ACTIONS[bare];
69
- }
70
- function resolveItemAction(slug, entry, itemType) {
71
- var _a, _b;
72
- const curated = (_a = findItemAction(slug)) != null ? _a : null;
73
- const override = entry.overrides;
74
- const overrideCost = override == null ? void 0 : override.action;
75
- const overrideRange = override == null ? void 0 : override.range;
76
- const cost = (_b = overrideCost != null ? overrideCost : curated == null ? void 0 : curated.cost) != null ? _b : itemType === "potion" ? "bonus-action" : void 0;
77
- if (!cost) return null;
78
- return {
79
- cost,
80
- range: overrideRange != null ? overrideRange : curated == null ? void 0 : curated.range,
81
- max_charges: curated == null ? void 0 : curated.max_charges,
82
- recovery: curated == null ? void 0 : curated.recovery
83
- };
84
- }
1
+ import {
2
+ ITEM_ACTIONS,
3
+ findItemAction,
4
+ resolveItemAction
5
+ } from "../chunk-ZUQW5VBZ.js";
85
6
  export {
86
7
  ITEM_ACTIONS,
87
8
  findItemAction,
@@ -1,12 +1,6 @@
1
- // src/item/item.attunement.ts
2
- function requiresAttunement(entity) {
3
- if (!entity || !("attunement" in entity)) return false;
4
- const a = entity.attunement;
5
- if (a === true) return true;
6
- if (typeof a === "string") return a.length > 0;
7
- if (typeof a === "object" && a !== null) return a.required === true;
8
- return false;
9
- }
1
+ import {
2
+ requiresAttunement
3
+ } from "../chunk-IHE6KVC3.js";
10
4
  export {
11
5
  requiresAttunement
12
6
  };
@@ -1,7 +1,10 @@
1
1
  import {
2
2
  readNumericBonus
3
- } from "../chunk-LWFTHJIE.js";
4
- import "../chunk-DNAJRMNN.js";
3
+ } from "../chunk-HHBD4SQ6.js";
4
+ import "../chunk-A54HHCWW.js";
5
+ import "../chunk-LHZXYFBU.js";
6
+ import "../chunk-CM5CWO4K.js";
7
+ import "../chunk-ZCTUYGNV.js";
5
8
  export {
6
9
  readNumericBonus
7
10
  };
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  itemCodec
3
- } from "../chunk-4XTNPNQB.js";
4
- import "../chunk-SMLXZUBH.js";
5
- import "../chunk-GFZ7PITJ.js";
3
+ } from "../chunk-VPYBK2MG.js";
4
+ import "../chunk-EYX4JMAU.js";
5
+ import "../chunk-S3YUXDSC.js";
6
6
  import "../chunk-UA5KS2PL.js";
7
7
  export {
8
8
  itemCodec
@@ -1,7 +1,10 @@
1
1
  import {
2
2
  evaluateCondition,
3
3
  evaluateConditions
4
- } from "../chunk-DNAJRMNN.js";
4
+ } from "../chunk-A54HHCWW.js";
5
+ import "../chunk-LHZXYFBU.js";
6
+ import "../chunk-CM5CWO4K.js";
7
+ import "../chunk-ZCTUYGNV.js";
5
8
  export {
6
9
  evaluateCondition,
7
10
  evaluateConditions
@@ -1,5 +1,6 @@
1
1
  import type { EquippedSlots, ClassEntry } from "../pc/pc.types.js";
2
2
  import type { BonusFieldPath, Condition } from "../types/item-conditions.types.js";
3
+ import type { EntityRegistry } from "@archivist-gg/core";
3
4
  export type { Tier1Condition, Tier2Condition, Tier3Condition, Tier4Condition, FreeTextCondition, AnyOfCondition, Condition, ConditionalBonus, BonusFieldPath, } from "../types/item-conditions.types.js";
4
5
  export interface InformationalBonus {
5
6
  field: BonusFieldPath;
@@ -15,6 +16,9 @@ export interface ConditionContext {
15
16
  classList: ClassEntry[];
16
17
  race: string | null;
17
18
  subclasses: string[];
19
+ /** H234 H2: lets `wielding_two_handed` read a MAGIC main-hand weapon through its `base_item`. Optional: every test literal
20
+ * stays valid, and without it only the entity's own properties are read. */
21
+ registry?: EntityRegistry;
18
22
  }
19
23
  export type BonusReadResult = {
20
24
  kind: "applied";
@@ -0,0 +1,3 @@
1
+ export declare function costToCopper(cost: string | number | undefined): number;
2
+ export declare function formatCopper(cp: number): string;
3
+ export declare function formatItemCost(cost: string): string;
@@ -0,0 +1,29 @@
1
+ // src/item/item.cost.ts
2
+ var GP_DECIMAL = /^\d+(\.\d+)?$/;
3
+ function costToCopper(cost) {
4
+ let gp;
5
+ if (typeof cost === "number") gp = cost;
6
+ else if (typeof cost === "string" && GP_DECIMAL.test(cost)) gp = Number.parseFloat(cost);
7
+ else return 0;
8
+ if (!Number.isFinite(gp) || gp < 0) return 0;
9
+ return Math.round(gp * 100);
10
+ }
11
+ var group = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
12
+ function formatCopper(cp) {
13
+ const c = Math.max(0, Math.round(cp));
14
+ if (c === 0) return "0 gp";
15
+ const gp = Math.floor(c / 100);
16
+ const rest = c % 100;
17
+ const restText = rest === 0 ? "" : rest % 10 === 0 ? `${rest / 10} sp` : `${rest} cp`;
18
+ if (gp === 0) return restText;
19
+ return rest === 0 ? `${group(gp)} gp` : `${group(gp)} gp ${restText}`;
20
+ }
21
+ function formatItemCost(cost) {
22
+ const cp = costToCopper(cost);
23
+ return cp > 0 ? formatCopper(cp) : cost;
24
+ }
25
+ export {
26
+ costToCopper,
27
+ formatCopper,
28
+ formatItemCost
29
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The icon key of an item, weapon or armor entity (inventory arc I3). The key is DATA: an entity's own `icon`
3
+ * wins; otherwise these rules read the entity's own fields (the tattoo flag, the weapon's base, the armor's
4
+ * category, the item's type and focus kind, the approved coverage words of its name). A renderer maps a key to
5
+ * its drawing and each GENERIC_ICON key to a neutral glyph of its own. Every game word lives here, never in the
6
+ * renderer (memo rendering-policy-from-schema-not-renderer).
7
+ */
8
+ export declare const GENERIC_ICON: {
9
+ readonly weapon: "generic:weapon";
10
+ readonly armor: "generic:armor";
11
+ readonly item: "generic:item";
12
+ };
13
+ /** Every non-generic key the rules can return; the renderer's icon set must hold each one. */
14
+ export declare const ITEM_ICON_KEYS: readonly string[];
15
+ export declare function itemIconKey(entity: unknown, entityType: string | null): string;
@@ -0,0 +1,211 @@
1
+ // src/item/item.icon.ts
2
+ var GENERIC_ICON = { weapon: "generic:weapon", armor: "generic:armor", item: "generic:item" };
3
+ var WEAPON_KEYS = /* @__PURE__ */ new Set([
4
+ "club",
5
+ "dagger",
6
+ "greatclub",
7
+ "handaxe",
8
+ "javelin",
9
+ "light-hammer",
10
+ "mace",
11
+ "quarterstaff",
12
+ "sickle",
13
+ "spear",
14
+ "light-crossbow",
15
+ "dart",
16
+ "shortbow",
17
+ "sling",
18
+ "battleaxe",
19
+ "flail",
20
+ "glaive",
21
+ "greataxe",
22
+ "greatsword",
23
+ "halberd",
24
+ "lance",
25
+ "longsword",
26
+ "maul",
27
+ "morningstar",
28
+ "pike",
29
+ "rapier",
30
+ "scimitar",
31
+ "shortsword",
32
+ "trident",
33
+ "war-pick",
34
+ "warhammer",
35
+ "whip",
36
+ "blowgun",
37
+ "hand-crossbow",
38
+ "heavy-crossbow",
39
+ "longbow",
40
+ "net"
41
+ ]);
42
+ var WEAPON_ALIAS = {
43
+ "crossbow-hand": "hand-crossbow",
44
+ "crossbow-light": "light-crossbow",
45
+ "crossbow-heavy": "heavy-crossbow"
46
+ };
47
+ var ARMOR_CATEGORY_KEY = {
48
+ light: "light-armor",
49
+ medium: "medium-armor",
50
+ heavy: "heavy-armor",
51
+ shield: "shield"
52
+ };
53
+ var ARMOR_BASE_CATEGORY = {
54
+ padded: "light",
55
+ leather: "light",
56
+ "studded-leather": "light",
57
+ hide: "medium",
58
+ "chain-shirt": "medium",
59
+ "scale-mail": "medium",
60
+ breastplate: "medium",
61
+ "half-plate": "medium",
62
+ "ring-mail": "heavy",
63
+ "chain-mail": "heavy",
64
+ splint: "heavy",
65
+ plate: "heavy",
66
+ shield: "shield"
67
+ };
68
+ var TYPE_DIRECT = {
69
+ ring: "ring",
70
+ potion: "potion",
71
+ scroll: "scroll",
72
+ wand: "wand",
73
+ staff: "staff",
74
+ rod: "rod",
75
+ shield: "shield"
76
+ };
77
+ var NAME_WORDS = [
78
+ ["backpack", ["backpack", "haversack"]],
79
+ ["pouch", ["pouch", "coin purse"]],
80
+ ["quiver", ["quiver", "bolt case"]],
81
+ ["chest", ["chest"]],
82
+ ["barrel", ["barrel", "basket", "bucket"]],
83
+ ["pot", ["pot", "jug"]],
84
+ ["sack", ["sack", "bag"]],
85
+ ["amulet", ["amulet", "necklace", "periapt"]],
86
+ ["cloak", ["cloak", "robe", "robes"]],
87
+ ["boots", ["boots", "slippers"]],
88
+ ["gloves", ["gloves", "gauntlets", "bracers"]],
89
+ ["belt", ["belt", "girdle"]],
90
+ ["circlet", ["circlet", "headband", "diadem"]],
91
+ ["crown", ["crown"]],
92
+ ["helmet", ["helm", "helmet"]],
93
+ ["rations", ["rations"]],
94
+ ["waterskin", ["waterskin"]],
95
+ ["instrument", ["instrument", "instruments"]],
96
+ ["dice", ["dice", "dice set", "gaming set"]],
97
+ ["gem", ["gem", "gems"]],
98
+ ["hourglass", ["hourglass"]],
99
+ ["flask", ["flask", "vial", "bottle", "oil", "holy water", "acid"]],
100
+ ["torch", ["torch"]],
101
+ ["lantern", ["lantern", "lamp"]],
102
+ ["candle", ["candle", "tinderbox"]],
103
+ ["rope", ["rope", "chain"]],
104
+ ["crowbar", ["crowbar"]],
105
+ ["manacles", ["manacles"]],
106
+ ["mirror", ["mirror"]],
107
+ ["spyglass", ["spyglass"]],
108
+ ["compass", ["compass"]],
109
+ ["map", ["map"]],
110
+ ["spellbook", ["spellbook"]],
111
+ ["book", ["book", "journal"]],
112
+ ["quill", ["ink", "ink pen", "paper"]],
113
+ ["bedroll", ["bedroll", "blanket"]],
114
+ ["tent", ["tent"]],
115
+ ["holy-symbol", ["holy symbol", "reliquary"]],
116
+ ["healer-kit", ["healer's kit"]],
117
+ ["herbs", ["herbalism kit", "herbs"]],
118
+ ["key", ["thieves' tools", "key", "lock"]],
119
+ ["tools", ["artisan's tools", "hammer", "smith's tools"]],
120
+ ["cards", ["playing cards", "playing card set"]],
121
+ ["coins", ["coin", "coins", "trade bar", "trade bars"]],
122
+ ["stone", ["stone", "stones"]],
123
+ ["wand", ["wand"]],
124
+ ["rod", ["rod"]],
125
+ ["staff", ["staff"]],
126
+ ["ring", ["ring"]],
127
+ ["net", ["net"]]
128
+ ];
129
+ var FOCUS_KEY = { holy: "holy-symbol", arcane: "wondrous", druid: "herbs" };
130
+ var TYPE_FALLBACK = {
131
+ instrument: "instrument",
132
+ "artisan's tools": "tools",
133
+ tool: "tools",
134
+ tools: "tools",
135
+ "gaming set": "dice",
136
+ ammunition: "quiver",
137
+ food: "rations",
138
+ wondrous: "wondrous"
139
+ };
140
+ var AMMUNITION_NAME = /\b(?:ammunition|arrows?|bolts?|bullets?|needles?)\b/i;
141
+ var TATTOO_NAME = /\btattoo\b/i;
142
+ var escapeRe = (w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
143
+ var NAME_RULES = NAME_WORDS.map(
144
+ ([key, words]) => [key, new RegExp(`\\b(?:${words.map(escapeRe).join("|")})\\b`, "i")]
145
+ );
146
+ var ITEM_ICON_KEYS = [.../* @__PURE__ */ new Set([
147
+ "tattoo",
148
+ "quiver",
149
+ ...WEAPON_KEYS,
150
+ ...Object.values(ARMOR_CATEGORY_KEY),
151
+ ...Object.values(TYPE_DIRECT),
152
+ ...NAME_WORDS.map(([k]) => k),
153
+ ...Object.values(FOCUS_KEY),
154
+ ...Object.values(TYPE_FALLBACK)
155
+ ])].sort();
156
+ var text = (v) => typeof v === "string" ? v : "";
157
+ function canon(raw) {
158
+ var _a;
159
+ let s = raw.toLowerCase().replace(/\s*\([^)]*\)/g, " ").trim();
160
+ const comma = /^([^,]+),\s*(.+)$/.exec(s);
161
+ if (comma) s = `${comma[2]} ${comma[1]}`;
162
+ s = s.replace(/[\s-]+armou?r$/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
163
+ return (_a = WEAPON_ALIAS[s]) != null ? _a : s;
164
+ }
165
+ var weaponKey = (raw) => {
166
+ const k = canon(raw);
167
+ return WEAPON_KEYS.has(k) ? k : void 0;
168
+ };
169
+ var armorKey = (raw) => {
170
+ const cat = ARMOR_BASE_CATEGORY[canon(raw)];
171
+ return cat ? ARMOR_CATEGORY_KEY[cat] : void 0;
172
+ };
173
+ function baseName(link) {
174
+ const raw = text(link).trim();
175
+ if (!raw) return "";
176
+ const m = /^\[\[([^\]|]+)(?:\|[^\]]*)?\]\]$/.exec(raw);
177
+ const inner = m ? m[1] : raw;
178
+ return inner.includes("/") ? inner.slice(inner.lastIndexOf("/") + 1) : inner.slice(inner.lastIndexOf("_") + 1);
179
+ }
180
+ function itemIconKey(entity, entityType) {
181
+ var _a, _b, _c, _d, _e, _f, _g, _h;
182
+ const e = entity !== null && typeof entity === "object" ? entity : {};
183
+ const own = text(e.icon).trim();
184
+ if (own) return own;
185
+ const name = text(e.name);
186
+ if (e.tattoo === true || TATTOO_NAME.test(name)) return "tattoo";
187
+ if (entityType === "weapon") return (_b = (_a = weaponKey(baseName(e.slug))) != null ? _a : weaponKey(name)) != null ? _b : GENERIC_ICON.weapon;
188
+ if (entityType === "armor") {
189
+ const cat = text(e.category).toLowerCase().replace(/\s*armou?r\s*$/, "").trim();
190
+ return (_d = (_c = ARMOR_CATEGORY_KEY[cat]) != null ? _c : armorKey(name)) != null ? _d : GENERIC_ICON.armor;
191
+ }
192
+ const rawType = text(e.type).toLowerCase().trim();
193
+ const paren = /^([^()]+?)\s*\(([^)]+)\)\s*$/.exec(rawType);
194
+ const type = (paren ? paren[1] : rawType).trim().replace(/\s+item$/, "");
195
+ const inner = paren ? paren[2].trim() : "";
196
+ if (type === "weapon") {
197
+ return (_e = weaponKey(baseName(e.base_item) || inner)) != null ? _e : AMMUNITION_NAME.test(name) ? "quiver" : GENERIC_ICON.weapon;
198
+ }
199
+ if (type === "armor") return (_f = armorKey(baseName(e.base_item) || inner)) != null ? _f : GENERIC_ICON.armor;
200
+ const direct = TYPE_DIRECT[type];
201
+ if (direct) return direct;
202
+ const bare = name.replace(/\s*\([^)]*\)/g, " ").trim();
203
+ for (const [key, re] of NAME_RULES) if (re.test(bare)) return key;
204
+ if (type === "spellcasting focus") return (_g = FOCUS_KEY[text(e.focus).toLowerCase()]) != null ? _g : "wondrous";
205
+ return (_h = TYPE_FALLBACK[type]) != null ? _h : GENERIC_ICON.item;
206
+ }
207
+ export {
208
+ GENERIC_ICON,
209
+ ITEM_ICON_KEYS,
210
+ itemIconKey
211
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseItem
3
- } from "../chunk-SMLXZUBH.js";
4
- import "../chunk-GFZ7PITJ.js";
3
+ } from "../chunk-EYX4JMAU.js";
4
+ import "../chunk-S3YUXDSC.js";
5
5
  import "../chunk-UA5KS2PL.js";
6
6
  export {
7
7
  parseItem
@@ -1,6 +1,18 @@
1
1
  import { z } from "zod";
2
2
  import type { Condition } from "@archivist-gg/dnd5e/types/item-conditions.types";
3
3
  export declare const conditionSchema: z.ZodType<Condition>;
4
+ export declare const containerSchema: z.ZodObject<{
5
+ capacity_weight: z.ZodOptional<z.ZodNumber>;
6
+ holds_items: z.ZodOptional<z.ZodBoolean>;
7
+ pack_contents: z.ZodOptional<z.ZodArray<z.ZodString>>;
8
+ pack_atomic: z.ZodOptional<z.ZodBoolean>;
9
+ capacity: z.ZodOptional<z.ZodObject<{
10
+ weight: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
11
+ item: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodNumber>>>;
12
+ weightless: z.ZodOptional<z.ZodBoolean>;
13
+ volume: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
14
+ }, z.core.$strict>>;
15
+ }, z.core.$strip>;
4
16
  export declare const itemEntitySchema: z.ZodObject<{
5
17
  name: z.ZodString;
6
18
  slug: z.ZodOptional<z.ZodString>;
@@ -182,8 +194,9 @@ export declare const itemEntitySchema: z.ZodObject<{
182
194
  }, z.core.$strip>>;
183
195
  container: z.ZodOptional<z.ZodObject<{
184
196
  capacity_weight: z.ZodOptional<z.ZodNumber>;
185
- weightless: z.ZodOptional<z.ZodBoolean>;
197
+ holds_items: z.ZodOptional<z.ZodBoolean>;
186
198
  pack_contents: z.ZodOptional<z.ZodArray<z.ZodString>>;
199
+ pack_atomic: z.ZodOptional<z.ZodBoolean>;
187
200
  capacity: z.ZodOptional<z.ZodObject<{
188
201
  weight: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
189
202
  item: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodNumber>>>;
@@ -201,6 +214,7 @@ export declare const itemEntitySchema: z.ZodObject<{
201
214
  }, z.core.$strict>>]>>;
202
215
  cursed: z.ZodOptional<z.ZodBoolean>;
203
216
  sentient: z.ZodOptional<z.ZodBoolean>;
217
+ tattoo: z.ZodOptional<z.ZodBoolean>;
204
218
  focus: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString, z.ZodArray<z.ZodString>]>>;
205
219
  tier: z.ZodOptional<z.ZodEnum<{
206
220
  major: "major";
@@ -241,6 +255,7 @@ export declare const itemEntitySchema: z.ZodObject<{
241
255
  bonus: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
242
256
  }, z.core.$strict>>;
243
257
  rendering_hint: z.ZodOptional<z.ZodString>;
258
+ icon: z.ZodOptional<z.ZodString>;
244
259
  has_fluff: z.ZodOptional<z.ZodBoolean>;
245
260
  has_fluff_images: z.ZodOptional<z.ZodBoolean>;
246
261
  image: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  conditionSchema,
3
+ containerSchema,
3
4
  itemEntitySchema
4
- } from "../chunk-GFZ7PITJ.js";
5
+ } from "../chunk-S3YUXDSC.js";
5
6
  import "../chunk-UA5KS2PL.js";
6
7
  export {
7
8
  conditionSchema,
9
+ containerSchema,
8
10
  itemEntitySchema
9
11
  };
@@ -109,12 +109,16 @@ export interface ItemEntity {
109
109
  blindsight?: number;
110
110
  };
111
111
  };
112
+ /** No top-level `weightless` (I2a): `capacity.weightless` is the one kept spelling. */
112
113
  container?: {
113
114
  capacity_weight?: number;
114
- weightless?: boolean;
115
+ holds_items?: boolean;
115
116
  pack_contents?: string[];
117
+ pack_atomic?: boolean;
116
118
  /** Structured 5etools capacity. `item` entries are records of
117
- * "<item tag>": <count>, e.g. {"sling bullet|xphb": 20}. */
119
+ * "<item tag>": <count>, e.g. {"sling bullet|xphb": 20}. `item` record keys
120
+ * are 5etools uids ("sling bullet|xphb") in converted data and item display
121
+ * names ("Sling Bullet") in the SRD bundle (I2a). */
118
122
  capacity?: {
119
123
  weight?: number[];
120
124
  item?: Array<Record<string, number>>;
@@ -135,6 +139,7 @@ export interface ItemEntity {
135
139
  }>;
136
140
  cursed?: boolean;
137
141
  sentient?: boolean;
142
+ tattoo?: boolean;
138
143
  focus?: boolean | "arcane" | "druid" | "holy" | string[];
139
144
  tier?: "major" | "minor";
140
145
  damage?: WeaponEntity["damage"] | string;
@@ -176,6 +181,8 @@ export interface ItemEntity {
176
181
  };
177
182
  /** Carried by every converter item doc, always as "" today. */
178
183
  rendering_hint?: string;
184
+ /** The icon key (I3): a key of the renderer's icon set or a Lucide name. */
185
+ icon?: string;
179
186
  has_fluff?: boolean;
180
187
  has_fluff_images?: boolean;
181
188
  /** One wikilink, or an array for >= 2 fluff images (images-ON emit). */
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  migrateLegacy,
3
3
  parseMonster
4
- } from "../chunk-QHMWA3SZ.js";
5
- import "../chunk-G247QXWW.js";
6
- import "../chunk-PI4LLJG4.js";
4
+ } from "../chunk-VDPRBUU5.js";
5
+ import "../chunk-EL6QPF6I.js";
6
+ import "../chunk-FPGXFD2M.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
8
  import "../chunk-ZJXSXVFP.js";
9
- import "../chunk-2M34FLAY.js";
10
- import "../chunk-XTRDCSJB.js";
9
+ import "../chunk-BRGLDWUP.js";
10
+ import "../chunk-ZMJQUZQH.js";
11
11
  import "../chunk-UA5KS2PL.js";
12
12
  export {
13
13
  migrateLegacy,
@@ -11,12 +11,12 @@ import {
11
11
  monsterSpeedSchema,
12
12
  monsterSpellcastingSchema,
13
13
  monsterTypeSchema
14
- } from "../chunk-G247QXWW.js";
15
- import "../chunk-PI4LLJG4.js";
14
+ } from "../chunk-EL6QPF6I.js";
15
+ import "../chunk-FPGXFD2M.js";
16
16
  import "../chunk-WYGD2UGN.js";
17
17
  import "../chunk-ZJXSXVFP.js";
18
- import "../chunk-2M34FLAY.js";
19
- import "../chunk-XTRDCSJB.js";
18
+ import "../chunk-BRGLDWUP.js";
19
+ import "../chunk-ZMJQUZQH.js";
20
20
  import "../chunk-UA5KS2PL.js";
21
21
  export {
22
22
  MONSTER_KNOWN_KEYS,