ttrpg-engine-dnd 0.1.0-alpha.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.
Files changed (329) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/CONTRIBUTING.md +98 -0
  3. package/DEVELOPMENT.md +70 -0
  4. package/LICENSE +21 -0
  5. package/README.md +247 -0
  6. package/VERSIONING.md +151 -0
  7. package/dist/content/index.d.ts +3 -0
  8. package/dist/content/index.d.ts.map +1 -0
  9. package/dist/content/pack.d.ts +1657 -0
  10. package/dist/content/pack.d.ts.map +1 -0
  11. package/dist/content/packs/starter.d.ts +4 -0
  12. package/dist/content/packs/starter.d.ts.map +1 -0
  13. package/dist/content/validate.d.ts +8 -0
  14. package/dist/content/validate.d.ts.map +1 -0
  15. package/dist/derive/ability-check.d.ts +26 -0
  16. package/dist/derive/ability-check.d.ts.map +1 -0
  17. package/dist/derive/ability.d.ts +9 -0
  18. package/dist/derive/ability.d.ts.map +1 -0
  19. package/dist/derive/ac.d.ts +19 -0
  20. package/dist/derive/ac.d.ts.map +1 -0
  21. package/dist/derive/action-economy.d.ts +17 -0
  22. package/dist/derive/action-economy.d.ts.map +1 -0
  23. package/dist/derive/attack.d.ts +20 -0
  24. package/dist/derive/attack.d.ts.map +1 -0
  25. package/dist/derive/character-view.d.ts +29 -0
  26. package/dist/derive/character-view.d.ts.map +1 -0
  27. package/dist/derive/damage-mitigation.d.ts +18 -0
  28. package/dist/derive/damage-mitigation.d.ts.map +1 -0
  29. package/dist/derive/effect-stack.d.ts +15 -0
  30. package/dist/derive/effect-stack.d.ts.map +1 -0
  31. package/dist/derive/encumbrance.d.ts +17 -0
  32. package/dist/derive/encumbrance.d.ts.map +1 -0
  33. package/dist/derive/index.d.ts +12 -0
  34. package/dist/derive/index.d.ts.map +1 -0
  35. package/dist/derive/save.d.ts +23 -0
  36. package/dist/derive/save.d.ts.map +1 -0
  37. package/dist/derive/spell-dc.d.ts +21 -0
  38. package/dist/derive/spell-dc.d.ts.map +1 -0
  39. package/dist/derive/spell-slots.d.ts +21 -0
  40. package/dist/derive/spell-slots.d.ts.map +1 -0
  41. package/dist/derive/terrain.d.ts +10 -0
  42. package/dist/derive/terrain.d.ts.map +1 -0
  43. package/dist/effects/builder.d.ts +66 -0
  44. package/dist/effects/builder.d.ts.map +1 -0
  45. package/dist/effects/formula.d.ts +12 -0
  46. package/dist/effects/formula.d.ts.map +1 -0
  47. package/dist/effects/index.d.ts +4 -0
  48. package/dist/effects/index.d.ts.map +1 -0
  49. package/dist/effects/predicate.d.ts +12 -0
  50. package/dist/effects/predicate.d.ts.map +1 -0
  51. package/dist/engine/apply.d.ts +5 -0
  52. package/dist/engine/apply.d.ts.map +1 -0
  53. package/dist/engine/commit.d.ts +12 -0
  54. package/dist/engine/commit.d.ts.map +1 -0
  55. package/dist/engine/conveniences.d.ts +7124 -0
  56. package/dist/engine/conveniences.d.ts.map +1 -0
  57. package/dist/engine/ids-utils.d.ts +2 -0
  58. package/dist/engine/ids-utils.d.ts.map +1 -0
  59. package/dist/engine/index.d.ts +107 -0
  60. package/dist/engine/index.d.ts.map +1 -0
  61. package/dist/engine/plan/action-surge.d.ts +10 -0
  62. package/dist/engine/plan/action-surge.d.ts.map +1 -0
  63. package/dist/engine/plan/attack.d.ts +30 -0
  64. package/dist/engine/plan/attack.d.ts.map +1 -0
  65. package/dist/engine/plan/cast-spell.d.ts +18 -0
  66. package/dist/engine/plan/cast-spell.d.ts.map +1 -0
  67. package/dist/engine/plan/checks.d.ts +26 -0
  68. package/dist/engine/plan/checks.d.ts.map +1 -0
  69. package/dist/engine/plan/concentration.d.ts +12 -0
  70. package/dist/engine/plan/concentration.d.ts.map +1 -0
  71. package/dist/engine/plan/contested.d.ts +28 -0
  72. package/dist/engine/plan/contested.d.ts.map +1 -0
  73. package/dist/engine/plan/encounter.d.ts +47 -0
  74. package/dist/engine/plan/encounter.d.ts.map +1 -0
  75. package/dist/engine/plan/falling.d.ts +11 -0
  76. package/dist/engine/plan/falling.d.ts.map +1 -0
  77. package/dist/engine/plan/index.d.ts +20 -0
  78. package/dist/engine/plan/index.d.ts.map +1 -0
  79. package/dist/engine/plan/level-up.d.ts +22 -0
  80. package/dist/engine/plan/level-up.d.ts.map +1 -0
  81. package/dist/engine/plan/movement.d.ts +25 -0
  82. package/dist/engine/plan/movement.d.ts.map +1 -0
  83. package/dist/engine/plan/multiattack.d.ts +12 -0
  84. package/dist/engine/plan/multiattack.d.ts.map +1 -0
  85. package/dist/engine/plan/npc.d.ts +21 -0
  86. package/dist/engine/plan/npc.d.ts.map +1 -0
  87. package/dist/engine/plan/offhand-attack.d.ts +13 -0
  88. package/dist/engine/plan/offhand-attack.d.ts.map +1 -0
  89. package/dist/engine/plan/opportunity-attack.d.ts +14 -0
  90. package/dist/engine/plan/opportunity-attack.d.ts.map +1 -0
  91. package/dist/engine/plan/reactive-spells.d.ts +34 -0
  92. package/dist/engine/plan/reactive-spells.d.ts.map +1 -0
  93. package/dist/engine/plan/rest.d.ts +16 -0
  94. package/dist/engine/plan/rest.d.ts.map +1 -0
  95. package/dist/engine/plan/travel.d.ts +21 -0
  96. package/dist/engine/plan/travel.d.ts.map +1 -0
  97. package/dist/engine/plan/weapon-mastery.d.ts +15 -0
  98. package/dist/engine/plan/weapon-mastery.d.ts.map +1 -0
  99. package/dist/engine/reducers/action-economy.d.ts +12 -0
  100. package/dist/engine/reducers/action-economy.d.ts.map +1 -0
  101. package/dist/engine/reducers/attack.d.ts +6 -0
  102. package/dist/engine/reducers/attack.d.ts.map +1 -0
  103. package/dist/engine/reducers/bastion.d.ts +10 -0
  104. package/dist/engine/reducers/bastion.d.ts.map +1 -0
  105. package/dist/engine/reducers/charges.d.ts +7 -0
  106. package/dist/engine/reducers/charges.d.ts.map +1 -0
  107. package/dist/engine/reducers/checks.d.ts +6 -0
  108. package/dist/engine/reducers/checks.d.ts.map +1 -0
  109. package/dist/engine/reducers/combat.d.ts +12 -0
  110. package/dist/engine/reducers/combat.d.ts.map +1 -0
  111. package/dist/engine/reducers/concentration.d.ts +6 -0
  112. package/dist/engine/reducers/concentration.d.ts.map +1 -0
  113. package/dist/engine/reducers/downtime.d.ts +5 -0
  114. package/dist/engine/reducers/downtime.d.ts.map +1 -0
  115. package/dist/engine/reducers/encounter.d.ts +11 -0
  116. package/dist/engine/reducers/encounter.d.ts.map +1 -0
  117. package/dist/engine/reducers/inventory.d.ts +9 -0
  118. package/dist/engine/reducers/inventory.d.ts.map +1 -0
  119. package/dist/engine/reducers/level-up.d.ts +7 -0
  120. package/dist/engine/reducers/level-up.d.ts.map +1 -0
  121. package/dist/engine/reducers/locations.d.ts +8 -0
  122. package/dist/engine/reducers/locations.d.ts.map +1 -0
  123. package/dist/engine/reducers/mounts-vehicles.d.ts +11 -0
  124. package/dist/engine/reducers/mounts-vehicles.d.ts.map +1 -0
  125. package/dist/engine/reducers/movement.d.ts +7 -0
  126. package/dist/engine/reducers/movement.d.ts.map +1 -0
  127. package/dist/engine/reducers/npc.d.ts +7 -0
  128. package/dist/engine/reducers/npc.d.ts.map +1 -0
  129. package/dist/engine/reducers/party.d.ts +10 -0
  130. package/dist/engine/reducers/party.d.ts.map +1 -0
  131. package/dist/engine/reducers/progression.d.ts +5 -0
  132. package/dist/engine/reducers/progression.d.ts.map +1 -0
  133. package/dist/engine/reducers/quests.d.ts +14 -0
  134. package/dist/engine/reducers/quests.d.ts.map +1 -0
  135. package/dist/engine/reducers/reactive-spells.d.ts +7 -0
  136. package/dist/engine/reducers/reactive-spells.d.ts.map +1 -0
  137. package/dist/engine/reducers/resources.d.ts +7 -0
  138. package/dist/engine/reducers/resources.d.ts.map +1 -0
  139. package/dist/engine/reducers/rest.d.ts +8 -0
  140. package/dist/engine/reducers/rest.d.ts.map +1 -0
  141. package/dist/engine/reducers/resurrection.d.ts +5 -0
  142. package/dist/engine/reducers/resurrection.d.ts.map +1 -0
  143. package/dist/engine/reducers/session.d.ts +8 -0
  144. package/dist/engine/reducers/session.d.ts.map +1 -0
  145. package/dist/engine/reducers/settings.d.ts +5 -0
  146. package/dist/engine/reducers/settings.d.ts.map +1 -0
  147. package/dist/engine/reducers/spellcasting.d.ts +7 -0
  148. package/dist/engine/reducers/spellcasting.d.ts.map +1 -0
  149. package/dist/engine/reducers/transformations.d.ts +8 -0
  150. package/dist/engine/reducers/transformations.d.ts.map +1 -0
  151. package/dist/engine/reducers/travel.d.ts +7 -0
  152. package/dist/engine/reducers/travel.d.ts.map +1 -0
  153. package/dist/engine/reducers/triggers.d.ts +9 -0
  154. package/dist/engine/reducers/triggers.d.ts.map +1 -0
  155. package/dist/engine/reducers/weapon-mastery.d.ts +5 -0
  156. package/dist/engine/reducers/weapon-mastery.d.ts.map +1 -0
  157. package/dist/engine/replay.d.ts +4 -0
  158. package/dist/engine/replay.d.ts.map +1 -0
  159. package/dist/engine/triggers/dispatch.d.ts +13 -0
  160. package/dist/engine/triggers/dispatch.d.ts.map +1 -0
  161. package/dist/engine/undo-redo.d.ts +4 -0
  162. package/dist/engine/undo-redo.d.ts.map +1 -0
  163. package/dist/handlers/context.d.ts +7 -0
  164. package/dist/handlers/context.d.ts.map +1 -0
  165. package/dist/handlers/index.d.ts +12 -0
  166. package/dist/handlers/index.d.ts.map +1 -0
  167. package/dist/ids.d.ts +64 -0
  168. package/dist/ids.d.ts.map +1 -0
  169. package/dist/index.d.ts +72 -0
  170. package/dist/index.d.ts.map +1 -0
  171. package/dist/internal/clock.d.ts +2 -0
  172. package/dist/internal/clock.d.ts.map +1 -0
  173. package/dist/internal/constants.d.ts +6 -0
  174. package/dist/internal/constants.d.ts.map +1 -0
  175. package/dist/internal/immer.d.ts +4 -0
  176. package/dist/internal/immer.d.ts.map +1 -0
  177. package/dist/internal/invariants.d.ts +5 -0
  178. package/dist/internal/invariants.d.ts.map +1 -0
  179. package/dist/migrations/index.d.ts +5 -0
  180. package/dist/migrations/index.d.ts.map +1 -0
  181. package/dist/rng/default.d.ts +6 -0
  182. package/dist/rng/default.d.ts.map +1 -0
  183. package/dist/rng/dice.d.ts +20 -0
  184. package/dist/rng/dice.d.ts.map +1 -0
  185. package/dist/rng/index.d.ts +10 -0
  186. package/dist/rng/index.d.ts.map +1 -0
  187. package/dist/rng/seeded.d.ts +9 -0
  188. package/dist/rng/seeded.d.ts.map +1 -0
  189. package/dist/rng/throw.d.ts +9 -0
  190. package/dist/rng/throw.d.ts.map +1 -0
  191. package/dist/schemas/content/background.d.ts +46 -0
  192. package/dist/schemas/content/background.d.ts.map +1 -0
  193. package/dist/schemas/content/class.d.ts +264 -0
  194. package/dist/schemas/content/class.d.ts.map +1 -0
  195. package/dist/schemas/content/condition.d.ts +90 -0
  196. package/dist/schemas/content/condition.d.ts.map +1 -0
  197. package/dist/schemas/content/feat.d.ts +25 -0
  198. package/dist/schemas/content/feat.d.ts.map +1 -0
  199. package/dist/schemas/content/index.d.ts +9 -0
  200. package/dist/schemas/content/index.d.ts.map +1 -0
  201. package/dist/schemas/content/item.d.ts +602 -0
  202. package/dist/schemas/content/item.d.ts.map +1 -0
  203. package/dist/schemas/content/monster.d.ts +203 -0
  204. package/dist/schemas/content/monster.d.ts.map +1 -0
  205. package/dist/schemas/content/species.d.ts +63 -0
  206. package/dist/schemas/content/species.d.ts.map +1 -0
  207. package/dist/schemas/content/spell.d.ts +253 -0
  208. package/dist/schemas/content/spell.d.ts.map +1 -0
  209. package/dist/schemas/effects.d.ts +175 -0
  210. package/dist/schemas/effects.d.ts.map +1 -0
  211. package/dist/schemas/events/action-economy.d.ts +38 -0
  212. package/dist/schemas/events/action-economy.d.ts.map +1 -0
  213. package/dist/schemas/events/attack.d.ts +139 -0
  214. package/dist/schemas/events/attack.d.ts.map +1 -0
  215. package/dist/schemas/events/bastion.d.ts +227 -0
  216. package/dist/schemas/events/bastion.d.ts.map +1 -0
  217. package/dist/schemas/events/charges.d.ts +110 -0
  218. package/dist/schemas/events/charges.d.ts.map +1 -0
  219. package/dist/schemas/events/checks.d.ts +103 -0
  220. package/dist/schemas/events/checks.d.ts.map +1 -0
  221. package/dist/schemas/events/combat.d.ts +308 -0
  222. package/dist/schemas/events/combat.d.ts.map +1 -0
  223. package/dist/schemas/events/concentration.d.ts +99 -0
  224. package/dist/schemas/events/concentration.d.ts.map +1 -0
  225. package/dist/schemas/events/downtime.d.ts +53 -0
  226. package/dist/schemas/events/downtime.d.ts.map +1 -0
  227. package/dist/schemas/events/encounter.d.ts +260 -0
  228. package/dist/schemas/events/encounter.d.ts.map +1 -0
  229. package/dist/schemas/events/envelope.d.ts +22 -0
  230. package/dist/schemas/events/envelope.d.ts.map +1 -0
  231. package/dist/schemas/events/index.d.ts +4594 -0
  232. package/dist/schemas/events/index.d.ts.map +1 -0
  233. package/dist/schemas/events/inventory.d.ts +253 -0
  234. package/dist/schemas/events/inventory.d.ts.map +1 -0
  235. package/dist/schemas/events/level-up.d.ts +141 -0
  236. package/dist/schemas/events/level-up.d.ts.map +1 -0
  237. package/dist/schemas/events/locations.d.ts +183 -0
  238. package/dist/schemas/events/locations.d.ts.map +1 -0
  239. package/dist/schemas/events/mounts-vehicles.d.ts +233 -0
  240. package/dist/schemas/events/mounts-vehicles.d.ts.map +1 -0
  241. package/dist/schemas/events/movement.d.ts +131 -0
  242. package/dist/schemas/events/movement.d.ts.map +1 -0
  243. package/dist/schemas/events/npc.d.ts +113 -0
  244. package/dist/schemas/events/npc.d.ts.map +1 -0
  245. package/dist/schemas/events/party.d.ts +260 -0
  246. package/dist/schemas/events/party.d.ts.map +1 -0
  247. package/dist/schemas/events/progression.d.ts +698 -0
  248. package/dist/schemas/events/progression.d.ts.map +1 -0
  249. package/dist/schemas/events/quests.d.ts +426 -0
  250. package/dist/schemas/events/quests.d.ts.map +1 -0
  251. package/dist/schemas/events/reactive-spells.d.ts +98 -0
  252. package/dist/schemas/events/reactive-spells.d.ts.map +1 -0
  253. package/dist/schemas/events/resources.d.ts +107 -0
  254. package/dist/schemas/events/resources.d.ts.map +1 -0
  255. package/dist/schemas/events/rest.d.ts +104 -0
  256. package/dist/schemas/events/rest.d.ts.map +1 -0
  257. package/dist/schemas/events/resurrection.d.ts +44 -0
  258. package/dist/schemas/events/resurrection.d.ts.map +1 -0
  259. package/dist/schemas/events/session.d.ts +144 -0
  260. package/dist/schemas/events/session.d.ts.map +1 -0
  261. package/dist/schemas/events/settings.d.ts +47 -0
  262. package/dist/schemas/events/settings.d.ts.map +1 -0
  263. package/dist/schemas/events/spellcasting.d.ts +103 -0
  264. package/dist/schemas/events/spellcasting.d.ts.map +1 -0
  265. package/dist/schemas/events/transformations.d.ts +279 -0
  266. package/dist/schemas/events/transformations.d.ts.map +1 -0
  267. package/dist/schemas/events/travel.d.ts +143 -0
  268. package/dist/schemas/events/travel.d.ts.map +1 -0
  269. package/dist/schemas/events/triggers.d.ts +60 -0
  270. package/dist/schemas/events/triggers.d.ts.map +1 -0
  271. package/dist/schemas/events/weapon-mastery.d.ts +38 -0
  272. package/dist/schemas/events/weapon-mastery.d.ts.map +1 -0
  273. package/dist/schemas/formula.d.ts +103 -0
  274. package/dist/schemas/formula.d.ts.map +1 -0
  275. package/dist/schemas/index.d.ts +8 -0
  276. package/dist/schemas/index.d.ts.map +1 -0
  277. package/dist/schemas/predicate.d.ts +72 -0
  278. package/dist/schemas/predicate.d.ts.map +1 -0
  279. package/dist/schemas/primitives.d.ts +156 -0
  280. package/dist/schemas/primitives.d.ts.map +1 -0
  281. package/dist/schemas/runtime/bastion.d.ts +130 -0
  282. package/dist/schemas/runtime/bastion.d.ts.map +1 -0
  283. package/dist/schemas/runtime/campaign.d.ts +2122 -0
  284. package/dist/schemas/runtime/campaign.d.ts.map +1 -0
  285. package/dist/schemas/runtime/character.d.ts +580 -0
  286. package/dist/schemas/runtime/character.d.ts.map +1 -0
  287. package/dist/schemas/runtime/currency.d.ts +9 -0
  288. package/dist/schemas/runtime/currency.d.ts.map +1 -0
  289. package/dist/schemas/runtime/downtime.d.ts +31 -0
  290. package/dist/schemas/runtime/downtime.d.ts.map +1 -0
  291. package/dist/schemas/runtime/effect-instance.d.ts +65 -0
  292. package/dist/schemas/runtime/effect-instance.d.ts.map +1 -0
  293. package/dist/schemas/runtime/encounter.d.ts +264 -0
  294. package/dist/schemas/runtime/encounter.d.ts.map +1 -0
  295. package/dist/schemas/runtime/in-game-time.d.ts +18 -0
  296. package/dist/schemas/runtime/in-game-time.d.ts.map +1 -0
  297. package/dist/schemas/runtime/index.d.ts +15 -0
  298. package/dist/schemas/runtime/index.d.ts.map +1 -0
  299. package/dist/schemas/runtime/item-instance.d.ts +66 -0
  300. package/dist/schemas/runtime/item-instance.d.ts.map +1 -0
  301. package/dist/schemas/runtime/location.d.ts +111 -0
  302. package/dist/schemas/runtime/location.d.ts.map +1 -0
  303. package/dist/schemas/runtime/party.d.ts +52 -0
  304. package/dist/schemas/runtime/party.d.ts.map +1 -0
  305. package/dist/schemas/runtime/pending-choice.d.ts +77 -0
  306. package/dist/schemas/runtime/pending-choice.d.ts.map +1 -0
  307. package/dist/schemas/runtime/quest.d.ts +207 -0
  308. package/dist/schemas/runtime/quest.d.ts.map +1 -0
  309. package/dist/schemas/runtime/session.d.ts +102 -0
  310. package/dist/schemas/runtime/session.d.ts.map +1 -0
  311. package/dist/schemas/runtime/settings.d.ts +26 -0
  312. package/dist/schemas/runtime/settings.d.ts.map +1 -0
  313. package/dist/schemas/runtime/travel.d.ts +34 -0
  314. package/dist/schemas/runtime/travel.d.ts.map +1 -0
  315. package/dist/schemas/runtime/vehicle.d.ts +49 -0
  316. package/dist/schemas/runtime/vehicle.d.ts.map +1 -0
  317. package/dist/ttrpg-engine-dnd.cjs +6 -0
  318. package/dist/ttrpg-engine-dnd.cjs.map +1 -0
  319. package/dist/ttrpg-engine-dnd.js +10464 -0
  320. package/dist/ttrpg-engine-dnd.js.map +1 -0
  321. package/dist/types/index.d.ts +8 -0
  322. package/dist/types/index.d.ts.map +1 -0
  323. package/dist/version.d.ts +3 -0
  324. package/dist/version.d.ts.map +1 -0
  325. package/docs/api-overview.md +111 -0
  326. package/docs/concepts.md +154 -0
  327. package/docs/getting-started.md +142 -0
  328. package/docs/recipes.md +302 -0
  329. package/package.json +83 -0
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const L=require("ulid"),t=require("zod"),qt=require("immer"),ze=1,Ht=()=>L.ulid(),fi=()=>L.ulid(),Ii=()=>L.ulid(),Gt=()=>L.ulid(),Kt=()=>L.ulid(),gi=()=>L.ulid(),yi=()=>L.ulid(),bi=()=>L.ulid(),Si=()=>L.ulid(),I=()=>L.ulid(),Vt=()=>L.ulid(),Wt=()=>L.ulid(),W=()=>L.ulid(),vi=()=>L.ulid(),zi=a=>a,Ci=a=>a,Ei=a=>a,ki=a=>a,Ai=a=>a,wi=a=>a,Ri=a=>a,Ti=a=>a,Di=a=>a,Bi=a=>a,xi=a=>a,Mi=a=>a,Pi=a=>a,Li=a=>a,$i=a=>a,Oi=a=>a,Xt=["STR","DEX","CON","INT","WIS","CHA"],B=t.z.enum(Xt),Qt=1,Yt=30,ee=t.z.number().int().min(Qt).max(Yt),he=t.z.object({STR:ee,DEX:ee,CON:ee,INT:ee,WIS:ee,CHA:ee}),Jt=["Tiny","Small","Medium","Large","Huge","Gargantuan"],je=t.z.enum(Jt),Zt=["Aberration","Beast","Celestial","Construct","Dragon","Elemental","Fey","Fiend","Giant","Humanoid","Monstrosity","Ooze","Plant","Undead"],qe=t.z.enum(Zt),ea=["acid","bludgeoning","cold","fire","force","lightning","necrotic","piercing","poison","psychic","radiant","slashing","thunder"],M=t.z.enum(ea),ta=["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"],ae=t.z.enum(ta),aa={acrobatics:"DEX","animal-handling":"WIS",arcana:"INT",athletics:"STR",deception:"CHA",history:"INT",insight:"WIS",intimidation:"CHA",investigation:"INT",medicine:"WIS",nature:"INT",perception:"WIS",performance:"CHA",persuasion:"CHA",religion:"INT","sleight-of-hand":"DEX",stealth:"DEX",survival:"WIS"},na=t.z.enum(["none","half","proficient","expertise"]),oa={none:0,half:.5,proficient:1,expertise:2},ra=t.z.union([t.z.literal(6),t.z.literal(8),t.z.literal(10),t.z.literal(12)]),ia=t.z.enum(["walk","fly","swim","climb","burrow"]),He=t.z.object({walk:t.z.number().int().min(0).default(0),fly:t.z.number().int().min(0).optional(),swim:t.z.number().int().min(0).optional(),climb:t.z.number().int().min(0).optional(),burrow:t.z.number().int().min(0).optional(),hover:t.z.boolean().optional()}),sa=t.z.enum(["darkvision","blindsight","tremorsense","truesight"]),ca=t.z.object({darkvision:t.z.number().int().min(0).optional(),blindsight:t.z.number().int().min(0).optional(),tremorsense:t.z.number().int().min(0).optional(),truesight:t.z.number().int().min(0).optional(),passivePerceptionOverride:t.z.number().int().min(0).optional()}),da=t.z.enum(["abjuration","conjuration","divination","enchantment","evocation","illusion","necromancy","transmutation"]),la=0,ua=9,ge=t.z.number().int().min(la).max(ua),Ge=1,Ce=20,ma=t.z.number().int().min(Ge).max(Ce),pa=0,Ke=6,ha=t.z.number().int().min(pa).max(Ke),_i=["lawful","neutral","chaotic"],Ni=["good","neutral","evil"],fa=t.z.union([t.z.literal("unaligned"),t.z.literal("any"),t.z.object({lawChaos:t.z.enum(_i),goodEvil:t.z.enum(Ni)})]),s=t.z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/i,"Expected a ULID"),ye=t.z.object({cp:t.z.number().int().min(0).default(0),sp:t.z.number().int().min(0).default(0),ep:t.z.number().int().min(0).default(0),gp:t.z.number().int().min(0).default(0),pp:t.z.number().int().min(0).default(0)}),Ia=["cp","sp","ep","gp","pp"],Ve=t.z.enum(["shortRest","longRest","turn","round","dawn","never"]),ga=["ammunition","finesse","heavy","light","loading","reach","thrown","two-handed","versatile","special"],We=t.z.enum(ga),ya=["Vex","Topple","Sap","Nick","Push","Slow","Cleave","Graze","Flex"],Ee=t.z.enum(ya),_=t.z.string().regex(/^\d+d\d+(?:[+-]\d+)?$/,{message:'Expected dice expression like "2d6", "1d8+3", "3d6-1"'}),Fi=t.z.object({kind:t.z.literal("const"),value:t.z.number()}),Ui=t.z.object({kind:t.z.literal("ability"),ability:B}),ji=t.z.object({kind:t.z.literal("abilityMod"),ability:B}),qi=t.z.object({kind:t.z.literal("profBonus")}),Hi=t.z.object({kind:t.z.literal("level"),classId:t.z.string().optional()}),Gi=t.z.object({kind:t.z.literal("classCol"),classId:t.z.string(),column:t.z.string()}),Ki=t.z.object({kind:t.z.literal("dice"),expression:_,average:t.z.boolean().optional()}),P=t.z.lazy(()=>t.z.union([Fi,Ui,ji,qi,Hi,Gi,Ki,t.z.object({kind:t.z.literal("add"),terms:t.z.array(P)}),t.z.object({kind:t.z.literal("max"),terms:t.z.array(P).min(1)}),t.z.object({kind:t.z.literal("min"),terms:t.z.array(P).min(1)}),t.z.object({kind:t.z.literal("multiply"),terms:t.z.array(P)}),t.z.object({kind:t.z.literal("floor"),term:P}),t.z.object({kind:t.z.literal("ceil"),term:P})])),Vi=a=>P.safeParse(a).success,Wi=t.z.object({kind:t.z.literal("eq"),path:t.z.string(),value:t.z.union([t.z.string(),t.z.number(),t.z.boolean(),t.z.null()])}),Xi=t.z.object({kind:t.z.literal("self")}),Qi=t.z.object({kind:t.z.literal("hasProperty"),property:We}),Yi=t.z.object({kind:t.z.literal("hasCondition"),conditionId:t.z.string()}),Ji=t.z.object({kind:t.z.literal("damageType"),type:M}),Zi=t.z.lazy(()=>t.z.object({kind:t.z.literal("not"),term:H})),H=t.z.lazy(()=>t.z.union([Wi,Xi,Qi,Yi,Ji,t.z.object({kind:t.z.literal("all"),terms:t.z.array(H)}),t.z.object({kind:t.z.literal("any"),terms:t.z.array(H)}),Zi,t.z.object({kind:t.z.literal("always")}),t.z.object({kind:t.z.literal("never")})])),es=a=>H.safeParse(a).success,ba=t.z.union([t.z.literal("ac"),t.z.literal("attack"),t.z.literal("damage"),t.z.literal("initiative"),t.z.literal("spellAttack"),t.z.literal("spellSaveDC"),t.z.literal("hpMax"),t.z.literal("speed"),t.z.literal("passivePerception"),t.z.object({kind:t.z.literal("save"),ability:B}),t.z.object({kind:t.z.literal("check"),ability:B}),t.z.object({kind:t.z.literal("skill"),skill:ae})]),Sa=t.z.union([t.z.literal("attack"),t.z.literal("damage"),t.z.literal("initiative"),t.z.object({kind:t.z.literal("save"),ability:B}),t.z.object({kind:t.z.literal("check"),ability:B}),t.z.object({kind:t.z.literal("skill"),skill:ae})]),ts=t.z.union([t.z.object({kind:t.z.literal("AddDamage"),dice:_,damageType:M}),t.z.object({kind:t.z.literal("Heal"),amount:t.z.union([t.z.number(),P])}),t.z.object({kind:t.z.literal("ApplyCondition"),conditionId:t.z.string(),durationRounds:t.z.number().int().optional()}),t.z.object({kind:t.z.literal("SpendResource"),resourceId:t.z.string(),amount:t.z.number().int().min(1)}),t.z.object({kind:t.z.literal("ModifyDamageTaken"),amount:t.z.union([t.z.number(),P]),cap:t.z.number().optional()}),t.z.object({kind:t.z.literal("EmitEvent"),eventType:t.z.string(),payload:t.z.unknown().optional()})]),U=t.z.lazy(()=>t.z.union([t.z.object({kind:t.z.literal("GrantProficiency"),target:t.z.enum(["skill","tool","weapon","armor","save","language"]),id:t.z.string(),level:na}),t.z.object({kind:t.z.literal("GrantSense"),sense:sa,range:t.z.number().int().min(0)}),t.z.object({kind:t.z.literal("ModifySpeed"),mode:ia,op:t.z.enum(["set","add","multiply"]),value:t.z.number()}),t.z.object({kind:t.z.literal("AddModifier"),target:ba,value:t.z.union([t.z.number(),P]),condition:H.optional()}),t.z.object({kind:t.z.literal("SetAdvantage"),on:Sa,mode:t.z.enum(["advantage","disadvantage","auto-crit","auto-fail"]),condition:H.optional()}),t.z.object({kind:t.z.literal("GrantResistance"),damageType:t.z.union([M,t.z.literal("all")]),condition:H.optional()}),t.z.object({kind:t.z.literal("GrantImmunity"),damageType:t.z.union([M,t.z.literal("all")])}),t.z.object({kind:t.z.literal("GrantVulnerability"),damageType:M}),t.z.object({kind:t.z.literal("GrantConditionImmunity"),conditionId:t.z.string()}),t.z.object({kind:t.z.literal("OverrideACFormula"),base:t.z.union([t.z.number(),t.z.literal("dex"),t.z.literal("con"),t.z.literal("wis")]),abilityModifiers:t.z.array(B),dexCap:t.z.number().optional(),priority:t.z.number().int().optional()}),t.z.object({kind:t.z.literal("GrantResource"),resourceId:t.z.string(),max:t.z.union([t.z.number().int().min(0),P]),recharge:Ve,diceSize:t.z.number().int().optional()}),t.z.object({kind:t.z.literal("GrantSpellSlots"),level:ge,count:t.z.number().int().min(0),source:t.z.enum(["full","half","third","pact"])}),t.z.object({kind:t.z.literal("GrantSpell"),spellId:t.z.string(),preparation:t.z.enum(["always-prepared","prepared","known","at-will","oncePerLongRest","oncePerShortRest"]),spellcastingAbility:B.optional()}),t.z.object({kind:t.z.literal("OnEvent"),id:t.z.string().optional(),trigger:t.z.object({eventType:t.z.string(),filter:H.optional()}),actions:t.z.array(ts),oncePer:t.z.enum(["turn","round","shortRest","longRest"]).optional(),requiresReaction:t.z.boolean().optional()}),t.z.object({kind:t.z.literal("RecoverResource"),resourceId:t.z.string(),amount:t.z.union([t.z.number(),t.z.literal("all"),P]),when:t.z.enum(["shortRest","longRest","turnStart","turnEnd","dawn"])}),t.z.object({kind:t.z.literal("GrantAction"),actionId:t.z.string(),name:t.z.string(),cost:t.z.enum(["action","bonusAction","reaction","free"]),resourceCost:t.z.object({resourceId:t.z.string(),amount:t.z.number().int().min(1)}).optional()}),t.z.object({kind:t.z.literal("ModifyActionEconomy"),op:t.z.enum(["extraAttack","extraAction","extraBonusAction"]),count:t.z.number().int().min(1),condition:H.optional()}),t.z.object({kind:t.z.literal("GrantWeaponMastery"),masteries:t.z.array(Ee),slots:t.z.number().int().min(1)}),t.z.object({kind:t.z.literal("ExpandSpellList"),classId:t.z.string(),spellIds:t.z.array(t.z.string())}),t.z.object({kind:t.z.literal("SetHPMaxFormula"),formula:P}),t.z.object({kind:t.z.literal("OfferChoice"),choiceId:t.z.string(),prompt:t.z.string(),options:t.z.array(t.z.object({id:t.z.string(),label:t.z.string(),effects:t.z.array(U)})).min(1),oneOf:t.z.number().int().min(1),when:t.z.enum(["onAcquire","onLevelUp","onLongRest"])}),t.z.object({kind:t.z.literal("FlatDamageReduction"),damageTypes:t.z.array(M).min(1),amount:t.z.number().int().min(1)}),t.z.object({kind:t.z.literal("Custom"),handlerId:t.z.string(),params:t.z.unknown().optional()})])),as=["GrantProficiency","GrantSense","ModifySpeed","AddModifier","SetAdvantage","GrantResistance","GrantImmunity","GrantVulnerability","GrantConditionImmunity","OverrideACFormula","GrantResource","GrantSpellSlots","GrantSpell","OnEvent","RecoverResource","GrantAction","ModifyActionEconomy","GrantWeaponMastery","ExpandSpellList","SetHPMaxFormula","OfferChoice","FlatDamageReduction","Custom"],va=t.z.object({id:t.z.string(),name:t.z.string(),description:t.z.string().optional(),effects:t.z.array(U).default([]),stackable:t.z.boolean().default(!1),endsOn:t.z.array(t.z.union([t.z.object({kind:t.z.literal("shortRest")}),t.z.object({kind:t.z.literal("longRest")}),t.z.object({kind:t.z.literal("turnEnd"),ownerId:t.z.string().optional()}),t.z.object({kind:t.z.literal("saveSuccess"),ability:t.z.string(),dc:t.z.number().int()}),t.z.object({kind:t.z.literal("damageTaken")})])).default([])}),za=t.z.object({id:t.z.string(),name:t.z.string(),size:je,creatureType:qe.default("Humanoid"),speed:He,languages:t.z.array(t.z.string()).default([]),traits:t.z.array(U).default([])}),Ca=t.z.object({id:t.z.string(),name:t.z.string(),abilityScoreIncreases:t.z.object({options:t.z.array(B).min(2),pattern:t.z.enum(["+2/+1","+1/+1/+1"])}),skillProficiencies:t.z.array(ae).default([]),toolProficiencies:t.z.array(t.z.string()).default([]),languages:t.z.array(t.z.string()).default([]),originFeatId:t.z.string(),traits:t.z.array(U).default([])}),Ea=t.z.object({id:t.z.string(),name:t.z.string(),category:t.z.enum(["origin","general","fighting-style","epic-boon"]),repeatable:t.z.boolean().default(!1),prerequisites:t.z.array(t.z.string()).default([]),effects:t.z.array(U).default([])}),Xe=t.z.object({id:t.z.string(),name:t.z.string(),description:t.z.string().optional(),effects:t.z.array(U).default([])}),ns=t.z.object({proficiencyBonus:t.z.number().int().min(2).max(6),features:t.z.array(Xe).default([]),columns:t.z.record(t.z.string(),t.z.union([t.z.number(),t.z.string()])).default({})}),ka=t.z.object({ability:B,type:t.z.enum(["full","half","third","pact"]),preparedFormula:t.z.string().optional()}),Aa=t.z.object({id:t.z.string(),name:t.z.string(),hitDie:ra,primaryAbility:t.z.array(B).min(1),savingThrowProficiencies:t.z.array(B).length(2),armorProficiencies:t.z.array(t.z.string()).default([]),weaponProficiencies:t.z.array(t.z.string()).default([]),toolProficiencies:t.z.array(t.z.string()).default([]),skillChoices:t.z.object({choices:t.z.number().int().min(0),from:t.z.array(ae)}).optional(),levelTable:t.z.record(t.z.string().regex(/^([1-9]|1[0-9]|20)$/,"Level keys must be 1..20"),ns).superRefine((a,e)=>{for(const n of Object.keys(a)){const o=Number.parseInt(n,10);(o<Ge||o>Ce)&&e.addIssue({code:t.z.ZodIssueCode.custom,message:`Level key ${n} out of range`})}}),subclassLevel:t.z.number().int().min(1).max(Ce).optional(),spellcasting:ka.optional()}),wa=t.z.object({id:t.z.string(),parentClassId:t.z.string(),name:t.z.string(),levelGrants:t.z.record(t.z.string(),t.z.array(Xe)).default({})}),os=[5,11,17],rs=t.z.object({kind:t.z.literal("attack"),damageDice:_,damageType:M,extraDicePerSlotLevel:t.z.number().int().min(0).optional(),cantripScalingDice:_.optional()}),is=t.z.object({kind:t.z.literal("save"),ability:B,damageDice:_.optional(),damageType:M.optional(),halfOnSuccess:t.z.boolean().optional(),conditionOnFail:t.z.string().optional(),extraDicePerSlotLevel:t.z.number().int().min(0).optional(),cantripScalingDice:_.optional()}),ss=t.z.object({kind:t.z.literal("heal"),amountDice:_,extraDicePerSlotLevel:t.z.number().int().min(0).optional()}),cs=["cone","cube","line","sphere","cylinder"],ds=t.z.enum(cs),ls=t.z.object({shape:ds,size:t.z.number().int().min(1)}),Ra=a=>{let e=0;for(const n of os)a>=n&&(e+=1);return e},us=t.z.discriminatedUnion("kind",[rs,is,ss]),Ta=t.z.object({id:t.z.string(),name:t.z.string(),level:ge,school:da,castingTime:t.z.string(),range:t.z.string(),components:t.z.object({verbal:t.z.boolean().default(!1),somatic:t.z.boolean().default(!1),material:t.z.string().optional()}),duration:t.z.string(),concentration:t.z.boolean().default(!1),ritual:t.z.boolean().default(!1),classes:t.z.array(t.z.string()).default([]),description:t.z.string().optional(),mechanicalEffects:t.z.array(us).default([]),targeting:ls.optional()}),ce=t.z.object({id:t.z.string(),name:t.z.string(),weight:t.z.number().nonnegative().optional(),cost:t.z.object({amount:t.z.number().int().min(0),currency:t.z.enum(["cp","sp","ep","gp","pp"])}).optional()}),Da=ce.extend({itemKind:t.z.literal("weapon"),category:t.z.enum(["simple","martial"]),attackKind:t.z.enum(["melee","ranged"]),damageType:M,damageDice:_,versatileDice:_.optional(),properties:t.z.array(We).default([]),mastery:Ee.optional(),rangeNormal:t.z.number().int().optional(),rangeLong:t.z.number().int().optional()}),Ba=ce.extend({itemKind:t.z.literal("armor"),category:t.z.enum(["light","medium","heavy","shield"]),baseAC:t.z.number().int().min(0),dexCap:t.z.number().int().optional(),strRequirement:t.z.number().int().optional(),stealthDisadvantage:t.z.boolean().default(!1)}),xa=ce.extend({itemKind:t.z.literal("tool"),category:t.z.enum(["artisan","gaming","musical","other"])}),Ma=ce.extend({itemKind:t.z.literal("magic"),rarity:t.z.enum(["common","uncommon","rare","very-rare","legendary","artifact"]),requiresAttunement:t.z.boolean().default(!1),attunementCondition:t.z.string().optional(),charges:t.z.object({max:t.z.number().int().min(1),recharge:Ve,rechargeFormula:_.optional()}).optional(),effects:t.z.array(U).default([])}),Pa=ce.extend({itemKind:t.z.literal("consumable"),onConsume:t.z.array(U).default([]),description:t.z.string().optional()}),La=ce.extend({itemKind:t.z.literal("gear"),description:t.z.string().optional()}),$a=t.z.discriminatedUnion("itemKind",[Da,Ba,xa,Ma,Pa,La]),Oa=t.z.object({id:t.z.string(),name:t.z.string(),size:je,type:qe,subtype:t.z.string().optional(),alignment:fa.default("unaligned"),ac:t.z.number().int().min(0),hp:t.z.object({average:t.z.number().int().min(1),formula:t.z.string()}),speed:He,abilityScores:he,savingThrows:t.z.record(t.z.string(),t.z.number().int()).optional(),skills:t.z.record(ae,t.z.number().int()).optional(),damageResistances:t.z.array(M).default([]),damageImmunities:t.z.array(M).default([]),damageVulnerabilities:t.z.array(M).default([]),conditionImmunities:t.z.array(t.z.string()).default([]),senses:ca.optional(),languages:t.z.array(t.z.string()).default([]),cr:t.z.number().min(0),xp:t.z.number().int().min(0),proficiencyBonus:t.z.number().int().min(2).max(9),traits:t.z.array(U).default([])}),_a=t.z.object({resourceId:t.z.string(),current:t.z.number().int().min(0),max:t.z.number().int().min(0)}),Na=t.z.object({id:s,conditionId:t.z.string(),sourceEventId:s.optional(),level:t.z.number().int().min(1).optional(),expiresOnRound:t.z.number().int().optional()}),Fa=t.z.object({current:t.z.number().int(),max:t.z.number().int().min(1),temp:t.z.number().int().min(0).default(0)}),Ua=t.z.object({successes:t.z.number().int().min(0).max(3).default(0),failures:t.z.number().int().min(0).max(3).default(0),stable:t.z.boolean().default(!1)}),ja=t.z.object({classId:t.z.string(),subclassId:t.z.string().optional(),level:ma,hitDiceRemaining:t.z.number().int().min(0)}),ms=["pc","npc","creature"],ps=t.z.enum(ms),hs=t.z.object({name:t.z.string(),attacks:t.z.array(t.z.object({weaponInstanceId:s,count:t.z.number().int().min(1)})).min(1)}),ke=t.z.object({id:s,kind:ps.default("pc"),statblockId:t.z.string().optional(),multiattack:hs.optional(),name:t.z.string().min(1),playerId:t.z.string().optional(),speciesId:t.z.string(),backgroundId:t.z.string(),classes:t.z.array(ja).min(1),abilityScores:he,hp:Fa,deathSaves:Ua.default({successes:0,failures:0,stable:!1}),exhaustion:ha.default(0),speedFeet:t.z.number().int().min(0).default(30),inventory:t.z.array(s).default([]),equipped:t.z.object({mainHand:s.optional(),offHand:s.optional(),armor:s.optional(),shield:s.optional(),attuned:t.z.array(s).max(3).default([])}).default({attuned:[]}),resources:t.z.array(_a).default([]),appliedConditions:t.z.array(Na).default([]),knownSpells:t.z.array(t.z.string()).default([]),preparedSpells:t.z.array(t.z.string()).default([]),spellSlotsUsed:t.z.record(t.z.string().regex(/^[1-9]$/,"Slot level keys must be 1..9"),t.z.number().int().min(0)).default({}),pactSlotsUsed:t.z.number().int().min(0).default(0),concentrationEffectId:s.optional(),triggerCounters:t.z.record(t.z.string(),t.z.object({firedThisTurn:t.z.boolean().optional(),firedThisRound:t.z.boolean().optional(),firedThisShortRest:t.z.boolean().optional(),firedThisLongRest:t.z.boolean().optional()})).default({}),featsTaken:t.z.array(t.z.string()).default([]),pendingChoiceIds:t.z.array(s).default([]),xp:t.z.number().int().min(0).default(0),mountedOnId:s.optional(),attitude:t.z.enum(["hostile","unfriendly","indifferent","friendly","helpful"]).optional(),morale:t.z.object({current:t.z.number().int(),max:t.z.number().int().min(1)}).optional(),moraleBroken:t.z.boolean().default(!1),polymorphedSnapshot:t.z.object({hp:t.z.object({current:t.z.number().int(),max:t.z.number().int().min(1),temp:t.z.number().int().min(0).default(0)}),abilityScores:he,speedFeet:t.z.number().int().min(0),speciesId:t.z.string(),kind:t.z.enum(["polymorph","wild-shape","true-polymorph"]),formName:t.z.string()}).optional()}),N=a=>a.classes.reduce((e,n)=>e+n.level,0),Qe=t.z.object({id:s,definitionId:t.z.string(),customName:t.z.string().optional(),quantity:t.z.number().int().min(1).default(1),chargesRemaining:t.z.number().int().min(0).optional(),attuned:t.z.boolean().default(!1),attunedTo:s.optional(),equippedBy:s.optional(),containerId:s.optional(),acquiredAtEventId:s.optional(),identifiedByCharacterIds:t.z.array(s).default([]),maxCharges:t.z.number().int().min(0).optional(),sentient:t.z.object({ego:t.z.number().int().min(0),alignment:t.z.string(),personality:t.z.string().optional()}).optional()}),qa=t.z.object({targetId:s,conditionId:t.z.string(),appliedConditionId:s}),fs=t.z.object({id:s,spellId:t.z.string(),casterId:s,targetIds:t.z.array(s).default([]),conditionsApplied:t.z.array(qa).default([]),requiresConcentration:t.z.boolean(),durationRounds:t.z.number().int().min(0).optional(),startedAtEventId:s}),Ye=t.z.object({id:t.z.string(),label:t.z.string(),effects:t.z.array(U).default([])}),Ha=t.z.object({id:s,prompt:t.z.string(),options:t.z.array(Ye).min(1),oneOf:t.z.number().int().min(1).default(1),forCharacterId:s,triggerEventId:s,resolution:t.z.object({selectedOptionIds:t.z.array(t.z.string()).min(1),atEventId:s}).optional()}),Ga=t.z.enum(["planning","active","ended"]),fe=t.z.object({x:t.z.number(),y:t.z.number()}),Is=t.z.object({actionUsed:t.z.boolean().default(!1),bonusActionUsed:t.z.boolean().default(!1),attacksMadeThisTurn:t.z.number().int().min(0).default(0),reactionUsedThisRound:t.z.boolean().default(!1),feetMovedThisTurn:t.z.number().min(0).default(0),dashed:t.z.boolean().default(!1),disengaged:t.z.boolean().default(!1)}),gs={actionUsed:!1,bonusActionUsed:!1,attacksMadeThisTurn:0,reactionUsedThisRound:!1,feetMovedThisTurn:0,dashed:!1,disengaged:!1},Ka=t.z.object({combatantId:s,initiative:t.z.number().int(),initiativeOrder:t.z.number().int().min(0),hasActedThisRound:t.z.boolean().default(!1),turnUsage:Is.default(gs),position:fe.optional()}),Va=t.z.object({id:s,name:t.z.string().optional(),status:Ga,combatants:t.z.array(Ka).default([]),round:t.z.number().int().min(0),activeIndex:t.z.number().int().min(0),startedAtEventId:s.optional(),endedAtEventId:s.optional(),outcome:t.z.enum(["victory","defeat","fled","parley"]).optional()}),Je=Ia,ys=10,bs=50,Ss=100,vs=1e3,zs={cp:1,sp:ys,ep:bs,gp:Ss,pp:vs},de=()=>({cp:0,sp:0,ep:0,gp:0,pp:0}),Cs=a=>Je.reduce((e,n)=>e+a[n]*zs[n],0),Ze=(a,e)=>({cp:a.cp+e.cp,sp:a.sp+e.sp,ep:a.ep+e.ep,gp:a.gp+e.gp,pp:a.pp+e.pp}),Wa=(a,e)=>{const n={cp:a.cp-e.cp,sp:a.sp-e.sp,ep:a.ep-e.ep,gp:a.gp-e.gp,pp:a.pp-e.pp};for(const o of Je)if(n[o]<0)throw new Error(`Insufficient ${o}: have ${a[o]}, need ${e[o]}`);return n},Xa=t.z.object({id:s,name:t.z.string().min(1),memberIds:t.z.array(s).default([]),sharedInventory:t.z.array(s).default([]),purse:ye.default(de())}),se=t.z.object({totalMinutes:t.z.number().int().min(0).default(0)}),Oe=60,Es=24,kt=Oe*Es,Qa=a=>({days:Math.floor(a.totalMinutes/kt),hours:Math.floor(a.totalMinutes%kt/Oe),minutes:a.totalMinutes%Oe}),ks=a=>{const{days:e,hours:n,minutes:o}=Qa(a),r=String(e).padStart(2,"0"),i=String(n).padStart(2,"0"),d=String(o).padStart(2,"0");return`Day ${r} ${i}:${d}`},Ya=(a,e)=>{if(e<0)throw new Error("Cannot advance in-game time by a negative amount");return{totalMinutes:a.totalMinutes+e}},Ja=t.z.object({id:s,name:t.z.string().min(1),startedAtIso:t.z.string(),endedAtIso:t.z.string().optional(),inGameStart:se,inGameEnd:se.optional(),summary:t.z.string().optional(),journalEntryIds:t.z.array(s).default([])}),Za=["player","dm"],et=t.z.enum(Za),en=["party","dm-only","character"],tt=t.z.enum(en),tn=t.z.object({id:s,sessionId:s.optional(),authorKind:et,authorCharacterId:s.optional(),visibility:tt,visibleToCharacterIds:t.z.array(s).default([]),title:t.z.string().min(1),body:t.z.string(),createdAtIso:t.z.string(),inGameAt:se}),an=["normal","difficult","impassable","water"],nn=t.z.enum(an),Ae=5,on=1,rn=2,at=t.z.object({widthCells:t.z.number().int().min(1),heightCells:t.z.number().int().min(1),cellSizeFeet:t.z.number().int().min(1).default(Ae),terrain:t.z.array(t.z.array(nn))}),sn=["open","closed","locked"],we=t.z.enum(sn),cn=t.z.object({id:s,locationId:s,name:t.z.string().optional(),position:fe,state:we}),dn=t.z.object({id:s,name:t.z.string().min(1),description:t.z.string().optional(),parentLocationId:s.optional(),map:at.optional(),doorIds:t.z.array(s).default([])}),ln=["active","completed","failed","abandoned"],un=t.z.enum(ln),mn=["pending","completed","failed"],pn=t.z.enum(mn),nt=t.z.object({id:s,description:t.z.string().min(1),status:pn.default("pending"),optional:t.z.boolean().default(!1),progress:t.z.number().int().min(0).default(0),required:t.z.number().int().min(1).optional()}),ot=t.z.object({xpPerCharacter:t.z.number().int().min(0).default(0),currency:ye.default(de()),itemDefinitionIds:t.z.array(t.z.string()).default([])}),hn=t.z.object({id:s,title:t.z.string().min(1),description:t.z.string().optional(),status:un.default("active"),partyId:s.optional(),objectives:t.z.array(nt).default([]),reward:ot.default({xpPerCharacter:0,currency:de(),itemDefinitionIds:[]}),rewardClaimed:t.z.boolean().default(!1),startedAtIso:t.z.string().optional(),endedAtIso:t.z.string().optional()}),f=t.z.object({id:s,at:t.z.string(),sessionId:s.optional(),causedByEventId:s.optional(),actorId:s.optional()}),fn=f.extend({type:t.z.literal("QuestStarted"),questId:s,title:t.z.string().min(1),description:t.z.string().optional(),partyId:s.optional(),objectives:t.z.array(nt).default([]),reward:ot.optional()}),In=f.extend({type:t.z.literal("ObjectiveProgressed"),questId:s,objectiveId:s,delta:t.z.number().int().min(1).default(1)}),gn=f.extend({type:t.z.literal("ObjectiveCompleted"),questId:s,objectiveId:s}),yn=f.extend({type:t.z.literal("ObjectiveFailed"),questId:s,objectiveId:s}),bn=f.extend({type:t.z.literal("QuestCompleted"),questId:s}),Sn=f.extend({type:t.z.literal("QuestFailed"),questId:s,reason:t.z.string().optional()}),vn=f.extend({type:t.z.literal("QuestAbandoned"),questId:s,reason:t.z.string().optional()}),zn=f.extend({type:t.z.literal("QuestRewardClaimed"),questId:s,beneficiaryCharacterIds:t.z.array(s).default([])}),Cn=f.extend({type:t.z.literal("XPAwarded"),characterId:s,amount:t.z.number().int().min(1),source:t.z.string().optional(),questId:s.optional()}),En=["minor","major","campaign"],rt=t.z.enum(En),kn=f.extend({type:t.z.literal("MilestoneAwarded"),kind:rt,title:t.z.string().min(1),partyId:s.optional(),questId:s.optional()}),An=["land","water","air"],it=t.z.enum(An),wn=t.z.object({id:s,name:t.z.string().min(1),kind:it,speedFeet:t.z.number().int().min(0),ac:t.z.number().int().min(0),hp:t.z.object({current:t.z.number().int(),max:t.z.number().int().min(1)}),capacity:t.z.number().int().min(1),occupantIds:t.z.array(s).default([])}),As=["slow","normal","fast"],Rn=t.z.enum(As),ws=t.z.object({partyId:s,pace:Rn,hours:t.z.number().min(0),miles:t.z.number().min(0),fromLocationId:s.optional(),toLocationId:s.optional(),notes:t.z.string().optional(),atIso:t.z.string()}),Tn=["crafting","training","recuperating","research","work","other"],st=t.z.enum(Tn),Dn=["success","partial","failure"],ct=t.z.enum(Dn),Bn=f.extend({type:t.z.literal("DowntimeActivityResolved"),characterId:s,kind:st,days:t.z.number().int().min(1),outcome:ct,summary:t.z.string().min(1),producedItemDefinitionId:t.z.string().optional(),toolProficiencyGained:t.z.string().optional()}),Rs=t.z.object({characterId:s,kind:st,days:t.z.number().int().min(1),outcome:ct,summary:t.z.string(),atIso:t.z.string(),producedItemDefinitionId:t.z.string().optional(),toolProficiencyGained:t.z.string().optional()}),Ts=["basic","special"],xn=t.z.enum(Ts),Ds=["cramped","roomy","vast"],Mn=t.z.enum(Ds),Bs=t.z.object({id:s,name:t.z.string().min(1),kind:xn,space:Mn,description:t.z.string().optional()}),xs=t.z.object({id:s,name:t.z.string().min(1),role:t.z.string().min(1)}),Ms=t.z.object({id:s,name:t.z.string().min(1),ownerCharacterId:s,locationId:s.optional(),level:t.z.number().int().min(1).max(9),facilities:t.z.array(Bs).default([]),hirelings:t.z.array(xs).default([]),defenders:t.z.number().int().min(0).default(0),treasuryGp:t.z.number().int().min(0).default(0),hpCurrent:t.z.number().int().min(0),hpMax:t.z.number().int().min(1)}),Pn=t.z.object({grittyRest:t.z.boolean().default(!1),heroPoints:t.z.boolean().default(!1),sanity:t.z.boolean().default(!1),massCombat:t.z.boolean().default(!1),feaCharacterFlaws:t.z.boolean().default(!1),customHouserules:t.z.array(t.z.string()).default([])}),dt=()=>({grittyRest:!1,heroPoints:!1,sanity:!1,massCombat:!1,feaCharacterFlaws:!1,customHouserules:[]}),Ps=t.z.object({characters:t.z.record(s,ke).default({}),itemInstances:t.z.record(s,Qe).default({}),pendingChoices:t.z.record(s,Ha).default({}),encounters:t.z.record(s,Va).default({}),effectInstances:t.z.record(s,fs).default({}),parties:t.z.record(s,Xa).default({}),sessions:t.z.record(s,Ja).default({}),journalEntries:t.z.record(s,tn).default({}),locations:t.z.record(s,dn).default({}),doors:t.z.record(s,cn).default({}),characterLocations:t.z.record(s,s).default({}),quests:t.z.record(s,hn).default({}),vehicles:t.z.record(s,wn).default({}),travelLog:t.z.array(ws).default([]),downtimeLog:t.z.array(Rs).default([]),toolProficienciesByCharacter:t.z.record(s,t.z.array(t.z.string())).default({}),bastions:t.z.record(s,Ms).default({}),settings:Pn.default(dt()),milestones:t.z.array(t.z.object({kind:rt,title:t.z.string(),atIso:t.z.string(),partyId:s.optional(),questId:s.optional()})).default([]),inGameTime:se.default({totalMinutes:0}),activeSessionId:s.optional(),activeShortRest:t.z.object({startedAtEventId:s,participantIds:t.z.array(s)}).optional(),activeLongRest:t.z.object({startedAtEventId:s,participantIds:t.z.array(s)}).optional(),activeEncounterId:s.optional(),version:t.z.number().int().min(0).default(0)}),lt=()=>({characters:{},itemInstances:{},pendingChoices:{},encounters:{},effectInstances:{},parties:{},sessions:{},journalEntries:{},locations:{},doors:{},characterLocations:{},quests:{},vehicles:{},travelLog:[],downtimeLog:[],toolProficienciesByCharacter:{},bastions:{},settings:dt(),milestones:[],inGameTime:{totalMinutes:0},version:0}),Ls=["resisted","immune","vulnerable"],$s=t.z.enum(Ls),Os=t.z.object({amount:t.z.number().int().min(0),type:M,rawAmount:t.z.number().int().min(0).optional(),mitigation:$s.optional()}),Ln=f.extend({type:t.z.literal("DamageApplied"),targetId:s,components:t.z.array(Os).min(1)}),$n=f.extend({type:t.z.literal("Healed"),targetId:s,amount:t.z.number().int().min(0),source:t.z.string().optional()}),On=f.extend({type:t.z.literal("TempHPGranted"),targetId:s,amount:t.z.number().int().min(0),source:t.z.string().optional()}),_n=f.extend({type:t.z.literal("ConditionApplied"),targetId:s,conditionId:t.z.string(),level:t.z.number().int().min(1).optional(),expiresOnRound:t.z.number().int().optional(),appliedConditionId:s.optional()}),Nn=f.extend({type:t.z.literal("ConditionRemoved"),targetId:s,conditionId:t.z.string()}),Fn=f.extend({type:t.z.literal("ExhaustionChanged"),targetId:s,fromLevel:t.z.number().int().min(0).max(6),toLevel:t.z.number().int().min(0).max(6)}),Un=f.extend({type:t.z.literal("DeathSaveRolled"),targetId:s,d20:t.z.number().int().min(1).max(20),success:t.z.boolean(),critical:t.z.boolean().default(!1)}),jn=f.extend({type:t.z.literal("Stabilized"),targetId:s}),qn=f.extend({type:t.z.literal("ResourceSpent"),characterId:s,resourceId:t.z.string(),amount:t.z.number().int().min(1)}),Hn=f.extend({type:t.z.literal("ResourceRestored"),characterId:s,resourceId:t.z.string(),amount:t.z.union([t.z.number().int().min(0),t.z.literal("all")])}),Gn=f.extend({type:t.z.literal("HitDieSpent"),characterId:s,die:t.z.union([t.z.literal(6),t.z.literal(8),t.z.literal(10),t.z.literal(12)]),rolled:t.z.number().int().min(1),conMod:t.z.number().int(),healed:t.z.number().int().min(0)}),Kn=f.extend({type:t.z.literal("ShortRestStarted"),participantIds:t.z.array(s).min(1)}),Vn=f.extend({type:t.z.literal("ShortRestEnded")}),Wn=f.extend({type:t.z.literal("LongRestStarted"),participantIds:t.z.array(s).min(1)}),Xn=f.extend({type:t.z.literal("LongRestEnded")}),Qn=f.extend({type:t.z.literal("CharacterCreated"),snapshot:ke}),Yn=f.extend({type:t.z.literal("EncounterCreated"),encounterId:s,name:t.z.string().optional(),combatantIds:t.z.array(s).min(1)}),Jn=t.z.object({combatantId:s,d20:t.z.number().int().min(1).max(20),modifier:t.z.number().int(),total:t.z.number().int()}),Zn=f.extend({type:t.z.literal("InitiativeRolled"),encounterId:s,rolls:t.z.array(Jn).min(1)}),eo=f.extend({type:t.z.literal("EncounterStarted"),encounterId:s}),to=f.extend({type:t.z.literal("TurnStarted"),encounterId:s,combatantId:s,round:t.z.number().int().min(1)}),ao=f.extend({type:t.z.literal("TurnEnded"),encounterId:s,combatantId:s,round:t.z.number().int().min(1)}),no=f.extend({type:t.z.literal("RoundEnded"),encounterId:s,round:t.z.number().int().min(1)}),oo=f.extend({type:t.z.literal("EncounterEnded"),encounterId:s,outcome:t.z.enum(["victory","defeat","fled","parley"])}),ro=t.z.enum(["none","advantage","disadvantage"]),io=f.extend({type:t.z.literal("AttackRolled"),attackerId:s,targetId:s,weaponInstanceId:s,d20:t.z.array(t.z.number().int().min(1).max(20)).min(1).max(2),used:ro,attackBonus:t.z.number().int(),total:t.z.number().int(),targetAC:t.z.number().int(),hit:t.z.boolean(),critical:t.z.boolean()}),so=t.z.object({expression:_,rolls:t.z.array(t.z.number().int().min(1)),modifier:t.z.number().int(),type:M}),co=f.extend({type:t.z.literal("DamageRolled"),attackerId:s,targetId:s,weaponInstanceId:s,rolls:t.z.array(so).min(1),critical:t.z.boolean()}),lo=f.extend({type:t.z.literal("ItemAcquired"),instance:Qe}),_s=["mainHand","offHand","armor","shield"],uo=t.z.enum(_s),Ns=f.extend({type:t.z.literal("ItemEquipped"),characterId:s,instanceId:s,slot:uo}),Fs=f.extend({type:t.z.literal("ItemUnequipped"),characterId:s,slot:uo}),Us=f.extend({type:t.z.literal("ItemAttuned"),characterId:s,instanceId:s}),js=f.extend({type:t.z.literal("ItemUnattuned"),characterId:s,instanceId:s}),mo=t.z.enum(["roll","average"]),po=f.extend({type:t.z.literal("LevelUpResolved"),characterId:s,classId:t.z.string(),newClassLevel:t.z.number().int().min(2).max(20),hpStrategy:mo,hpRoll:t.z.number().int().min(1).optional(),hpGained:t.z.number().int().min(1)}),ho=f.extend({type:t.z.literal("ChoiceRequired"),choiceId:s,characterId:s,promptKey:t.z.string(),prompt:t.z.string(),options:t.z.array(Ye).min(1),oneOf:t.z.number().int().min(1)}),fo=f.extend({type:t.z.literal("ChoiceResolved"),choiceId:s,characterId:s,selectedOptionIds:t.z.array(t.z.string()).min(1)}),ut=t.z.enum(["none","advantage","disadvantage"]),Io=f.extend({type:t.z.literal("SaveRolled"),targetId:s,ability:B,dc:t.z.number().int().min(1),d20:t.z.array(t.z.number().int().min(1).max(20)).min(1).max(2),used:ut,bonus:t.z.number().int(),total:t.z.number().int(),success:t.z.boolean()}),go=f.extend({type:t.z.literal("AbilityCheckRolled"),characterId:s,ability:B,skill:ae.optional(),dc:t.z.number().int().min(1).optional(),d20:t.z.array(t.z.number().int().min(1).max(20)).min(1).max(2),used:ut,bonus:t.z.number().int(),total:t.z.number().int(),success:t.z.boolean().optional()}),qs=t.z.enum(["standard","pact"]),Hs=f.extend({type:t.z.literal("SpellCastDeclared"),characterId:s,spellId:t.z.string(),slotLevel:ge,slotSource:qs,targetIds:t.z.array(s).default([]),castAsRitual:t.z.boolean().default(!1)}),Gs=f.extend({type:t.z.literal("SpellSlotConsumed"),characterId:s,slotLevel:ge}),Ks=f.extend({type:t.z.literal("PactSlotConsumed"),characterId:s}),Vs=f.extend({type:t.z.literal("ConcentrationStarted"),effectInstanceId:s,casterId:s,spellId:t.z.string(),targetIds:t.z.array(s).default([]),conditionsApplied:t.z.array(qa).default([]),durationRounds:t.z.number().int().min(0).optional()}),Ws=t.z.enum(["failedSave","newConcentrationSpell","voluntary","incapacitated","dead","durationEnded"]),Xs=f.extend({type:t.z.literal("ConcentrationBroken"),effectInstanceId:s,casterId:s,reason:Ws}),Qs=f.extend({type:t.z.literal("TriggerFired"),characterId:s,triggerId:t.z.string(),cadence:t.z.object({firedThisTurn:t.z.boolean().optional(),firedThisRound:t.z.boolean().optional(),firedThisShortRest:t.z.boolean().optional(),firedThisLongRest:t.z.boolean().optional()}).default({})}),Ys=["action","bonusAction","reaction","attack"],Js=t.z.enum(Ys),Zs=f.extend({type:t.z.literal("ActionEconomyConsumed"),encounterId:s,combatantId:s,kind:Js}),ec=f.extend({type:t.z.literal("CombatantMoved"),encounterId:s,combatantId:s,fromPosition:fe.optional(),toPosition:fe,feetTraveled:t.z.number().min(0)}),tc=f.extend({type:t.z.literal("Dashed"),encounterId:s,combatantId:s}),ac=f.extend({type:t.z.literal("Disengaged"),encounterId:s,combatantId:s}),nc=f.extend({type:t.z.literal("PartyCreated"),partyId:s,name:t.z.string().min(1),memberIds:t.z.array(s).default([])}),oc=f.extend({type:t.z.literal("PartyMembersChanged"),partyId:s,added:t.z.array(s).default([]),removed:t.z.array(s).default([])}),rc=f.extend({type:t.z.literal("CurrencyAcquired"),partyId:s,amounts:ye,source:t.z.string().optional()}),ic=f.extend({type:t.z.literal("CurrencySpent"),partyId:s,amounts:ye,purpose:t.z.string().optional()}),sc=f.extend({type:t.z.literal("ItemDepositedToParty"),partyId:s,itemInstanceId:s,sourceCharacterId:s.optional()}),cc=f.extend({type:t.z.literal("ItemWithdrawnFromParty"),partyId:s,itemInstanceId:s,recipientCharacterId:s.optional()}),dc=f.extend({type:t.z.literal("SessionStarted"),sessionId:s,name:t.z.string().min(1),inGameStart:se.optional()}),lc=f.extend({type:t.z.literal("SessionEnded"),sessionId:s,summary:t.z.string().optional()}),uc=f.extend({type:t.z.literal("JournalEntryAdded"),entryId:s,sessionId:s.optional(),authorKind:et,authorCharacterId:s.optional(),visibility:tt,visibleToCharacterIds:t.z.array(s).default([]),title:t.z.string().min(1),body:t.z.string()}),mc=f.extend({type:t.z.literal("InGameTimeAdvanced"),minutes:t.z.number().int().min(1),reason:t.z.string().optional()}),yo=f.extend({type:t.z.literal("LocationCreated"),locationId:s,name:t.z.string().min(1),description:t.z.string().optional(),parentLocationId:s.optional(),map:at.optional()}),bo=f.extend({type:t.z.literal("DoorAdded"),doorId:s,locationId:s,name:t.z.string().optional(),position:fe,state:we}),So=f.extend({type:t.z.literal("DoorStateChanged"),doorId:s,toState:we,byCharacterId:s.optional()}),vo=f.extend({type:t.z.literal("CharacterLocationChanged"),characterId:s,toLocationId:s.optional()}),zo=f.extend({type:t.z.literal("SpellCountered"),originalSpellEventId:s,counterCasterId:s,targetCasterId:s,spellId:t.z.string()}),Co=f.extend({type:t.z.literal("SpellDispelled"),effectInstanceId:s,dispelledByCharacterId:s}),Eo=f.extend({type:t.z.literal("ItemIdentified"),itemInstanceId:s,identifiedByCharacterId:s}),ko=f.extend({type:t.z.literal("WeaponMasteryActivated"),mastery:Ee,attackerId:s,targetId:s.optional(),weaponInstanceId:s}),Ao=f.extend({type:t.z.literal("Mounted"),riderId:s,mountId:s}),wo=f.extend({type:t.z.literal("Dismounted"),riderId:s,mountId:s,voluntary:t.z.boolean().default(!0)}),Ro=f.extend({type:t.z.literal("VehicleAcquired"),vehicleId:s,name:t.z.string().min(1),kind:it,speedFeet:t.z.number().int().min(0),ac:t.z.number().int().min(0),maxHp:t.z.number().int().min(1),capacity:t.z.number().int().min(1)}),To=f.extend({type:t.z.literal("VehicleBoarded"),vehicleId:s,characterId:s}),Do=f.extend({type:t.z.literal("VehicleDeparted"),vehicleId:s,characterId:s}),Bo=f.extend({type:t.z.literal("VehicleDamaged"),vehicleId:s,amount:t.z.number().int().min(0),source:t.z.string().optional()}),xo=f.extend({type:t.z.literal("VehicleRepaired"),vehicleId:s,amount:t.z.number().int().min(0)}),Mo=f.extend({type:t.z.literal("TravelLegCompleted"),partyId:s,pace:Rn,hours:t.z.number().min(0),miles:t.z.number().min(0),fromLocationId:s.optional(),toLocationId:s.optional(),notes:t.z.string().optional()}),Po=f.extend({type:t.z.literal("NavigationCheckRolled"),partyId:s,navigatorId:s,d20:t.z.number().int().min(1).max(20),bonus:t.z.number().int(),total:t.z.number().int(),dc:t.z.number().int(),success:t.z.boolean()}),Lo=f.extend({type:t.z.literal("ForagedFor"),partyId:s,foragerId:s,d20:t.z.number().int().min(1).max(20),bonus:t.z.number().int(),total:t.z.number().int(),dc:t.z.number().int(),success:t.z.boolean(),foodPounds:t.z.number().int().min(0).default(0),waterPounds:t.z.number().int().min(0).default(0)}),$o=["hostile","unfriendly","indifferent","friendly","helpful"],_e=t.z.enum($o),Oo=f.extend({type:t.z.literal("AttitudeChanged"),characterId:s,fromAttitude:_e.optional(),toAttitude:_e,cause:t.z.string().optional()}),_o=f.extend({type:t.z.literal("MoraleCheckRolled"),characterId:s,d20:t.z.number().int().min(1).max(20),bonus:t.z.number().int(),total:t.z.number().int(),dc:t.z.number().int(),success:t.z.boolean()}),No=f.extend({type:t.z.literal("MoraleBroken"),characterId:s,action:t.z.enum(["flee","surrender"])}),Fo=["dawn","dusk","shortRest","longRest","manual"],Uo=t.z.enum(Fo),jo=f.extend({type:t.z.literal("ItemChargeConsumed"),itemInstanceId:s,amount:t.z.number().int().min(1),byCharacterId:s.optional(),forEffect:t.z.string().optional()}),qo=f.extend({type:t.z.literal("ItemRecharged"),itemInstanceId:s,amount:t.z.number().int().min(1),cadence:Uo}),Ho=f.extend({type:t.z.literal("SentientItemConflict"),itemInstanceId:s,wielderId:s,winner:t.z.enum(["item","wielder"]),description:t.z.string().optional()}),Go=["maintain","craft","recruit","research","trade","empower"],Ko=t.z.enum(Go),Vo=f.extend({type:t.z.literal("BastionFounded"),bastionId:s,name:t.z.string().min(1),ownerCharacterId:s,locationId:s.optional(),level:t.z.number().int().min(1).max(9).default(1),hpMax:t.z.number().int().min(1).default(50)}),Wo=f.extend({type:t.z.literal("BastionFacilityAdded"),bastionId:s,facilityId:s,name:t.z.string().min(1),kind:xn,space:Mn,description:t.z.string().optional()}),Xo=f.extend({type:t.z.literal("BastionHirelingAdded"),bastionId:s,hirelingId:s,name:t.z.string().min(1),role:t.z.string().min(1)}),Qo=f.extend({type:t.z.literal("BastionTurnTaken"),bastionId:s,order:Ko,treasuryDeltaGp:t.z.number().int().default(0),summary:t.z.string().optional()}),Yo=f.extend({type:t.z.literal("BastionDamaged"),bastionId:s,amount:t.z.number().int().min(0),source:t.z.string().optional()}),Jo=f.extend({type:t.z.literal("BastionLevelChanged"),bastionId:s,fromLevel:t.z.number().int().min(1).max(9),toLevel:t.z.number().int().min(1).max(9)}),Zo=f.extend({type:t.z.literal("CampaignSettingsChanged"),grittyRest:t.z.boolean().optional(),heroPoints:t.z.boolean().optional(),sanity:t.z.boolean().optional(),massCombat:t.z.boolean().optional(),feaCharacterFlaws:t.z.boolean().optional(),customHouserulesAdd:t.z.array(t.z.string()).optional(),customHouserulesRemove:t.z.array(t.z.string()).optional()}),er=["revivify","raise-dead","reincarnate","resurrection","true-resurrection"],tr=t.z.enum(er),ar=f.extend({type:t.z.literal("CharacterResurrected"),characterId:s,spell:tr,byCharacterId:s.optional(),hpAfter:t.z.number().int().min(1),newSpeciesId:t.z.string().optional()}),nr=["polymorph","wild-shape","true-polymorph"],or=t.z.enum(nr),rr=t.z.object({name:t.z.string().min(1),hp:t.z.number().int().min(1),ac:t.z.number().int().min(0),abilityScores:he,speedFeet:t.z.number().int().min(0),speciesId:t.z.string().optional()}),ir=f.extend({type:t.z.literal("PolymorphApplied"),targetId:s,casterId:s.optional(),kind:or,form:rr}),sr=f.extend({type:t.z.literal("PolymorphReverted"),targetId:s,reason:t.z.enum(["voluntary","forced-zero-hp","duration-expired"]).default("voluntary")}),cr=f.extend({type:t.z.literal("SimulacrumCreated"),simulacrumId:s,originalId:s,hpMax:t.z.number().int().min(1)}),dr=f.extend({type:t.z.literal("WishGranted"),granterId:s,description:t.z.string().min(1),stressApplied:t.z.boolean().default(!1)}),lr=t.z.discriminatedUnion("type",[Qn,Ln,$n,On,_n,Nn,Fn,Un,jn,qn,Hn,Gn,Kn,Vn,Wn,Xn,Yn,eo,Zn,to,ao,no,oo,io,co,lo,po,ho,fo,Io,go,Hs,Gs,Ks,Vs,Xs,Qs,Zs,ec,tc,ac,Ns,Fs,Us,js,nc,oc,rc,ic,sc,cc,dc,lc,uc,mc,yo,bo,So,vo,fn,In,gn,yn,bn,Sn,vn,zn,Cn,kn,zo,Co,Eo,ko,Ao,wo,Ro,To,Do,Bo,xo,Mo,Po,Lo,Oo,_o,No,Bn,jo,qo,Ho,Vo,Wo,Xo,Qo,Yo,Jo,ar,ir,sr,cr,dr,Zo]),pc=["CharacterCreated","DamageApplied","Healed","TempHPGranted","ConditionApplied","ConditionRemoved","ExhaustionChanged","DeathSaveRolled","Stabilized","ResourceSpent","ResourceRestored","HitDieSpent","ShortRestStarted","ShortRestEnded","LongRestStarted","LongRestEnded","EncounterCreated","EncounterStarted","InitiativeRolled","TurnStarted","TurnEnded","RoundEnded","EncounterEnded","AttackRolled","DamageRolled","ItemAcquired","LevelUpResolved","ChoiceRequired","ChoiceResolved","SaveRolled","AbilityCheckRolled","SpellCastDeclared","SpellSlotConsumed","PactSlotConsumed","ConcentrationStarted","ConcentrationBroken","TriggerFired","ActionEconomyConsumed","CombatantMoved","Dashed","Disengaged","ItemEquipped","ItemUnequipped","ItemAttuned","ItemUnattuned","PartyCreated","PartyMembersChanged","CurrencyAcquired","CurrencySpent","ItemDepositedToParty","ItemWithdrawnFromParty","SessionStarted","SessionEnded","JournalEntryAdded","InGameTimeAdvanced","LocationCreated","DoorAdded","DoorStateChanged","CharacterLocationChanged","QuestStarted","ObjectiveProgressed","ObjectiveCompleted","ObjectiveFailed","QuestCompleted","QuestFailed","QuestAbandoned","QuestRewardClaimed","XPAwarded","MilestoneAwarded","SpellCountered","SpellDispelled","ItemIdentified","WeaponMasteryActivated","Mounted","Dismounted","VehicleAcquired","VehicleBoarded","VehicleDeparted","VehicleDamaged","VehicleRepaired","TravelLegCompleted","NavigationCheckRolled","ForagedFor","AttitudeChanged","MoraleCheckRolled","MoraleBroken","DowntimeActivityResolved","ItemChargeConsumed","ItemRecharged","SentientItemConflict","BastionFounded","BastionFacilityAdded","BastionHirelingAdded","BastionTurnTaken","BastionDamaged","BastionLevelChanged","CharacterResurrected","PolymorphApplied","PolymorphReverted","SimulacrumCreated","WishGranted","CampaignSettingsChanged"],ur=t.z.object({id:t.z.string(),name:t.z.string(),version:t.z.string(),species:t.z.array(za).default([]),backgrounds:t.z.array(Ca).default([]),classes:t.z.array(Aa).default([]),subclasses:t.z.array(wa).default([]),feats:t.z.array(Ea).default([]),spells:t.z.array(Ta).default([]),items:t.z.array($a).default([]),monsters:t.z.array(Oa).default([]),conditions:t.z.array(va).default([])}),mr=a=>{const e=new Map,n=new Map,o=new Map,r=new Map,i=new Map,d=new Map,p=new Map,l=new Map,c=new Map;for(const u of a){for(const h of u.species)e.set(h.id,h);for(const h of u.backgrounds)n.set(h.id,h);for(const h of u.classes)o.set(h.id,h);for(const h of u.subclasses)r.set(h.id,h);for(const h of u.feats)i.set(h.id,h);for(const h of u.spells)d.set(h.id,h);for(const h of u.items)p.set(h.id,h);for(const h of u.monsters)l.set(h.id,h);for(const h of u.conditions)c.set(h.id,h)}return{species:e,backgrounds:n,classes:o,subclasses:r,feats:i,spells:d,items:p,monsters:l,conditions:c}},hc=a=>a.length===0?"<root>":a.map(e=>String(e)).join(".");class pr extends Error{issues;constructor(e){const n=e.length===1?"1 issue":`${e.length} issues`,o=e.map(r=>` ${r.path}: ${r.message}`).join(`
2
+ `);super(`Content pack failed validation (${n}):
3
+ ${o}`),this.name="ContentPackLoadError",this.issues=e}}const hr=a=>{const e=ur.safeParse(a);if(e.success)return e.data;const n=e.error.issues.map(o=>({path:hc(o.path),message:o.message}));throw new pr(n)},fc=3,Ic=(a,e)=>{if(a===e)return 0;if(a.length===0)return e.length;if(e.length===0)return a.length;const n=Array.from({length:e.length+1},(o,r)=>r);for(let o=1;o<=a.length;o++){let r=o-1;n[0]=o;for(let i=1;i<=e.length;i++){const d=n[i],p=a[o-1]===e[i-1]?0:1;n[i]=Math.min(n[i]+1,n[i-1]+1,r+p),r=d}}return n[e.length]},gc=(a,e)=>{let n;for(const o of e){const r=Ic(a,o);r<=fc&&(n===void 0||r<n.distance)&&(n={id:o,distance:r})}return n?.id},At=(a,e,n,o)=>{const r=gc(n,o);return r!==void 0?{path:a,message:e,suggestion:`Did you mean "${r}"?`}:{path:a,message:e}},fr=a=>{const e=[];for(const[n,o]of a.backgrounds)a.feats.has(o.originFeatId)||e.push(At(`backgrounds.${n}.originFeatId`,`Origin feat "${o.originFeatId}" not found`,o.originFeatId,a.feats.keys()));for(const[n,o]of a.subclasses)a.classes.has(o.parentClassId)||e.push(At(`subclasses.${n}.parentClassId`,`Parent class "${o.parentClassId}" not found`,o.parentClassId,a.classes.keys()));return e},yc="starter-pack",bc="ttrpg-engine-dnd starter pack",Sc="0.1.0",vc=[{id:"human",name:"Human",size:"Medium",creatureType:"Humanoid",speed:{walk:30},languages:["common"],traits:[]},{id:"elf",name:"Elf",size:"Medium",creatureType:"Humanoid",speed:{walk:30},languages:["common","elvish"],traits:[]},{id:"dwarf",name:"Dwarf",size:"Medium",creatureType:"Humanoid",speed:{walk:30},languages:["common","dwarvish"],traits:[]},{id:"halfling",name:"Halfling",size:"Small",creatureType:"Humanoid",speed:{walk:30},languages:["common","halfling"],traits:[]},{id:"tiefling",name:"Tiefling",size:"Medium",creatureType:"Humanoid",speed:{walk:30},languages:["common","infernal"],traits:[]},{id:"dragonborn",name:"Dragonborn",size:"Medium",creatureType:"Humanoid",speed:{walk:30},languages:["common","draconic"],traits:[]},{id:"gnome",name:"Gnome",size:"Small",creatureType:"Humanoid",speed:{walk:30},languages:["common","gnomish"],traits:[]}],zc=[{id:"soldier",name:"Soldier",abilityScoreIncreases:{options:["STR","DEX","CON"],pattern:"+2/+1"},skillProficiencies:["athletics","intimidation"],toolProficiencies:["gaming"],languages:[],originFeatId:"savage-attacker",traits:[]},{id:"sage",name:"Sage",abilityScoreIncreases:{options:["INT","WIS","CHA"],pattern:"+2/+1"},skillProficiencies:["arcana","history"],toolProficiencies:["calligraphers-supplies"],languages:[],originFeatId:"magic-initiate-wizard",traits:[]},{id:"criminal",name:"Criminal",abilityScoreIncreases:{options:["DEX","CON","INT"],pattern:"+2/+1"},skillProficiencies:["sleight-of-hand","stealth"],toolProficiencies:["thieves-tools"],languages:[],originFeatId:"alert",traits:[]},{id:"acolyte",name:"Acolyte",abilityScoreIncreases:{options:["INT","WIS","CHA"],pattern:"+2/+1"},skillProficiencies:["insight","religion"],toolProficiencies:["calligraphers-supplies"],languages:[],originFeatId:"magic-initiate-cleric",traits:[]},{id:"folk-hero",name:"Folk Hero",abilityScoreIncreases:{options:["STR","CON","WIS"],pattern:"+2/+1"},skillProficiencies:["animal-handling","survival"],toolProficiencies:["smiths-tools"],languages:[],originFeatId:"tough",traits:[]},{id:"noble",name:"Noble",abilityScoreIncreases:{options:["STR","INT","CHA"],pattern:"+2/+1"},skillProficiencies:["history","persuasion"],toolProficiencies:["gaming"],languages:[],originFeatId:"skilled",traits:[]},{id:"guild-artisan",name:"Guild Artisan",abilityScoreIncreases:{options:["STR","DEX","WIS"],pattern:"+2/+1"},skillProficiencies:["insight","persuasion"],toolProficiencies:["smiths-tools"],languages:[],originFeatId:"crafter",traits:[]},{id:"outlander",name:"Outlander",abilityScoreIncreases:{options:["STR","DEX","WIS"],pattern:"+2/+1"},skillProficiencies:["athletics","survival"],toolProficiencies:["musical"],languages:[],originFeatId:"tough",traits:[]}],Cc=[{id:"savage-attacker",name:"Savage Attacker",category:"origin",repeatable:!1,prerequisites:[],effects:[]},{id:"unarmored-defense-barbarian",name:"Unarmored Defense (Barbarian)",category:"general",repeatable:!1,prerequisites:[],effects:[{kind:"OverrideACFormula",base:10,abilityModifiers:["DEX","CON"]}]},{id:"alert",name:"Alert",category:"origin",repeatable:!1,prerequisites:[],effects:[]},{id:"magic-initiate-cleric",name:"Magic Initiate (Cleric)",category:"origin",repeatable:!0,prerequisites:[],effects:[]},{id:"magic-initiate-wizard",name:"Magic Initiate (Wizard)",category:"origin",repeatable:!0,prerequisites:[],effects:[]},{id:"magic-initiate-druid",name:"Magic Initiate (Druid)",category:"origin",repeatable:!0,prerequisites:[],effects:[]},{id:"tough",name:"Tough",category:"origin",repeatable:!1,prerequisites:[],effects:[]},{id:"skilled",name:"Skilled",category:"origin",repeatable:!0,prerequisites:[],effects:[]},{id:"crafter",name:"Crafter",category:"origin",repeatable:!1,prerequisites:[],effects:[]},{id:"lucky",name:"Lucky",category:"origin",repeatable:!1,prerequisites:[],effects:[{kind:"GrantResource",resourceId:"luck",max:3,recharge:"longRest"}]},{id:"great-weapon-master",name:"Great Weapon Master",category:"general",repeatable:!1,prerequisites:[],effects:[]},{id:"sharpshooter",name:"Sharpshooter",category:"general",repeatable:!1,prerequisites:[],effects:[]},{id:"polearm-master",name:"Polearm Master",category:"general",repeatable:!1,prerequisites:[],effects:[]},{id:"war-caster",name:"War Caster",category:"general",repeatable:!1,prerequisites:[],effects:[]},{id:"resilient-con",name:"Resilient (Constitution)",category:"general",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-archery",name:"Fighting Style: Archery",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-defense",name:"Fighting Style: Defense",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-dueling",name:"Fighting Style: Dueling",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-great-weapon",name:"Fighting Style: Great Weapon Fighting",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-protection",name:"Fighting Style: Protection",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"fighting-style-two-weapon",name:"Fighting Style: Two-Weapon Fighting",category:"fighting-style",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-combat-prowess",name:"Boon of Combat Prowess",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-dimensional-travel",name:"Boon of Dimensional Travel",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-energy-resistance",name:"Boon of Energy Resistance",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-fortitude",name:"Boon of Fortitude",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-irresistible-offense",name:"Boon of Irresistible Offense",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-skill",name:"Boon of Skill",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-spell-recall",name:"Boon of Spell Recall",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-the-night-spirit",name:"Boon of the Night Spirit",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]},{id:"boon-of-truesight",name:"Boon of Truesight",category:"epic-boon",repeatable:!1,prerequisites:[],effects:[]}],Ec=[{id:"fighter",name:"Fighter",hitDie:10,primaryAbility:["STR","DEX"],savingThrowProficiencies:["STR","CON"],armorProficiencies:["light","medium","heavy","shield"],weaponProficiencies:["simple","martial"],toolProficiencies:[],skillChoices:{choices:2,from:["acrobatics","athletics","history","insight","intimidation","perception","survival"]},levelTable:{1:{proficiencyBonus:2,features:[{id:"second-wind",name:"Second Wind",effects:[{kind:"GrantResource",resourceId:"second-wind",max:2,recharge:"shortRest"}]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"action-surge",name:"Action Surge",effects:[{kind:"GrantResource",resourceId:"action-surge",max:1,recharge:"shortRest"}]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[{id:"extra-attack",name:"Extra Attack",effects:[{kind:"ModifyActionEconomy",op:"extraAttack",count:1}]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},subclassLevel:3},{id:"wizard",name:"Wizard",hitDie:6,primaryAbility:["INT"],savingThrowProficiencies:["INT","WIS"],armorProficiencies:[],weaponProficiencies:[],toolProficiencies:[],levelTable:{1:{proficiencyBonus:2,features:[],columns:{}},2:{proficiencyBonus:2,features:[],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"INT",type:"full"}},{id:"rogue",name:"Rogue",hitDie:8,primaryAbility:["DEX"],savingThrowProficiencies:["DEX","INT"],armorProficiencies:["light"],weaponProficiencies:["simple"],toolProficiencies:["thieves-tools"],levelTable:{1:{proficiencyBonus:2,features:[{id:"sneak-attack",name:"Sneak Attack",effects:[{kind:"OnEvent",id:"sneak-attack",trigger:{eventType:"AttackRolled",filter:{kind:"all",terms:[{kind:"eq",path:"event.attackerIsSelf",value:!0},{kind:"eq",path:"event.hit",value:!0},{kind:"eq",path:"event.used",value:"advantage"}]}},actions:[{kind:"AddDamage",dice:"1d6",damageType:"piercing"}],oncePer:"turn"}]}],columns:{}},2:{proficiencyBonus:2,features:[],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}}},{id:"warlock",name:"Warlock",hitDie:8,primaryAbility:["CHA"],savingThrowProficiencies:["WIS","CHA"],armorProficiencies:["light"],weaponProficiencies:["simple"],toolProficiencies:[],levelTable:{1:{proficiencyBonus:2,features:[],columns:{}},2:{proficiencyBonus:2,features:[],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"CHA",type:"pact"}},{id:"paladin",name:"Paladin",hitDie:10,primaryAbility:["STR","CHA"],savingThrowProficiencies:["WIS","CHA"],armorProficiencies:["light","medium","heavy","shield"],weaponProficiencies:["simple","martial"],toolProficiencies:[],levelTable:{1:{proficiencyBonus:2,features:[],columns:{}},2:{proficiencyBonus:2,features:[],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"CHA",type:"half"}},{id:"barbarian",name:"Barbarian",hitDie:12,primaryAbility:["STR"],savingThrowProficiencies:["STR","CON"],armorProficiencies:["light","medium","shield"],weaponProficiencies:["simple","martial"],toolProficiencies:[],skillChoices:{choices:2,from:["animal-handling","athletics","intimidation","nature","perception","survival"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"rage",name:"Rage",effects:[{kind:"GrantResource",resourceId:"rage",max:2,recharge:"longRest"}]},{id:"unarmored-defense-barbarian-feature",name:"Unarmored Defense",effects:[]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"reckless-attack",name:"Reckless Attack",effects:[]},{id:"danger-sense",name:"Danger Sense",effects:[]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[{id:"extra-attack-barb",name:"Extra Attack",effects:[{kind:"ModifyActionEconomy",op:"extraAttack",count:1}]},{id:"fast-movement",name:"Fast Movement",effects:[{kind:"ModifySpeed",mode:"walk",op:"add",value:10}]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[{id:"feral-instinct",name:"Feral Instinct",effects:[]}],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}}},{id:"bard",name:"Bard",hitDie:8,primaryAbility:["CHA"],savingThrowProficiencies:["DEX","CHA"],armorProficiencies:["light"],weaponProficiencies:["simple"],toolProficiencies:["musical"],skillChoices:{choices:3,from:["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"bardic-inspiration",name:"Bardic Inspiration",effects:[{kind:"GrantResource",resourceId:"bardic-inspiration",max:3,recharge:"longRest"}]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"jack-of-all-trades",name:"Jack of All Trades",effects:[]}],columns:{}},3:{proficiencyBonus:2,features:[{id:"expertise-bard",name:"Expertise",effects:[]}],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[{id:"font-of-inspiration",name:"Font of Inspiration",effects:[]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"CHA",type:"full"}},{id:"cleric",name:"Cleric",hitDie:8,primaryAbility:["WIS"],savingThrowProficiencies:["WIS","CHA"],armorProficiencies:["light","medium","shield"],weaponProficiencies:["simple"],toolProficiencies:[],skillChoices:{choices:2,from:["history","insight","medicine","persuasion","religion"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"channel-divinity",name:"Channel Divinity",effects:[{kind:"GrantResource",resourceId:"channel-divinity",max:1,recharge:"shortRest"}]}],columns:{}},2:{proficiencyBonus:2,features:[],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[{id:"channel-divinity-cleric-2",name:"Channel Divinity (2/rest)",effects:[{kind:"GrantResource",resourceId:"channel-divinity",max:2,recharge:"shortRest"}]}],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"WIS",type:"full"}},{id:"druid",name:"Druid",hitDie:8,primaryAbility:["WIS"],savingThrowProficiencies:["INT","WIS"],armorProficiencies:["light","medium","shield"],weaponProficiencies:["simple"],toolProficiencies:["herbalism"],skillChoices:{choices:2,from:["arcana","animal-handling","insight","medicine","nature","perception","religion","survival"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"druidic",name:"Druidic",effects:[]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"wild-shape",name:"Wild Shape",effects:[{kind:"GrantResource",resourceId:"wild-shape",max:2,recharge:"shortRest"}]},{id:"wild-companion",name:"Wild Companion",effects:[]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"WIS",type:"full"}},{id:"monk",name:"Monk",hitDie:8,primaryAbility:["DEX","WIS"],savingThrowProficiencies:["STR","DEX"],armorProficiencies:[],weaponProficiencies:["simple"],toolProficiencies:[],skillChoices:{choices:2,from:["acrobatics","athletics","history","insight","religion","stealth"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"martial-arts",name:"Martial Arts",effects:[]},{id:"unarmored-defense-monk",name:"Unarmored Defense (Monk)",effects:[{kind:"OverrideACFormula",base:10,abilityModifiers:["DEX","WIS"]}]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"monks-focus",name:"Monk's Focus (Ki)",effects:[{kind:"GrantResource",resourceId:"ki",max:2,recharge:"shortRest"}]},{id:"unarmored-movement-monk",name:"Unarmored Movement",effects:[{kind:"ModifySpeed",mode:"walk",op:"add",value:10}]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[{id:"slow-fall",name:"Slow Fall",effects:[]}],columns:{}},5:{proficiencyBonus:3,features:[{id:"extra-attack-monk",name:"Extra Attack",effects:[{kind:"ModifyActionEconomy",op:"extraAttack",count:1}]},{id:"stunning-strike",name:"Stunning Strike",effects:[]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[{id:"evasion-monk",name:"Evasion",effects:[]}],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}}},{id:"ranger",name:"Ranger",hitDie:10,primaryAbility:["DEX","WIS"],savingThrowProficiencies:["STR","DEX"],armorProficiencies:["light","medium","shield"],weaponProficiencies:["simple","martial"],toolProficiencies:[],skillChoices:{choices:3,from:["animal-handling","athletics","insight","investigation","nature","perception","stealth","survival"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"favored-enemy",name:"Favored Enemy",effects:[{kind:"GrantResource",resourceId:"hunters-mark",max:2,recharge:"longRest"}]},{id:"weapon-mastery-ranger",name:"Weapon Mastery",effects:[{kind:"GrantWeaponMastery",masteries:["Sap","Vex","Topple","Push","Slow","Cleave","Nick","Graze","Flex"],slots:2}]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"deft-explorer",name:"Deft Explorer (Expertise)",effects:[]},{id:"fighting-style-ranger",name:"Fighting Style",effects:[]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[{id:"extra-attack-ranger",name:"Extra Attack",effects:[{kind:"ModifyActionEconomy",op:"extraAttack",count:1}]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"WIS",type:"half"}},{id:"sorcerer",name:"Sorcerer",hitDie:6,primaryAbility:["CHA"],savingThrowProficiencies:["CON","CHA"],armorProficiencies:[],weaponProficiencies:["simple"],toolProficiencies:[],skillChoices:{choices:2,from:["arcana","deception","insight","intimidation","persuasion","religion"]},subclassLevel:3,levelTable:{1:{proficiencyBonus:2,features:[{id:"innate-sorcery",name:"Innate Sorcery",effects:[{kind:"GrantResource",resourceId:"innate-sorcery",max:2,recharge:"longRest"}]}],columns:{}},2:{proficiencyBonus:2,features:[{id:"font-of-magic",name:"Font of Magic (Sorcery Points)",effects:[{kind:"GrantResource",resourceId:"sorcery-points",max:2,recharge:"longRest"}]},{id:"metamagic",name:"Metamagic",effects:[]}],columns:{}},3:{proficiencyBonus:2,features:[],columns:{}},4:{proficiencyBonus:2,features:[],columns:{}},5:{proficiencyBonus:3,features:[{id:"sorcerous-restoration",name:"Sorcerous Restoration",effects:[]}],columns:{}},6:{proficiencyBonus:3,features:[],columns:{}},7:{proficiencyBonus:3,features:[],columns:{}},8:{proficiencyBonus:3,features:[],columns:{}},9:{proficiencyBonus:4,features:[],columns:{}},10:{proficiencyBonus:4,features:[],columns:{}},11:{proficiencyBonus:4,features:[],columns:{}},12:{proficiencyBonus:4,features:[],columns:{}},13:{proficiencyBonus:5,features:[],columns:{}},14:{proficiencyBonus:5,features:[],columns:{}},15:{proficiencyBonus:5,features:[],columns:{}},16:{proficiencyBonus:5,features:[],columns:{}},17:{proficiencyBonus:6,features:[],columns:{}},18:{proficiencyBonus:6,features:[],columns:{}},19:{proficiencyBonus:6,features:[],columns:{}},20:{proficiencyBonus:6,features:[],columns:{}}},spellcasting:{ability:"CHA",type:"full"}}],kc=[],Ac=[{id:"fire-bolt",name:"Fire Bolt",level:0,school:"evocation",castingTime:"Action",range:"120 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["wizard","sorcerer"],mechanicalEffects:[{kind:"attack",damageDice:"1d10",damageType:"fire",cantripScalingDice:"1d10"}]},{id:"magic-missile",name:"Magic Missile",level:1,school:"evocation",castingTime:"Action",range:"120 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["wizard","sorcerer"],mechanicalEffects:[]},{id:"fireball",name:"Fireball",level:3,school:"evocation",castingTime:"Action",range:"150 feet",components:{verbal:!0,somatic:!0,material:"a tiny ball of bat guano and sulfur"},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["wizard","sorcerer"],targeting:{shape:"sphere",size:20},mechanicalEffects:[{kind:"save",ability:"DEX",damageDice:"8d6",damageType:"fire",halfOnSuccess:!0,extraDicePerSlotLevel:1}]},{id:"detect-magic",name:"Detect Magic",level:1,school:"divination",castingTime:"Action",range:"Self",components:{verbal:!0,somatic:!0},duration:"Concentration, up to 10 minutes",concentration:!0,ritual:!0,classes:["wizard","cleric","druid","bard","paladin","ranger","sorcerer"],mechanicalEffects:[]},{id:"hold-person",name:"Hold Person",level:2,school:"enchantment",castingTime:"Action",range:"60 feet",components:{verbal:!0,somatic:!0,material:"a small straight piece of iron"},duration:"Concentration, up to 1 minute",concentration:!0,ritual:!1,classes:["wizard","cleric","bard"],mechanicalEffects:[{kind:"save",ability:"WIS",conditionOnFail:"paralyzed"}]},{id:"cure-wounds",name:"Cure Wounds",level:1,school:"abjuration",castingTime:"Action",range:"Touch",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["cleric","druid","paladin","ranger"],mechanicalEffects:[{kind:"heal",amountDice:"2d8",extraDicePerSlotLevel:2}]},{id:"sacred-flame",name:"Sacred Flame",level:0,school:"evocation",castingTime:"Action",range:"60 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["cleric"],cantripScalingDice:{5:"2d8",11:"3d8",17:"4d8"},mechanicalEffects:[{kind:"save",ability:"DEX",onFailure:{damageDice:"1d8",damageType:"radiant"}}]},{id:"eldritch-blast",name:"Eldritch Blast",level:0,school:"evocation",castingTime:"Action",range:"120 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["warlock"],cantripScalingDice:{5:"2d10",11:"3d10",17:"4d10"},mechanicalEffects:[{kind:"attack",attackKind:"ranged",damageDice:"1d10",damageType:"force"}]},{id:"ray-of-frost",name:"Ray of Frost",level:0,school:"evocation",castingTime:"Action",range:"60 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["wizard","sorcerer"],cantripScalingDice:{5:"2d8",11:"3d8",17:"4d8"},mechanicalEffects:[{kind:"attack",attackKind:"ranged",damageDice:"1d8",damageType:"cold"}]},{id:"shocking-grasp",name:"Shocking Grasp",level:0,school:"evocation",castingTime:"Action",range:"Touch",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["wizard","sorcerer"],cantripScalingDice:{5:"2d8",11:"3d8",17:"4d8"},mechanicalEffects:[{kind:"attack",attackKind:"melee",damageDice:"1d8",damageType:"lightning"}]},{id:"guidance",name:"Guidance",level:0,school:"divination",castingTime:"Action",range:"Touch",components:{verbal:!0,somatic:!0},duration:"1 minute",concentration:!0,ritual:!1,classes:["cleric","druid"]},{id:"light",name:"Light",level:0,school:"evocation",castingTime:"Action",range:"Touch",components:{verbal:!0,material:"a firefly or phosphorescent moss"},duration:"1 hour",concentration:!1,ritual:!1,classes:["bard","cleric","sorcerer","wizard"]},{id:"mage-hand",name:"Mage Hand",level:0,school:"conjuration",castingTime:"Action",range:"30 feet",components:{verbal:!0,somatic:!0},duration:"1 minute",concentration:!1,ritual:!1,classes:["bard","sorcerer","warlock","wizard"]},{id:"prestidigitation",name:"Prestidigitation",level:0,school:"transmutation",castingTime:"Action",range:"10 feet",components:{verbal:!0,somatic:!0},duration:"Up to 1 hour",concentration:!1,ritual:!1,classes:["bard","sorcerer","warlock","wizard"]},{id:"bless",name:"Bless",level:1,school:"enchantment",castingTime:"Action",range:"30 feet",components:{verbal:!0,somatic:!0,material:"a sprinkling of holy water"},duration:"Up to 1 minute",concentration:!0,ritual:!1,classes:["cleric","paladin"]},{id:"healing-word",name:"Healing Word",level:1,school:"abjuration",castingTime:"Bonus Action",range:"60 feet",components:{verbal:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["bard","cleric","druid"],mechanicalEffects:[{kind:"heal",amountDice:"1d4",extraDicePerSlotLevel:1}]},{id:"shield",name:"Shield",level:1,school:"abjuration",castingTime:"Reaction",range:"Self",components:{verbal:!0,somatic:!0},duration:"1 round",concentration:!1,ritual:!1,classes:["sorcerer","wizard"]},{id:"burning-hands",name:"Burning Hands",level:1,school:"evocation",castingTime:"Action",range:"Self (15-foot cone)",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["sorcerer","wizard"],targeting:{shape:"cone",size:15},mechanicalEffects:[{kind:"save",ability:"DEX",onFailure:{damageDice:"3d6",damageType:"fire",extraDicePerSlotLevel:1},onSuccess:"half"}]},{id:"thunderwave",name:"Thunderwave",level:1,school:"evocation",castingTime:"Action",range:"Self (15-foot cube)",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["bard","druid","sorcerer","wizard"],targeting:{shape:"cube",size:15},mechanicalEffects:[{kind:"save",ability:"CON",onFailure:{damageDice:"2d8",damageType:"thunder",extraDicePerSlotLevel:1},onSuccess:"half"}]},{id:"mage-armor",name:"Mage Armor",level:1,school:"abjuration",castingTime:"Action",range:"Touch",components:{verbal:!0,somatic:!0,material:"a piece of cured leather"},duration:"8 hours",concentration:!1,ritual:!1,classes:["sorcerer","wizard"]},{id:"faerie-fire",name:"Faerie Fire",level:1,school:"evocation",castingTime:"Action",range:"60 feet",components:{verbal:!0},duration:"Up to 1 minute",concentration:!0,ritual:!1,classes:["bard","druid"],targeting:{shape:"cube",size:20}},{id:"bane",name:"Bane",level:1,school:"enchantment",castingTime:"Action",range:"30 feet",components:{verbal:!0,somatic:!0,material:"a drop of blood"},duration:"Up to 1 minute",concentration:!0,ritual:!1,classes:["bard","cleric"]},{id:"sleep",name:"Sleep",level:1,school:"enchantment",castingTime:"Action",range:"90 feet",components:{verbal:!0,somatic:!0,material:"a pinch of fine sand"},duration:"Up to 1 minute",concentration:!0,ritual:!1,classes:["bard","sorcerer","wizard"],targeting:{shape:"sphere",size:20}},{id:"misty-step",name:"Misty Step",level:2,school:"conjuration",castingTime:"Bonus Action",range:"Self",components:{verbal:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["sorcerer","warlock","wizard"]},{id:"spiritual-weapon",name:"Spiritual Weapon",level:2,school:"evocation",castingTime:"Bonus Action",range:"60 feet",components:{verbal:!0,somatic:!0},duration:"1 minute",concentration:!1,ritual:!1,classes:["cleric"],mechanicalEffects:[{kind:"attack",attackKind:"melee",damageDice:"1d8",damageType:"force"}]},{id:"web",name:"Web",level:2,school:"conjuration",castingTime:"Action",range:"60 feet",components:{verbal:!0,somatic:!0,material:"a bit of spiderweb"},duration:"Up to 1 hour",concentration:!0,ritual:!1,classes:["sorcerer","wizard"],targeting:{shape:"cube",size:20}},{id:"aid",name:"Aid",level:2,school:"abjuration",castingTime:"Action",range:"30 feet",components:{verbal:!0,somatic:!0,material:"a tiny strip of white cloth"},duration:"8 hours",concentration:!1,ritual:!1,classes:["bard","cleric","paladin"]},{id:"lesser-restoration",name:"Lesser Restoration",level:2,school:"abjuration",castingTime:"Action",range:"Touch",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["bard","cleric","druid","paladin","ranger"]},{id:"counterspell",name:"Counterspell",level:3,school:"abjuration",castingTime:"Reaction",range:"60 feet",components:{somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["sorcerer","warlock","wizard"]},{id:"dispel-magic",name:"Dispel Magic",level:3,school:"abjuration",castingTime:"Action",range:"120 feet",components:{verbal:!0,somatic:!0},duration:"Instantaneous",concentration:!1,ritual:!1,classes:["bard","cleric","druid","paladin","sorcerer","warlock","wizard"]},{id:"spirit-guardians",name:"Spirit Guardians",level:3,school:"conjuration",castingTime:"Action",range:"Self (15-foot radius)",components:{verbal:!0,somatic:!0,material:"a holy symbol"},duration:"Up to 10 minutes",concentration:!0,ritual:!1,classes:["cleric"],targeting:{shape:"sphere",size:15}},{id:"identify",name:"Identify",level:1,school:"divination",castingTime:"1 minute",range:"Touch",components:{verbal:!0,somatic:!0,material:"a pearl worth 100+ gp and an owl feather"},duration:"Instantaneous",concentration:!1,ritual:!0,classes:["bard","wizard"]}],wc=[{id:"longsword",itemKind:"weapon",name:"Longsword",category:"martial",attackKind:"melee",damageType:"slashing",damageDice:"1d8",versatileDice:"1d10",properties:["versatile"],mastery:"Sap"},{id:"rapier",itemKind:"weapon",name:"Rapier",category:"martial",attackKind:"melee",damageType:"piercing",damageDice:"1d8",properties:["finesse"],mastery:"Vex"},{id:"dagger",itemKind:"weapon",name:"Dagger",category:"simple",attackKind:"melee",damageType:"piercing",damageDice:"1d4",properties:["finesse","light","thrown"],mastery:"Nick"},{id:"shortsword",itemKind:"weapon",name:"Shortsword",category:"martial",attackKind:"melee",damageType:"piercing",damageDice:"1d6",properties:["finesse","light"],mastery:"Vex"},{id:"longbow",itemKind:"weapon",name:"Longbow",category:"martial",attackKind:"ranged",damageType:"piercing",damageDice:"1d8",properties:["ammunition","heavy","two-handed"],mastery:"Slow",rangeNormal:150,rangeLong:600},{id:"leather-armor",itemKind:"armor",name:"Leather Armor",category:"light",baseAC:11,stealthDisadvantage:!1},{id:"chain-shirt",itemKind:"armor",name:"Chain Shirt",category:"medium",baseAC:13,dexCap:2,stealthDisadvantage:!1},{id:"chain-mail",itemKind:"armor",name:"Chain Mail",category:"heavy",baseAC:16,strRequirement:13,stealthDisadvantage:!0},{id:"plate",itemKind:"armor",name:"Plate Armor",category:"heavy",baseAC:18,strRequirement:15,stealthDisadvantage:!0},{id:"shield",itemKind:"armor",name:"Shield",category:"shield",baseAC:2,stealthDisadvantage:!1},{id:"healing-potion",itemKind:"consumable",name:"Potion of Healing",onConsume:[],description:"Heals 2d4+2 hit points when consumed"},{id:"greatsword",itemKind:"weapon",name:"Greatsword",category:"martial",attackKind:"melee",damageType:"slashing",damageDice:"2d6",properties:["heavy","two-handed"],mastery:"Graze"},{id:"greataxe",itemKind:"weapon",name:"Greataxe",category:"martial",attackKind:"melee",damageType:"slashing",damageDice:"1d12",properties:["heavy","two-handed"],mastery:"Cleave"},{id:"warhammer",itemKind:"weapon",name:"Warhammer",category:"martial",attackKind:"melee",damageType:"bludgeoning",damageDice:"1d8",versatileDice:"1d10",properties:["versatile"],mastery:"Push"},{id:"mace",itemKind:"weapon",name:"Mace",category:"simple",attackKind:"melee",damageType:"bludgeoning",damageDice:"1d6",properties:[],mastery:"Sap"},{id:"spear",itemKind:"weapon",name:"Spear",category:"simple",attackKind:"melee",damageType:"piercing",damageDice:"1d6",versatileDice:"1d8",properties:["thrown","versatile"],mastery:"Sap",rangeNormal:20,rangeLong:60},{id:"quarterstaff",itemKind:"weapon",name:"Quarterstaff",category:"simple",attackKind:"melee",damageType:"bludgeoning",damageDice:"1d6",versatileDice:"1d8",properties:["versatile"],mastery:"Topple"},{id:"handaxe",itemKind:"weapon",name:"Handaxe",category:"simple",attackKind:"melee",damageType:"slashing",damageDice:"1d6",properties:["light","thrown"],mastery:"Vex",rangeNormal:20,rangeLong:60},{id:"crossbow-light",itemKind:"weapon",name:"Crossbow, light",category:"simple",attackKind:"ranged",damageType:"piercing",damageDice:"1d8",properties:["ammunition","loading","two-handed"],mastery:"Slow",rangeNormal:80,rangeLong:320},{id:"studded-leather",itemKind:"armor",name:"Studded Leather",category:"light",baseAC:12,stealthDisadvantage:!1},{id:"scale-mail",itemKind:"armor",name:"Scale Mail",category:"medium",baseAC:14,stealthDisadvantage:!0,dexCap:2},{id:"breastplate",itemKind:"armor",name:"Breastplate",category:"medium",baseAC:14,stealthDisadvantage:!1,dexCap:2},{id:"half-plate",itemKind:"armor",name:"Half Plate",category:"medium",baseAC:15,stealthDisadvantage:!0,dexCap:2},{id:"ring-mail",itemKind:"armor",name:"Ring Mail",category:"heavy",baseAC:14,stealthDisadvantage:!0},{id:"splint",itemKind:"armor",name:"Splint",category:"heavy",baseAC:17,stealthDisadvantage:!0,strRequirement:15},{id:"thieves-tools",itemKind:"tool",name:"Thieves' Tools",category:"artisan"},{id:"smiths-tools",itemKind:"tool",name:"Smith's Tools",category:"artisan"},{id:"herbalism-kit",itemKind:"tool",name:"Herbalism Kit",category:"artisan"},{id:"calligraphers-supplies",itemKind:"tool",name:"Calligrapher's Supplies",category:"artisan"},{id:"musical-lute",itemKind:"tool",name:"Lute",category:"musical"},{id:"torch",itemKind:"gear",name:"Torch"},{id:"rope-hempen-50",itemKind:"gear",name:"Rope, hempen (50 feet)"},{id:"backpack",itemKind:"gear",name:"Backpack"},{id:"rations-1-day",itemKind:"gear",name:"Rations (1 day)"},{id:"waterskin",itemKind:"gear",name:"Waterskin"},{id:"bedroll",itemKind:"gear",name:"Bedroll"},{id:"tinderbox",itemKind:"gear",name:"Tinderbox"},{id:"potion-of-greater-healing",itemKind:"consumable",name:"Potion of Greater Healing",onConsume:[],description:"Heals 4d4+4 hit points when consumed"},{id:"potion-of-superior-healing",itemKind:"consumable",name:"Potion of Superior Healing",onConsume:[],description:"Heals 8d4+8 hit points when consumed"},{id:"bag-of-holding",itemKind:"magic",name:"Bag of Holding",rarity:"uncommon",requiresAttunement:!1,effects:[]},{id:"cloak-of-protection",itemKind:"magic",name:"Cloak of Protection",rarity:"uncommon",requiresAttunement:!0,effects:[]},{id:"ring-of-protection",itemKind:"magic",name:"Ring of Protection",rarity:"rare",requiresAttunement:!0,effects:[]},{id:"boots-of-elvenkind",itemKind:"magic",name:"Boots of Elvenkind",rarity:"uncommon",requiresAttunement:!1,effects:[]},{id:"wand-of-magic-missiles",itemKind:"magic",name:"Wand of Magic Missiles",rarity:"uncommon",requiresAttunement:!1,charges:{max:7,recharge:"dawn",rechargeFormula:"1d6+1"},effects:[]},{id:"amulet-of-health",itemKind:"magic",name:"Amulet of Health",rarity:"rare",requiresAttunement:!0,effects:[]},{id:"gauntlets-of-ogre-power",itemKind:"magic",name:"Gauntlets of Ogre Power",rarity:"uncommon",requiresAttunement:!0,effects:[]},{id:"flametongue-longsword",itemKind:"magic",name:"Flametongue Longsword",rarity:"rare",requiresAttunement:!0,effects:[]},{id:"deck-of-many-things",itemKind:"magic",name:"Deck of Many Things",rarity:"legendary",requiresAttunement:!1,effects:[]}],Rc=[{id:"goblin",name:"Goblin",size:"Small",type:"Humanoid",alignment:{lawChaos:"neutral",goodEvil:"evil"},ac:15,hp:{average:7,formula:"2d6"},speed:{walk:30},abilityScores:{STR:8,DEX:14,CON:10,INT:10,WIS:8,CHA:8},cr:.25,xp:50,proficiencyBonus:2,languages:["common","goblin"]},{id:"orc",name:"Orc",size:"Medium",type:"Humanoid",alignment:{lawChaos:"chaotic",goodEvil:"evil"},ac:13,hp:{average:15,formula:"2d8+6"},speed:{walk:30},abilityScores:{STR:16,DEX:12,CON:16,INT:7,WIS:11,CHA:10},cr:.5,xp:100,proficiencyBonus:2,languages:["common","orc"]},{id:"wolf",name:"Wolf",size:"Medium",type:"Beast",alignment:"unaligned",ac:13,hp:{average:11,formula:"2d8+2"},speed:{walk:40},abilityScores:{STR:12,DEX:15,CON:12,INT:3,WIS:12,CHA:6},skills:{perception:3,stealth:4},cr:.25,xp:50,proficiencyBonus:2,senses:{passivePerception:13},languages:[]},{id:"skeleton",name:"Skeleton",size:"Medium",type:"Undead",alignment:{lawChaos:"lawful",goodEvil:"evil"},ac:13,hp:{average:13,formula:"2d8+4"},speed:{walk:30},abilityScores:{STR:10,DEX:14,CON:15,INT:6,WIS:8,CHA:5},damageVulnerabilities:["bludgeoning"],damageImmunities:["poison"],conditionImmunities:["exhaustion","poisoned"],cr:.25,xp:50,proficiencyBonus:2,languages:["common"]},{id:"ogre",name:"Ogre",size:"Large",type:"Giant",alignment:{lawChaos:"chaotic",goodEvil:"evil"},ac:11,hp:{average:59,formula:"7d10+21"},speed:{walk:40},abilityScores:{STR:19,DEX:8,CON:16,INT:5,WIS:7,CHA:7},cr:2,xp:450,proficiencyBonus:2,languages:["common","giant"]},{id:"young-red-dragon",name:"Young Red Dragon",size:"Large",type:"Dragon",alignment:{lawChaos:"chaotic",goodEvil:"evil"},ac:18,hp:{average:178,formula:"17d10+85"},speed:{walk:40,fly:80,climb:40},abilityScores:{STR:23,DEX:10,CON:21,INT:14,WIS:11,CHA:19},savingThrows:{DEX:4,CON:9,WIS:4,CHA:8},skills:{perception:8,stealth:4},damageImmunities:["fire"],senses:{blindsight:30,darkvision:120,passivePerception:18},cr:10,xp:5900,proficiencyBonus:4,languages:["common","draconic"]}],Tc=[{id:"exhaustion",name:"Exhaustion",stackable:!0,endsOn:[{kind:"longRest"}],effects:[]},{id:"prone",name:"Prone",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:"attack",mode:"disadvantage"}]},{id:"blessed",name:"Blessed",stackable:!1,endsOn:[],effects:[{kind:"AddModifier",target:{kind:"save",ability:"WIS"},value:4}]},{id:"blinded",name:"Blinded",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:"attack",mode:"disadvantage"}]},{id:"charmed",name:"Charmed",stackable:!1,endsOn:[],effects:[]},{id:"deafened",name:"Deafened",stackable:!1,endsOn:[],effects:[]},{id:"frightened",name:"Frightened",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:"attack",mode:"disadvantage"},{kind:"SetAdvantage",on:{kind:"check",ability:"STR"},mode:"disadvantage"}]},{id:"grappled",name:"Grappled",stackable:!1,endsOn:[],effects:[{kind:"ModifySpeed",mode:"walk",op:"set",value:0}]},{id:"incapacitated",name:"Incapacitated",stackable:!1,endsOn:[],effects:[]},{id:"invisible",name:"Invisible",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:"attack",mode:"advantage"}]},{id:"paralyzed",name:"Paralyzed",stackable:!1,endsOn:[],effects:[{kind:"ModifySpeed",mode:"walk",op:"set",value:0},{kind:"SetAdvantage",on:{kind:"save",ability:"STR"},mode:"auto-fail"},{kind:"SetAdvantage",on:{kind:"save",ability:"DEX"},mode:"auto-fail"}]},{id:"petrified",name:"Petrified",stackable:!1,endsOn:[],effects:[{kind:"ModifySpeed",mode:"walk",op:"set",value:0},{kind:"GrantResistance",damageType:"all"},{kind:"GrantConditionImmunity",conditionId:"poisoned"}]},{id:"poisoned",name:"Poisoned",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:"attack",mode:"disadvantage"},{kind:"SetAdvantage",on:{kind:"check",ability:"STR"},mode:"disadvantage"},{kind:"SetAdvantage",on:{kind:"check",ability:"DEX"},mode:"disadvantage"}]},{id:"restrained",name:"Restrained",stackable:!1,endsOn:[],effects:[{kind:"ModifySpeed",mode:"walk",op:"set",value:0},{kind:"SetAdvantage",on:"attack",mode:"disadvantage"},{kind:"SetAdvantage",on:{kind:"save",ability:"DEX"},mode:"disadvantage"}]},{id:"stunned",name:"Stunned",stackable:!1,endsOn:[],effects:[{kind:"SetAdvantage",on:{kind:"save",ability:"STR"},mode:"auto-fail"},{kind:"SetAdvantage",on:{kind:"save",ability:"DEX"},mode:"auto-fail"}]},{id:"unconscious",name:"Unconscious",stackable:!1,endsOn:[],effects:[{kind:"ModifySpeed",mode:"walk",op:"set",value:0},{kind:"SetAdvantage",on:{kind:"save",ability:"STR"},mode:"auto-fail"},{kind:"SetAdvantage",on:{kind:"save",ability:"DEX"},mode:"auto-fail"}]}],Ir={id:yc,name:bc,version:Sc,species:vc,backgrounds:zc,feats:Cc,classes:Ec,subclasses:kc,spells:Ac,items:wc,monsters:Rc,conditions:Tc},Dc=Ir,Bc=()=>hr(Ir);class gr{next(){return Math.random()}}const yr=()=>new gr,xc=1831565813,Mc=2654435769,Pc=4294967296;class Re{state;constructor(e){this.state=(e|0)>>>0}next(){let e=this.state=this.state+Mc>>>0;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/Pc}fork(e){return new Re((this.state^Math.imul(e|0,xc))>>>0)}}const Lc=a=>new Re(a);class $c extends Error{constructor(e="RNG was called inside a context that must be deterministic (e.g. apply())."){super(e),this.name="RNGCalledInPureContextError"}}class br{next(){throw new $c}}const Oc=()=>new br,_c=/^(\d+)d(\d+)([+-]\d+)?$/i,Q=a=>{const e=_c.exec(a.trim());if(!e)throw new Error(`Invalid dice expression: ${a}`);const n=e[1],o=e[2],r=e[3];if(n===void 0||o===void 0)throw new Error(`Invalid dice expression: ${a}`);const i=Number.parseInt(n,10),d=Number.parseInt(o,10),p=r===void 0?0:Number.parseInt(r,10);if(i<=0)throw new Error(`Dice count must be > 0: ${a}`);if(d<=1)throw new Error(`Die size must be > 1: ${a}`);return{count:i,die:d,modifier:p}},E=(a,e)=>{if(a<=1||!Number.isInteger(a))throw new Error(`Invalid die size: ${a}`);return Math.floor(e.next()*a)+1},Sr=(a,e,n)=>{if(a<=0||!Number.isInteger(a))throw new Error(`Invalid dice count: ${a}`);const o=[];for(let r=0;r<a;r++)o.push({die:e,value:E(e,n)});return o},Nc=(a,e)=>{const n=Q(a),o=Sr(n.count,n.die,e),r=o.reduce((i,d)=>i+d.value,0);return{rolls:o,modifier:n.modifier,total:r+n.modifier}},wt=1,Rt=30,Tt=1,Dt=20,C=a=>{if(!Number.isInteger(a))throw new Error(`abilityModifier requires an integer; got ${a}`);if(a<wt||a>Rt)throw new Error(`abilityModifier: score ${a} out of range [${wt}, ${Rt}]`);return Math.floor((a-10)/2)},j=a=>{if(!Number.isInteger(a))throw new Error(`proficiencyBonus requires an integer level; got ${a}`);if(a<Tt||a>Dt)throw new Error(`proficiencyBonus: level ${a} out of range [${Tt}, ${Dt}]`);return Math.floor((a-1)/4)+2},$e=a=>{if(typeof a=="string")return a;switch(a.kind){case"save":return`save:${a.ability}`;case"check":return`check:${a.ability}`;case"skill":return`skill:${a.skill}`}},Bt=a=>{if(typeof a=="string")return a;switch(a.kind){case"save":return`save:${a.ability}`;case"check":return`check:${a.ability}`;case"skill":return`skill:${a.skill}`}},xt=()=>({advantage:!1,disadvantage:!1,autoCrit:!1,autoFail:!1});class vr{modifiers=new Map;advantages=new Map;resistances=new Set;immunities=new Set;vulnerabilities=new Set;conditionImmunities=new Set;acOverrides=[];resourceGrants=[];proficiencies=new Map;actionEconomyMods=new Map;flatDamageReductions=new Map;addModifier(e,n,o){const r=$e(e);let i=this.modifiers.get(r);i===void 0&&(i=[],this.modifiers.set(r,i)),i.push({source:o,value:n})}setAdvantage(e,n){const o=Bt(e);let r=this.advantages.get(o);r===void 0&&(r=xt(),this.advantages.set(o,r)),n==="advantage"?r.advantage=!0:n==="disadvantage"?r.disadvantage=!0:n==="auto-crit"?r.autoCrit=!0:r.autoFail=!0}addResistance(e){this.resistances.add(e)}addImmunity(e){this.immunities.add(e)}addVulnerability(e){this.vulnerabilities.add(e)}addConditionImmunity(e){this.conditionImmunities.add(e)}addACOverride(e){this.acOverrides.push(e)}addResourceGrant(e){this.resourceGrants.push(e)}addProficiency(e,n,o){const r=`${e}:${n}`,i=this.proficiencies.get(r),d={half:1,proficient:2,expertise:3};(i===void 0||d[o]>d[i])&&this.proficiencies.set(r,o)}modifierSum(e){const n=this.modifiers.get($e(e));return n===void 0?0:n.reduce((o,r)=>o+r.value,0)}modifierBreakdown(e){return this.modifiers.get($e(e))??[]}advantageFor(e){return this.advantages.get(Bt(e))??xt()}hasResistance(e){return this.resistances.has(e)||this.resistances.has("all")}hasImmunity(e){return this.immunities.has(e)||this.immunities.has("all")}hasVulnerability(e){return this.vulnerabilities.has(e)}hasConditionImmunity(e){return this.conditionImmunities.has(e)}effectiveACOverride(){if(this.acOverrides.length!==0)return this.acOverrides.reduce((e,n)=>n.priority>e.priority?n:e)}resources(){return this.resourceGrants}proficiencyLevel(e,n){return this.proficiencies.get(`${e}:${n}`)??"none"}addActionEconomy(e,n){const o=this.actionEconomyMods.get(e)??0;this.actionEconomyMods.set(e,o+n)}actionEconomyTotal(e){return this.actionEconomyMods.get(e)??0}addFlatDamageReduction(e,n){const o=this.flatDamageReductions.get(e)??0;this.flatDamageReductions.set(e,Math.max(o,n))}flatDamageReductionFor(e){return this.flatDamageReductions.get(e)??0}}const J=(a,e,n)=>{switch(a.kind){case"AddModifier":{typeof a.value=="number"&&e.addModifier(a.target,a.value,n.source);return}case"SetAdvantage":e.setAdvantage(a.on,a.mode);return;case"GrantResistance":e.addResistance(a.damageType);return;case"GrantImmunity":e.addImmunity(a.damageType);return;case"GrantVulnerability":e.addVulnerability(a.damageType);return;case"GrantConditionImmunity":e.addConditionImmunity(a.conditionId);return;case"OverrideACFormula":e.addACOverride({base:a.base,abilityModifiers:a.abilityModifiers,dexCap:a.dexCap,priority:a.priority??0,source:n.source});return;case"GrantResource":typeof a.max=="number"&&e.addResourceGrant({resourceId:a.resourceId,max:a.max,recharge:a.recharge,source:n.source});return;case"GrantProficiency":e.addProficiency(a.target,a.id,a.level==="none"?"proficient":a.level);return;case"ModifyActionEconomy":e.addActionEconomy(a.op,a.count);return;case"FlatDamageReduction":for(const o of a.damageTypes)e.addFlatDamageReduction(o,a.amount);return;case"GrantSense":case"ModifySpeed":case"GrantSpellSlots":case"GrantSpell":case"OnEvent":case"RecoverResource":case"GrantAction":case"GrantWeaponMastery":case"ExpandSpellList":case"SetHPMaxFormula":case"OfferChoice":case"Custom":return;default:return}},zr=(a,e)=>{const n=[];for(const o of a.pendingChoiceIds){const r=e[o];if(r?.resolution)for(const i of r.resolution.selectedOptionIds){const d=r.options.find(p=>p.id===i);d&&n.push(...d.effects)}}return n},Cr=(a,e)=>{const n=[];for(const o of a.classes){const r=e.classes.get(o.classId);if(r){for(let i=1;i<=o.level;i++){const d=r.levelTable[String(i)];if(d)for(const p of d.features)n.push(...p.effects)}if(o.subclassId!==void 0){const i=e.subclasses.get(o.subclassId);if(i)for(let d=1;d<=o.level;d++){const p=i.levelGrants[String(d)]??[];for(const l of p)n.push(...l.effects)}}}}return n},Er=(a,e)=>{const n=[];for(const o of a.featsTaken){const r=e.feats.get(o);r&&n.push(...r.effects)}return n},kr=(a,e,n)=>{const o=[];for(const r of a.equipped.attuned){const i=e[r];if(!i)continue;const d=n.items.get(i.definitionId);d&&d.itemKind==="magic"&&o.push(...d.effects)}return o},Ar=(a,e)=>{const n=[];for(const o of a.appliedConditions){const r=e.conditions.get(o.conditionId);r&&n.push(...r.effects)}return n},Fc=a=>{const{character:e,content:n,itemInstances:o,pendingChoices:r}=a,i=[],d=n.species.get(e.speciesId);d&&i.push(...d.traits);const p=n.backgrounds.get(e.backgroundId);return p&&i.push(...p.traits),i.push(...Cr(e,n)),i.push(...Er(e,n)),i.push(...kr(e,o,n)),i.push(...Ar(e,n)),r&&i.push(...zr(e,r)),i},X=a=>{const{character:e,content:n,itemInstances:o,pendingChoices:r}=a,i=new vr,d=n.species.get(e.speciesId);if(d)for(const l of d.traits)J(l,i,{source:`species:${d.id}`});const p=n.backgrounds.get(e.backgroundId);if(p)for(const l of p.traits)J(l,i,{source:`background:${p.id}`});for(const l of Cr(e,n))J(l,i,{source:"class"});for(const l of Er(e,n))J(l,i,{source:"feat"});for(const l of kr(e,o,n))J(l,i,{source:"item"});for(const l of Ar(e,n))J(l,i,{source:"condition"});if(r)for(const l of zr(e,r))J(l,i,{source:"choice"});return i},Mt=10,Pt=(a,e,n)=>{const o=[],r=a.equipped.armor,i=C(a.abilityScores.DEX);if(r!==void 0){const p=e[r],l=p?n.items.get(p.definitionId):void 0;if(l&&l.itemKind==="armor"&&l.category!=="shield"){o.push({source:`armor:${l.id}`,value:l.baseAC});const c=l.dexCap===void 0?i:Math.min(i,l.dexCap);l.category!=="heavy"&&o.push({source:"DEX",value:c})}else o.push({source:"unarmored-base",value:Mt}),o.push({source:"DEX",value:i})}else o.push({source:"unarmored-base",value:Mt}),o.push({source:"DEX",value:i});const d=a.equipped.shield;if(d!==void 0){const p=e[d],l=p?n.items.get(p.definitionId):void 0;l&&l.itemKind==="armor"&&l.category==="shield"&&o.push({source:`shield:${l.id}`,value:l.baseAC})}return o},Uc=(a,e)=>{const n=e.effectiveACOverride();if(!n)return null;const o=[],r=typeof n.base=="number"?n.base:n.base==="dex"?C(a.abilityScores.DEX):n.base==="con"?C(a.abilityScores.CON):C(a.abilityScores.WIS);o.push({source:`override-base:${n.source}`,value:r});for(const d of n.abilityModifiers){const p=C(a.abilityScores[d]),l=n.dexCap!==void 0&&d==="DEX"?Math.min(p,n.dexCap):p;o.push({source:`${d}-mod`,value:l})}return a.equipped.shield!==void 0&&o.push({source:"shield",value:2}),o},le=a=>{const e=X(a),n=a.character.equipped.armor;let o;n===void 0?o=Uc(a.character,e)??Pt(a.character,a.itemInstances,a.content):o=Pt(a.character,a.itemInstances,a.content);const r=e.modifierSum("ac");return r!==0&&o.push({source:"modifier",value:r}),{total:o.reduce((d,p)=>d+p.value,0),breakdown:o}},jc=(a,e)=>{const n=e.properties.includes("finesse");return e.attackKind==="ranged"&&!e.properties.includes("thrown")||n&&C(a.abilityScores.DEX)>=C(a.abilityScores.STR)?"DEX":"STR"},qc=(a,e,n)=>{for(const o of a.classes){const r=n.classes.get(o.classId);if(r&&(r.weaponProficiencies.includes(e.id)||r.weaponProficiencies.includes(e.category)||r.weaponProficiencies.includes("all")))return!0}return!1},Te=a=>{const e=a.itemInstances[a.weaponInstanceId];if(!e)throw new Error(`Unknown weapon instance: ${a.weaponInstanceId}`);const n=a.content.items.get(e.definitionId);if(!n||n.itemKind!=="weapon")throw new Error(`Item instance ${a.weaponInstanceId} is not a weapon (definition ${e.definitionId})`);const o=n,r=jc(a.character,o),i=[{source:`${r}-mod`,value:C(a.character.abilityScores[r])}];qc(a.character,o,a.content)&&i.push({source:"proficiency",value:j(N(a.character))});const p=X(a).modifierSum("attack");return p!==0&&i.push({source:"modifier",value:p}),{total:i.reduce((c,u)=>c+u.value,0),breakdown:i}},w=20,mt=20,pt=1,wr=-2,Ie=0,Hc=(a,e,n)=>{for(const o of a.classes)if(n.classes.get(o.classId)?.savingThrowProficiencies.includes(e))return!0;return!1},ue=a=>{const e=[],n=C(a.character.abilityScores[a.ability]);e.push({source:`${a.ability}-mod`,value:n});const o=N(a.character);Hc(a.character,a.ability,a.content)&&e.push({source:"proficiency",value:j(o)});const r=X(a),i={kind:"save",ability:a.ability},d=r.modifierSum(i);if(d!==0&&e.push({source:"modifier",value:d}),a.character.exhaustion>0){const c=wr*a.character.exhaustion;e.push({source:"exhaustion",value:c})}const p=r.advantageFor(i);return{total:e.reduce((c,u)=>c+u.value,0),breakdown:e,hasAdvantage:p.advantage&&!p.disadvantage,hasDisadvantage:p.disadvantage&&!p.advantage}},Gc=8,Rr=a=>{const e=a.content.classes.get(a.classId);if(!e?.spellcasting)return;const n=e.spellcasting.ability;if(n==="INT"||n==="WIS"||n==="CHA")return n},De=a=>{const e=Rr(a);if(e===void 0)return{total:0,breakdown:[]};const n=[{source:"base",value:Gc},{source:"proficiency",value:j(N(a.character))},{source:`${e}-mod`,value:C(a.character.abilityScores[e])}],r=X(a).modifierSum("spellSaveDC");return r!==0&&n.push({source:"modifier",value:r}),{total:n.reduce((d,p)=>d+p.value,0),breakdown:n}},ht=a=>{const e=Rr(a);if(e===void 0)return{total:0,breakdown:[]};const n=[{source:"proficiency",value:j(N(a.character))},{source:`${e}-mod`,value:C(a.character.abilityScores[e])}],r=X(a).modifierSum("spellAttack");return r!==0&&n.push({source:"modifier",value:r}),{total:n.reduce((d,p)=>d+p.value,0),breakdown:n}},Lt=[[2,0,0,0,0,0,0,0,0],[3,0,0,0,0,0,0,0,0],[4,2,0,0,0,0,0,0,0],[4,3,0,0,0,0,0,0,0],[4,3,2,0,0,0,0,0,0],[4,3,3,0,0,0,0,0,0],[4,3,3,1,0,0,0,0,0],[4,3,3,2,0,0,0,0,0],[4,3,3,3,1,0,0,0,0],[4,3,3,3,2,0,0,0,0],[4,3,3,3,2,1,0,0,0],[4,3,3,3,2,1,0,0,0],[4,3,3,3,2,1,1,0,0],[4,3,3,3,2,1,1,0,0],[4,3,3,3,2,1,1,1,0],[4,3,3,3,2,1,1,1,0],[4,3,3,3,2,1,1,1,1],[4,3,3,3,3,1,1,1,1],[4,3,3,3,3,2,1,1,1],[4,3,3,3,3,2,2,1,1]],Kc=[{level:1,count:1},{level:1,count:2},{level:2,count:2},{level:2,count:2},{level:3,count:2},{level:3,count:2},{level:4,count:2},{level:4,count:2},{level:5,count:2},{level:5,count:2},{level:5,count:3},{level:5,count:3},{level:5,count:3},{level:5,count:3},{level:5,count:3},{level:5,count:3},{level:5,count:4},{level:5,count:4},{level:5,count:4},{level:5,count:4}],Vc=(a,e)=>{if(!e)return 0;switch(e.type){case"full":return a.level;case"half":return a.level>=2?Math.floor(a.level/2):0;case"third":return a.level>=3?Math.floor(a.level/3):0;case"pact":return 0}},Be=(a,e)=>{let n=0,o=0,r=null,i=!1;for(const l of a.classes){const u=e.get(l.classId)?.spellcasting;if(u){if(u.type==="pact"){o=Math.max(o,l.level);continue}n+=Vc(l,u),r===null?r=l:i=!0}}const d=new Array(9).fill(0);if(n>0){let l=n;if(!i&&r!==null){const u=e.get(r.classId)?.spellcasting;u?.type==="half"&&r.level===1&&(l=0),u?.type==="third"&&r.level<3&&(l=0)}if(l>0&&l<=Lt.length){const c=Lt[l-1];if(c!==void 0)for(let u=0;u<c.length&&u<d.length;u++)d[u]=c[u]??0}}return o>0?{slotsByLevel:d,pactSlots:Kc[o-1]??{level:1,count:0}}:{slotsByLevel:d}},Wc=(a,e)=>e===0?Number.POSITIVE_INFINITY:a.slotsByLevel[e-1]??0,Tr=(a,e)=>{const n=Be(a,e),o=n.slotsByLevel.map((i,d)=>{const p=String(d+1),l=a.spellSlotsUsed[p]??0;return Math.max(0,i-l)}),r=n.pactSlots?{level:n.pactSlots.level,count:Math.max(0,n.pactSlots.count-a.pactSlotsUsed)}:void 0;return{standardByLevel:o,pact:r}},$t=["STR","DEX","CON","INT","WIS","CHA"],Dr=a=>{const e=N(a.character),n=Object.fromEntries($t.map(i=>[i,C(a.character.abilityScores[i])])),o=le(a),r=Object.fromEntries($t.map(i=>[i,ue({...a,ability:i})]));return{id:a.character.id,name:a.character.name,totalLevel:e,proficiencyBonus:j(e),abilityModifiers:n,hp:a.character.hp,ac:o,savingThrows:r,spellSlots:Be(a.character,a.content.classes),hasPendingChoices:a.character.pendingChoiceIds.some(i=>a.pendingChoices?.[i]?.resolution===void 0)||a.pendingChoices===void 0&&a.character.pendingChoiceIds.length>0,pendingChoiceIds:[...a.character.pendingChoiceIds]}},Xc=a=>wr*a,ne=a=>{const e=[{source:`${a.ability}-mod`,value:C(a.character.abilityScores[a.ability])}],n=X(a);if(a.skill!==void 0&&aa[a.skill]===a.ability){const c=n.proficiencyLevel("skill",a.skill),u=oa[c];if(u>0){const h=Math.floor(j(N(a.character))*u);e.push({source:`skill-prof(${c})`,value:h})}}const o=a.skill!==void 0?n.modifierSum({kind:"skill",skill:a.skill}):0;o!==0&&e.push({source:"skill-modifier",value:o});const r=n.modifierSum({kind:"check",ability:a.ability});r!==0&&e.push({source:"check-modifier",value:r}),a.character.exhaustion>0&&e.push({source:"exhaustion",value:Xc(a.character.exhaustion)});const i=a.skill!==void 0?{kind:"skill",skill:a.skill}:{kind:"check",ability:a.ability},d=n.advantageFor(i);return{total:e.reduce((l,c)=>l+c.value,0),breakdown:e,hasAdvantage:d.advantage&&!d.disadvantage,hasDisadvantage:d.disadvantage&&!d.advantage}},Qc=a=>{const n=ne(a),o=n.hasAdvantage?5:n.hasDisadvantage?-5:0;return 10+n.total+o},Yc=1,Jc=a=>{const e=X(a);return{maxAttacksPerAction:Yc+e.actionEconomyTotal("extraAttack"),extraActionsPerTurn:e.actionEconomyTotal("extraAction"),extraBonusActionsPerTurn:e.actionEconomyTotal("extraBonusAction")}},ft=(a,e,n)=>{if(!(e<0||e>=a.widthCells)&&!(n<0||n>=a.heightCells))return a.terrain[n]?.[e]},Br=a=>{switch(a){case"normal":return on;case"water":case"difficult":return rn;case"impassable":return Number.POSITIVE_INFINITY}},Zc=(a,e,n)=>{const o=ft(a,e,n);return o===void 0?Number.POSITIVE_INFINITY:Br(o)},ed=(a,e)=>Math.max(Math.abs(a.x-e.x),Math.abs(a.y-e.y)),xr=(a,e,n=Ae)=>ed(a,e)*n,td=(a,e,n,o=Ae)=>xr(a,e,o)<=n,ad=(a,e)=>{const n=[];let o=a.x,r=a.y;const i=e.x,d=e.y,p=Math.abs(i-o),l=-Math.abs(d-r),c=o<i?1:-1,u=r<d?1:-1;let h=p+l;for(;n.push({x:o,y:r}),!(o===i&&r===d);){const y=2*h;y>=l&&(h+=l,o+=c),y<=p&&(h+=p,r+=u)}return n},nd=a=>a.state==="closed"||a.state==="locked",Mr=(a,e,n,o)=>{const r=ad(n,o);for(let i=1;i<r.length-1;i++){const d=r[i];if(ft(a,d.x,d.y)==="impassable")return!1;for(const p of e)if(p.position.x===d.x&&p.position.y===d.y&&nd(p))return!1}return!0},od=Mr,rd=a=>Math.floor((a-10)/2),id=a=>{const e=Q(a),n=(e.die+1)/2;return e.count*n+e.modifier},te=(a,e)=>{switch(a.kind){case"const":return a.value;case"ability":return e.abilityScores[a.ability];case"abilityMod":return rd(e.abilityScores[a.ability]);case"profBonus":return e.proficiencyBonus;case"level":return a.classId===void 0?e.totalLevel:e.classLevels.get(a.classId)??0;case"classCol":return e.classColumns?.get(a.classId)?.get(a.column)??0;case"dice":return id(a.expression);case"add":return a.terms.reduce((n,o)=>n+te(o,e),0);case"multiply":return a.terms.reduce((n,o)=>n*te(o,e),1);case"max":{const n=a.terms.map(o=>te(o,e));return Math.max(...n)}case"min":{const n=a.terms.map(o=>te(o,e));return Math.min(...n)}case"floor":return Math.floor(te(a.term,e));case"ceil":return Math.ceil(te(a.term,e))}},sd=(a,e)=>a?.get(e),pe=(a,e)=>{switch(a.kind){case"always":return!0;case"never":return!1;case"self":return e.self===!0;case"eq":return sd(e.facts,a.path)===a.value;case"hasProperty":return e.weaponProperties?.has(a.property)===!0;case"hasCondition":return e.activeConditions?.has(a.conditionId)===!0;case"damageType":return e.damageType===a.type;case"not":return!pe(a.term,e);case"all":return a.terms.every(n=>pe(n,e));case"any":return a.terms.some(n=>pe(n,e))}};qt.enableMapSet();const cd=(a,e)=>qt.produce(a,e);class dd extends Error{constructor(e){super(e),this.name="InvariantViolationError"}}function m(a,e){if(!a)throw new dd(e)}const ld=(a,e)=>{m(a.characters[e.snapshot.id]===void 0,`Character ${e.snapshot.id} already exists`),a.characters[e.snapshot.id]=e.snapshot},Ot=3,Pr=3,ud=20,md=1,pd=10,hd=2,fd=1,Id=1,Y=(a,e)=>{const n=a.characters[e];return m(n!==void 0,`Character ${e} not found`),n},gd=(a,e,n)=>a>0&&e<0&&Math.abs(e)>=n,xe=a=>{a.successes=0,a.failures=0,a.stable=!1},yd=(a,e)=>{if(a.hp.temp<=0)return e;const n=Math.min(a.hp.temp,e);return a.hp.temp-=n,e-n},bd=a=>a.components.reduce((e,n)=>e+n.amount,0),Ne=(a,e)=>{a.failures=Math.min(a.failures+e,Pr)},Sd=(a,e)=>{const n=Y(a,e.targetId),o=yd(n,bd(e)),r=n.hp.current>0,i=n.hp.current-o;if(n.hp.current=Math.max(i,-n.hp.max),!r&&o>0){Ne(n.deathSaves,1),n.deathSaves.stable=!1;return}if(gd(n.hp.current+o,i,n.hp.max)){n.hp.current=-n.hp.max,n.deathSaves.failures=Pr,n.deathSaves.stable=!1;return}r&&n.hp.current<=0&&xe(n.deathSaves)},vd=(a,e)=>{const n=Y(a,e.targetId);if(e.amount<=0)return;const o=n.hp.current<=0;n.hp.current<0&&(n.hp.current=0),o&&xe(n.deathSaves),n.hp.current=Math.min(n.hp.current+e.amount,n.hp.max)},zd=(a,e)=>{const n=Y(a,e.targetId);e.amount>n.hp.temp&&(n.hp.temp=e.amount)},Cd=(a,e)=>{const n=Y(a,e.targetId);if(e.conditionId==="exhaustion"){const r=e.level??Id;n.exhaustion=Math.min(Ke,n.exhaustion+r);return}n.appliedConditions.find(r=>r.conditionId===e.conditionId)||n.appliedConditions.push({id:e.appliedConditionId??e.id,conditionId:e.conditionId,sourceEventId:e.id,...e.level!==void 0?{level:e.level}:{},...e.expiresOnRound!==void 0?{expiresOnRound:e.expiresOnRound}:{}})},Ed=(a,e)=>{const n=Y(a,e.targetId);n.appliedConditions=n.appliedConditions.filter(o=>o.conditionId!==e.conditionId)},kd=(a,e)=>{const n=Y(a,e.targetId);m(n.exhaustion===e.fromLevel,`Exhaustion mismatch on ${e.targetId}: expected ${e.fromLevel}, was ${n.exhaustion}`),n.exhaustion=e.toLevel},Ad=(a,e)=>{const n=Y(a,e.targetId);if(m(n.hp.current===0,`Death saves only apply at 0 HP (character ${e.targetId} has ${n.hp.current})`),e.d20===ud){n.hp.current=fd,xe(n.deathSaves);return}if(e.d20===md){Ne(n.deathSaves,hd);return}if(e.d20>=pd){n.deathSaves.successes=Math.min(n.deathSaves.successes+1,Ot),n.deathSaves.successes>=Ot&&(n.deathSaves.stable=!0);return}Ne(n.deathSaves,1)},wd=(a,e)=>{const n=Y(a,e.targetId);xe(n.deathSaves),n.deathSaves.stable=!0},Rd="action-surge",Td=(a,e)=>{if(e.resourceId!==Rd)return;const n=a.activeEncounterId;if(n===void 0)return;const o=a.encounters[n];if(!o)return;const r=o.combatants.find(i=>i.combatantId===e.characterId);r&&(r.turnUsage.actionUsed=!1,r.turnUsage.attacksMadeThisTurn=0)},Dd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`);const o=n.combatants.find(r=>r.combatantId===e.combatantId);switch(m(o!==void 0,`Combatant ${e.combatantId} not in encounter`),e.kind){case"action":m(!o.turnUsage.actionUsed,"Action already used this turn"),o.turnUsage.actionUsed=!0;break;case"bonusAction":m(!o.turnUsage.bonusActionUsed,"Bonus action already used this turn"),o.turnUsage.bonusActionUsed=!0;break;case"reaction":m(!o.turnUsage.reactionUsedThisRound,"Reaction already used this round"),o.turnUsage.reactionUsedThisRound=!0;break;case"attack":o.turnUsage.attacksMadeThisTurn+=1;break}},It=(a,e)=>{const n=a.characters[e];return m(n!==void 0,`Character ${e} not found`),n},Bd=(a,e)=>{const o=It(a,e.characterId).resources.find(r=>r.resourceId===e.resourceId);m(o!==void 0,`Resource ${e.resourceId} not on character`),m(o.current>=e.amount,`Resource ${e.resourceId} insufficient: have ${o.current}, spend ${e.amount}`),o.current-=e.amount,Td(a,e)},xd=(a,e)=>{const o=It(a,e.characterId).resources.find(i=>i.resourceId===e.resourceId);m(o!==void 0,`Resource ${e.resourceId} not on character`);const r=e.amount==="all"?o.max:e.amount;o.current=Math.min(o.current+r,o.max)},Md=(a,e)=>{const n=It(a,e.characterId),o=n.classes.find(r=>r.hitDiceRemaining>0);m(o!==void 0,`No hit dice remaining for ${e.characterId}`),o.hitDiceRemaining-=1,n.hp.current>0&&(n.hp.current=Math.min(n.hp.current+e.healed,n.hp.max))},Lr=["firedThisTurn","firedThisRound","firedThisShortRest","firedThisLongRest"],Pd=(a,e)=>{const n=a.characters[e];return m(n!==void 0,`Character ${e} not found`),n},Ld=(a,e)=>{const n=Pd(a,e.characterId),r={...n.triggerCounters[e.triggerId]??{}};for(const i of Lr){const d=e.cadence[i];d!==void 0&&(r[i]=d)}n.triggerCounters[e.triggerId]=r},$r=(a,e)=>{for(const n of Object.keys(a.triggerCounters)){const o=a.triggerCounters[n];if(o!==void 0)for(const r of e)o[r]=!1}},gt=(a,e,n)=>{for(const o of e){const r=a.characters[o];r!==void 0&&$r(r,n)}},$d=(a,e)=>{const n=a.characters[e];n&&$r(n,["firedThisTurn"])},Od=(a,e)=>gt(a,e,["firedThisRound"]),_d=(a,e)=>gt(a,e,["firedThisShortRest"]),Nd=(a,e)=>gt(a,e,Lr),Fd=(a,e)=>{m(a.activeShortRest===void 0,"A short rest is already in progress"),m(a.activeLongRest===void 0,"Cannot short rest during a long rest"),a.activeShortRest={startedAtEventId:e.id,participantIds:[...e.participantIds]}},Ud=(a,e)=>{const n=a.activeShortRest;m(n!==void 0,"No active short rest to end"),a.activeShortRest=void 0;for(const o of n.participantIds){const r=a.characters[o];r&&(r.pactSlotsUsed=0)}_d(a,n.participantIds)},jd=a=>Math.floor(a/2),qd=a=>Math.max(1,a),Hd=(a,e)=>{m(a.activeShortRest===void 0,"Cannot long rest during a short rest"),m(a.activeLongRest===void 0,"A long rest is already in progress"),a.activeLongRest={startedAtEventId:e.id,participantIds:[...e.participantIds]}},Gd=(a,e)=>{const n=a.activeLongRest;m(n!==void 0,"No active long rest to end"),a.activeLongRest=void 0;for(const o of n.participantIds){const r=a.characters[o];if(!r)continue;r.hp.current=r.hp.max,r.hp.temp=0,r.deathSaves.successes=0,r.deathSaves.failures=0,r.deathSaves.stable=!1,r.exhaustion>0&&(r.exhaustion=r.exhaustion-1);let i=0;for(const l of r.classes)i+=l.level;let p=qd(jd(i));for(const l of r.classes){if(p<=0)break;const c=l.level-l.hitDiceRemaining,u=Math.min(p,c);l.hitDiceRemaining+=u,p-=u}for(const l of r.resources)l.current=l.max;r.spellSlotsUsed={},r.pactSlotsUsed=0}Nd(a,n.participantIds)},Kd=(a,e)=>{m(a.encounters[e.encounterId]===void 0,`Encounter ${e.encounterId} already exists`),a.encounters[e.encounterId]={id:e.encounterId,...e.name!==void 0?{name:e.name}:{},status:"planning",combatants:e.combatantIds.map(n=>({combatantId:n,initiative:0,initiativeOrder:0,hasActedThisRound:!1,turnUsage:{actionUsed:!1,bonusActionUsed:!1,attacksMadeThisTurn:0,reactionUsedThisRound:!1,feetMovedThisTurn:0,dashed:!1,disengaged:!1}})),round:0,activeIndex:0}},Vd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="planning","Initiative can only be rolled while planning");const o=new Map(e.rolls.map(d=>[d.combatantId,d.total])),r=[...e.rolls].sort((d,p)=>p.total-d.total),i=new Map(r.map((d,p)=>[d.combatantId,p]));for(const d of n.combatants){const p=o.get(d.combatantId);m(p!==void 0,`Combatant ${d.combatantId} missing initiative roll`),d.initiative=p,d.initiativeOrder=i.get(d.combatantId)??0}n.combatants.sort((d,p)=>d.initiativeOrder-p.initiativeOrder)},Wd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="planning","Encounter already started"),m(n.combatants.length>0,"No combatants in encounter"),m(n.combatants.every(o=>o.initiative!==0||o.initiativeOrder>=0),"Initiative must be rolled before starting encounter"),n.status="active",n.round=1,n.activeIndex=0,n.startedAtEventId=e.id,a.activeEncounterId=e.encounterId},Xd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="active","Encounter not active");const o=n.combatants[n.activeIndex];m(o!==void 0&&o.combatantId===e.combatantId,`Turn-start mismatch: expected ${o?.combatantId}, got ${e.combatantId}`),m(n.round===e.round,"Round mismatch"),$d(a,e.combatantId),o.turnUsage.actionUsed=!1,o.turnUsage.bonusActionUsed=!1,o.turnUsage.attacksMadeThisTurn=0},Qd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="active","Encounter not active");const o=n.combatants[n.activeIndex];m(o!==void 0&&o.combatantId===e.combatantId,"Turn-end mismatch"),o.hasActedThisRound=!0,n.activeIndex+=1},Yd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="active","Encounter not active"),m(n.activeIndex>=n.combatants.length,"Not all combatants have acted");for(const o of n.combatants)o.hasActedThisRound=!1,o.turnUsage.reactionUsedThisRound=!1;n.round+=1,n.activeIndex=0,Od(a,n.combatants.map(o=>o.combatantId))},Jd=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`),m(n.status==="active","Encounter already ended or not started"),n.status="ended",n.outcome=e.outcome,n.endedAtEventId=e.id,a.activeEncounterId===e.encounterId&&(a.activeEncounterId=void 0)},_t=3,Zd=(a,e)=>{m(a.itemInstances[e.instance.id]===void 0,`Item instance ${e.instance.id} already exists`),a.itemInstances[e.instance.id]=e.instance},el=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`);const o=a.itemInstances[e.instanceId];m(o!==void 0,`Item instance ${e.instanceId} not found`),n.equipped[e.slot]=e.instanceId,o.equippedBy=e.characterId},tl=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`);const o=n.equipped[e.slot];if(o!==void 0){const r=a.itemInstances[o];r!==void 0&&(r.equippedBy=void 0)}n.equipped[e.slot]=void 0},al=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`);const o=a.itemInstances[e.instanceId];m(o!==void 0,`Item instance ${e.instanceId} not found`),m(!o.attuned,`Item ${e.instanceId} already attuned`),m(n.equipped.attuned.length<_t,`Character already has the maximum of ${_t} attuned items`),o.attuned=!0,o.attunedTo=e.characterId,n.equipped.attuned.push(e.instanceId)},nl=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`);const o=a.itemInstances[e.instanceId];m(o!==void 0,`Item instance ${e.instanceId} not found`),m(o.attuned,`Item ${e.instanceId} not attuned`),o.attuned=!1,o.attunedTo=void 0,n.equipped.attuned=n.equipped.attuned.filter(r=>r!==e.instanceId)},ol=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`);const o=n.classes.find(r=>r.classId===e.classId);m(o!==void 0,`Character ${e.characterId} has no enrollment in class ${e.classId}`),m(o.level+1===e.newClassLevel,`Level-up must advance by 1: current ${o.level}, requested ${e.newClassLevel}`),o.level=e.newClassLevel,o.hitDiceRemaining+=1,n.hp.max+=e.hpGained,n.hp.current+=e.hpGained},rl=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),m(a.pendingChoices[e.choiceId]===void 0,`Choice ${e.choiceId} already exists`),a.pendingChoices[e.choiceId]={id:e.choiceId,prompt:e.prompt,options:[...e.options],oneOf:e.oneOf,forCharacterId:e.characterId,triggerEventId:e.id},n.pendingChoiceIds.push(e.choiceId)},il=(a,e)=>{const n=a.pendingChoices[e.choiceId];m(n!==void 0,`Choice ${e.choiceId} not found`),m(n.resolution===void 0,`Choice ${e.choiceId} already resolved`),m(n.forCharacterId===e.characterId,`Choice ${e.choiceId} belongs to a different character`),m(e.selectedOptionIds.length===n.oneOf,`Expected exactly ${n.oneOf} selection(s), got ${e.selectedOptionIds.length}`);for(const o of e.selectedOptionIds)m(n.options.some(r=>r.id===o),`Option ${o} not in choice ${e.choiceId}`);n.resolution={selectedOptionIds:[...e.selectedOptionIds],atEventId:e.id}},Or=(a,e)=>{const n=a.characters[e];return m(n!==void 0,`Character ${e} not found`),n},sl=(a,e)=>{const n=Or(a,e.characterId),o=String(e.slotLevel),r=n.spellSlotsUsed[o]??0;n.spellSlotsUsed[o]=r+1},cl=(a,e)=>{const n=Or(a,e.characterId);n.pactSlotsUsed+=1},dl=(a,e)=>{const n=a.characters[e.casterId];m(n!==void 0,`Caster ${e.casterId} not found`),m(a.effectInstances[e.effectInstanceId]===void 0,`EffectInstance ${e.effectInstanceId} already exists`),a.effectInstances[e.effectInstanceId]={id:e.effectInstanceId,spellId:e.spellId,casterId:e.casterId,targetIds:[...e.targetIds],conditionsApplied:[...e.conditionsApplied],requiresConcentration:!0,...e.durationRounds!==void 0?{durationRounds:e.durationRounds}:{},startedAtEventId:e.id},n.concentrationEffectId=e.effectInstanceId},ll=(a,e)=>{const n=a.effectInstances[e.effectInstanceId];m(n!==void 0,`EffectInstance ${e.effectInstanceId} not found`);const o=a.characters[n.casterId];for(const r of n.conditionsApplied){const i=a.characters[r.targetId];i&&(i.appliedConditions=i.appliedConditions.filter(d=>d.id!==r.appliedConditionId))}o?.concentrationEffectId===e.effectInstanceId&&(o.concentrationEffectId=void 0),delete a.effectInstances[e.effectInstanceId]},ul=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`);const o=n.combatants.find(r=>r.combatantId===e.combatantId);m(o!==void 0,`Combatant ${e.combatantId} not in encounter`),o.position={...e.toPosition},o.turnUsage.feetMovedThisTurn+=e.feetTraveled},ml=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`);const o=n.combatants.find(r=>r.combatantId===e.combatantId);m(o!==void 0,`Combatant ${e.combatantId} not in encounter`),m(!o.turnUsage.dashed,`${e.combatantId} already dashed this turn`),o.turnUsage.dashed=!0},pl=(a,e)=>{const n=a.encounters[e.encounterId];m(n!==void 0,`Encounter ${e.encounterId} not found`);const o=n.combatants.find(r=>r.combatantId===e.combatantId);m(o!==void 0,`Combatant ${e.combatantId} not in encounter`),m(!o.turnUsage.disengaged,`${e.combatantId} already disengaged this turn`),o.turnUsage.disengaged=!0},hl=(a,e)=>{m(a.parties[e.partyId]===void 0,`Party ${e.partyId} already exists`);for(const n of e.memberIds)m(a.characters[n]!==void 0,`Member ${n} not found`);a.parties[e.partyId]={id:e.partyId,name:e.name,memberIds:[...e.memberIds],sharedInventory:[],purse:de()}},fl=(a,e)=>{const n=a.parties[e.partyId];m(n!==void 0,`Party ${e.partyId} not found`);for(const o of e.added)m(a.characters[o]!==void 0,`Member ${o} not found`),n.memberIds.includes(o)||n.memberIds.push(o);e.removed.length>0&&(n.memberIds=n.memberIds.filter(o=>!e.removed.includes(o)))},Il=(a,e)=>{const n=a.parties[e.partyId];m(n!==void 0,`Party ${e.partyId} not found`),n.purse=Ze(n.purse,e.amounts)},gl=(a,e)=>{const n=a.parties[e.partyId];m(n!==void 0,`Party ${e.partyId} not found`),n.purse=Wa(n.purse,e.amounts)},yl=(a,e)=>{const n=a.parties[e.partyId];if(m(n!==void 0,`Party ${e.partyId} not found`),m(a.itemInstances[e.itemInstanceId]!==void 0,`Item instance ${e.itemInstanceId} not found`),e.sourceCharacterId!==void 0){const o=a.characters[e.sourceCharacterId];m(o!==void 0,`Character ${e.sourceCharacterId} not found`),o.inventory=o.inventory.filter(r=>r!==e.itemInstanceId)}n.sharedInventory.includes(e.itemInstanceId)||n.sharedInventory.push(e.itemInstanceId)},bl=(a,e)=>{const n=a.parties[e.partyId];if(m(n!==void 0,`Party ${e.partyId} not found`),m(n.sharedInventory.includes(e.itemInstanceId),`Item ${e.itemInstanceId} not in party ${e.partyId} inventory`),n.sharedInventory=n.sharedInventory.filter(o=>o!==e.itemInstanceId),e.recipientCharacterId!==void 0){const o=a.characters[e.recipientCharacterId];m(o!==void 0,`Character ${e.recipientCharacterId} not found`),o.inventory.includes(e.itemInstanceId)||o.inventory.push(e.itemInstanceId)}},Sl=(a,e)=>{m(a.sessions[e.sessionId]===void 0,`Session ${e.sessionId} already exists`),m(a.activeSessionId===void 0,`Another session ${a.activeSessionId} is already active`),e.inGameStart!==void 0&&(m(e.inGameStart.totalMinutes>=a.inGameTime.totalMinutes,"Session inGameStart cannot rewind the campaign clock"),a.inGameTime={totalMinutes:e.inGameStart.totalMinutes}),a.sessions[e.sessionId]={id:e.sessionId,name:e.name,startedAtIso:e.at,inGameStart:{totalMinutes:a.inGameTime.totalMinutes},journalEntryIds:[]},a.activeSessionId=e.sessionId},vl=(a,e)=>{const n=a.sessions[e.sessionId];m(n!==void 0,`Session ${e.sessionId} not found`),m(n.endedAtIso===void 0,`Session ${e.sessionId} already ended`),n.endedAtIso=e.at,n.inGameEnd=a.inGameTime,e.summary!==void 0&&(n.summary=e.summary),a.activeSessionId===e.sessionId&&(a.activeSessionId=void 0)},zl=(a,e)=>{m(a.journalEntries[e.entryId]===void 0,`Journal entry ${e.entryId} already exists`),e.sessionId!==void 0&&m(a.sessions[e.sessionId]!==void 0,`Session ${e.sessionId} not found`),e.authorCharacterId!==void 0&&m(a.characters[e.authorCharacterId]!==void 0,`Author ${e.authorCharacterId} not found`),a.journalEntries[e.entryId]={id:e.entryId,sessionId:e.sessionId,authorKind:e.authorKind,authorCharacterId:e.authorCharacterId,visibility:e.visibility,visibleToCharacterIds:[...e.visibleToCharacterIds],title:e.title,body:e.body,createdAtIso:e.at,inGameAt:a.inGameTime},e.sessionId!==void 0&&a.sessions[e.sessionId].journalEntryIds.push(e.entryId)},Cl=(a,e)=>{a.inGameTime=Ya(a.inGameTime,e.minutes)},El=(a,e)=>{if(m(a.locations[e.locationId]===void 0,`Location ${e.locationId} already exists`),e.parentLocationId!==void 0&&m(a.locations[e.parentLocationId]!==void 0,`Parent location ${e.parentLocationId} not found`),e.map!==void 0){m(e.map.terrain.length===e.map.heightCells,`Map terrain rows (${e.map.terrain.length}) must equal heightCells (${e.map.heightCells})`);for(const n of e.map.terrain)m(n.length===e.map.widthCells,`Map terrain row width (${n.length}) must equal widthCells (${e.map.widthCells})`)}a.locations[e.locationId]={id:e.locationId,name:e.name,description:e.description,parentLocationId:e.parentLocationId,map:e.map,doorIds:[]}},kl=(a,e)=>{m(a.doors[e.doorId]===void 0,`Door ${e.doorId} already exists`);const n=a.locations[e.locationId];m(n!==void 0,`Location ${e.locationId} not found`),n.map!==void 0&&(m(e.position.x>=0&&e.position.x<n.map.widthCells,`Door x ${e.position.x} out of map bounds`),m(e.position.y>=0&&e.position.y<n.map.heightCells,`Door y ${e.position.y} out of map bounds`)),a.doors[e.doorId]={id:e.doorId,locationId:e.locationId,name:e.name,position:{x:e.position.x,y:e.position.y},state:e.state},n.doorIds.push(e.doorId)},Al=(a,e)=>{const n=a.doors[e.doorId];m(n!==void 0,`Door ${e.doorId} not found`),e.byCharacterId!==void 0&&m(a.characters[e.byCharacterId]!==void 0,`Character ${e.byCharacterId} not found`),n.state=e.toState},wl=(a,e)=>{m(a.characters[e.characterId]!==void 0,`Character ${e.characterId} not found`),e.toLocationId===void 0?delete a.characterLocations[e.characterId]:(m(a.locations[e.toLocationId]!==void 0,`Location ${e.toLocationId} not found`),a.characterLocations[e.characterId]=e.toLocationId)},Rl=a=>a.objectives.map(e=>({id:e.id,description:e.description,status:e.status,optional:e.optional,progress:e.progress,...e.required!==void 0?{required:e.required}:{}})),Tl=(a,e)=>{m(a.quests[e.questId]===void 0,`Quest ${e.questId} already exists`),e.partyId!==void 0&&m(a.parties[e.partyId]!==void 0,`Party ${e.partyId} not found`),a.quests[e.questId]={id:e.questId,title:e.title,description:e.description,status:"active",partyId:e.partyId,objectives:Rl(e),reward:e.reward??{xpPerCharacter:0,currency:de(),itemDefinitionIds:[]},rewardClaimed:!1,startedAtIso:e.at}},yt=(a,e,n)=>{const o=a.quests[e];m(o!==void 0,`Quest ${e} not found`);const r=o.objectives.find(i=>i.id===n);return m(r!==void 0,`Objective ${n} not found on quest ${e}`),{quest:o,objective:r}},Dl=(a,e)=>{const{quest:n,objective:o}=yt(a,e.questId,e.objectiveId);m(n.status==="active",`Quest ${e.questId} is not active`),m(o.status==="pending",`Objective ${e.objectiveId} is not pending`),o.progress+=e.delta,o.required!==void 0&&o.progress>=o.required&&(o.status="completed")},Bl=(a,e)=>{const{objective:n}=yt(a,e.questId,e.objectiveId);m(n.status!=="completed",`Objective ${e.objectiveId} already completed`),n.status="completed",n.required!==void 0&&n.progress<n.required&&(n.progress=n.required)},xl=(a,e)=>{const{objective:n}=yt(a,e.questId,e.objectiveId);m(n.status==="pending",`Objective ${e.objectiveId} is not pending`),n.status="failed"},Ml=(a,e)=>{const n=a.quests[e.questId];m(n!==void 0,`Quest ${e.questId} not found`),m(n.status==="active",`Quest ${e.questId} is not active`);for(const o of n.objectives)o.optional||m(o.status==="completed",`Required objective ${o.id} is not completed`);n.status="completed",n.endedAtIso=e.at},Pl=(a,e)=>{const n=a.quests[e.questId];m(n!==void 0,`Quest ${e.questId} not found`),m(n.status==="active",`Quest ${e.questId} is not active`),n.status="failed",n.endedAtIso=e.at},Ll=(a,e)=>{const n=a.quests[e.questId];m(n!==void 0,`Quest ${e.questId} not found`),m(n.status==="active",`Quest ${e.questId} is not active`),n.status="abandoned",n.endedAtIso=e.at},$l=(a,e)=>{const n=a.quests[e.questId];m(n!==void 0,`Quest ${e.questId} not found`),m(n.status==="completed",`Quest ${e.questId} must be completed before claiming reward`),m(!n.rewardClaimed,`Quest ${e.questId} reward already claimed`);for(const o of e.beneficiaryCharacterIds){m(a.characters[o]!==void 0,`Beneficiary ${o} not found`);const r=a.characters[o];r.xp+=n.reward.xpPerCharacter}if(n.partyId!==void 0){const o=a.parties[n.partyId];m(o!==void 0,`Party ${n.partyId} not found`),o.purse=Ze(o.purse,n.reward.currency)}n.rewardClaimed=!0},Ol=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),n.xp+=e.amount},_l=(a,e)=>{e.partyId!==void 0&&m(a.parties[e.partyId]!==void 0,`Party ${e.partyId} not found`),e.questId!==void 0&&m(a.quests[e.questId]!==void 0,`Quest ${e.questId} not found`),a.milestones.push({kind:e.kind,title:e.title,atIso:e.at,partyId:e.partyId,questId:e.questId})},Nl=(a,e)=>{const n=a.effectInstances[e.effectInstanceId];m(n!==void 0,`EffectInstance ${e.effectInstanceId} not found`),m(a.characters[e.dispelledByCharacterId]!==void 0,`Caster ${e.dispelledByCharacterId} not found`);for(const r of n.conditionsApplied){const i=a.characters[r.targetId];i&&(i.appliedConditions=i.appliedConditions.filter(d=>d.id!==r.appliedConditionId))}const o=a.characters[n.casterId];o?.concentrationEffectId===e.effectInstanceId&&(o.concentrationEffectId=void 0),delete a.effectInstances[e.effectInstanceId]},Fl=(a,e)=>{const n=a.itemInstances[e.itemInstanceId];m(n!==void 0,`Item ${e.itemInstanceId} not found`),m(a.characters[e.identifiedByCharacterId]!==void 0,`Identifier ${e.identifiedByCharacterId} not found`),n.identifiedByCharacterIds.includes(e.identifiedByCharacterId)||n.identifiedByCharacterIds.push(e.identifiedByCharacterId)},Ul=(a,e)=>{m(a.characters[e.attackerId]!==void 0,`Attacker ${e.attackerId} not found`),m(a.itemInstances[e.weaponInstanceId]!==void 0,`Weapon ${e.weaponInstanceId} not found`),e.targetId!==void 0&&m(a.characters[e.targetId]!==void 0,`Target ${e.targetId} not found`)},jl=(a,e)=>{const n=a.characters[e.riderId];m(n!==void 0,`Rider ${e.riderId} not found`),m(n.mountedOnId===void 0,`${e.riderId} is already mounted`),m(a.characters[e.mountId]!==void 0,`Mount ${e.mountId} not found`),n.mountedOnId=e.mountId},ql=(a,e)=>{const n=a.characters[e.riderId];m(n!==void 0,`Rider ${e.riderId} not found`),m(n.mountedOnId===e.mountId,`${e.riderId} is not mounted on ${e.mountId}`),n.mountedOnId=void 0},Hl=(a,e)=>{m(a.vehicles[e.vehicleId]===void 0,`Vehicle ${e.vehicleId} already exists`),a.vehicles[e.vehicleId]={id:e.vehicleId,name:e.name,kind:e.kind,speedFeet:e.speedFeet,ac:e.ac,hp:{current:e.maxHp,max:e.maxHp},capacity:e.capacity,occupantIds:[]}},Gl=(a,e)=>{const n=a.vehicles[e.vehicleId];m(n!==void 0,`Vehicle ${e.vehicleId} not found`),m(a.characters[e.characterId]!==void 0,`Character ${e.characterId} not found`),m(n.occupantIds.length<n.capacity,`Vehicle ${e.vehicleId} is at capacity`),n.occupantIds.includes(e.characterId)||n.occupantIds.push(e.characterId)},Kl=(a,e)=>{const n=a.vehicles[e.vehicleId];m(n!==void 0,`Vehicle ${e.vehicleId} not found`),m(n.occupantIds.includes(e.characterId),`${e.characterId} is not aboard ${e.vehicleId}`),n.occupantIds=n.occupantIds.filter(o=>o!==e.characterId)},Vl=(a,e)=>{const n=a.vehicles[e.vehicleId];m(n!==void 0,`Vehicle ${e.vehicleId} not found`),n.hp.current=Math.max(0,n.hp.current-e.amount)},Wl=(a,e)=>{const n=a.vehicles[e.vehicleId];m(n!==void 0,`Vehicle ${e.vehicleId} not found`),n.hp.current=Math.min(n.hp.max,n.hp.current+e.amount)},Xl=(a,e)=>{m(a.parties[e.partyId]!==void 0,`Party ${e.partyId} not found`),e.fromLocationId!==void 0&&m(a.locations[e.fromLocationId]!==void 0,`From-location ${e.fromLocationId} not found`),e.toLocationId!==void 0&&m(a.locations[e.toLocationId]!==void 0,`To-location ${e.toLocationId} not found`),a.travelLog.push({partyId:e.partyId,pace:e.pace,hours:e.hours,miles:e.miles,fromLocationId:e.fromLocationId,toLocationId:e.toLocationId,notes:e.notes,atIso:e.at})},Ql=(a,e)=>{m(a.parties[e.partyId]!==void 0,`Party ${e.partyId} not found`),m(a.characters[e.navigatorId]!==void 0,`Navigator ${e.navigatorId} not found`)},Yl=(a,e)=>{m(a.parties[e.partyId]!==void 0,`Party ${e.partyId} not found`),m(a.characters[e.foragerId]!==void 0,`Forager ${e.foragerId} not found`)},Jl=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),n.attitude=e.toAttitude},Zl=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),!e.success&&n.morale!==void 0&&(n.morale.current=Math.max(0,n.morale.current-1))},eu=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),n.moraleBroken=!0},tu=(a,e)=>{if(m(a.characters[e.characterId]!==void 0,`Character ${e.characterId} not found`),a.downtimeLog.push({characterId:e.characterId,kind:e.kind,days:e.days,outcome:e.outcome,summary:e.summary,atIso:e.at,producedItemDefinitionId:e.producedItemDefinitionId,toolProficiencyGained:e.toolProficiencyGained}),e.toolProficiencyGained!==void 0){const n=a.toolProficienciesByCharacter[e.characterId]??[];n.includes(e.toolProficiencyGained)||(a.toolProficienciesByCharacter[e.characterId]=[...n,e.toolProficiencyGained])}},au=(a,e)=>{const n=a.itemInstances[e.itemInstanceId];m(n!==void 0,`Item ${e.itemInstanceId} not found`);const o=n.chargesRemaining??0;m(o>=e.amount,`Item ${e.itemInstanceId} has only ${o} charges`),n.chargesRemaining=o-e.amount,e.byCharacterId!==void 0&&m(a.characters[e.byCharacterId]!==void 0,`Wielder ${e.byCharacterId} not found`)},nu=(a,e)=>{const n=a.itemInstances[e.itemInstanceId];m(n!==void 0,`Item ${e.itemInstanceId} not found`);const o=n.chargesRemaining??0,r=n.maxCharges??o+e.amount;n.chargesRemaining=Math.min(r,o+e.amount)},ou=(a,e)=>{const n=a.itemInstances[e.itemInstanceId];m(n!==void 0,`Item ${e.itemInstanceId} not found`),m(n.sentient!==void 0,`Item ${e.itemInstanceId} is not sentient`),m(a.characters[e.wielderId]!==void 0,`Wielder ${e.wielderId} not found`)},ru=(a,e)=>{m(a.bastions[e.bastionId]===void 0,`Bastion ${e.bastionId} already exists`),m(a.characters[e.ownerCharacterId]!==void 0,`Owner ${e.ownerCharacterId} not found`),e.locationId!==void 0&&m(a.locations[e.locationId]!==void 0,`Location ${e.locationId} not found`),a.bastions[e.bastionId]={id:e.bastionId,name:e.name,ownerCharacterId:e.ownerCharacterId,locationId:e.locationId,level:e.level,facilities:[],hirelings:[],defenders:0,treasuryGp:0,hpCurrent:e.hpMax,hpMax:e.hpMax}},iu=(a,e)=>{const n=a.bastions[e.bastionId];m(n!==void 0,`Bastion ${e.bastionId} not found`),m(!n.facilities.some(o=>o.id===e.facilityId),`Facility ${e.facilityId} already exists on bastion`),n.facilities.push({id:e.facilityId,name:e.name,kind:e.kind,space:e.space,description:e.description})},su=(a,e)=>{const n=a.bastions[e.bastionId];m(n!==void 0,`Bastion ${e.bastionId} not found`),n.hirelings.push({id:e.hirelingId,name:e.name,role:e.role})},cu=(a,e)=>{const n=a.bastions[e.bastionId];m(n!==void 0,`Bastion ${e.bastionId} not found`),n.treasuryGp=Math.max(0,n.treasuryGp+e.treasuryDeltaGp)},du=(a,e)=>{const n=a.bastions[e.bastionId];m(n!==void 0,`Bastion ${e.bastionId} not found`),n.hpCurrent=Math.max(0,n.hpCurrent-e.amount)},lu=(a,e)=>{const n=a.bastions[e.bastionId];m(n!==void 0,`Bastion ${e.bastionId} not found`),m(n.level===e.fromLevel,`Bastion level mismatch (expected ${e.fromLevel}, got ${n.level})`),n.level=e.toLevel},uu=(a,e)=>{const n=a.settings;if(e.grittyRest!==void 0&&(n.grittyRest=e.grittyRest),e.heroPoints!==void 0&&(n.heroPoints=e.heroPoints),e.sanity!==void 0&&(n.sanity=e.sanity),e.massCombat!==void 0&&(n.massCombat=e.massCombat),e.feaCharacterFlaws!==void 0&&(n.feaCharacterFlaws=e.feaCharacterFlaws),e.customHouserulesAdd!==void 0)for(const o of e.customHouserulesAdd)n.customHouserules.includes(o)||n.customHouserules.push(o);e.customHouserulesRemove!==void 0&&(n.customHouserules=n.customHouserules.filter(o=>!e.customHouserulesRemove.includes(o)))},mu=(a,e)=>{const n=a.characters[e.characterId];m(n!==void 0,`Character ${e.characterId} not found`),n.hp.current=e.hpAfter,n.hp.temp=0,n.deathSaves={successes:0,failures:0,stable:!1},n.exhaustion=0,e.newSpeciesId!==void 0&&(n.speciesId=e.newSpeciesId),e.byCharacterId!==void 0&&m(a.characters[e.byCharacterId]!==void 0,`Caster ${e.byCharacterId} not found`)},pu=(a,e)=>{const n=a.characters[e.targetId];m(n!==void 0,`Target ${e.targetId} not found`),m(n.polymorphedSnapshot===void 0,`${e.targetId} is already polymorphed`),n.polymorphedSnapshot={hp:{current:n.hp.current,max:n.hp.max,temp:n.hp.temp},abilityScores:{...n.abilityScores},speedFeet:n.speedFeet,speciesId:n.speciesId,kind:e.kind,formName:e.form.name},n.hp.current=e.form.hp,n.hp.max=e.form.hp,n.hp.temp=0,n.abilityScores={...e.form.abilityScores},n.speedFeet=e.form.speedFeet,e.form.speciesId!==void 0&&(n.speciesId=e.form.speciesId)},hu=(a,e)=>{const n=a.characters[e.targetId];m(n!==void 0,`Target ${e.targetId} not found`);const o=n.polymorphedSnapshot;m(o!==void 0,`${e.targetId} is not polymorphed`),n.hp={current:o.hp.current,max:o.hp.max,temp:o.hp.temp},n.abilityScores={...o.abilityScores},n.speedFeet=o.speedFeet,n.speciesId=o.speciesId,n.polymorphedSnapshot=void 0},fu=(a,e)=>{const n=a.characters[e.originalId];m(n!==void 0,`Original ${e.originalId} not found`),m(a.characters[e.simulacrumId]===void 0,`Simulacrum ${e.simulacrumId} already exists`),a.characters[e.simulacrumId]={...n,id:e.simulacrumId,name:`Simulacrum of ${n.name}`,kind:"creature",hp:{current:e.hpMax,max:e.hpMax,temp:0},appliedConditions:[],triggerCounters:{},spellSlotsUsed:{},pactSlotsUsed:0,concentrationEffectId:void 0,inventory:[],equipped:{attuned:[]},pendingChoiceIds:[],polymorphedSnapshot:void 0,mountedOnId:void 0,moraleBroken:!1,xp:0}},Iu=(a,e)=>{if(m(a.characters[e.granterId]!==void 0,`Granter ${e.granterId} not found`),e.stressApplied){const n=a.characters[e.granterId];n.exhaustion=Math.min(6,n.exhaustion+1)}},Me=(a,e)=>cd(a,n=>{switch(e.type){case"CharacterCreated":ld(n,e);break;case"DamageApplied":Sd(n,e);break;case"Healed":vd(n,e);break;case"TempHPGranted":zd(n,e);break;case"ConditionApplied":Cd(n,e);break;case"ConditionRemoved":Ed(n,e);break;case"ExhaustionChanged":kd(n,e);break;case"DeathSaveRolled":Ad(n,e);break;case"Stabilized":wd(n,e);break;case"ResourceSpent":Bd(n,e);break;case"ResourceRestored":xd(n,e);break;case"HitDieSpent":Md(n,e);break;case"ShortRestStarted":Fd(n,e);break;case"ShortRestEnded":Ud(n);break;case"LongRestStarted":Hd(n,e);break;case"LongRestEnded":Gd(n);break;case"EncounterCreated":Kd(n,e);break;case"EncounterStarted":Wd(n,e);break;case"InitiativeRolled":Vd(n,e);break;case"TurnStarted":Xd(n,e);break;case"TurnEnded":Qd(n,e);break;case"RoundEnded":Yd(n,e);break;case"EncounterEnded":Jd(n,e);break;case"AttackRolled":break;case"DamageRolled":break;case"ItemAcquired":Zd(n,e);break;case"LevelUpResolved":ol(n,e);break;case"ChoiceRequired":rl(n,e);break;case"ChoiceResolved":il(n,e);break;case"SaveRolled":break;case"AbilityCheckRolled":break;case"SpellCastDeclared":break;case"SpellSlotConsumed":sl(n,e);break;case"PactSlotConsumed":cl(n,e);break;case"ConcentrationStarted":dl(n,e);break;case"ConcentrationBroken":ll(n,e);break;case"TriggerFired":Ld(n,e);break;case"ActionEconomyConsumed":Dd(n,e);break;case"CombatantMoved":ul(n,e);break;case"Dashed":ml(n,e);break;case"Disengaged":pl(n,e);break;case"ItemEquipped":el(n,e);break;case"ItemUnequipped":tl(n,e);break;case"ItemAttuned":al(n,e);break;case"ItemUnattuned":nl(n,e);break;case"PartyCreated":hl(n,e);break;case"PartyMembersChanged":fl(n,e);break;case"CurrencyAcquired":Il(n,e);break;case"CurrencySpent":gl(n,e);break;case"ItemDepositedToParty":yl(n,e);break;case"ItemWithdrawnFromParty":bl(n,e);break;case"SessionStarted":Sl(n,e);break;case"SessionEnded":vl(n,e);break;case"JournalEntryAdded":zl(n,e);break;case"InGameTimeAdvanced":Cl(n,e);break;case"LocationCreated":El(n,e);break;case"DoorAdded":kl(n,e);break;case"DoorStateChanged":Al(n,e);break;case"CharacterLocationChanged":wl(n,e);break;case"QuestStarted":Tl(n,e);break;case"ObjectiveProgressed":Dl(n,e);break;case"ObjectiveCompleted":Bl(n,e);break;case"ObjectiveFailed":xl(n,e);break;case"QuestCompleted":Ml(n,e);break;case"QuestFailed":Pl(n,e);break;case"QuestAbandoned":Ll(n,e);break;case"QuestRewardClaimed":$l(n,e);break;case"XPAwarded":Ol(n,e);break;case"MilestoneAwarded":_l(n,e);break;case"SpellCountered":break;case"SpellDispelled":Nl(n,e);break;case"ItemIdentified":Fl(n,e);break;case"WeaponMasteryActivated":Ul(n,e);break;case"Mounted":jl(n,e);break;case"Dismounted":ql(n,e);break;case"VehicleAcquired":Hl(n,e);break;case"VehicleBoarded":Gl(n,e);break;case"VehicleDeparted":Kl(n,e);break;case"VehicleDamaged":Vl(n,e);break;case"VehicleRepaired":Wl(n,e);break;case"TravelLegCompleted":Xl(n,e);break;case"NavigationCheckRolled":Ql(n,e);break;case"ForagedFor":Yl(n,e);break;case"AttitudeChanged":Jl(n,e);break;case"MoraleCheckRolled":Zl(n,e);break;case"MoraleBroken":eu(n,e);break;case"DowntimeActivityResolved":tu(n,e);break;case"ItemChargeConsumed":au(n,e);break;case"ItemRecharged":nu(n,e);break;case"SentientItemConflict":ou(n,e);break;case"BastionFounded":ru(n,e);break;case"BastionFacilityAdded":iu(n,e);break;case"BastionHirelingAdded":su(n,e);break;case"BastionTurnTaken":cu(n,e);break;case"BastionDamaged":du(n,e);break;case"BastionLevelChanged":lu(n,e);break;case"CharacterResurrected":mu(n,e);break;case"PolymorphApplied":pu(n,e);break;case"PolymorphReverted":hu(n,e);break;case"SimulacrumCreated":fu(n,e);break;case"WishGranted":Iu(n,e);break;case"CampaignSettingsChanged":uu(n,e);break;default:m(!1,`Unhandled event: ${JSON.stringify(e)}`)}n.version+=1}),Pe=(a,e)=>e.reduce(Me,a),be=a=>Pe(lt(),a),bt=(a,e)=>{let n=a.state;for(const i of e)n=Me(n,i);const r=[...a.events.slice(0,a.cursor),...e];return{...a,state:n,events:r,cursor:r.length}},_r=a=>{if(a.cursor===0)return a;const e=a.cursor-1,n=a.events.slice(0,e);return{...a,state:be(n),cursor:e}},Nr=a=>{if(a.cursor>=a.events.length)return a;const e=a.cursor+1,n=a.events.slice(0,e);return{...a,state:be(n),cursor:e}},Fr=(a,e,n)=>{const r={Attack:l=>a.plan.attack(e.state,l),OpportunityAttack:l=>a.plan.opportunityAttack(e.state,l),ShortRest:l=>a.plan.shortRest(e.state,l),LongRest:l=>a.plan.longRest(e.state,l),CastSpell:l=>a.plan.castSpell(e.state,l),CheckConcentration:l=>a.plan.checkConcentration(e.state,l),Save:l=>a.plan.save(e.state,l),AbilityCheck:l=>a.plan.abilityCheck(e.state,l),LevelUp:l=>a.plan.levelUp(e.state,l),ResolveChoice:l=>a.plan.resolveChoice(e.state,l),Move:l=>a.plan.move(e.state,l),Dash:l=>a.plan.dash(e.state,l),Disengage:l=>a.plan.disengage(e.state,l),ActionSurge:l=>a.plan.actionSurge(e.state,l),OffHandAttack:l=>a.plan.offHandAttack(e.state,l),Multiattack:l=>a.plan.multiattack(e.state,l),Falling:l=>a.plan.falling(e.state,l),Grapple:l=>a.plan.grapple(e.state,l),Shove:l=>a.plan.shove(e.state,l),Hide:l=>a.plan.hide(e.state,l),Counterspell:l=>a.plan.counterspell(e.state,l),DispelMagic:l=>a.plan.dispelMagic(e.state,l),Identify:l=>a.plan.identify(e.state,l),WeaponMastery:l=>a.plan.weaponMastery(e.state,l),Forage:l=>a.plan.forage(e.state,l),NavigationCheck:l=>a.plan.navigationCheck(e.state,l),MoraleCheck:l=>a.plan.moraleCheck(e.state,l),ReactionRoll:l=>a.plan.reactionRoll(e.state,l)}[n.type];if(r===void 0)throw new Error(`Unknown intent type: ${n.type}`);const{type:i,...d}=n,p=r(d);return bt(e,p.events)},gu=t.z.object({id:t.z.string(),name:t.z.string(),schemaVersion:t.z.number().int(),events:t.z.array(lr)}),yu=a=>JSON.stringify({id:a.id,name:a.name,schemaVersion:a.schemaVersion,events:[...a.events]}),bu=a=>{const e=gu.parse(JSON.parse(a)),n=be(e.events);return{id:e.id,name:e.name,state:n,events:e.events,cursor:e.events.length,schemaVersion:e.schemaVersion}},Su={STR:14,DEX:12,CON:14,INT:10,WIS:10,CHA:10},vu=a=>{const e=a.level??1;return ke.parse({id:a.id??Ht(),name:a.name,speciesId:a.speciesId,backgroundId:a.backgroundId,classes:[{classId:a.classId,level:e,hitDiceRemaining:e}],abilityScores:a.abilityScores??Su,hp:{current:a.hpCurrent??a.hpMax,max:a.hpMax,temp:0},featsTaken:a.featsTaken??[]})},v=()=>new Date().toISOString(),Fe=(a,e)=>{const n=e.at??v(),o={id:I(),at:n,type:"ShortRestStarted",participantIds:[...e.participantIds]},r={id:I(),at:n,type:"ShortRestEnded",causedByEventId:o.id};return[o,r]},Ue=(a,e)=>{const n=e.at??v(),o={id:I(),at:n,type:"LongRestStarted",participantIds:[...e.participantIds]},r={id:I(),at:n,type:"LongRestEnded",causedByEventId:o.id};return[o,r]},zu=2,Cu=2,Eu=a=>Math.floor(a/zu),Se=a=>{const e=X(a);return a.rawComponents.map(n=>{const o=n.amount,r=e.flatDamageReductionFor(n.type),i=Math.max(0,o-r);return e.hasImmunity(n.type)?{amount:0,type:n.type,rawAmount:o,mitigation:"immune"}:e.hasVulnerability(n.type)?{amount:i*Cu,type:n.type,rawAmount:o,mitigation:"vulnerable"}:e.hasResistance(n.type)?{amount:Eu(i),type:n.type,rawAmount:o,mitigation:"resisted"}:r>0?{amount:i,type:n.type,rawAmount:o,mitigation:"resisted"}:{amount:o,type:n.type}})},ku=(a,e)=>{const n=new Map([["event.type",a.type]]);return a.type==="AttackRolled"?(n.set("event.attackerIsSelf",a.attackerId===e),n.set("event.targetIsSelf",a.targetId===e),n.set("event.hit",a.hit),n.set("event.critical",a.critical),n.set("event.used",a.used),n.set("event.weaponInstanceId",a.weaponInstanceId)):a.type==="DamageApplied"&&n.set("event.targetIsSelf",a.targetId===e),n},Au=(a,e,n)=>{if(n===void 0)return!0;const o=a.triggerCounters[e];if(o===void 0)return!0;switch(n){case"turn":return o.firedThisTurn!==!0;case"round":return o.firedThisRound!==!0;case"shortRest":return o.firedThisShortRest!==!0;case"longRest":return o.firedThisLongRest!==!0}},wu=a=>{if(a===void 0)return{};switch(a){case"turn":return{firedThisTurn:!0};case"round":return{firedThisRound:!0};case"shortRest":return{firedThisShortRest:!0};case"longRest":return{firedThisLongRest:!0}}},Ru=(a,e,n)=>{const o=Q(a.dice),r=n?o.count*2:o.count,i=[];for(let p=0;p<r;p++)i.push(E(o.die,e));const d=i.reduce((p,l)=>p+l,0)+o.modifier;return{amount:Math.max(0,d),rolls:i}},Tu=(a,e,n,o)=>{if(e.type!=="AttackRolled")return[];const{amount:r}=Ru(a,n,e.critical);return r<=0?[]:[{id:I(),at:e.at,type:"DamageApplied",targetId:e.targetId,components:[{amount:r,type:a.damageType}],causedByEventId:o}]},Du=(a,e,n,o,r,i)=>{const d=wu(a.oncePer),p={id:I(),at:i,type:"TriggerFired",characterId:e.id,triggerId:n,cadence:d},l=[p];for(const c of a.actions)c.kind==="AddDamage"&&l.push(...Tu(c,o,r,p.id));return{events:l,triggerId:n,cadence:d}},Bu=(a,e)=>{const n=a.id;if(typeof n=="string")return`${e}:${n}`;const o=JSON.stringify(a.trigger);return`${e}:${a.trigger.eventType}:${o}`},xu=a=>{const{state:e,content:n,rng:o,event:r,at:i}=a,d=[];for(const p of Object.keys(e.characters)){const l=e.characters[p];if(l===void 0)continue;const c=Fc({character:l,content:n,itemInstances:e.itemInstances,pendingChoices:e.pendingChoices});for(const u of c){if(u.kind!=="OnEvent"||u.trigger.eventType!==r.type)continue;const h=ku(r,p),y=u.trigger.filter;if(y!==void 0&&!pe(y,{facts:h}))continue;const g=Bu(u,p);if(!Au(l,g,u.oncePer))continue;const b=Du(u,l,g,r,o,i);b!==null&&d.push(...b.events)}}return d},Mu=2,Pu=5,Lu=a=>{switch(a){case"half":return Mu;case"three-quarters":return Pu;case"none":case"total":return 0}},$u=(a,e)=>{const n=e.properties.includes("finesse");return e.attackKind==="ranged"&&!e.properties.includes("thrown")||n&&C(a.abilityScores.DEX)>=C(a.abilityScores.STR)?"DEX":"STR"},St=a=>{const{state:e,content:n,rng:o,at:r}=a,i=e.characters[a.attackerId];if(!i)throw new Error(`Unknown attacker ${a.attackerId}`);const d=e.characters[a.targetId];if(!d)throw new Error(`Unknown target ${a.targetId}`);const p=e.itemInstances[a.weaponInstanceId];if(!p)throw new Error(`Unknown weapon ${a.weaponInstanceId}`);const l=n.items.get(p.definitionId);if(!l||l.itemKind!=="weapon")throw new Error(`Item ${p.definitionId} is not a weapon`);const c=Te({character:i,itemInstances:e.itemInstances,content:n,weaponInstanceId:a.weaponInstanceId}),u=a.cover??"none";if(u==="total")throw new Error(`${d.name} has total cover and cannot be targeted`);const h=le({character:d,itemInstances:e.itemInstances,content:n}),y=Lu(u),g={...h,total:h.total+y},b=a.advantage??"none",S=[E(w,o)];b!=="none"&&S.push(E(w,o));const k=b==="advantage"?Math.max(...S):b==="disadvantage"?Math.min(...S):S[0]??0,z=k+c.total,A=k===mt,T=!(k===pt)&&(A||z>=g.total),x=A,D={id:I(),at:r,type:"AttackRolled",attackerId:a.attackerId,targetId:a.targetId,weaponInstanceId:a.weaponInstanceId,d20:S,used:b,attackBonus:c.total,total:z,targetAC:g.total,hit:T,critical:x},q=Pe(e,[D]),G=xu({state:q,content:n,rng:o,event:D,at:r});if(!T)return[D,...G];const K=$u(i,l),V=C(i.abilityScores[K]),$=Q(l.damageDice),F=x?$.count*2:$.count,O=[];for(let ve=0;ve<F;ve++)O.push(E($.die,o));const oe={expression:l.damageDice,rolls:O,modifier:V+$.modifier,type:l.damageType},re={id:I(),at:r,type:"DamageRolled",attackerId:a.attackerId,targetId:a.targetId,weaponInstanceId:a.weaponInstanceId,rolls:[oe],critical:x,causedByEventId:D.id},me=O.reduce((ve,hi)=>ve+hi,0)+oe.modifier,ie=Se({character:d,itemInstances:e.itemInstances,content:n,rawComponents:[{amount:Math.max(0,me),type:l.damageType}]}),Le={id:I(),at:r,type:"DamageApplied",targetId:a.targetId,components:ie,causedByEventId:re.id};return[D,...G,re,Le]},Ur=(a,e,n,o)=>{const r=_u(a,e,o),i=o.at??v(),d=St({state:a,content:e,rng:n,attackerId:o.attackerId,targetId:o.targetId,weaponInstanceId:o.weaponInstanceId,...o.cover!==void 0?{cover:o.cover}:{},...o.advantage!==void 0?{advantage:o.advantage}:{},at:i});return[...r,...d]},Ou=(a,e)=>{const n=a.activeEncounterId;if(n===void 0)return;const o=a.encounters[n];if(!o||o.status!=="active")return;const r=o.combatants[o.activeIndex];if(!(!r||r.combatantId!==e))return{encounterId:n,attacksMadeThisTurn:r.turnUsage.attacksMadeThisTurn,actionUsed:r.turnUsage.actionUsed}},_u=(a,e,n)=>{const o=a.characters[n.attackerId];if(!o)return[];const r=Ou(a,n.attackerId);if(r===void 0)return[];const i=Jc({character:o,itemInstances:a.itemInstances,content:e});if(r.attacksMadeThisTurn>=i.maxAttacksPerAction)throw new Error(`Attack budget exhausted: ${o.name} has already made ${r.attacksMadeThisTurn} attacks this turn (max ${i.maxAttacksPerAction})`);const d=n.at??v(),p=[];return r.actionUsed||p.push({id:I(),at:d,type:"ActionEconomyConsumed",encounterId:r.encounterId,combatantId:n.attackerId,kind:"action"}),p.push({id:I(),at:d,type:"ActionEconomyConsumed",encounterId:r.encounterId,combatantId:n.attackerId,kind:"attack"}),p},Nu=(a,e)=>{const n=a.activeEncounterId;if(n===void 0)return;const o=a.encounters[n];if(!o||o.status!=="active")return;const r=o.combatants.find(d=>d.combatantId===e);if(r===void 0)return;const i=o.combatants[o.activeIndex];return{encounterId:n,reactionUsedThisRound:r.turnUsage.reactionUsedThisRound,isActiveCombatant:i?.combatantId===e}},jr=(a,e,n,o)=>{const r=a.characters[o.reactorId];if(!r)throw new Error(`Unknown reactor ${o.reactorId}`);const i=Nu(a,o.reactorId);if(i===void 0)throw new Error("Opportunity attacks require an active encounter that includes the reactor");if(i.isActiveCombatant)throw new Error(`${r.name} cannot take an opportunity attack on their own turn`);if(i.reactionUsedThisRound)throw new Error(`${r.name} has already used their reaction this round`);const d=o.at??v(),p={id:I(),at:d,type:"ActionEconomyConsumed",encounterId:i.encounterId,combatantId:o.reactorId,kind:"reaction"},l=St({state:a,content:e,rng:n,attackerId:o.reactorId,targetId:o.targetId,weaponInstanceId:o.weaponInstanceId,...o.advantage!==void 0?{advantage:o.advantage}:{},at:d});return[p,...l]},qr=(a,e,n)=>{const o=n.encounterId??Gt(),r=n.at??v();return{events:[{id:I(),at:r,type:"EncounterCreated",encounterId:o,...n.name!==void 0?{name:n.name}:{},combatantIds:[...n.combatantIds]}],encounterId:o}},Hr=(a,e,n,o)=>{const r=a.encounters[o.encounterId];if(!r)throw new Error(`Unknown encounter ${o.encounterId}`);const i=o.at??v(),d=r.combatants.map(l=>{const c=a.characters[l.combatantId],u=c?C(c.abilityScores.DEX):0,h=E(w,n);return{combatantId:l.combatantId,d20:h,modifier:u,total:h+u}});return[{id:I(),at:i,type:"InitiativeRolled",encounterId:o.encounterId,rolls:d}]},Gr=(a,e,n)=>[{id:I(),at:n.at??v(),type:"EncounterStarted",encounterId:n.encounterId}],Kr=(a,e,n)=>{const o=a.encounters[n.encounterId];if(!o)throw new Error(`Unknown encounter ${n.encounterId}`);const r=n.at??v(),i=o.combatants[o.activeIndex];if(!i)throw new Error("No active combatant");const d={id:I(),at:r,type:"TurnEnded",encounterId:n.encounterId,combatantId:i.combatantId,round:o.round};if(o.activeIndex>=o.combatants.length-1){const u={id:I(),at:r,type:"RoundEnded",encounterId:n.encounterId,round:o.round},h=o.combatants[0];if(!h)throw new Error("No combatants");const y={id:I(),at:r,type:"TurnStarted",encounterId:n.encounterId,combatantId:h.combatantId,round:o.round+1};return[d,u,y]}const l=o.combatants[o.activeIndex+1];if(!l)throw new Error("Bad combatant index");const c={id:I(),at:r,type:"TurnStarted",encounterId:n.encounterId,combatantId:l.combatantId,round:o.round};return[d,c]},Vr=(a,e,n)=>{const o=a.encounters[n.encounterId];if(!o)throw new Error(`Unknown encounter ${n.encounterId}`);const r=o.combatants[0];if(!r)throw new Error("No combatants");return[{id:I(),at:n.at??v(),type:"TurnStarted",encounterId:n.encounterId,combatantId:r.combatantId,round:o.round}]},Wr=(a,e,n)=>[{id:I(),at:n.at??v(),type:"EncounterEnded",encounterId:n.encounterId,outcome:n.outcome}],Fu={6:4,8:5,10:6,12:7},Xr=(a,e,n,o)=>{const r=a.characters[o.characterId];if(!r)throw new Error(`Unknown character ${o.characterId}`);if(r.pendingChoiceIds.some(z=>a.pendingChoices[z]?.resolution===void 0))throw new Error("Character has unresolved choices from a previous level-up");const i=r.classes.find(z=>z.classId===o.classId);if(!i)throw new Error(`Character has no enrollment in ${o.classId}`);if(i.level>=20)throw new Error("Already at max level");const d=e.classes.get(o.classId);if(!d)throw new Error(`Unknown class ${o.classId}`);const p=i.level+1,l=d.hitDie,c=C(r.abilityScores.CON);let u,h;if(o.hpStrategy==="roll")u=E(l,n),h=u;else{const z=Fu[l];if(z===void 0)throw new Error(`No HP average for d${l}`);h=z}const y=Math.max(1,h+c),g=o.at??v(),b={id:I(),at:g,type:"LevelUpResolved",characterId:o.characterId,classId:o.classId,newClassLevel:p,hpStrategy:o.hpStrategy,...u!==void 0?{hpRoll:u}:{},hpGained:y},S=[b],k=d.levelTable[String(p)];if(k!==void 0){for(const z of k.features)for(const A of z.effects)if(A.kind==="OfferChoice"&&A.when!=="onLongRest"){const R={id:I(),at:g,type:"ChoiceRequired",choiceId:Vt(),characterId:o.characterId,promptKey:A.choiceId,prompt:A.prompt,options:A.options.map(T=>({id:T.id,label:T.label,effects:T.effects})),oneOf:A.oneOf,causedByEventId:b.id};S.push(R)}}return S},Qr=(a,e,n)=>{const o=a.pendingChoices[n.choiceId];if(!o)throw new Error(`Unknown choice ${n.choiceId}`);if(o.resolution!==void 0)throw new Error(`Choice ${n.choiceId} already resolved`);if(o.forCharacterId!==n.characterId)throw new Error(`Choice ${n.choiceId} belongs to a different character`);if(n.selectedOptionIds.length!==o.oneOf)throw new Error(`Expected exactly ${o.oneOf} selection(s), got ${n.selectedOptionIds.length}`);for(const i of n.selectedOptionIds)if(!o.options.some(d=>d.id===i))throw new Error(`Option ${i} not in choice ${n.choiceId}`);return[{id:I(),at:n.at??v(),type:"ChoiceResolved",choiceId:n.choiceId,characterId:n.characterId,selectedOptionIds:[...n.selectedOptionIds]}]},Yr=(a,e)=>{const n=E(w,a);if(e==="none")return{rolls:[n],used:n};const o=E(w,a),r=e==="advantage"?Math.max(n,o):Math.min(n,o);return{rolls:[n,o],used:r}},Jr=(a,e,n)=>a!==void 0&&a!=="none"?a:e&&!n?"advantage":n&&!e?"disadvantage":"none",Zr=(a,e,n,o)=>{const r=a.characters[o.characterId];if(!r)throw new Error(`Unknown character ${o.characterId}`);const i=ue({character:r,itemInstances:a.itemInstances,content:e,ability:o.ability,pendingChoices:a.pendingChoices}),d=Jr(o.advantage,i.hasAdvantage,i.hasDisadvantage),{rolls:p,used:l}=Yr(n,d),c=l+i.total;return[{id:I(),at:o.at??v(),type:"SaveRolled",targetId:o.characterId,ability:o.ability,dc:o.dc,d20:p,used:d,bonus:i.total,total:c,success:c>=o.dc}]},ei=(a,e,n,o)=>{const r=a.characters[o.characterId];if(!r)throw new Error(`Unknown character ${o.characterId}`);const i=ne({character:r,itemInstances:a.itemInstances,content:e,ability:o.ability,...o.skill!==void 0?{skill:o.skill}:{},pendingChoices:a.pendingChoices}),d=Jr(o.advantage,i.hasAdvantage,i.hasDisadvantage),{rolls:p,used:l}=Yr(n,d),c=l+i.total;return[{id:I(),at:o.at??v(),type:"AbilityCheckRolled",characterId:o.characterId,ability:o.ability,...o.skill!==void 0?{skill:o.skill}:{},...o.dc!==void 0?{dc:o.dc,success:c>=o.dc}:{},d20:p,used:d,bonus:i.total,total:c}]},Uu=(a,e,n)=>{if(n!==void 0)return n;for(const o of a.classes)if(e.classes.get(o.classId)?.spellcasting!==void 0)return o.classId;throw new Error("Character has no spellcasting class")},ju=(a,e)=>a.knownSpells.includes(e)||a.preparedSpells.includes(e),qu=(a,e,n,o)=>{if(e.slotSource!==void 0)return e.slotSource;if(a.level===Ie)return"standard";const r=n.characters[e.characterId];if(!r)throw new Error(`Unknown character ${e.characterId}`);const i=Tr(r,o.classes);return i.pact!==void 0&&i.pact.count>0&&e.slotLevel<=i.pact.level?"pact":"standard"},vt=(a,e,n,o)=>{const r=Q(a),i=(r.count+e)*(o?2:1),d=[];for(let p=0;p<i;p++)d.push(E(r.die,n));return{rolls:d,modifier:r.modifier}},ti=(a,e,n,o)=>{if(a===void 0||e<=0)return[];const r=Q(a),i=r.count*e*(o?2:1),d=[];for(let p=0;p<i;p++)d.push(E(r.die,n));return d},Hu=a=>Math.floor(a/2),Gu=(a,e,n,o,r,i,d,p,l)=>{const c=a.characters[o.characterId];if(!c)throw new Error(`Unknown character ${o.characterId}`);const u=ht({character:c,itemInstances:a.itemInstances,content:e,classId:l}),h=(i.extraDicePerSlotLevel??0)*Math.max(0,o.slotLevel-r.level),y=r.level===Ie?Ra(N(c)):0,g=[];for(const b of o.targetIds){const S=a.characters[b];if(!S)continue;const k=le({character:S,itemInstances:a.itemInstances,content:e}),z=E(w,n),A=z+u.total,R=z===mt,x=!(z===pt)&&(R||A>=k.total),D={id:I(),at:p,type:"AttackRolled",attackerId:o.characterId,targetId:b,weaponInstanceId:o.spellId,d20:[z],used:"none",attackBonus:u.total,total:A,targetAC:k.total,hit:x,critical:R,causedByEventId:d};if(g.push(D),!x)continue;const{rolls:q,modifier:G}=vt(i.damageDice,h,n,R),K=ti(i.cantripScalingDice,y,n,R),V=[...q,...K],$=V.reduce((re,me)=>re+me,0)+G,F={id:I(),at:p,type:"DamageRolled",attackerId:o.characterId,targetId:b,weaponInstanceId:o.spellId,rolls:[{expression:i.damageDice,rolls:V,modifier:G,type:i.damageType}],critical:R,causedByEventId:D.id};g.push(F);const O=Se({character:S,itemInstances:a.itemInstances,content:e,rawComponents:[{amount:Math.max(0,$),type:i.damageType}]}),oe={id:I(),at:p,type:"DamageApplied",targetId:b,components:O,causedByEventId:F.id};g.push(oe)}return g},Ku=(a,e,n,o,r,i,d,p,l)=>{const c=a.characters[o.characterId];if(!c)throw new Error(`Unknown character ${o.characterId}`);const u=De({character:c,itemInstances:a.itemInstances,content:e,classId:l}),h=(i.extraDicePerSlotLevel??0)*Math.max(0,o.slotLevel-r.level),y=r.level===Ie?Ra(N(c)):0,g=[],b=[];for(const S of o.targetIds){const k=a.characters[S];if(!k)continue;const z=ue({character:k,itemInstances:a.itemInstances,content:e,ability:i.ability}),A=E(w,n),R=A+z.total,T=R>=u.total,x={id:I(),at:p,type:"SaveRolled",targetId:S,ability:i.ability,dc:u.total,d20:[A],used:"none",bonus:z.total,total:R,success:T,causedByEventId:d};if(g.push(x),i.damageDice!==void 0&&i.damageType!==void 0){const{rolls:D,modifier:q}=vt(i.damageDice,h,n,!1),G=ti(i.cantripScalingDice,y,n,!1),V=[...D,...G].reduce((F,O)=>F+O,0)+q,$=T&&i.halfOnSuccess===!0?Hu(V):T?0:V;if($>0){const F=Se({character:k,itemInstances:a.itemInstances,content:e,rawComponents:[{amount:$,type:i.damageType}]}),O={id:I(),at:p,type:"DamageApplied",targetId:S,components:F,causedByEventId:x.id};g.push(O)}}if(!T&&i.conditionOnFail!==void 0){const D=W(),q={id:I(),at:p,type:"ConditionApplied",targetId:S,conditionId:i.conditionOnFail,appliedConditionId:D,causedByEventId:x.id};g.push(q),b.push({targetId:S,conditionId:i.conditionOnFail,appliedConditionId:D})}}return{events:g,conditionsApplied:b}},Vu=(a,e,n,o,r,i,d)=>{const p=a.characters[n.characterId];if(!p)throw new Error(`Unknown character ${n.characterId}`);const l=C(p.abilityScores.WIS),c=(r.extraDicePerSlotLevel??0)*Math.max(0,n.slotLevel-o.level),u=[];for(const h of n.targetIds){const{rolls:y,modifier:g}=vt(r.amountDice,c,e,!1),b=Math.max(0,y.reduce((k,z)=>k+z,0)+g+l),S={id:I(),at:d,type:"Healed",targetId:h,amount:b,source:o.id,causedByEventId:i};u.push(S)}return u},Wu=(a,e,n,o)=>{const r=a.characters[o.characterId];if(!r)throw new Error(`Unknown character ${o.characterId}`);const i=e.spells.get(o.spellId);if(!i)throw new Error(`Unknown spell ${o.spellId}`);if(!ju(r,o.spellId))throw new Error(`Character does not know or prepare spell ${o.spellId}`);if(o.slotLevel<i.level)throw new Error(`Slot level ${o.slotLevel} insufficient for spell level ${i.level}`);const d=Uu(r,e,o.castingClassId),p=qu(i,o,a,e),l=o.asRitual===!0;if(l&&i.ritual!==!0)throw new Error(`Spell ${i.id} cannot be cast as a ritual`);if(i.level>Ie&&!l){const g=Tr(r,e.classes);if(p==="pact"){if(g.pact===void 0||g.pact.count<=0)throw new Error("No pact slots available");if(o.slotLevel!==g.pact.level)throw new Error(`Pact slots are level ${g.pact.level}; requested level ${o.slotLevel}`)}else if((g.standardByLevel[o.slotLevel-1]??0)<=0)throw new Error(`No spell slots of level ${o.slotLevel} available`)}const c=o.at??v(),u={id:I(),at:c,type:"SpellCastDeclared",characterId:o.characterId,spellId:o.spellId,slotLevel:o.slotLevel,slotSource:p,targetIds:[...o.targetIds],castAsRitual:l},h=[u];if(i.level>Ie&&!l)if(p==="pact"){const g={id:I(),at:c,type:"PactSlotConsumed",characterId:o.characterId,causedByEventId:u.id};h.push(g)}else{const g={id:I(),at:c,type:"SpellSlotConsumed",characterId:o.characterId,slotLevel:o.slotLevel,causedByEventId:u.id};h.push(g)}const y=[];for(const g of i.mechanicalEffects)if(g.kind==="attack")h.push(...Gu(a,e,n,o,i,g,u.id,c,d));else if(g.kind==="save"){const b=Ku(a,e,n,o,i,g,u.id,c,d);h.push(...b.events),y.push(...b.conditionsApplied)}else h.push(...Vu(a,n,o,i,g,u.id,c));if(i.concentration===!0){if(r.concentrationEffectId!==void 0){const b={id:I(),at:c,type:"ConcentrationBroken",effectInstanceId:r.concentrationEffectId,casterId:o.characterId,reason:"newConcentrationSpell",causedByEventId:u.id};h.push(b)}const g={id:I(),at:c,type:"ConcentrationStarted",effectInstanceId:Wt(),casterId:o.characterId,spellId:o.spellId,targetIds:[...o.targetIds],conditionsApplied:y,causedByEventId:u.id};h.push(g)}return h},Xu=10,Qu=2,Yu=a=>Math.max(Xu,Math.floor(a/Qu)),Ju=(a,e,n,o)=>{const r=a.characters[o.characterId];if(!r)throw new Error(`Unknown character ${o.characterId}`);if(r.concentrationEffectId===void 0)return[];if(o.damageTaken<=0)return[];const i=o.at??v(),d=Yu(o.damageTaken),p=ue({character:r,itemInstances:a.itemInstances,content:e,ability:"CON"}),l=E(w,n),c=l+p.total,u=c>=d,h={id:I(),at:i,type:"SaveRolled",targetId:o.characterId,ability:"CON",dc:d,d20:[l],used:"none",bonus:p.total,total:c,success:u},y=[h];if(!u){const g={id:I(),at:i,type:"ConcentrationBroken",effectInstanceId:r.concentrationEffectId,casterId:o.characterId,reason:"failedSave",causedByEventId:h.id};y.push(g)}return y},Zu=(a,e)=>Math.max(Math.abs(a.x-e.x),Math.abs(a.y-e.y)),zt=(a,e)=>{const n=a.activeEncounterId;if(n===void 0)throw new Error("Movement requires an active encounter");const o=a.encounters[n];if(!o||o.status!=="active")throw new Error("Movement requires an active encounter");const r=o.combatants.find(d=>d.combatantId===e);if(!r)throw new Error(`Combatant ${e} not in active encounter`);const i=o.combatants[o.activeIndex]?.combatantId===e;return{encounterId:n,combatant:r,isActive:i}},em=(a,e)=>a.characters[e]?.speedFeet??30,tm=(a,e,n)=>{const{encounterId:o,combatant:r,isActive:i}=zt(a,n.combatantId);if(!i)throw new Error("Only the active combatant may move on their turn");if(r.position===void 0)throw new Error("Combatant has no position set");const d=Zu(r.position,n.to),p=em(a,n.combatantId),l=r.turnUsage.dashed?p*2:p,c=l-r.turnUsage.feetMovedThisTurn;if(d>c)throw new Error(`Move of ${d}ft exceeds remaining movement (${c}ft of ${l}ft)`);const u=n.at??v();return[{id:I(),at:u,type:"CombatantMoved",encounterId:o,combatantId:n.combatantId,fromPosition:{...r.position},toPosition:{...n.to},feetTraveled:d}]},am=(a,e,n)=>{const{encounterId:o,combatant:r,isActive:i}=zt(a,n.combatantId);if(!i)throw new Error("Only the active combatant may Dash on their turn");if(r.turnUsage.actionUsed)throw new Error("Action already used this turn");if(r.turnUsage.dashed)throw new Error("Already dashed this turn");const d=n.at??v(),p={id:I(),at:d,type:"ActionEconomyConsumed",encounterId:o,combatantId:n.combatantId,kind:"action"},l={id:I(),at:d,type:"Dashed",encounterId:o,combatantId:n.combatantId};return[p,l]},nm=(a,e,n)=>{const{encounterId:o,combatant:r,isActive:i}=zt(a,n.combatantId);if(!i)throw new Error("Only the active combatant may Disengage on their turn");if(r.turnUsage.actionUsed)throw new Error("Action already used this turn");if(r.turnUsage.disengaged)throw new Error("Already disengaged this turn");const d=n.at??v(),p={id:I(),at:d,type:"ActionEconomyConsumed",encounterId:o,combatantId:n.combatantId,kind:"action"},l={id:I(),at:d,type:"Disengaged",encounterId:o,combatantId:n.combatantId};return[p,l]},Nt="action-surge",om=(a,e)=>{const n=a.activeEncounterId;if(n===void 0)throw new Error("Action Surge requires an active encounter");const o=a.encounters[n];if(!o||o.status!=="active")throw new Error("Action Surge requires an active encounter");const r=o.combatants[o.activeIndex];if(!r||r.combatantId!==e)throw new Error("Action Surge can only be used on your own turn");return{encounterId:n,combatant:r,activeIndex:o.activeIndex}},rm=(a,e,n)=>{const o=a.characters[n.combatantId];if(!o)throw new Error(`Unknown character ${n.combatantId}`);const r=o.resources.find(l=>l.resourceId===Nt);if(!r||r.current<=0)throw new Error(`${o.name} has no Action Surge available`);const{combatant:i}=om(a,n.combatantId);if(!i.turnUsage.actionUsed)throw new Error("Action Surge is only meaningful after the Action is used");const d=n.at??v();return[{id:I(),at:d,type:"ResourceSpent",characterId:n.combatantId,resourceId:Nt,amount:1}]},im=(a,e)=>{const n=a.activeEncounterId;if(n===void 0)return;const o=a.encounters[n];if(!o||o.status!=="active")return;const r=o.combatants[o.activeIndex];if(!(!r||r.combatantId!==e))return{encounterId:n,bonusActionUsed:r.turnUsage.bonusActionUsed}},sm=(a,e,n,o)=>{const r=a.characters[o.attackerId];if(!r)throw new Error(`Unknown attacker ${o.attackerId}`);const i=a.characters[o.targetId];if(!i)throw new Error(`Unknown target ${o.targetId}`);const d=a.itemInstances[o.weaponInstanceId];if(!d)throw new Error(`Unknown weapon ${o.weaponInstanceId}`);const p=e.items.get(d.definitionId);if(!p||p.itemKind!=="weapon")throw new Error(`Item ${d.definitionId} is not a weapon`);if(!p.properties.includes("light"))throw new Error(`Off-hand attacks require a 'light' weapon; ${p.name} is not light`);const l=im(a,o.attackerId);if(l===void 0)throw new Error("Off-hand attack requires being the active combatant in an active encounter");if(l.bonusActionUsed)throw new Error("Bonus action already used this turn");const c=o.at??v(),u={id:I(),at:c,type:"ActionEconomyConsumed",encounterId:l.encounterId,combatantId:o.attackerId,kind:"bonusAction"},h=Te({character:r,itemInstances:a.itemInstances,content:e,weaponInstanceId:o.weaponInstanceId}),y=le({character:i,itemInstances:a.itemInstances,content:e}),g=E(w,n),b=g+h.total,S=g===mt,z=!(g===pt)&&(S||b>=y.total),A=S,R={id:I(),at:c,type:"AttackRolled",attackerId:o.attackerId,targetId:o.targetId,weaponInstanceId:o.weaponInstanceId,d20:[g],used:"none",attackBonus:h.total,total:b,targetAC:y.total,hit:z,critical:A};if(!z)return[u,R];const T=C(r.abilityScores.STR),x=C(r.abilityScores.DEX),q=p.properties.includes("finesse")?Math.max(T,x):T,G=q<0?q:0,K=Q(p.damageDice),V=A?K.count*2:K.count,$=[];for(let ie=0;ie<V;ie++)$.push(E(K.die,n));const F={expression:p.damageDice,rolls:$,modifier:G+K.modifier,type:p.damageType},O={id:I(),at:c,type:"DamageRolled",attackerId:o.attackerId,targetId:o.targetId,weaponInstanceId:o.weaponInstanceId,rolls:[F],critical:A,causedByEventId:R.id},oe=$.reduce((ie,Le)=>ie+Le,0)+F.modifier,re=Se({character:i,itemInstances:a.itemInstances,content:e,rawComponents:[{amount:Math.max(0,oe),type:p.damageType}]}),me={id:I(),at:c,type:"DamageApplied",targetId:o.targetId,components:re,causedByEventId:O.id};return[u,R,O,me]},cm=(a,e,n,o)=>{const r=a.characters[o.attackerId];if(!r)throw new Error(`Unknown attacker ${o.attackerId}`);const i=r.multiattack;if(i===void 0)throw new Error(`${r.name} has no multiattack pattern`);const d=o.at??v(),p=[],l=a.activeEncounterId;if(l!==void 0){const c=a.encounters[l];if(c&&c.status==="active"){const u=c.combatants[c.activeIndex];if(u?.combatantId===o.attackerId&&!u.turnUsage.actionUsed){const h={id:I(),at:d,type:"ActionEconomyConsumed",encounterId:l,combatantId:o.attackerId,kind:"action"};p.push(h)}}}for(const c of i.attacks)for(let u=0;u<c.count;u++){const h=St({state:a,content:e,rng:n,attackerId:o.attackerId,targetId:o.targetId,weaponInstanceId:c.weaponInstanceId,at:d});p.push(...h)}return p},dm=10,lm=3.5,um=20,mm=a=>Math.min(um,Math.floor(a/dm)),pm=a=>{const e=mm(a);return Math.round(e*lm)},hm=(a,e,n)=>{const o=a.characters[n.characterId];if(!o)throw new Error(`Unknown character ${n.characterId}`);if(n.distanceFeet<0)throw new Error("Falling distance must be non-negative");const r=pm(n.distanceFeet);if(r<=0)return[];const i=Se({character:o,itemInstances:a.itemInstances,content:e,rawComponents:[{amount:r,type:"bludgeoning"}]}),d=n.at??v();return[{id:I(),at:d,type:"DamageApplied",targetId:n.characterId,components:i}]},fm=8,Im=15,Ft=5,ai=a=>{const e=C(a.abilityScores.STR),n=j(N(a));return fm+e+n},Ct=(a,e,n)=>{if(a.activeEncounterId===void 0)return;const o=a.encounters[a.activeEncounterId];if(o!==void 0&&o.combatants.some(r=>r.combatantId===e))return{id:I(),at:n,type:"ActionEconomyConsumed",encounterId:o.id,combatantId:e,kind:"action"}},ni=(a,e,n,o)=>{const r=a.characters[o.attackerId];m(r!==void 0,`Attacker ${o.attackerId} not found`);const i=a.characters[o.targetId];m(i!==void 0,`Target ${o.targetId} not found`);const d=o.at??v(),p=o.targetAbility??"STR",l=ai(r),c=E(w,n),u=C(i.abilityScores[p]),h=c+u,y=h>=l,g=[],b=Ct(a,o.attackerId,d);return b!==void 0&&g.push(b),g.push({id:I(),at:d,type:"SaveRolled",targetId:o.targetId,ability:p,dc:l,d20:[c],used:"none",bonus:u,total:h,success:y}),y||g.push({id:I(),at:d,type:"ConditionApplied",targetId:o.targetId,conditionId:"grappled",appliedConditionId:W()}),g},oi=(a,e,n,o)=>{const r=a.characters[o.attackerId];m(r!==void 0,`Attacker ${o.attackerId} not found`);const i=a.characters[o.targetId];m(i!==void 0,`Target ${o.targetId} not found`);const d=o.at??v(),p=ai(r),l=E(w,n),c=C(i.abilityScores.STR),u=l+c,h=u>=p,y=[],g=Ct(a,o.attackerId,d);if(g!==void 0&&y.push(g),y.push({id:I(),at:d,type:"SaveRolled",targetId:o.targetId,ability:"STR",dc:p,d20:[l],used:"none",bonus:c,total:u,success:h}),!h)if(o.mode==="prone")y.push({id:I(),at:d,type:"ConditionApplied",targetId:o.targetId,conditionId:"prone",appliedConditionId:W()});else{const b=a.activeEncounterId!==void 0?a.encounters[a.activeEncounterId]:void 0,S=b?.combatants.find(k=>k.combatantId===o.targetId);if(S?.position!==void 0){const z=b?.combatants.find(D=>D.combatantId===o.attackerId)?.position,A=z!==void 0&&Math.sign(S.position.x-z.x)||1,R=z!==void 0&&Math.sign(S.position.y-z.y)||0,x=Ft/5;y.push({id:I(),at:d,type:"CombatantMoved",encounterId:b.id,combatantId:o.targetId,fromPosition:{x:S.position.x,y:S.position.y},toPosition:{x:S.position.x+A*x,y:S.position.y+R*x},feetTraveled:Ft})}}return y},ri=(a,e,n,o)=>{const r=a.characters[o.characterId];m(r!==void 0,`Character ${o.characterId} not found`);const i=o.at??v(),d=o.dc??Im,p=ne({character:r,itemInstances:a.itemInstances,content:e,ability:"DEX",skill:"stealth",pendingChoices:a.pendingChoices}),l=E(w,n),c=l+p.total,u=c>=d,h=[],y=Ct(a,o.characterId,i);return y!==void 0&&h.push(y),h.push({id:I(),at:i,type:"AbilityCheckRolled",characterId:o.characterId,ability:"DEX",skill:"stealth",dc:d,success:u,d20:[l],used:"none",bonus:p.total,total:c}),u&&h.push({id:I(),at:i,type:"ConditionApplied",targetId:o.characterId,conditionId:"invisible",appliedConditionId:W()}),h},gm=10,Ut=3,Et=(a,e,n,o)=>{if(a.activeEncounterId===void 0)return;const r=a.encounters[a.activeEncounterId];if(r!==void 0&&r.combatants.some(i=>i.combatantId===e))return{id:I(),at:n,type:"ActionEconomyConsumed",encounterId:r.id,combatantId:e,kind:o}},ii=(a,e,n,o)=>{const r=a.characters[o.counterCasterId];m(r!==void 0,`Counter caster ${o.counterCasterId} not found`);const i=a.characters[o.targetCasterId];m(i!==void 0,`Target caster ${o.targetCasterId} not found`);const d=o.at??v(),l=De({character:r,itemInstances:a.itemInstances,content:e,pendingChoices:a.pendingChoices,classId:o.castingClassId}).total,c=C(i.abilityScores.CON),u=E(w,n),h=u+c,y=h>=l,g=o.slotLevelToConsume??Ut;m(g>=Ut,"Counterspell requires a 3rd-level or higher slot");const b=[],S=Et(a,o.counterCasterId,d,"reaction");return S!==void 0&&b.push(S),b.push({id:I(),at:d,type:"SpellSlotConsumed",characterId:o.counterCasterId,slotLevel:g}),b.push({id:I(),at:d,type:"SaveRolled",targetId:o.targetCasterId,ability:"CON",dc:l,d20:[u],used:"none",bonus:c,total:h,success:y}),y||b.push({id:I(),at:d,type:"SpellCountered",originalSpellEventId:o.originalSpellEventId,counterCasterId:o.counterCasterId,targetCasterId:o.targetCasterId,spellId:o.spellId}),b},si=(a,e,n,o)=>{const r=a.characters[o.casterId];m(r!==void 0,`Caster ${o.casterId} not found`);const i=a.effectInstances[o.effectInstanceId];m(i!==void 0,`EffectInstance ${o.effectInstanceId} not found`),m(o.slotLevel>=3,"Dispel Magic requires a 3rd-level or higher slot");const d=o.at??v(),p=[],l=Et(a,o.casterId,d,"action");l!==void 0&&p.push(l),p.push({id:I(),at:d,type:"SpellSlotConsumed",characterId:o.casterId,slotLevel:o.slotLevel});const c=o.targetSpellLevel<=o.slotLevel;let u=c;if(!c){const h=gm+o.targetSpellLevel,g=e.classes.get(o.castingClassId)?.spellcasting?.ability,b=g==="INT"||g==="WIS"||g==="CHA"?g:"INT",S=N(r),k=C(r.abilityScores[b])+j(S),z=E(w,n),A=z+k;u=A>=h,p.push({id:I(),at:d,type:"AbilityCheckRolled",characterId:o.casterId,ability:b,dc:h,success:u,d20:[z],used:"none",bonus:k,total:A})}return u&&p.push({id:I(),at:d,type:"SpellDispelled",effectInstanceId:o.effectInstanceId,dispelledByCharacterId:o.casterId}),p},ci=(a,e,n,o)=>{const r=a.characters[o.casterId];m(r!==void 0,`Caster ${o.casterId} not found`);const i=a.itemInstances[o.itemInstanceId];m(i!==void 0,`Item ${o.itemInstanceId} not found`);const d=o.at??v(),p=[],l=Et(a,o.casterId,d,"action");return l!==void 0&&p.push(l),o.slotLevel!==void 0&&o.slotLevel>=1&&p.push({id:I(),at:d,type:"SpellSlotConsumed",characterId:o.casterId,slotLevel:o.slotLevel}),p.push({id:I(),at:d,type:"ItemIdentified",itemInstanceId:o.itemInstanceId,identifiedByCharacterId:o.casterId}),p},ym=8,bm=5,jt=10,Sm=a=>ym+C(a.abilityScores.STR)+j(N(a)),vm=(a,e,n,o,r)=>({id:I(),at:r,type:"WeaponMasteryActivated",mastery:a,attackerId:e,weaponInstanceId:o,...n!==void 0?{targetId:n}:{}}),di=(a,e,n,o)=>{const r=a.characters[o.attackerId];m(r!==void 0,`Attacker ${o.attackerId} not found`);const i=a.characters[o.targetId];m(i!==void 0,`Target ${o.targetId} not found`);const d=a.itemInstances[o.weaponInstanceId];m(d!==void 0,`Weapon ${o.weaponInstanceId} not found`);const p=e.items.get(d.definitionId);m(p!==void 0,`Weapon definition ${d.definitionId} not found`),m(p.itemKind==="weapon",`Item ${d.definitionId} is not a weapon`),m(p.mastery===o.mastery,`Weapon ${d.definitionId} mastery is ${p.mastery??"none"}, not ${o.mastery}`);const l=o.at??v(),c=[vm(o.mastery,o.attackerId,o.targetId,o.weaponInstanceId,l)];switch(o.mastery){case"Sap":c.push({id:I(),at:l,type:"ConditionApplied",targetId:o.targetId,conditionId:"sapped",appliedConditionId:W()});break;case"Vex":c.push({id:I(),at:l,type:"ConditionApplied",targetId:o.targetId,conditionId:"vexed-by",appliedConditionId:W()});break;case"Slow":c.push({id:I(),at:l,type:"ConditionApplied",targetId:o.targetId,conditionId:"slowed-10ft",appliedConditionId:W()});break;case"Topple":{const u=Sm(r),h=E(w,n),y=C(i.abilityScores.CON),g=h+y,b=g>=u;c.push({id:I(),at:l,type:"SaveRolled",targetId:o.targetId,ability:"CON",dc:u,d20:[h],used:"none",bonus:y,total:g,success:b}),b||c.push({id:I(),at:l,type:"ConditionApplied",targetId:o.targetId,conditionId:"prone",appliedConditionId:W()});break}case"Push":{const u=a.activeEncounterId!==void 0?a.encounters[a.activeEncounterId]:void 0,h=u?.combatants.find(y=>y.combatantId===o.targetId);if(u!==void 0&&h?.position!==void 0){const g=u.combatants.find(z=>z.combatantId===o.attackerId)?.position,b=g!==void 0&&Math.sign(h.position.x-g.x)||1,S=g!==void 0&&Math.sign(h.position.y-g.y)||0,k=jt/bm;c.push({id:I(),at:l,type:"CombatantMoved",encounterId:u.id,combatantId:o.targetId,fromPosition:{x:h.position.x,y:h.position.y},toPosition:{x:h.position.x+b*k,y:h.position.y+S*k},feetTraveled:jt})}break}case"Graze":{const u=p.damageType,h=Math.max(0,C(r.abilityScores.STR));h>0&&c.push({id:I(),at:l,type:"DamageApplied",targetId:o.targetId,components:[{amount:h,type:u,rawAmount:h}]});break}}return c},zm=4,Cm=4,li=(a,e,n,o)=>{m(a.parties[o.partyId]!==void 0,`Party ${o.partyId} not found`);const r=a.characters[o.foragerId];m(r!==void 0,`Forager ${o.foragerId} not found`);const i=ne({character:r,itemInstances:a.itemInstances,content:e,ability:"WIS",skill:"survival",pendingChoices:a.pendingChoices}),d=E(w,n),p=d+i.total,l=p>=o.dc,c=o.at??v();return[{id:I(),at:c,type:"ForagedFor",partyId:o.partyId,foragerId:o.foragerId,d20:d,bonus:i.total,total:p,dc:o.dc,success:l,foodPounds:l?zm:0,waterPounds:l?Cm:0}]},ui=(a,e,n,o)=>{m(a.parties[o.partyId]!==void 0,`Party ${o.partyId} not found`);const r=a.characters[o.navigatorId];m(r!==void 0,`Navigator ${o.navigatorId} not found`);const i=ne({character:r,itemInstances:a.itemInstances,content:e,ability:"WIS",skill:"survival",pendingChoices:a.pendingChoices}),d=E(w,n),p=d+i.total,l=o.at??v();return[{id:I(),at:l,type:"NavigationCheckRolled",partyId:o.partyId,navigatorId:o.navigatorId,d20:d,bonus:i.total,total:p,dc:o.dc,success:p>=o.dc}]},mi=(a,e,n,o)=>{const r=a.characters[o.npcId];m(r!==void 0,`NPC ${o.npcId} not found`);const i=o.at??v(),d=C(r.abilityScores.WIS),p=E(w,n),l=p+d,c=l>=o.dc,u=[];return u.push({id:I(),at:i,type:"MoraleCheckRolled",characterId:o.npcId,d20:p,bonus:d,total:l,dc:o.dc,success:c}),!c&&r.morale!==void 0&&r.morale.current<=1&&u.push({id:I(),at:i,type:"MoraleBroken",characterId:o.npcId,action:o.breakAction??"flee"}),u},Em=(a,e)=>{const n=a-e;return n>=10?"helpful":n>=5?"friendly":n>=0?"indifferent":n>=-5?"unfriendly":"hostile"},pi=(a,e,n,o)=>{const r=a.characters[o.npcId];m(r!==void 0,`NPC ${o.npcId} not found`);const i=a.characters[o.presenterId];m(i!==void 0,`Presenter ${o.presenterId} not found`);const d=o.dc??10,p=o.at??v(),l=ne({character:i,itemInstances:a.itemInstances,content:e,ability:"CHA",skill:"persuasion",pendingChoices:a.pendingChoices}),c=E(w,n),u=c+l.total,h=Em(u,d);return[{id:I(),at:p,type:"AbilityCheckRolled",characterId:o.presenterId,ability:"CHA",skill:"persuasion",dc:d,success:u>=d,d20:[c],used:"none",bonus:l.total,total:u},{id:I(),at:p,type:"AttitudeChanged",characterId:o.npcId,...r.attitude!==void 0?{fromAttitude:r.attitude}:{},toAttitude:h,cause:"reaction roll"}]},Z=(a,e)=>{const n=a.characters[e];if(!n)throw new Error(`Unknown character ${e}`);return n},km=a=>{const e=mr(a.contentPacks),n=fr(e);if(n.length>0){const c=n.map(u=>`${u.path}: ${u.message}`).join(`
4
+ `);throw new Error(`Content pack cross-reference validation failed:
5
+ ${c}`)}const o=a.rng??yr(),r={shortRest(c,u){return{events:Fe(c,{...u})}},longRest(c,u){return{events:Ue(c,{...u})}},rest(c,u){return u.type==="ShortRest"?{events:Fe(c,u)}:{events:Ue(c,u)}},attack(c,u){return{events:Ur(c,e,o,{...u})}},opportunityAttack(c,u){return{events:jr(c,e,o,{...u})}},createEncounter(c,u){return qr(c,e,{...u})},rollInitiative(c,u){return{events:Hr(c,e,o,{...u})}},startEncounter(c,u){return{events:Gr(c,e,{...u})}},beginFirstTurn(c,u){return{events:Vr(c,e,{...u})}},advanceTurn(c,u){return{events:Kr(c,e,{...u})}},endEncounter(c,u){return{events:Wr(c,e,{...u})}},levelUp(c,u){return{events:Xr(c,e,o,{...u})}},resolveChoice(c,u){return{events:Qr(c,e,{...u})}},save(c,u){return{events:Zr(c,e,o,{...u})}},abilityCheck(c,u){return{events:ei(c,e,o,{...u})}},castSpell(c,u){return{events:Wu(c,e,o,{...u})}},checkConcentration(c,u){return{events:Ju(c,e,o,{...u})}},move(c,u){return{events:tm(c,e,{...u})}},dash(c,u){return{events:am(c,e,{...u})}},disengage(c,u){return{events:nm(c,e,{...u})}},actionSurge(c,u){return{events:rm(c,e,{...u})}},offHandAttack(c,u){return{events:sm(c,e,o,{...u})}},multiattack(c,u){return{events:cm(c,e,o,{...u})}},falling(c,u){return{events:hm(c,e,{...u})}},grapple(c,u){return{events:ni(c,e,o,{...u})}},shove(c,u){return{events:oi(c,e,o,{...u})}},hide(c,u){return{events:ri(c,e,o,{...u})}},counterspell(c,u){return{events:ii(c,e,o,{...u})}},dispelMagic(c,u){return{events:si(c,e,o,{...u})}},identify(c,u){return{events:ci(c,e,o,{...u})}},weaponMastery(c,u){return{events:di(c,e,o,{...u})}},forage(c,u){return{events:li(c,e,o,{...u})}},navigationCheck(c,u){return{events:ui(c,e,o,{...u})}},moraleCheck(c,u){return{events:mi(c,e,o,{...u})}},reactionRoll(c,u){return{events:pi(c,e,o,{...u})}}},i=new Map;let d=-1;const p=(c,u,h)=>{u.version!==d&&(i.clear(),d=u.version);const y=c.join("|");if(i.has(y))return i.get(y);const g=h();return i.set(y,g),g};return{content:e,schemaVersion:ze,rng:o,createCampaign(c){return{id:c.id??Kt(),name:c.name,state:lt(),events:[],cursor:0,schemaVersion:ze}},apply:Me,applyAll:Pe,replay:be,commit:bt,undo:_r,redo:Nr,do(c,u){return Fr(this,c,u)},plan:r,derive:{character(c,u){return p(["character",u],c,()=>Dr({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices}))},ac(c,u){return p(["ac",u],c,()=>le({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices}))},savingThrow(c,u,h){return p(["save",u,h],c,()=>ue({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices,ability:h}))},attackBonus(c,u,h){return p(["attack",u,h],c,()=>Te({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices,weaponInstanceId:h}))},spellSaveDC(c,u,h){return p(["spellDC",u,h],c,()=>De({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices,classId:h}))},spellAttackBonus(c,u,h){return p(["spellAtk",u,h],c,()=>ht({character:Z(c,u),itemInstances:c.itemInstances,content:e,pendingChoices:c.pendingChoices,classId:h}))},spellSlots(c,u){return p(["slots",u],c,()=>Be(Z(c,u),e.classes))},abilityModifier(c){return C(c)},proficiencyBonus(c){return j(c)}}}},Am=new Map([[0,a=>a]]),wm=(a,e,n=ze)=>{if(e===n)return a;if(e>n)throw new Error(`Cannot downgrade schema from ${e} to ${n}`);let o=a;for(let r=e;r<n;r++){const i=Am.get(r);if(!i)throw new Error(`No migration from version ${r}`);o=i(o)}return o};exports.ABILITY_SCORES=Xt;exports.ABILITY_SCORE_MAX=Yt;exports.ABILITY_SCORE_MIN=Qt;exports.ATTITUDES=$o;exports.AbilityCheckRolledEventSchema=go;exports.AbilityScoreSchema=B;exports.AbilityScoreValueSchema=ee;exports.AbilityScoresSchema=he;exports.AlignmentSchema=fa;exports.AppliedConditionSchema=Na;exports.ArmorSchema=Ba;exports.AttackAdvantageSchema=ro;exports.AttackRolledEventSchema=io;exports.AttitudeChangedEventSchema=Oo;exports.AttitudeSchema=_e;exports.BASTION_TURN_ORDERS=Go;exports.BackgroundSchema=Ca;exports.BastionDamagedEventSchema=Yo;exports.BastionFacilityAddedEventSchema=Wo;exports.BastionFoundedEventSchema=Vo;exports.BastionHirelingAddedEventSchema=Xo;exports.BastionLevelChangedEventSchema=Jo;exports.BastionTurnOrderSchema=Ko;exports.BastionTurnTakenEventSchema=Qo;exports.CHARACTER_LEVEL_MAX=Ce;exports.CHARACTER_LEVEL_MIN=Ge;exports.CREATURE_TYPES=Zt;exports.CURRENCY_DENOMINATIONS=Je;exports.CURRENCY_KEYS=Ia;exports.CampaignSettingsChangedEventSchema=Zo;exports.CampaignSettingsSchema=Pn;exports.CampaignStateSchema=Ps;exports.CharacterCreatedEventSchema=Qn;exports.CharacterLevelSchema=ma;exports.CharacterLocationChangedEventSchema=vo;exports.CharacterResurrectedEventSchema=ar;exports.CharacterSchema=ke;exports.CheckAdvantageSchema=ut;exports.ChoiceOptionSchema=Ye;exports.ChoiceRequiredEventSchema=ho;exports.ChoiceResolvedEventSchema=fo;exports.ClassEnrollmentSchema=ja;exports.ClassFeatureSchema=Xe;exports.ClassSchema=Aa;exports.CombatantSchema=Ka;exports.ConditionAppliedEventSchema=_n;exports.ConditionRemovedEventSchema=Nn;exports.ConditionSchema=va;exports.ConsumableSchema=Pa;exports.ContentPackLoadError=pr;exports.ContentPackSchema=ur;exports.CreatureTypeSchema=qe;exports.CurrencySchema=ye;exports.DAMAGE_TYPES=ea;exports.DEFAULT_CELL_SIZE_FEET=Ae;exports.DIFFICULT_MOVEMENT_COST=rn;exports.DOOR_STATES=sn;exports.DOWNTIME_KINDS=Tn;exports.DOWNTIME_OUTCOMES=Dn;exports.DamageAppliedEventSchema=Ln;exports.DamageRollSchema=so;exports.DamageRolledEventSchema=co;exports.DamageTypeSchema=M;exports.DeathSaveRolledEventSchema=Un;exports.DeathSavesSchema=Ua;exports.DefaultRNG=gr;exports.DiceExpressionSchema=_;exports.DismountedEventSchema=wo;exports.DoorAddedEventSchema=bo;exports.DoorSchema=cn;exports.DoorStateChangedEventSchema=So;exports.DoorStateSchema=we;exports.DowntimeActivityResolvedEventSchema=Bn;exports.DowntimeKindSchema=st;exports.DowntimeOutcomeSchema=ct;exports.EFFECT_KINDS=as;exports.EVENT_TYPES=pc;exports.EXHAUSTION_MAX=Ke;exports.EXHAUSTION_MIN=pa;exports.EffectAccumulator=vr;exports.EffectSchema=U;exports.EncounterCreatedEventSchema=Yn;exports.EncounterEndedEventSchema=oo;exports.EncounterSchema=Va;exports.EncounterStartedEventSchema=eo;exports.EncounterStatusSchema=Ga;exports.EventEnvelopeSchema=f;exports.EventSchema=lr;exports.ExhaustionChangedEventSchema=Fn;exports.ExhaustionLevelSchema=ha;exports.FeatSchema=Ea;exports.ForagedForEventSchema=Lo;exports.FormulaSchema=P;exports.GearSchema=La;exports.HPSchema=Fa;exports.HPStrategySchema=mo;exports.HealedEventSchema=$n;exports.HitDieSchema=ra;exports.HitDieSpentEventSchema=Gn;exports.InGameTimeSchema=se;exports.InitiativeRollSchema=Jn;exports.InitiativeRolledEventSchema=Zn;exports.ItemAcquiredEventSchema=lo;exports.ItemChargeConsumedEventSchema=jo;exports.ItemDefinitionSchema=$a;exports.ItemIdentifiedEventSchema=Eo;exports.ItemInstanceSchema=Qe;exports.ItemRechargedEventSchema=qo;exports.JOURNAL_AUTHOR_KINDS=Za;exports.JOURNAL_VISIBILITIES=en;exports.JournalAuthorKindSchema=et;exports.JournalEntrySchema=tn;exports.JournalVisibilitySchema=tt;exports.LevelUpResolvedEventSchema=po;exports.LocationCreatedEventSchema=yo;exports.LocationMapSchema=at;exports.LocationSchema=dn;exports.LongRestEndedEventSchema=Xn;exports.LongRestStartedEventSchema=Wn;exports.MILESTONE_KINDS=En;exports.MagicItemSchema=Ma;exports.MilestoneAwardedEventSchema=kn;exports.MilestoneKindSchema=rt;exports.ModifierTargetSchema=ba;exports.MonsterStatblockSchema=Oa;exports.MoraleBrokenEventSchema=No;exports.MoraleCheckRolledEventSchema=_o;exports.MountedEventSchema=Ao;exports.MovementModeSchema=ia;exports.NORMAL_MOVEMENT_COST=on;exports.NavigationCheckRolledEventSchema=Po;exports.OBJECTIVE_STATUSES=mn;exports.ObjectiveCompletedEventSchema=gn;exports.ObjectiveFailedEventSchema=yn;exports.ObjectiveProgressedEventSchema=In;exports.ObjectiveStatusSchema=pn;exports.POLYMORPH_KINDS=nr;exports.PROFICIENCY_MULTIPLIER=oa;exports.PartySchema=Xa;exports.PendingChoiceSchema=Ha;exports.PolymorphAppliedEventSchema=ir;exports.PolymorphFormSchema=rr;exports.PolymorphKindSchema=or;exports.PolymorphRevertedEventSchema=sr;exports.PredicateSchema=H;exports.ProficiencyLevelSchema=na;exports.QUEST_STATUSES=ln;exports.QuestAbandonedEventSchema=vn;exports.QuestCompletedEventSchema=bn;exports.QuestFailedEventSchema=Sn;exports.QuestObjectiveSchema=nt;exports.QuestRewardClaimedEventSchema=zn;exports.QuestRewardSchema=ot;exports.QuestSchema=hn;exports.QuestStartedEventSchema=fn;exports.QuestStatusSchema=un;exports.RECHARGE_CADENCES=Fo;exports.RESURRECTION_SPELLS=er;exports.RechargeCadenceSchema=Uo;exports.RechargeSchema=Ve;exports.ResourceRestoredEventSchema=Hn;exports.ResourceSpentEventSchema=qn;exports.ResourceStateSchema=_a;exports.ResurrectionSpellSchema=tr;exports.RollTargetSchema=Sa;exports.RoundEndedEventSchema=no;exports.SCHEMA_VERSION=ze;exports.SIZES=Jt;exports.SKILLS=ta;exports.SKILL_ABILITY=aa;exports.SPELL_LEVEL_MAX=ua;exports.SPELL_LEVEL_MIN=la;exports.STARTER_PACK_RAW=Dc;exports.SaveRolledEventSchema=Io;exports.SeededRNG=Re;exports.SenseSchema=sa;exports.SensesSchema=ca;exports.SentientItemConflictEventSchema=Ho;exports.SessionSchema=Ja;exports.ShortRestEndedEventSchema=Vn;exports.ShortRestStartedEventSchema=Kn;exports.SimulacrumCreatedEventSchema=cr;exports.SizeSchema=je;exports.SkillSchema=ae;exports.SpeciesSchema=za;exports.SpeedSchema=He;exports.SpellCounteredEventSchema=zo;exports.SpellDispelledEventSchema=Co;exports.SpellLevelSchema=ge;exports.SpellSchema=Ta;exports.SpellSchoolSchema=da;exports.SpellcastingProgressionSchema=ka;exports.StabilizedEventSchema=jn;exports.SubclassSchema=wa;exports.TERRAIN_KINDS=an;exports.TempHPGrantedEventSchema=On;exports.TerrainKindSchema=nn;exports.ThrowOnCallRNG=br;exports.ToolSchema=xa;exports.TravelLegCompletedEventSchema=Mo;exports.TurnEndedEventSchema=ao;exports.TurnStartedEventSchema=to;exports.ULIDSchema=s;exports.VEHICLE_KINDS=An;exports.VehicleAcquiredEventSchema=Ro;exports.VehicleBoardedEventSchema=To;exports.VehicleDamagedEventSchema=Bo;exports.VehicleDepartedEventSchema=Do;exports.VehicleKindSchema=it;exports.VehicleRepairedEventSchema=xo;exports.VehicleSchema=wn;exports.WEAPON_MASTERIES=ya;exports.WEAPON_PROPERTIES=ga;exports.WeaponMasteryActivatedEventSchema=ko;exports.WeaponMasterySchema=Ee;exports.WeaponPropertySchema=We;exports.WeaponSchema=Da;exports.WishGrantedEventSchema=dr;exports.XPAwardedEventSchema=Cn;exports.abilityModifier=C;exports.addCurrency=Ze;exports.advanceInGameTime=Ya;exports.apply=Me;exports.applyAll=Pe;exports.asBackgroundId=ki;exports.asCharacterId=zi;exports.asClassFeatureId=Ri;exports.asClassId=Ai;exports.asConditionId=Bi;exports.asContentPackId=$i;exports.asCreatureId=Ci;exports.asFeatId=Ti;exports.asHandlerId=Oi;exports.asItemDefinitionId=Pi;exports.asItemInstanceId=Li;exports.asMonsterStatblockId=xi;exports.asResourceId=Mi;exports.asSpeciesId=Ei;exports.asSpellId=Di;exports.asSubclassId=wi;exports.breakdownInGameTime=Qa;exports.buildEffectStack=X;exports.chebyshevDistanceFeet=xr;exports.commit=bt;exports.computeAC=le;exports.computeAbilityCheck=ne;exports.computeAttackBonus=Te;exports.computeDerivedCharacter=Dr;exports.computePassiveScore=Qc;exports.computeSavingThrow=ue;exports.computeSpellAttackBonus=ht;exports.computeSpellSaveDC=De;exports.computeSpellSlots=Be;exports.computeTotalLevel=N;exports.createEngine=km;exports.createPC=vu;exports.defaultCampaignSettings=dt;exports.defaultRNG=yr;exports.emptyCampaignState=lt;exports.emptyCurrency=de;exports.evaluateFormula=te;exports.evaluatePredicate=pe;exports.formatInGameTime=ks;exports.hasLineOfEffect=od;exports.hasLineOfSight=Mr;exports.isFormula=Vi;exports.isInRangeFeet=td;exports.isPredicate=es;exports.loadCampaign=bu;exports.loadContentPack=hr;exports.loadStarterPack=Bc;exports.migrate=wm;exports.movementCostAt=Zc;exports.movementCostFor=Br;exports.newAppliedConditionId=W;exports.newCampaignId=Kt;exports.newCharacterId=Ht;exports.newChoiceId=Vt;exports.newCreatureId=fi;exports.newEffectInstanceId=Wt;exports.newEncounterId=Gt;exports.newEventId=I;exports.newItemInstanceId=vi;exports.newJournalEntryId=Si;exports.newLocationId=yi;exports.newPartyId=Ii;exports.newQuestId=bi;exports.newSessionId=gi;exports.parseDiceExpression=Q;exports.performIntent=Fr;exports.planAbilityCheck=ei;exports.planAdvanceTurn=Kr;exports.planAttack=Ur;exports.planBeginFirstTurn=Vr;exports.planCounterspell=ii;exports.planCreateEncounter=qr;exports.planDispelMagic=si;exports.planEndEncounter=Wr;exports.planForage=li;exports.planGrapple=ni;exports.planHide=ri;exports.planIdentify=ci;exports.planLevelUp=Xr;exports.planLongRest=Ue;exports.planMoraleCheck=mi;exports.planNavigationCheck=ui;exports.planOpportunityAttack=jr;exports.planReactionRoll=pi;exports.planResolveChoice=Qr;exports.planRollInitiative=Hr;exports.planSave=Zr;exports.planShortRest=Fe;exports.planShove=oi;exports.planStartEncounter=Gr;exports.planWeaponMastery=di;exports.proficiencyBonus=j;exports.redo=Nr;exports.replay=be;exports.resolveContent=mr;exports.rollDice=Sr;exports.rollDie=E;exports.rollExpression=Nc;exports.seededRNG=Lc;exports.serializeCampaign=yu;exports.spellSlotsForLevel=Wc;exports.subtractCurrency=Wa;exports.terrainAt=ft;exports.throwOnCallRNG=Oc;exports.totalInCopper=Cs;exports.undo=_r;exports.validateCrossReferences=fr;
6
+ //# sourceMappingURL=ttrpg-engine-dnd.cjs.map