@jgengine/core 0.9.0 → 0.11.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 (631) hide show
  1. package/CHANGELOG.md +34 -3
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/spawnDirector.d.ts +19 -1
  21. package/dist/ai/spawnDirector.js +53 -26
  22. package/dist/ai/spawnPoint.d.ts +7 -0
  23. package/dist/ai/spawnPoint.js +7 -0
  24. package/dist/ai/targetAcquisition.d.ts +84 -0
  25. package/dist/ai/targetAcquisition.js +92 -0
  26. package/dist/anim/easing.d.ts +19 -0
  27. package/dist/anim/easing.js +19 -0
  28. package/dist/anim/oscillator.d.ts +12 -0
  29. package/dist/anim/oscillator.js +25 -0
  30. package/dist/area/areaEffectField.d.ts +127 -0
  31. package/dist/area/areaEffectField.js +175 -0
  32. package/dist/area/stackPolicy.d.ts +47 -0
  33. package/dist/area/stackPolicy.js +99 -0
  34. package/dist/audio/audioFalloff.d.ts +5 -2
  35. package/dist/audio/music.d.ts +53 -0
  36. package/dist/audio/music.js +34 -0
  37. package/dist/audio/synth.d.ts +60 -0
  38. package/dist/audio/synth.js +8 -0
  39. package/dist/authoring.d.ts +15 -0
  40. package/dist/authoring.js +15 -0
  41. package/dist/board/laneBoard.d.ts +13 -0
  42. package/dist/board/laneBoard.js +13 -0
  43. package/dist/board/timelineBoard.d.ts +10 -0
  44. package/dist/board/timelineBoard.js +10 -0
  45. package/dist/combat/abilityKit.d.ts +18 -0
  46. package/dist/combat/abilityKit.js +24 -9
  47. package/dist/combat/animationState.d.ts +5 -0
  48. package/dist/combat/animationState.js +5 -0
  49. package/dist/combat/breakMeters.d.ts +10 -0
  50. package/dist/combat/breakMeters.js +10 -0
  51. package/dist/combat/castRunner.d.ts +5 -0
  52. package/dist/combat/castRunner.js +5 -0
  53. package/dist/combat/comboPoints.d.ts +5 -0
  54. package/dist/combat/comboPoints.js +5 -0
  55. package/dist/combat/comboString.d.ts +5 -0
  56. package/dist/combat/comboString.js +5 -0
  57. package/dist/combat/damageInterceptors.d.ts +192 -0
  58. package/dist/combat/damageInterceptors.js +251 -0
  59. package/dist/combat/damageMatchup.d.ts +68 -0
  60. package/dist/combat/damageMatchup.js +42 -0
  61. package/dist/combat/damageResolution.d.ts +63 -0
  62. package/dist/combat/damageResolution.js +50 -0
  63. package/dist/combat/death.d.ts +7 -1
  64. package/dist/combat/death.js +5 -0
  65. package/dist/combat/deathReason.d.ts +14 -0
  66. package/dist/combat/deathReason.js +1 -0
  67. package/dist/combat/defensiveWindow.d.ts +5 -0
  68. package/dist/combat/defensiveWindow.js +5 -0
  69. package/dist/combat/dotField.d.ts +47 -0
  70. package/dist/combat/dotField.js +52 -0
  71. package/dist/combat/downed.d.ts +5 -0
  72. package/dist/combat/downed.js +5 -0
  73. package/dist/combat/effects.d.ts +5 -0
  74. package/dist/combat/effects.js +5 -0
  75. package/dist/combat/encounterSequence.d.ts +258 -0
  76. package/dist/combat/encounterSequence.js +426 -0
  77. package/dist/combat/hitReaction.d.ts +57 -1
  78. package/dist/combat/hitReaction.js +45 -5
  79. package/dist/combat/magazine.d.ts +54 -0
  80. package/dist/combat/magazine.js +96 -0
  81. package/dist/combat/projectiles.d.ts +7 -2
  82. package/dist/combat/projectiles.js +48 -17
  83. package/dist/combat/receivedDamage.d.ts +117 -0
  84. package/dist/combat/receivedDamage.js +92 -0
  85. package/dist/combat/regenShield.d.ts +39 -0
  86. package/dist/combat/regenShield.js +49 -0
  87. package/dist/combat/renderCues.d.ts +51 -0
  88. package/dist/combat/renderCues.js +44 -0
  89. package/dist/combat/resourcePool.d.ts +5 -0
  90. package/dist/combat/resourcePool.js +5 -0
  91. package/dist/combat/rewardAllocation.d.ts +121 -0
  92. package/dist/combat/rewardAllocation.js +251 -0
  93. package/dist/combat/shotOrigin.d.ts +30 -1
  94. package/dist/combat/shotOrigin.js +70 -2
  95. package/dist/combat/statusApplication.d.ts +96 -0
  96. package/dist/combat/statusApplication.js +81 -0
  97. package/dist/combat/telegraph.d.ts +11 -2
  98. package/dist/combat/telegraph.js +11 -2
  99. package/dist/combat/thresholdCrossings.d.ts +85 -0
  100. package/dist/combat/thresholdCrossings.js +116 -0
  101. package/dist/combat.d.ts +34 -0
  102. package/dist/combat.js +34 -0
  103. package/dist/commands/commandRegistry.d.ts +11 -0
  104. package/dist/commands/commandRegistry.js +9 -2
  105. package/dist/crafting/crop.d.ts +18 -0
  106. package/dist/crafting/crop.js +18 -0
  107. package/dist/crafting/production.d.ts +5 -0
  108. package/dist/crafting/production.js +5 -0
  109. package/dist/devtools/rewriteTunables.d.ts +17 -0
  110. package/dist/devtools/rewriteTunables.js +276 -0
  111. package/dist/devtools/saveEndpoint.d.ts +46 -0
  112. package/dist/devtools/saveEndpoint.js +48 -0
  113. package/dist/devtools/transformTunables.d.ts +3 -0
  114. package/dist/devtools/transformTunables.js +3 -0
  115. package/dist/devtools/tunableSchema.d.ts +31 -0
  116. package/dist/devtools/tunableSchema.js +31 -0
  117. package/dist/economy/currency.d.ts +12 -1
  118. package/dist/economy/currency.js +12 -1
  119. package/dist/economy/listingBook.d.ts +91 -0
  120. package/dist/economy/listingBook.js +144 -0
  121. package/dist/economy/resourceLedger.d.ts +222 -0
  122. package/dist/economy/resourceLedger.js +353 -0
  123. package/dist/economy/sharedWallet.d.ts +14 -0
  124. package/dist/economy/sharedWallet.js +14 -0
  125. package/dist/economy/techTree.d.ts +12 -0
  126. package/dist/economy/techTree.js +12 -0
  127. package/dist/economy/wallet.d.ts +26 -2
  128. package/dist/economy/wallet.js +35 -6
  129. package/dist/editor/commands.d.ts +248 -0
  130. package/dist/editor/commands.js +865 -0
  131. package/dist/editor/document.d.ts +186 -0
  132. package/dist/editor/document.js +884 -0
  133. package/dist/editor/grid.d.ts +229 -0
  134. package/dist/editor/grid.js +366 -0
  135. package/dist/editor/gridAdapters.d.ts +80 -0
  136. package/dist/editor/gridAdapters.js +134 -0
  137. package/dist/editor/index.d.ts +97 -0
  138. package/dist/editor/index.js +10 -0
  139. package/dist/editor/liveSync.d.ts +127 -0
  140. package/dist/editor/liveSync.js +249 -0
  141. package/dist/editor/runtimeInspector.d.ts +88 -0
  142. package/dist/editor/runtimeInspector.js +239 -0
  143. package/dist/editor/types.d.ts +175 -0
  144. package/dist/editor/types.js +29 -0
  145. package/dist/faction/reputation.d.ts +5 -0
  146. package/dist/faction/reputation.js +5 -0
  147. package/dist/format/distance.d.ts +17 -0
  148. package/dist/format/distance.js +18 -0
  149. package/dist/format/duration.d.ts +27 -0
  150. package/dist/format/duration.js +45 -0
  151. package/dist/format/speed.d.ts +17 -0
  152. package/dist/format/speed.js +25 -0
  153. package/dist/game/connectedPlayers.d.ts +30 -0
  154. package/dist/game/connectedPlayers.js +21 -0
  155. package/dist/game/cosmetics.d.ts +9 -0
  156. package/dist/game/cosmetics.js +16 -0
  157. package/dist/game/defineGame.d.ts +141 -2
  158. package/dist/game/defineGame.js +39 -1
  159. package/dist/game/defineSystem.d.ts +88 -0
  160. package/dist/game/defineSystem.js +45 -0
  161. package/dist/game/dialogue.d.ts +33 -0
  162. package/dist/game/dialogue.js +21 -0
  163. package/dist/game/events.d.ts +50 -13
  164. package/dist/game/events.js +5 -0
  165. package/dist/game/feed.d.ts +33 -0
  166. package/dist/game/feed.js +35 -2
  167. package/dist/game/gamePhase.d.ts +11 -0
  168. package/dist/game/gamePhase.js +16 -0
  169. package/dist/game/keyValueStore.d.ts +25 -0
  170. package/dist/game/keyValueStore.js +61 -0
  171. package/dist/game/leaderboard.d.ts +5 -0
  172. package/dist/game/leaderboard.js +5 -0
  173. package/dist/game/levelSequence.d.ts +24 -2
  174. package/dist/game/levelSequence.js +51 -2
  175. package/dist/game/loadout.d.ts +5 -0
  176. package/dist/game/loadout.js +5 -0
  177. package/dist/game/lootFilter.d.ts +2 -0
  178. package/dist/game/lootFilter.js +2 -0
  179. package/dist/game/lootPipeline.d.ts +164 -0
  180. package/dist/game/lootPipeline.js +216 -0
  181. package/dist/game/lootTable.d.ts +21 -0
  182. package/dist/game/lootTable.js +15 -4
  183. package/dist/game/modelAnimation.d.ts +8 -0
  184. package/dist/game/modelAnimation.js +18 -0
  185. package/dist/game/objectives.d.ts +43 -0
  186. package/dist/game/objectives.js +36 -0
  187. package/dist/game/paramLayers.d.ts +148 -0
  188. package/dist/game/paramLayers.js +185 -0
  189. package/dist/game/ping.d.ts +5 -0
  190. package/dist/game/ping.js +5 -0
  191. package/dist/game/playableGame.d.ts +160 -12
  192. package/dist/game/quest.d.ts +8 -0
  193. package/dist/game/quest.js +29 -0
  194. package/dist/game/race.d.ts +141 -0
  195. package/dist/game/race.js +169 -0
  196. package/dist/game/recordBook.d.ts +5 -5
  197. package/dist/game/recordBook.js +4 -1
  198. package/dist/game/ruleSelection.d.ts +75 -0
  199. package/dist/game/ruleSelection.js +127 -0
  200. package/dist/game/runDraft.d.ts +5 -0
  201. package/dist/game/runDraft.js +5 -0
  202. package/dist/game/saveStore.d.ts +111 -0
  203. package/dist/game/saveStore.js +312 -0
  204. package/dist/game/snapshotHistory.d.ts +67 -0
  205. package/dist/game/snapshotHistory.js +95 -0
  206. package/dist/game/social.d.ts +38 -1
  207. package/dist/game/social.js +71 -0
  208. package/dist/game/spawnPoints.d.ts +5 -0
  209. package/dist/game/spawnPoints.js +5 -0
  210. package/dist/game/systemRuntime.d.ts +50 -0
  211. package/dist/game/systemRuntime.js +157 -0
  212. package/dist/game/systemSchedule.d.ts +72 -0
  213. package/dist/game/systemSchedule.js +242 -0
  214. package/dist/game/toasts.d.ts +43 -0
  215. package/dist/game/toasts.js +44 -0
  216. package/dist/game/trade.d.ts +10 -0
  217. package/dist/game/trade.js +10 -0
  218. package/dist/game/unlocks.d.ts +8 -0
  219. package/dist/game/unlocks.js +16 -0
  220. package/dist/game/vfxInstance.d.ts +138 -0
  221. package/dist/game/vfxInstance.js +96 -0
  222. package/dist/game/worldItem.d.ts +17 -4
  223. package/dist/game/worldItem.js +17 -4
  224. package/dist/gameplay.d.ts +91 -0
  225. package/dist/gameplay.js +91 -0
  226. package/dist/index.d.ts +5 -7
  227. package/dist/index.js +5 -7
  228. package/dist/input/actionBindings.d.ts +24 -5
  229. package/dist/input/actionBindings.js +23 -5
  230. package/dist/input/axisInput.d.ts +13 -1
  231. package/dist/input/axisInput.js +22 -1
  232. package/dist/input/controlGroups.d.ts +67 -0
  233. package/dist/input/controlGroups.js +41 -0
  234. package/dist/input/touchScheme.d.ts +82 -6
  235. package/dist/input/touchScheme.js +123 -10
  236. package/dist/interaction/contextMenu.d.ts +1 -0
  237. package/dist/interaction/contextMenu.js +1 -0
  238. package/dist/interaction/lockpick.d.ts +61 -0
  239. package/dist/interaction/lockpick.js +168 -0
  240. package/dist/interaction/proximityPrompt.d.ts +5 -1
  241. package/dist/interaction/proximityPrompt.js +5 -3
  242. package/dist/interaction/qte.d.ts +5 -0
  243. package/dist/interaction/qte.js +5 -0
  244. package/dist/interaction/skillCheck.d.ts +5 -0
  245. package/dist/interaction/skillCheck.js +5 -0
  246. package/dist/inventory/inventoryModel.d.ts +12 -0
  247. package/dist/inventory/inventoryModel.js +12 -0
  248. package/dist/inventory/shapedGrid.d.ts +16 -0
  249. package/dist/inventory/shapedGrid.js +16 -0
  250. package/dist/inventory/slotModel.d.ts +10 -0
  251. package/dist/inventory/slotModel.js +10 -0
  252. package/dist/item/durability.d.ts +5 -0
  253. package/dist/item/durability.js +5 -0
  254. package/dist/item/itemIdentity.d.ts +171 -0
  255. package/dist/item/itemIdentity.js +138 -0
  256. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  257. package/dist/item/itemInstanceRegistry.js +34 -0
  258. package/dist/item/itemgen.d.ts +163 -0
  259. package/dist/item/itemgen.js +151 -0
  260. package/dist/item/modularItem.d.ts +5 -0
  261. package/dist/item/modularItem.js +5 -0
  262. package/dist/item/use.d.ts +5 -0
  263. package/dist/item/use.js +5 -0
  264. package/dist/item/useBehavior.d.ts +142 -0
  265. package/dist/item/useBehavior.js +105 -0
  266. package/dist/item/weapon.d.ts +5 -0
  267. package/dist/item/weapon.js +5 -0
  268. package/dist/math/scalar.d.ts +25 -0
  269. package/dist/math/scalar.js +47 -0
  270. package/dist/meta/changelog.d.ts +4 -1
  271. package/dist/meta/changelog.js +36 -1
  272. package/dist/movement/avoidance.d.ts +45 -0
  273. package/dist/movement/avoidance.js +123 -0
  274. package/dist/movement/cameraRig.d.ts +8 -0
  275. package/dist/movement/cameraRig.js +8 -0
  276. package/dist/movement/dash.d.ts +11 -0
  277. package/dist/movement/dash.js +11 -0
  278. package/dist/movement/formation.d.ts +135 -0
  279. package/dist/movement/formation.js +194 -0
  280. package/dist/movement/glideModel.d.ts +5 -0
  281. package/dist/movement/glideModel.js +5 -0
  282. package/dist/movement/grappleSwing.d.ts +5 -0
  283. package/dist/movement/grappleSwing.js +5 -0
  284. package/dist/movement/leaderTrail.d.ts +5 -0
  285. package/dist/movement/leaderTrail.js +5 -0
  286. package/dist/movement/movementModel.d.ts +38 -7
  287. package/dist/movement/movementModel.js +54 -13
  288. package/dist/movement/playerMovement.d.ts +41 -0
  289. package/dist/movement/playerMovement.js +236 -0
  290. package/dist/movement/poseState.d.ts +13 -0
  291. package/dist/movement/poseState.js +16 -0
  292. package/dist/movement/steering.d.ts +8 -0
  293. package/dist/movement/steering.js +18 -0
  294. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  295. package/dist/multiplayer/combatSnapshot.js +3 -0
  296. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  297. package/dist/multiplayer/lagCompensation.js +5 -0
  298. package/dist/multiplayer/presenceModel.d.ts +9 -1
  299. package/dist/multiplayer/presenceModel.js +9 -1
  300. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  301. package/dist/multiplayer/simultaneousCommit.js +3 -0
  302. package/dist/multiplayer.d.ts +11 -0
  303. package/dist/multiplayer.js +11 -0
  304. package/dist/nav/pathFollow.d.ts +57 -0
  305. package/dist/nav/pathFollow.js +109 -0
  306. package/dist/orders/orderKinds.d.ts +156 -0
  307. package/dist/orders/orderKinds.js +197 -0
  308. package/dist/orders/orderQueue.d.ts +208 -0
  309. package/dist/orders/orderQueue.js +211 -0
  310. package/dist/physics/drivableVehicle.d.ts +29 -0
  311. package/dist/physics/drivableVehicle.js +16 -0
  312. package/dist/physics/kinematicVehicle.d.ts +21 -1
  313. package/dist/physics/kinematicVehicle.js +23 -8
  314. package/dist/physics/physicsWorld.d.ts +24 -12
  315. package/dist/physics/physicsWorld.js +11 -5
  316. package/dist/physics/radialImpulse.d.ts +25 -0
  317. package/dist/physics/radialImpulse.js +27 -0
  318. package/dist/procedural.d.ts +3 -0
  319. package/dist/procedural.js +3 -0
  320. package/dist/progression/statGraph.d.ts +116 -0
  321. package/dist/progression/statGraph.js +318 -0
  322. package/dist/puzzle/cellGrid.d.ts +9 -0
  323. package/dist/puzzle/cellGrid.js +9 -0
  324. package/dist/puzzle/fallingPiece.d.ts +9 -0
  325. package/dist/puzzle/fallingPiece.js +9 -0
  326. package/dist/puzzle/nonogram.d.ts +39 -0
  327. package/dist/puzzle/nonogram.js +136 -0
  328. package/dist/random/nameGen.d.ts +5 -0
  329. package/dist/random/nameGen.js +5 -0
  330. package/dist/random/pick.d.ts +8 -0
  331. package/dist/random/pick.js +31 -0
  332. package/dist/random/rng.d.ts +24 -0
  333. package/dist/random/rng.js +30 -8
  334. package/dist/random/seedLink.d.ts +4 -0
  335. package/dist/random/seedLink.js +4 -0
  336. package/dist/relation/keyedValues.d.ts +54 -0
  337. package/dist/relation/keyedValues.js +115 -0
  338. package/dist/relation/thresholds.d.ts +62 -0
  339. package/dist/relation/thresholds.js +62 -0
  340. package/dist/render/color.d.ts +12 -0
  341. package/dist/render/color.js +26 -0
  342. package/dist/render/lookPreset.d.ts +41 -0
  343. package/dist/render/lookPreset.js +29 -0
  344. package/dist/render/postProcessing.d.ts +76 -0
  345. package/dist/render/postProcessing.js +21 -0
  346. package/dist/rules/predicate.d.ts +53 -0
  347. package/dist/rules/predicate.js +64 -0
  348. package/dist/rules/ruleEffects.d.ts +38 -0
  349. package/dist/rules/ruleEffects.js +37 -0
  350. package/dist/rules/triggeredRules.d.ts +160 -0
  351. package/dist/rules/triggeredRules.js +241 -0
  352. package/dist/runtime/adapter.d.ts +58 -0
  353. package/dist/runtime/adapter.js +54 -5
  354. package/dist/runtime/cameraDirector.d.ts +1 -0
  355. package/dist/runtime/cameraDirector.js +1 -0
  356. package/dist/runtime/commandRunner.d.ts +1 -0
  357. package/dist/runtime/commandRunner.js +1 -0
  358. package/dist/runtime/context/combatFx.d.ts +23 -0
  359. package/dist/runtime/context/combatFx.js +161 -0
  360. package/dist/runtime/context/registries.d.ts +13 -0
  361. package/dist/runtime/context/registries.js +84 -0
  362. package/dist/runtime/context/worldItems.d.ts +21 -0
  363. package/dist/runtime/context/worldItems.js +37 -0
  364. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  365. package/dist/runtime/descriptors/baseline.js +134 -0
  366. package/dist/runtime/descriptors/features.d.ts +74 -0
  367. package/dist/runtime/descriptors/features.js +281 -0
  368. package/dist/runtime/gameContext.d.ts +163 -19
  369. package/dist/runtime/gameContext.js +385 -339
  370. package/dist/runtime/gameRuntime.d.ts +1 -0
  371. package/dist/runtime/gameRuntime.js +1 -0
  372. package/dist/runtime/headlessRunner.d.ts +60 -0
  373. package/dist/runtime/headlessRunner.js +44 -0
  374. package/dist/runtime/hostPersistence.d.ts +12 -0
  375. package/dist/runtime/hostPersistence.js +12 -0
  376. package/dist/runtime/hostedGameRunner.d.ts +54 -0
  377. package/dist/runtime/hostedGameRunner.js +85 -0
  378. package/dist/runtime/hostedWorldSession.d.ts +73 -0
  379. package/dist/runtime/hostedWorldSession.js +64 -0
  380. package/dist/runtime/inputSnapshot.d.ts +21 -3
  381. package/dist/runtime/inputSnapshot.js +8 -2
  382. package/dist/runtime/motionIntents.d.ts +12 -1
  383. package/dist/runtime/motionIntents.js +26 -1
  384. package/dist/runtime/perContext.d.ts +15 -0
  385. package/dist/runtime/perContext.js +21 -0
  386. package/dist/runtime/runtimeSave.d.ts +79 -0
  387. package/dist/runtime/runtimeSave.js +105 -0
  388. package/dist/runtime/save.d.ts +4 -0
  389. package/dist/runtime/save.js +4 -0
  390. package/dist/runtime/snapshot.d.ts +7 -0
  391. package/dist/runtime/snapshot.js +7 -0
  392. package/dist/runtime/visibility.d.ts +2 -1
  393. package/dist/runtime/visibility.js +2 -1
  394. package/dist/runtime/worldChannel.d.ts +62 -0
  395. package/dist/runtime/worldChannel.js +114 -0
  396. package/dist/runtime/worldMirror.d.ts +36 -0
  397. package/dist/runtime/worldMirror.js +44 -0
  398. package/dist/runtime/worldProjection.d.ts +47 -0
  399. package/dist/runtime/worldProjection.js +52 -0
  400. package/dist/runtime/worldReplication.d.ts +69 -0
  401. package/dist/runtime/worldReplication.js +217 -0
  402. package/dist/runtime/worldSnapshot.d.ts +44 -0
  403. package/dist/runtime/worldSnapshot.js +30 -0
  404. package/dist/scene/assetCatalog.d.ts +22 -0
  405. package/dist/scene/assetCatalog.js +4 -0
  406. package/dist/scene/assetDiagnostics.d.ts +69 -0
  407. package/dist/scene/assetDiagnostics.js +110 -0
  408. package/dist/scene/assetGenerator.d.ts +65 -0
  409. package/dist/scene/assetGenerator.js +64 -0
  410. package/dist/scene/assetSpace.d.ts +137 -0
  411. package/dist/scene/assetSpace.js +259 -0
  412. package/dist/scene/authoredTriggers.d.ts +169 -0
  413. package/dist/scene/authoredTriggers.js +340 -0
  414. package/dist/scene/behaviorRuntime.d.ts +75 -0
  415. package/dist/scene/behaviorRuntime.js +217 -0
  416. package/dist/scene/behaviors.d.ts +14 -2
  417. package/dist/scene/behaviors.js +7 -2
  418. package/dist/scene/bodyBind.d.ts +60 -0
  419. package/dist/scene/bodyBind.js +51 -0
  420. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  421. package/dist/scene/builtinSceneKinds.js +62 -0
  422. package/dist/scene/colliders.d.ts +18 -0
  423. package/dist/scene/colliders.js +61 -1
  424. package/dist/scene/entityStats.d.ts +13 -0
  425. package/dist/scene/entityStats.js +30 -0
  426. package/dist/scene/entityStore.d.ts +41 -1
  427. package/dist/scene/entityStore.js +75 -0
  428. package/dist/scene/facing.d.ts +18 -0
  429. package/dist/scene/facing.js +26 -0
  430. package/dist/scene/modelSockets.d.ts +33 -0
  431. package/dist/scene/modelSockets.js +29 -0
  432. package/dist/scene/objectQuery.d.ts +2 -0
  433. package/dist/scene/objectQuery.js +2 -0
  434. package/dist/scene/objectStore.d.ts +4 -0
  435. package/dist/scene/objectStore.js +6 -0
  436. package/dist/scene/possession.d.ts +8 -0
  437. package/dist/scene/possession.js +14 -0
  438. package/dist/scene/roster.d.ts +3 -0
  439. package/dist/scene/roster.js +12 -0
  440. package/dist/scene/sceneKinds.d.ts +240 -0
  441. package/dist/scene/sceneKinds.js +214 -0
  442. package/dist/scene/sceneOwnership.d.ts +169 -0
  443. package/dist/scene/sceneOwnership.js +179 -0
  444. package/dist/scene/selectionBookmarks.d.ts +93 -0
  445. package/dist/scene/selectionBookmarks.js +122 -0
  446. package/dist/scene/vehicleSeat.d.ts +68 -0
  447. package/dist/scene/vehicleSeat.js +59 -0
  448. package/dist/sensor/concealment.d.ts +3 -0
  449. package/dist/sensor/concealment.js +3 -0
  450. package/dist/sensor/freezeMonitor.d.ts +1 -0
  451. package/dist/sensor/freezeMonitor.js +1 -0
  452. package/dist/sensor/frustumSensor.d.ts +7 -3
  453. package/dist/sensor/frustumSensor.js +7 -3
  454. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  455. package/dist/sensor/hiddenStateProbe.js +5 -2
  456. package/dist/sensor/recordingBuffer.d.ts +2 -1
  457. package/dist/sensor/recordingBuffer.js +2 -1
  458. package/dist/sensor/replayLoop.d.ts +6 -2
  459. package/dist/sensor/replayLoop.js +6 -2
  460. package/dist/sensor/revealQuery.d.ts +2 -1
  461. package/dist/sensor/revealQuery.js +2 -1
  462. package/dist/sensor/visionCone.d.ts +10 -3
  463. package/dist/sensor/visionCone.js +10 -3
  464. package/dist/session/contestedChannel.d.ts +1 -0
  465. package/dist/session/contestedChannel.js +1 -0
  466. package/dist/session/extraction.d.ts +1 -0
  467. package/dist/session/extraction.js +1 -0
  468. package/dist/session/roles.d.ts +6 -0
  469. package/dist/session/roles.js +6 -0
  470. package/dist/session/roundState.d.ts +8 -0
  471. package/dist/session/roundState.js +2 -0
  472. package/dist/settings/settingsModel.d.ts +1 -0
  473. package/dist/settings/settingsModel.js +1 -0
  474. package/dist/stats/accumulatorMeter.d.ts +6 -0
  475. package/dist/stats/accumulatorMeter.js +6 -0
  476. package/dist/stats/eventMeter.d.ts +5 -0
  477. package/dist/stats/eventMeter.js +5 -0
  478. package/dist/stats/rollCheck.d.ts +5 -0
  479. package/dist/stats/rollCheck.js +5 -0
  480. package/dist/stats/statModifiers.d.ts +5 -0
  481. package/dist/stats/statModifiers.js +5 -0
  482. package/dist/store/defineKeyedStore.d.ts +38 -0
  483. package/dist/store/defineKeyedStore.js +42 -0
  484. package/dist/store/defineStore.d.ts +33 -0
  485. package/dist/store/defineStore.js +35 -0
  486. package/dist/store/observableKeyedStore.d.ts +9 -0
  487. package/dist/store/observableKeyedStore.js +43 -2
  488. package/dist/survival/decayMeter.d.ts +55 -0
  489. package/dist/survival/decayMeter.js +130 -55
  490. package/dist/survival/moodle.d.ts +2 -0
  491. package/dist/survival/regionHealth.d.ts +6 -0
  492. package/dist/survival/regionHealth.js +5 -0
  493. package/dist/tactics/fallingGrid.d.ts +6 -4
  494. package/dist/tactics/fallingGrid.js +6 -4
  495. package/dist/tactics/predictiveQuery.d.ts +3 -0
  496. package/dist/tactics/predictiveQuery.js +3 -0
  497. package/dist/tactics/snapshot.d.ts +2 -0
  498. package/dist/tactics/snapshot.js +2 -0
  499. package/dist/tactics/surface.d.ts +1 -0
  500. package/dist/tactics/surface.js +1 -0
  501. package/dist/tactics/tacticalGrid.d.ts +1 -0
  502. package/dist/tactics/tacticalGrid.js +1 -0
  503. package/dist/time/beatClock.d.ts +14 -4
  504. package/dist/time/beatClock.js +14 -4
  505. package/dist/time/calendarClock.d.ts +3 -0
  506. package/dist/time/calendarClock.js +3 -0
  507. package/dist/time/idleProgress.d.ts +4 -0
  508. package/dist/time/idleProgress.js +4 -0
  509. package/dist/time/simClock.d.ts +2 -0
  510. package/dist/time/simClock.js +20 -5
  511. package/dist/ui/actionModel.d.ts +110 -0
  512. package/dist/ui/actionModel.js +159 -0
  513. package/dist/ui/gameLayout.d.ts +144 -0
  514. package/dist/ui/gameLayout.js +148 -0
  515. package/dist/ui/hudDocument.d.ts +114 -0
  516. package/dist/ui/hudDocument.js +220 -0
  517. package/dist/ui/hudLayout.d.ts +33 -1
  518. package/dist/ui/hudLayout.js +204 -17
  519. package/dist/ui/orientation.d.ts +39 -0
  520. package/dist/ui/orientation.js +49 -0
  521. package/dist/ui/selectionModel.d.ts +92 -0
  522. package/dist/ui/selectionModel.js +88 -0
  523. package/dist/ui/swingTimer.d.ts +42 -0
  524. package/dist/ui/swingTimer.js +38 -0
  525. package/dist/ui/tooltipModel.d.ts +63 -0
  526. package/dist/ui/tooltipModel.js +82 -0
  527. package/dist/ui.d.ts +15 -0
  528. package/dist/ui.js +15 -0
  529. package/dist/visibility/bounds.d.ts +8 -1
  530. package/dist/visibility/bounds.js +8 -1
  531. package/dist/visibility/frustum.d.ts +12 -3
  532. package/dist/visibility/frustum.js +12 -3
  533. package/dist/visibility/spatialIndex.js +34 -20
  534. package/dist/work/jobQueue.d.ts +201 -0
  535. package/dist/work/jobQueue.js +253 -0
  536. package/dist/work/unitTraining.d.ts +58 -0
  537. package/dist/work/unitTraining.js +52 -0
  538. package/dist/world/authoredObjects.d.ts +58 -0
  539. package/dist/world/authoredObjects.js +69 -0
  540. package/dist/world/buildingGenerator.d.ts +18 -0
  541. package/dist/world/buildingGenerator.js +62 -0
  542. package/dist/world/buildings.d.ts +5 -0
  543. package/dist/world/buildings.js +5 -0
  544. package/dist/world/catenary.d.ts +22 -0
  545. package/dist/world/catenary.js +69 -0
  546. package/dist/world/environmentSummary.d.ts +11 -2
  547. package/dist/world/environmentSummary.js +11 -1
  548. package/dist/world/features.d.ts +244 -7
  549. package/dist/world/features.js +92 -4
  550. package/dist/world/footprintGrid.d.ts +59 -0
  551. package/dist/world/footprintGrid.js +141 -0
  552. package/dist/world/geometry.d.ts +64 -0
  553. package/dist/world/geometry.js +94 -0
  554. package/dist/world/grassKind.d.ts +51 -0
  555. package/dist/world/grassKind.js +101 -0
  556. package/dist/world/pathInstances.d.ts +27 -0
  557. package/dist/world/pathInstances.js +27 -0
  558. package/dist/world/pathTerrain.d.ts +80 -0
  559. package/dist/world/pathTerrain.js +142 -0
  560. package/dist/world/placeAsset.d.ts +81 -0
  561. package/dist/world/placeAsset.js +77 -0
  562. package/dist/world/placement.d.ts +4 -0
  563. package/dist/world/placement.js +4 -0
  564. package/dist/world/placementController.d.ts +6 -0
  565. package/dist/world/placementController.js +6 -0
  566. package/dist/world/polyline.d.ts +34 -0
  567. package/dist/world/polyline.js +81 -0
  568. package/dist/world/roads.d.ts +55 -0
  569. package/dist/world/roads.js +184 -0
  570. package/dist/world/scatterRegion.d.ts +164 -0
  571. package/dist/world/scatterRegion.js +409 -0
  572. package/dist/world/sceneShapes.d.ts +43 -0
  573. package/dist/world/sceneShapes.js +1 -0
  574. package/dist/world/segment.d.ts +27 -0
  575. package/dist/world/segment.js +43 -0
  576. package/dist/world/soilKind.d.ts +48 -0
  577. package/dist/world/soilKind.js +92 -0
  578. package/dist/world/spatialSample.d.ts +241 -0
  579. package/dist/world/spatialSample.js +465 -0
  580. package/dist/world/streets.d.ts +80 -0
  581. package/dist/world/streets.js +144 -0
  582. package/dist/world/terraform.d.ts +213 -1
  583. package/dist/world/terraform.js +655 -20
  584. package/dist/world/terrain.d.ts +138 -12
  585. package/dist/world/terrain.js +346 -28
  586. package/dist/world/terrainGuides.d.ts +182 -0
  587. package/dist/world/terrainGuides.js +343 -0
  588. package/dist/world/vec2.d.ts +81 -0
  589. package/dist/world/vec2.js +128 -0
  590. package/dist/world/vec3.d.ts +49 -0
  591. package/dist/world/vec3.js +76 -0
  592. package/dist/world/vegetation.d.ts +71 -0
  593. package/dist/world/vegetation.js +151 -0
  594. package/dist/world/visibilityField.d.ts +154 -0
  595. package/dist/world/visibilityField.js +271 -0
  596. package/dist/world/volumetricClouds.d.ts +52 -0
  597. package/dist/world/volumetricClouds.js +43 -0
  598. package/dist/world/walls.d.ts +9 -0
  599. package/dist/world/walls.js +9 -0
  600. package/dist/world/waterKind.d.ts +55 -0
  601. package/dist/world/waterKind.js +99 -0
  602. package/dist/world.d.ts +132 -0
  603. package/dist/world.js +132 -0
  604. package/package.json +32 -8
  605. package/skills/jgengine/SKILL.md +51 -0
  606. package/skills/jgengine/api.md +434 -0
  607. package/skills/jgengine/capabilities.md +29 -0
  608. package/skills/jgengine/reference-cartridge.md +72 -0
  609. package/skills/jgengine-combat/SKILL.md +34 -0
  610. package/skills/jgengine-combat/api.md +549 -0
  611. package/skills/jgengine-combat/capabilities.md +169 -0
  612. package/skills/jgengine-combat/reference.md +98 -0
  613. package/skills/jgengine-gameplay/SKILL.md +39 -0
  614. package/skills/jgengine-gameplay/api.md +1794 -0
  615. package/skills/jgengine-gameplay/capabilities.md +378 -0
  616. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  617. package/skills/jgengine-world/SKILL.md +38 -0
  618. package/skills/jgengine-world/api.md +2652 -0
  619. package/skills/jgengine-world/capabilities.md +370 -0
  620. package/skills/jgengine-world/reference.md +222 -0
  621. package/dist/cartridge/runtime.d.ts +0 -15
  622. package/dist/cartridge/runtime.js +0 -556
  623. package/dist/cartridge/spec.d.ts +0 -188
  624. package/dist/cartridge/spec.js +0 -19
  625. package/dist/cartridge/validate.d.ts +0 -2
  626. package/dist/cartridge/validate.js +0 -78
  627. package/dist/store/engineStore.d.ts +0 -22
  628. package/dist/store/engineStore.js +0 -50
  629. package/dist/store/features.d.ts +0 -10
  630. package/dist/store/features.js +0 -23
  631. package/llms.txt +0 -4983
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A cinematic "product shot" post preset — the full chain on (contact-AO, soft bloom, a warm film
3
+ * grade with vignette + a touch of grain + chromatic aberration). Meant for a `StudioStage` where a
4
+ * single parametric asset is framed on a backdrop, so every studio reads shipped, not intern-tier. DoF
5
+ * is left off by default (it needs a per-scene focus distance); set `dof` to enable it.
6
+ */
7
+ export const STUDIO_STAGE_POST = {
8
+ toneMapping: "aces",
9
+ exposure: 1.05,
10
+ bloom: { strength: 0.28, radius: 0.6, threshold: 0.8 },
11
+ ao: { radius: 1.4, intensity: 2.2, distanceFalloff: 3, blend: 1 },
12
+ grade: {
13
+ lift: [0.008, 0.008, 0.014],
14
+ gain: [1.05, 1.02, 0.98],
15
+ gamma: 0.96,
16
+ saturation: 1.12,
17
+ vignette: 0,
18
+ grain: 0.006,
19
+ chromaticAberration: 0.001,
20
+ },
21
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A declarative, serializable predicate AST evaluated against a plain fact bag. Predicates carry no
3
+ * closures, so they survive save/load and stay deterministic — the reusable condition seam that
4
+ * event-conditioned rules, quests, perks, and reactive AI gate on instead of hand-rolled callbacks.
5
+ */
6
+ /** A leaf value a predicate can compare against — JSON-safe so predicates serialize cleanly. */
7
+ export type PredicateValue = string | number | boolean | null;
8
+ /** Dot path into a fact bag, e.g. `"hit.crit"` or `"attacker.team"`. */
9
+ export type PredicatePath = string;
10
+ /**
11
+ * One node of the predicate tree. Combinators (`all`/`any`/`not`) nest; leaf comparators read a
12
+ * dot path from the facts and compare it. `has` passes when the path resolves to a non-nullish value.
13
+ */
14
+ export type Predicate = {
15
+ readonly all: readonly Predicate[];
16
+ } | {
17
+ readonly any: readonly Predicate[];
18
+ } | {
19
+ readonly not: Predicate;
20
+ } | {
21
+ readonly eq: readonly [PredicatePath, PredicateValue];
22
+ } | {
23
+ readonly ne: readonly [PredicatePath, PredicateValue];
24
+ } | {
25
+ readonly gt: readonly [PredicatePath, number];
26
+ } | {
27
+ readonly gte: readonly [PredicatePath, number];
28
+ } | {
29
+ readonly lt: readonly [PredicatePath, number];
30
+ } | {
31
+ readonly lte: readonly [PredicatePath, number];
32
+ } | {
33
+ readonly in: readonly [PredicatePath, readonly PredicateValue[]];
34
+ } | {
35
+ readonly has: PredicatePath;
36
+ };
37
+ /** Plain, serializable bag of facts a predicate reads by dot path. */
38
+ export type PredicateFacts = Record<string, unknown>;
39
+ /**
40
+ * Read a dot path out of a fact bag, descending only through plain objects. Returns `undefined` when
41
+ * any segment is missing or non-traversable. Bounded by the path's segment count.
42
+ *
43
+ * @capability declarative-predicate serializable data-driven conditions with no callbacks in saved content
44
+ */
45
+ export declare function readPath(facts: PredicateFacts, path: PredicatePath): unknown;
46
+ /**
47
+ * Evaluate a predicate against a fact bag. An omitted predicate matches unconditionally, so callers
48
+ * can treat "no condition" and "always" identically. Pure and deterministic — no allocation beyond
49
+ * path splits and no reliance on evaluation order between sibling clauses.
50
+ *
51
+ * @capability declarative-predicate serializable data-driven conditions with no callbacks in saved content
52
+ */
53
+ export declare function evaluatePredicate(predicate: Predicate | undefined, facts: PredicateFacts): boolean;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * A declarative, serializable predicate AST evaluated against a plain fact bag. Predicates carry no
3
+ * closures, so they survive save/load and stay deterministic — the reusable condition seam that
4
+ * event-conditioned rules, quests, perks, and reactive AI gate on instead of hand-rolled callbacks.
5
+ */
6
+ /**
7
+ * Read a dot path out of a fact bag, descending only through plain objects. Returns `undefined` when
8
+ * any segment is missing or non-traversable. Bounded by the path's segment count.
9
+ *
10
+ * @capability declarative-predicate serializable data-driven conditions with no callbacks in saved content
11
+ */
12
+ export function readPath(facts, path) {
13
+ let current = facts;
14
+ for (const segment of path.split(".")) {
15
+ if (typeof current !== "object" || current === null)
16
+ return undefined;
17
+ current = current[segment];
18
+ }
19
+ return current;
20
+ }
21
+ function asNumber(value) {
22
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
23
+ }
24
+ /**
25
+ * Evaluate a predicate against a fact bag. An omitted predicate matches unconditionally, so callers
26
+ * can treat "no condition" and "always" identically. Pure and deterministic — no allocation beyond
27
+ * path splits and no reliance on evaluation order between sibling clauses.
28
+ *
29
+ * @capability declarative-predicate serializable data-driven conditions with no callbacks in saved content
30
+ */
31
+ export function evaluatePredicate(predicate, facts) {
32
+ if (predicate === undefined)
33
+ return true;
34
+ if ("all" in predicate)
35
+ return predicate.all.every((child) => evaluatePredicate(child, facts));
36
+ if ("any" in predicate)
37
+ return predicate.any.some((child) => evaluatePredicate(child, facts));
38
+ if ("not" in predicate)
39
+ return !evaluatePredicate(predicate.not, facts);
40
+ if ("has" in predicate) {
41
+ const value = readPath(facts, predicate.has);
42
+ return value !== undefined && value !== null;
43
+ }
44
+ if ("eq" in predicate)
45
+ return readPath(facts, predicate.eq[0]) === predicate.eq[1];
46
+ if ("ne" in predicate)
47
+ return readPath(facts, predicate.ne[0]) !== predicate.ne[1];
48
+ if ("in" in predicate)
49
+ return predicate.in[1].includes(readPath(facts, predicate.in[0]));
50
+ if ("gt" in predicate) {
51
+ const value = asNumber(readPath(facts, predicate.gt[0]));
52
+ return value !== undefined && value > predicate.gt[1];
53
+ }
54
+ if ("gte" in predicate) {
55
+ const value = asNumber(readPath(facts, predicate.gte[0]));
56
+ return value !== undefined && value >= predicate.gte[1];
57
+ }
58
+ if ("lt" in predicate) {
59
+ const value = asNumber(readPath(facts, predicate.lt[0]));
60
+ return value !== undefined && value < predicate.lt[1];
61
+ }
62
+ const value = asNumber(readPath(facts, predicate.lte[0]));
63
+ return value !== undefined && value <= predicate.lte[1];
64
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A registration seam for the effect ids that triggered rules reference. Saved content names an
3
+ * effect by id; the game declares what that id means here (label for inspectors, optional param
4
+ * schema note) so authored rules validate against a known vocabulary instead of stringly-invented,
5
+ * un-inspectable callbacks. Mirrors the authored-trigger action registry for editor parity.
6
+ */
7
+ import type { PredicateValue } from "./predicate.js";
8
+ /** A declared effect a triggered rule may reference. Behavior lives in the game; this is metadata. */
9
+ export interface RuleEffectDefinition {
10
+ /** Effect id used in {@link TriggeredRule.effect} references. */
11
+ id: string;
12
+ /** Human label for debug/inspector surfaces. */
13
+ label?: string;
14
+ /** Default params merged under a rule's own params, for authoring convenience. */
15
+ defaults?: Readonly<Record<string, PredicateValue>>;
16
+ }
17
+ /**
18
+ * Declare a rule effect id. Idempotent per id (last registration wins); call at module load next to
19
+ * catalogs so authored content and inspectors share one vocabulary.
20
+ *
21
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
22
+ */
23
+ export declare function registerRuleEffect(definition: RuleEffectDefinition): void;
24
+ /**
25
+ * Look up a declared rule effect, or `undefined` when the id was never registered — lets callers
26
+ * reject unknown effect references in authored content.
27
+ *
28
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
29
+ */
30
+ export declare function getRuleEffect(id: string): RuleEffectDefinition | undefined;
31
+ /**
32
+ * Every declared rule effect, for populating inspector dropdowns and validating a content set.
33
+ *
34
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
35
+ */
36
+ export declare function listRuleEffects(): RuleEffectDefinition[];
37
+ /** Clear the rule-effect registry — tests only. @internal */
38
+ export declare function clearRuleEffects(): void;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * A registration seam for the effect ids that triggered rules reference. Saved content names an
3
+ * effect by id; the game declares what that id means here (label for inspectors, optional param
4
+ * schema note) so authored rules validate against a known vocabulary instead of stringly-invented,
5
+ * un-inspectable callbacks. Mirrors the authored-trigger action registry for editor parity.
6
+ */
7
+ const registry = new Map();
8
+ /**
9
+ * Declare a rule effect id. Idempotent per id (last registration wins); call at module load next to
10
+ * catalogs so authored content and inspectors share one vocabulary.
11
+ *
12
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
13
+ */
14
+ export function registerRuleEffect(definition) {
15
+ registry.set(definition.id, definition);
16
+ }
17
+ /**
18
+ * Look up a declared rule effect, or `undefined` when the id was never registered — lets callers
19
+ * reject unknown effect references in authored content.
20
+ *
21
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
22
+ */
23
+ export function getRuleEffect(id) {
24
+ return registry.get(id);
25
+ }
26
+ /**
27
+ * Every declared rule effect, for populating inspector dropdowns and validating a content set.
28
+ *
29
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
30
+ */
31
+ export function listRuleEffects() {
32
+ return [...registry.values()];
33
+ }
34
+ /** Clear the rule-effect registry — tests only. @internal */
35
+ export function clearRuleEffects() {
36
+ registry.clear();
37
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * The reusable bridge from typed runtime events to effects. A triggered rule is pure data — which
3
+ * event it listens to, a declarative predicate over the event facts, how the affected target is
4
+ * resolved, an effect *reference* (never a callback), and how the resulting effect is gated, lived,
5
+ * and stacked. Affixes, talents, perks, quests, achievements, environment rules, and reactive AI all
6
+ * subscribe through this one seam instead of owning parallel trigger runtimes.
7
+ *
8
+ * Core stays decoupled from any specific effect system: `dispatch` returns provenance-rich firings
9
+ * and the game applies them to whatever effect/stat system it owns. Gate state (cooldowns, rate
10
+ * windows, remaining charges) and active timed effects serialize cleanly so future triggers survive
11
+ * save/load.
12
+ */
13
+ import { type Predicate, type PredicateFacts, type PredicateValue } from "./predicate.js";
14
+ /** Role slots an event exposes; a target selector resolves one of these to a concrete id. */
15
+ export type TargetRole = "subject" | "object" | "source" | "owner";
16
+ /**
17
+ * How a rule picks the id its effect lands on: a fixed event role, a dot path into the event facts,
18
+ * or a literal id. Data-only so it saves with the rule.
19
+ */
20
+ export type TargetSelector = {
21
+ readonly role: TargetRole;
22
+ } | {
23
+ readonly path: string;
24
+ } | {
25
+ readonly literal: string;
26
+ };
27
+ /** A reference to an effect the game knows how to apply — id plus JSON-safe params, no closures. */
28
+ export interface EffectRef {
29
+ readonly id: string;
30
+ readonly params?: Readonly<Record<string, PredicateValue>>;
31
+ }
32
+ /**
33
+ * How a repeated application of the same rule's effect on the same target combines with a live one:
34
+ * `refresh` re-arms the timer at one stack, `stack` adds a stack up to `maxStacks` and re-arms,
35
+ * `independent` keeps each application as its own instance with its own expiry, `ignore` drops the
36
+ * new application while one is already active.
37
+ */
38
+ export type StackPolicy = "refresh" | "stack" | "independent" | "ignore";
39
+ /** Bounded firing budget over a sliding time window. */
40
+ export interface RateLimit {
41
+ readonly count: number;
42
+ readonly windowMs: number;
43
+ }
44
+ /**
45
+ * A declarative subscription from an event to an effect. Everything here is serializable content —
46
+ * the runtime reads it, it never embeds behavior. `effect` names an effect the game resolves; core
47
+ * only routes and gates.
48
+ */
49
+ export interface TriggeredRule {
50
+ /** Stable id, unique within an engine. */
51
+ readonly id: string;
52
+ /** Event type this rule subscribes to. */
53
+ readonly event: string;
54
+ /** Owner/source identity (item instance, talent node, quest id) for provenance and bulk cleanup. */
55
+ readonly owner?: string;
56
+ /** Declarative gate over the event facts; omitted fires unconditionally. */
57
+ readonly when?: Predicate;
58
+ /** How the affected target id is resolved; defaults to the `subject` role. */
59
+ readonly target?: TargetSelector;
60
+ /** The effect to apply when the rule fires. */
61
+ readonly effect: EffectRef;
62
+ /** Minimum ms between fires of this rule against the same resolved target. */
63
+ readonly cooldownMs?: number;
64
+ /** Sliding-window firing cap across all targets. */
65
+ readonly rateLimit?: RateLimit;
66
+ /** Total fires before the rule is spent; omitted is unlimited. */
67
+ readonly charges?: number;
68
+ /** Lifetime of the applied effect in ms; omitted is instantaneous (no active instance kept). */
69
+ readonly durationMs?: number;
70
+ /** Stacking policy for repeat applications while an instance is live; defaults to `refresh`. */
71
+ readonly stacking?: StackPolicy;
72
+ /** Cap for the `stack` policy; defaults to 1 (i.e. behaves like `refresh` until raised). */
73
+ readonly maxStacks?: number;
74
+ }
75
+ /** A typed event handed to the engine; roles feed target resolution, facts feed the predicate. */
76
+ export interface RuleEvent {
77
+ readonly type: string;
78
+ readonly subject?: string;
79
+ readonly object?: string;
80
+ readonly source?: string;
81
+ /** Fact bag the predicate and `{ path }` target selectors read. */
82
+ readonly facts?: PredicateFacts;
83
+ }
84
+ /** A live timed effect an engine is tracking until it expires or is cleaned up. */
85
+ export interface ActiveEffect {
86
+ readonly instanceId: string;
87
+ readonly ruleId: string;
88
+ readonly effectId: string;
89
+ readonly owner: string | undefined;
90
+ readonly target: string;
91
+ readonly params: Readonly<Record<string, PredicateValue>> | undefined;
92
+ readonly appliedAt: number;
93
+ readonly expiresAt: number;
94
+ readonly stacks: number;
95
+ }
96
+ /** Reason a firing did not produce an effect — surfaced for debug inspection, never thrown. */
97
+ export type FiringBlock = "predicate" | "no-target" | "cooldown" | "rate-limit" | "no-charges" | "stack-ignored";
98
+ /**
99
+ * The outcome of matching one rule against one event. `applied` is the effect the caller should now
100
+ * run through its own effect system; a blocked firing reports why. Provenance (rule, owner, event,
101
+ * timestamp) rides along for auditability.
102
+ */
103
+ export interface RuleFiring {
104
+ readonly ruleId: string;
105
+ readonly event: string;
106
+ readonly owner: string | undefined;
107
+ readonly target: string;
108
+ readonly effect: EffectRef;
109
+ readonly at: number;
110
+ /** Set when the firing produced/updated a timed instance. */
111
+ readonly instanceId?: string;
112
+ /** Stack count on the target after this firing (>= 1 for timed effects). */
113
+ readonly stacks?: number;
114
+ /** Absent when the effect was applied; set when the firing was gated out. */
115
+ readonly blocked?: FiringBlock;
116
+ }
117
+ /** Serializable runtime state — everything that changes future triggers. Rules travel with it. */
118
+ export interface TriggeredRuleState {
119
+ seq: number;
120
+ rules: TriggeredRule[];
121
+ charges: Record<string, number>;
122
+ cooldowns: Record<string, number>;
123
+ windows: Record<string, number[]>;
124
+ active: ActiveEffect[];
125
+ }
126
+ /** A running set of triggered rules with gating, timed lifetimes, stacking, cleanup, and save/load. */
127
+ export interface TriggeredRuleEngine {
128
+ /** Register or replace a rule by id. */
129
+ add(rule: TriggeredRule): void;
130
+ /** Drop a rule and any active effects it produced. */
131
+ remove(ruleId: string): void;
132
+ /** Drop every rule and active effect belonging to an owner (unequip, respec, entity removal). */
133
+ removeByOwner(owner: string): void;
134
+ /** Snapshot of registered rules in insertion order. */
135
+ rules(): readonly TriggeredRule[];
136
+ /** Match an event against all rules, gate, spawn/refresh timed effects, and return firings. */
137
+ dispatch(event: RuleEvent, now: number): readonly RuleFiring[];
138
+ /** Advance time and return the active effects that expired (and were removed) this tick. */
139
+ tick(now: number): readonly ActiveEffect[];
140
+ /** All live timed effects. */
141
+ active(): readonly ActiveEffect[];
142
+ /** Live timed effects landed on a given target. */
143
+ activeFor(target: string): readonly ActiveEffect[];
144
+ /** Drop all active timed effects but keep rules and gate state. */
145
+ clearActive(): void;
146
+ /** Reset gate state and active effects (respec/encounter reset) while keeping rules. */
147
+ reset(): void;
148
+ /** Serialize all future-affecting state. */
149
+ snapshot(): TriggeredRuleState;
150
+ /** Replace all state from a snapshot. */
151
+ hydrate(state: TriggeredRuleState): void;
152
+ }
153
+ /**
154
+ * Create an empty triggered-rule engine. Rules are added as data; dispatching an event returns the
155
+ * firings the caller applies to its own effect system. Time is caller-supplied (`now` in ms), so the
156
+ * engine is deterministic and drives equally from a fixed-step loop or a save-restored timeline.
157
+ *
158
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
159
+ */
160
+ export declare function createTriggeredRuleEngine(rules?: readonly TriggeredRule[]): TriggeredRuleEngine;
@@ -0,0 +1,241 @@
1
+ /**
2
+ * The reusable bridge from typed runtime events to effects. A triggered rule is pure data — which
3
+ * event it listens to, a declarative predicate over the event facts, how the affected target is
4
+ * resolved, an effect *reference* (never a callback), and how the resulting effect is gated, lived,
5
+ * and stacked. Affixes, talents, perks, quests, achievements, environment rules, and reactive AI all
6
+ * subscribe through this one seam instead of owning parallel trigger runtimes.
7
+ *
8
+ * Core stays decoupled from any specific effect system: `dispatch` returns provenance-rich firings
9
+ * and the game applies them to whatever effect/stat system it owns. Gate state (cooldowns, rate
10
+ * windows, remaining charges) and active timed effects serialize cleanly so future triggers survive
11
+ * save/load.
12
+ */
13
+ import { evaluatePredicate, readPath } from "./predicate.js";
14
+ function roleId(event, role, owner) {
15
+ switch (role) {
16
+ case "subject":
17
+ return event.subject;
18
+ case "object":
19
+ return event.object;
20
+ case "source":
21
+ return event.source;
22
+ case "owner":
23
+ return owner;
24
+ }
25
+ }
26
+ function resolveTarget(rule, event) {
27
+ const selector = rule.target ?? { role: "subject" };
28
+ if ("literal" in selector)
29
+ return selector.literal;
30
+ if ("path" in selector) {
31
+ const value = readPath(event.facts ?? {}, selector.path);
32
+ return typeof value === "string" ? value : undefined;
33
+ }
34
+ return roleId(event, selector.role, rule.owner);
35
+ }
36
+ function cooldownKey(ruleId, target) {
37
+ return `${ruleId}\u0000${target}`;
38
+ }
39
+ /**
40
+ * Create an empty triggered-rule engine. Rules are added as data; dispatching an event returns the
41
+ * firings the caller applies to its own effect system. Time is caller-supplied (`now` in ms), so the
42
+ * engine is deterministic and drives equally from a fixed-step loop or a save-restored timeline.
43
+ *
44
+ * @capability triggered-rules event-conditioned effects with declarative predicates, lifetimes, and stacking
45
+ */
46
+ export function createTriggeredRuleEngine(rules = []) {
47
+ const ruleList = [];
48
+ const ruleIndex = new Map();
49
+ const remainingCharges = new Map();
50
+ const lastFire = new Map();
51
+ const fireWindows = new Map();
52
+ let active = [];
53
+ let seq = 0;
54
+ function indexRules() {
55
+ ruleIndex.clear();
56
+ for (let i = 0; i < ruleList.length; i++)
57
+ ruleIndex.set(ruleList[i].id, i);
58
+ }
59
+ function add(rule) {
60
+ const existing = ruleIndex.get(rule.id);
61
+ if (existing !== undefined)
62
+ ruleList[existing] = rule;
63
+ else
64
+ ruleList.push(rule);
65
+ indexRules();
66
+ if (rule.charges !== undefined)
67
+ remainingCharges.set(rule.id, rule.charges);
68
+ else
69
+ remainingCharges.delete(rule.id);
70
+ }
71
+ for (const rule of rules)
72
+ add(rule);
73
+ function dropRuleState(ruleId) {
74
+ remainingCharges.delete(ruleId);
75
+ fireWindows.delete(ruleId);
76
+ for (const key of [...lastFire.keys()]) {
77
+ if (key.startsWith(`${ruleId}\u0000`))
78
+ lastFire.delete(key);
79
+ }
80
+ active = active.filter((instance) => instance.ruleId !== ruleId);
81
+ }
82
+ function passesRate(rule, now) {
83
+ if (rule.rateLimit === undefined)
84
+ return true;
85
+ const window = fireWindows.get(rule.id) ?? [];
86
+ const cutoff = now - rule.rateLimit.windowMs;
87
+ const kept = window.filter((stamp) => stamp > cutoff);
88
+ fireWindows.set(rule.id, kept);
89
+ return kept.length < rule.rateLimit.count;
90
+ }
91
+ function recordFire(rule, target, now) {
92
+ lastFire.set(cooldownKey(rule.id, target), now);
93
+ if (rule.rateLimit !== undefined) {
94
+ const window = fireWindows.get(rule.id) ?? [];
95
+ window.push(now);
96
+ fireWindows.set(rule.id, window);
97
+ }
98
+ if (rule.charges !== undefined) {
99
+ remainingCharges.set(rule.id, (remainingCharges.get(rule.id) ?? 0) - 1);
100
+ }
101
+ }
102
+ function applyTimed(rule, target, now) {
103
+ const duration = rule.durationMs;
104
+ const policy = rule.stacking ?? "refresh";
105
+ const expiresAt = now + duration;
106
+ if (policy !== "independent") {
107
+ const current = active.find((instance) => instance.ruleId === rule.id && instance.target === target);
108
+ if (current !== undefined) {
109
+ if (policy === "ignore")
110
+ return { blocked: "stack-ignored" };
111
+ const stacks = policy === "stack" ? Math.min(current.stacks + 1, Math.max(1, rule.maxStacks ?? 1)) : 1;
112
+ const updated = { ...current, expiresAt, stacks, appliedAt: now };
113
+ active = active.map((instance) => (instance === current ? updated : instance));
114
+ return { instanceId: updated.instanceId, stacks };
115
+ }
116
+ }
117
+ const instanceId = `${rule.id}#${seq++}`;
118
+ active.push({
119
+ instanceId,
120
+ ruleId: rule.id,
121
+ effectId: rule.effect.id,
122
+ owner: rule.owner,
123
+ target,
124
+ params: rule.effect.params,
125
+ appliedAt: now,
126
+ expiresAt,
127
+ stacks: 1,
128
+ });
129
+ return { instanceId, stacks: 1 };
130
+ }
131
+ function evaluate(rule, event, now) {
132
+ const base = { ruleId: rule.id, event: event.type, owner: rule.owner, effect: rule.effect, at: now };
133
+ if (!evaluatePredicate(rule.when, event.facts ?? {}))
134
+ return { ...base, target: "", blocked: "predicate" };
135
+ const target = resolveTarget(rule, event);
136
+ if (target === undefined || target === "")
137
+ return { ...base, target: "", blocked: "no-target" };
138
+ if (rule.charges !== undefined && (remainingCharges.get(rule.id) ?? 0) <= 0)
139
+ return { ...base, target, blocked: "no-charges" };
140
+ if (rule.cooldownMs !== undefined) {
141
+ const last = lastFire.get(cooldownKey(rule.id, target));
142
+ if (last !== undefined && now - last < rule.cooldownMs)
143
+ return { ...base, target, blocked: "cooldown" };
144
+ }
145
+ if (!passesRate(rule, now))
146
+ return { ...base, target, blocked: "rate-limit" };
147
+ if (rule.durationMs !== undefined) {
148
+ const outcome = applyTimed(rule, target, now);
149
+ if ("blocked" in outcome)
150
+ return { ...base, target, blocked: outcome.blocked };
151
+ recordFire(rule, target, now);
152
+ return { ...base, target, instanceId: outcome.instanceId, stacks: outcome.stacks };
153
+ }
154
+ recordFire(rule, target, now);
155
+ return { ...base, target };
156
+ }
157
+ return {
158
+ add,
159
+ remove(ruleId) {
160
+ const index = ruleIndex.get(ruleId);
161
+ if (index === undefined)
162
+ return;
163
+ ruleList.splice(index, 1);
164
+ indexRules();
165
+ dropRuleState(ruleId);
166
+ },
167
+ removeByOwner(owner) {
168
+ const removed = ruleList.filter((rule) => rule.owner === owner).map((rule) => rule.id);
169
+ if (removed.length === 0) {
170
+ active = active.filter((instance) => instance.owner !== owner);
171
+ return;
172
+ }
173
+ for (let i = ruleList.length - 1; i >= 0; i--) {
174
+ if (ruleList[i].owner === owner)
175
+ ruleList.splice(i, 1);
176
+ }
177
+ indexRules();
178
+ for (const ruleId of removed)
179
+ dropRuleState(ruleId);
180
+ active = active.filter((instance) => instance.owner !== owner);
181
+ },
182
+ rules: () => ruleList.slice(),
183
+ dispatch(event, now) {
184
+ const firings = [];
185
+ for (const rule of ruleList) {
186
+ if (rule.event !== event.type)
187
+ continue;
188
+ firings.push(evaluate(rule, event, now));
189
+ }
190
+ return firings;
191
+ },
192
+ tick(now) {
193
+ const expired = active.filter((instance) => instance.expiresAt <= now);
194
+ if (expired.length > 0)
195
+ active = active.filter((instance) => instance.expiresAt > now);
196
+ return expired;
197
+ },
198
+ active: () => active.slice(),
199
+ activeFor: (target) => active.filter((instance) => instance.target === target),
200
+ clearActive() {
201
+ active = [];
202
+ },
203
+ reset() {
204
+ remainingCharges.clear();
205
+ lastFire.clear();
206
+ fireWindows.clear();
207
+ active = [];
208
+ for (const rule of ruleList) {
209
+ if (rule.charges !== undefined)
210
+ remainingCharges.set(rule.id, rule.charges);
211
+ }
212
+ },
213
+ snapshot() {
214
+ return {
215
+ seq,
216
+ rules: ruleList.map((rule) => ({ ...rule })),
217
+ charges: Object.fromEntries(remainingCharges),
218
+ cooldowns: Object.fromEntries(lastFire),
219
+ windows: Object.fromEntries([...fireWindows].map(([id, stamps]) => [id, stamps.slice()])),
220
+ active: active.map((instance) => ({ ...instance })),
221
+ };
222
+ },
223
+ hydrate(state) {
224
+ ruleList.length = 0;
225
+ for (const rule of state.rules)
226
+ ruleList.push({ ...rule });
227
+ indexRules();
228
+ remainingCharges.clear();
229
+ for (const [id, value] of Object.entries(state.charges))
230
+ remainingCharges.set(id, value);
231
+ lastFire.clear();
232
+ for (const [key, value] of Object.entries(state.cooldowns))
233
+ lastFire.set(key, value);
234
+ fireWindows.clear();
235
+ for (const [id, stamps] of Object.entries(state.windows))
236
+ fireWindows.set(id, stamps.slice());
237
+ active = state.active.map((instance) => ({ ...instance }));
238
+ seq = state.seq;
239
+ },
240
+ };
241
+ }