@datamoc/mw_games 0.7.6 → 0.7.8

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 (367) hide show
  1. package/CHANGELOG.md +359 -0
  2. package/README.md +7 -7
  3. package/dist/actors/Inventory.d.ts +7 -1
  4. package/dist/actors/Inventory.d.ts.map +1 -1
  5. package/dist/actors/Inventory.js.map +1 -1
  6. package/dist/actors/Shop.d.ts.map +1 -1
  7. package/dist/actors/Shop.js +4 -1
  8. package/dist/actors/Shop.js.map +1 -1
  9. package/dist/actors/craft.d.ts +35 -14
  10. package/dist/actors/craft.d.ts.map +1 -1
  11. package/dist/actors/craft.js +56 -24
  12. package/dist/actors/craft.js.map +1 -1
  13. package/dist/actors/index.d.ts +1 -1
  14. package/dist/actors/index.d.ts.map +1 -1
  15. package/dist/ai/Heuristics.d.ts +240 -0
  16. package/dist/ai/Heuristics.d.ts.map +1 -0
  17. package/dist/ai/Heuristics.js +298 -0
  18. package/dist/ai/Heuristics.js.map +1 -0
  19. package/dist/ai/index.d.ts +4 -0
  20. package/dist/ai/index.d.ts.map +1 -1
  21. package/dist/ai/index.js +2 -0
  22. package/dist/ai/index.js.map +1 -1
  23. package/dist/ai/lua.d.ts +21 -0
  24. package/dist/ai/lua.d.ts.map +1 -1
  25. package/dist/ai/lua.js +21 -0
  26. package/dist/ai/lua.js.map +1 -1
  27. package/dist/ai/score.d.ts +162 -0
  28. package/dist/ai/score.d.ts.map +1 -0
  29. package/dist/ai/score.js +147 -0
  30. package/dist/ai/score.js.map +1 -0
  31. package/dist/assets/loader.d.ts +18 -4
  32. package/dist/assets/loader.d.ts.map +1 -1
  33. package/dist/assets/loader.js +40 -11
  34. package/dist/assets/loader.js.map +1 -1
  35. package/dist/audio/Positional.d.ts +125 -0
  36. package/dist/audio/Positional.d.ts.map +1 -0
  37. package/dist/audio/Positional.js +135 -0
  38. package/dist/audio/Positional.js.map +1 -0
  39. package/dist/audio/Sound.d.ts +7 -1
  40. package/dist/audio/Sound.d.ts.map +1 -1
  41. package/dist/audio/Sound.js +8 -2
  42. package/dist/audio/Sound.js.map +1 -1
  43. package/dist/audio/index.d.ts +2 -0
  44. package/dist/audio/index.d.ts.map +1 -1
  45. package/dist/audio/index.js +1 -0
  46. package/dist/audio/index.js.map +1 -1
  47. package/dist/battle/AttackDialog.d.ts +75 -0
  48. package/dist/battle/AttackDialog.d.ts.map +1 -0
  49. package/dist/battle/AttackDialog.js +115 -0
  50. package/dist/battle/AttackDialog.js.map +1 -0
  51. package/dist/battle/AttackPreview.d.ts +70 -0
  52. package/dist/battle/AttackPreview.d.ts.map +1 -0
  53. package/dist/battle/AttackPreview.js +78 -0
  54. package/dist/battle/AttackPreview.js.map +1 -0
  55. package/dist/battle/BattleStats.d.ts +45 -0
  56. package/dist/battle/BattleStats.d.ts.map +1 -0
  57. package/dist/battle/BattleStats.js +63 -0
  58. package/dist/battle/BattleStats.js.map +1 -0
  59. package/dist/battle/UnitSelector.d.ts +72 -0
  60. package/dist/battle/UnitSelector.d.ts.map +1 -0
  61. package/dist/battle/UnitSelector.js +117 -0
  62. package/dist/battle/UnitSelector.js.map +1 -0
  63. package/dist/battle/Whiteboard.d.ts +50 -0
  64. package/dist/battle/Whiteboard.d.ts.map +1 -0
  65. package/dist/battle/Whiteboard.js +94 -0
  66. package/dist/battle/Whiteboard.js.map +1 -0
  67. package/dist/battle/index.d.ts +10 -0
  68. package/dist/battle/index.d.ts.map +1 -1
  69. package/dist/battle/index.js +5 -0
  70. package/dist/battle/index.js.map +1 -1
  71. package/dist/board/Classics.d.ts.map +1 -1
  72. package/dist/board/Classics.js +51 -39
  73. package/dist/board/Classics.js.map +1 -1
  74. package/dist/board/FogOfWar.d.ts +32 -2
  75. package/dist/board/FogOfWar.d.ts.map +1 -1
  76. package/dist/board/FogOfWar.js +70 -6
  77. package/dist/board/FogOfWar.js.map +1 -1
  78. package/dist/board/HexSkirmish.d.ts.map +1 -1
  79. package/dist/board/HexSkirmish.js +69 -20
  80. package/dist/board/HexSkirmish.js.map +1 -1
  81. package/dist/board/Tactics.d.ts +7 -0
  82. package/dist/board/Tactics.d.ts.map +1 -1
  83. package/dist/board/Tactics.js +2 -2
  84. package/dist/board/Tactics.js.map +1 -1
  85. package/dist/core/Achievements.d.ts +40 -7
  86. package/dist/core/Achievements.d.ts.map +1 -1
  87. package/dist/core/Achievements.js +53 -7
  88. package/dist/core/Achievements.js.map +1 -1
  89. package/dist/core/Hex.d.ts +26 -6
  90. package/dist/core/Hex.d.ts.map +1 -1
  91. package/dist/core/Hex.js +40 -13
  92. package/dist/core/Hex.js.map +1 -1
  93. package/dist/core/Input.d.ts +36 -0
  94. package/dist/core/Input.d.ts.map +1 -1
  95. package/dist/core/Input.js +63 -1
  96. package/dist/core/Input.js.map +1 -1
  97. package/dist/core/Random.d.ts +93 -0
  98. package/dist/core/Random.d.ts.map +1 -1
  99. package/dist/core/Random.js +177 -0
  100. package/dist/core/Random.js.map +1 -1
  101. package/dist/core/SyncGuard.d.ts +57 -0
  102. package/dist/core/SyncGuard.d.ts.map +1 -0
  103. package/dist/core/SyncGuard.js +116 -0
  104. package/dist/core/SyncGuard.js.map +1 -0
  105. package/dist/core/index.d.ts +3 -1
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +2 -1
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/i18n/Po.d.ts +51 -0
  110. package/dist/i18n/Po.d.ts.map +1 -0
  111. package/dist/i18n/Po.js +176 -0
  112. package/dist/i18n/Po.js.map +1 -0
  113. package/dist/i18n/index.d.ts +2 -0
  114. package/dist/i18n/index.d.ts.map +1 -1
  115. package/dist/i18n/index.js +1 -0
  116. package/dist/i18n/index.js.map +1 -1
  117. package/dist/mw_games.global.js +104 -98
  118. package/dist/mwl/MapFile.d.ts +41 -0
  119. package/dist/mwl/MapFile.d.ts.map +1 -0
  120. package/dist/mwl/MapFile.js +43 -0
  121. package/dist/mwl/MapFile.js.map +1 -0
  122. package/dist/mwl/actors.d.ts +46 -2
  123. package/dist/mwl/actors.d.ts.map +1 -1
  124. package/dist/mwl/actors.js +46 -2
  125. package/dist/mwl/actors.js.map +1 -1
  126. package/dist/mwl/campaign.d.ts +51 -0
  127. package/dist/mwl/campaign.d.ts.map +1 -0
  128. package/dist/mwl/campaign.js +58 -0
  129. package/dist/mwl/campaign.js.map +1 -0
  130. package/dist/mwl/carryover.d.ts +86 -0
  131. package/dist/mwl/carryover.d.ts.map +1 -0
  132. package/dist/mwl/carryover.js +70 -0
  133. package/dist/mwl/carryover.js.map +1 -0
  134. package/dist/mwl/catalog.d.ts +10 -1
  135. package/dist/mwl/catalog.d.ts.map +1 -1
  136. package/dist/mwl/catalog.js +10 -1
  137. package/dist/mwl/catalog.js.map +1 -1
  138. package/dist/mwl/compiler.d.ts +70 -3
  139. package/dist/mwl/compiler.d.ts.map +1 -1
  140. package/dist/mwl/compiler.js +70 -3
  141. package/dist/mwl/compiler.js.map +1 -1
  142. package/dist/mwl/conditions.d.ts +10 -1
  143. package/dist/mwl/conditions.d.ts.map +1 -1
  144. package/dist/mwl/conditions.js +10 -1
  145. package/dist/mwl/conditions.js.map +1 -1
  146. package/dist/mwl/content.d.ts +21 -0
  147. package/dist/mwl/content.d.ts.map +1 -1
  148. package/dist/mwl/content.js +19 -0
  149. package/dist/mwl/content.js.map +1 -1
  150. package/dist/mwl/expression.d.ts +21 -0
  151. package/dist/mwl/expression.d.ts.map +1 -1
  152. package/dist/mwl/expression.js +21 -0
  153. package/dist/mwl/expression.js.map +1 -1
  154. package/dist/mwl/fengari.d.ts +12 -1
  155. package/dist/mwl/fengari.d.ts.map +1 -1
  156. package/dist/mwl/fengari.js +12 -1
  157. package/dist/mwl/fengari.js.map +1 -1
  158. package/dist/mwl/grammar.d.ts +45 -1
  159. package/dist/mwl/grammar.d.ts.map +1 -1
  160. package/dist/mwl/grammar.js +45 -1
  161. package/dist/mwl/grammar.js.map +1 -1
  162. package/dist/mwl/hooks.d.ts +51 -6
  163. package/dist/mwl/hooks.d.ts.map +1 -1
  164. package/dist/mwl/hooks.js +45 -1
  165. package/dist/mwl/hooks.js.map +1 -1
  166. package/dist/mwl/index.d.ts +9 -3
  167. package/dist/mwl/index.d.ts.map +1 -1
  168. package/dist/mwl/index.js +5 -2
  169. package/dist/mwl/index.js.map +1 -1
  170. package/dist/mwl/persistence.d.ts +32 -0
  171. package/dist/mwl/persistence.d.ts.map +1 -1
  172. package/dist/mwl/persistence.js +32 -0
  173. package/dist/mwl/persistence.js.map +1 -1
  174. package/dist/mwl/readers.d.ts +24 -2
  175. package/dist/mwl/readers.d.ts.map +1 -1
  176. package/dist/mwl/readers.js +27 -4
  177. package/dist/mwl/readers.js.map +1 -1
  178. package/dist/mwl/report.d.ts +21 -2
  179. package/dist/mwl/report.d.ts.map +1 -1
  180. package/dist/mwl/report.js +21 -2
  181. package/dist/mwl/report.js.map +1 -1
  182. package/dist/mwl/runtime.d.ts +212 -7
  183. package/dist/mwl/runtime.d.ts.map +1 -1
  184. package/dist/mwl/runtime.js +682 -90
  185. package/dist/mwl/runtime.js.map +1 -1
  186. package/dist/mwl/schema.d.ts +57 -1
  187. package/dist/mwl/schema.d.ts.map +1 -1
  188. package/dist/mwl/schema.js +181 -21
  189. package/dist/mwl/schema.js.map +1 -1
  190. package/dist/mwl/scripts.d.ts +12 -1
  191. package/dist/mwl/scripts.d.ts.map +1 -1
  192. package/dist/mwl/scripts.js +12 -1
  193. package/dist/mwl/scripts.js.map +1 -1
  194. package/dist/mwl/utils.d.ts +2 -0
  195. package/dist/mwl/utils.d.ts.map +1 -1
  196. package/dist/mwl/utils.js +4 -1
  197. package/dist/mwl/utils.js.map +1 -1
  198. package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
  199. package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
  200. package/dist/roguelike/MultiTurnBeam.js +100 -53
  201. package/dist/roguelike/MultiTurnBeam.js.map +1 -1
  202. package/dist/roguelike/Targeting.d.ts +94 -0
  203. package/dist/roguelike/Targeting.d.ts.map +1 -1
  204. package/dist/roguelike/Targeting.js +123 -0
  205. package/dist/roguelike/Targeting.js.map +1 -1
  206. package/dist/roguelike/index.d.ts +3 -1
  207. package/dist/roguelike/index.d.ts.map +1 -1
  208. package/dist/roguelike/index.js +1 -0
  209. package/dist/roguelike/index.js.map +1 -1
  210. package/dist/rpg/GameState.d.ts +2 -2
  211. package/dist/rpg/GameState.js +2 -2
  212. package/dist/simulation/CampaignSave.d.ts +68 -0
  213. package/dist/simulation/CampaignSave.d.ts.map +1 -0
  214. package/dist/simulation/CampaignSave.js +54 -0
  215. package/dist/simulation/CampaignSave.js.map +1 -0
  216. package/dist/simulation/EventPresentation.d.ts +111 -0
  217. package/dist/simulation/EventPresentation.d.ts.map +1 -0
  218. package/dist/simulation/EventPresentation.js +120 -0
  219. package/dist/simulation/EventPresentation.js.map +1 -0
  220. package/dist/simulation/index.d.ts +4 -0
  221. package/dist/simulation/index.d.ts.map +1 -1
  222. package/dist/simulation/index.js +2 -0
  223. package/dist/simulation/index.js.map +1 -1
  224. package/dist/two-d/pixi-interop.d.ts +18 -6
  225. package/dist/two-d/pixi-interop.d.ts.map +1 -1
  226. package/dist/two-d/pixi-interop.js +18 -6
  227. package/dist/two-d/pixi-interop.js.map +1 -1
  228. package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
  229. package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
  230. package/dist/two-d/render/AnimatedSprite.js +88 -26
  231. package/dist/two-d/render/AnimatedSprite.js.map +1 -1
  232. package/dist/two-d/render/Camera.d.ts +64 -4
  233. package/dist/two-d/render/Camera.d.ts.map +1 -1
  234. package/dist/two-d/render/Camera.js +132 -11
  235. package/dist/two-d/render/Camera.js.map +1 -1
  236. package/dist/two-d/render/ColorTransformBatcher.d.ts +7 -1
  237. package/dist/two-d/render/ColorTransformBatcher.d.ts.map +1 -1
  238. package/dist/two-d/render/ColorTransformBatcher.js +10 -1
  239. package/dist/two-d/render/ColorTransformBatcher.js.map +1 -1
  240. package/dist/two-d/render/Halo.d.ts +58 -0
  241. package/dist/two-d/render/Halo.d.ts.map +1 -0
  242. package/dist/two-d/render/Halo.js +48 -0
  243. package/dist/two-d/render/Halo.js.map +1 -0
  244. package/dist/two-d/render/ImageModifiers.d.ts +174 -0
  245. package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
  246. package/dist/two-d/render/ImageModifiers.js +454 -1
  247. package/dist/two-d/render/ImageModifiers.js.map +1 -1
  248. package/dist/two-d/render/LightningArc.d.ts +57 -0
  249. package/dist/two-d/render/LightningArc.d.ts.map +1 -0
  250. package/dist/two-d/render/LightningArc.js +91 -0
  251. package/dist/two-d/render/LightningArc.js.map +1 -0
  252. package/dist/two-d/render/PaletteRemap.d.ts +135 -0
  253. package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
  254. package/dist/two-d/render/PaletteRemap.js +181 -0
  255. package/dist/two-d/render/PaletteRemap.js.map +1 -0
  256. package/dist/two-d/render/Particles.d.ts +26 -0
  257. package/dist/two-d/render/Particles.d.ts.map +1 -1
  258. package/dist/two-d/render/Particles.js +23 -2
  259. package/dist/two-d/render/Particles.js.map +1 -1
  260. package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
  261. package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
  262. package/dist/two-d/render/SpriteAttachment.js +60 -0
  263. package/dist/two-d/render/SpriteAttachment.js.map +1 -0
  264. package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
  265. package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
  266. package/dist/two-d/render/TerrainGraphics.js +161 -0
  267. package/dist/two-d/render/TerrainGraphics.js.map +1 -0
  268. package/dist/two-d/render/TerrainGraphicsLayer.d.ts +55 -0
  269. package/dist/two-d/render/TerrainGraphicsLayer.d.ts.map +1 -0
  270. package/dist/two-d/render/TerrainGraphicsLayer.js +54 -0
  271. package/dist/two-d/render/TerrainGraphicsLayer.js.map +1 -0
  272. package/dist/two-d/render/TintedSprite.js +2 -2
  273. package/dist/two-d/render/TintedSprite.js.map +1 -1
  274. package/dist/two-d/render/index.d.ts +15 -3
  275. package/dist/two-d/render/index.d.ts.map +1 -1
  276. package/dist/two-d/render/index.js +7 -1
  277. package/dist/two-d/render/index.js.map +1 -1
  278. package/dist/two-d/stage/StoryScreen.d.ts +110 -0
  279. package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
  280. package/dist/two-d/stage/StoryScreen.js +178 -0
  281. package/dist/two-d/stage/StoryScreen.js.map +1 -0
  282. package/dist/two-d/stage/index.d.ts +2 -0
  283. package/dist/two-d/stage/index.d.ts.map +1 -1
  284. package/dist/two-d/stage/index.js +1 -0
  285. package/dist/two-d/stage/index.js.map +1 -1
  286. package/dist/two-d/ui/Checkbox.d.ts +44 -0
  287. package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
  288. package/dist/two-d/ui/Checkbox.js +89 -0
  289. package/dist/two-d/ui/Checkbox.js.map +1 -0
  290. package/dist/two-d/ui/DataTable.d.ts +79 -0
  291. package/dist/two-d/ui/DataTable.d.ts.map +1 -0
  292. package/dist/two-d/ui/DataTable.js +164 -0
  293. package/dist/two-d/ui/DataTable.js.map +1 -0
  294. package/dist/two-d/ui/Dropdown.d.ts +72 -0
  295. package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
  296. package/dist/two-d/ui/Dropdown.js +126 -0
  297. package/dist/two-d/ui/Dropdown.js.map +1 -0
  298. package/dist/two-d/ui/FloatingText.d.ts +43 -4
  299. package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
  300. package/dist/two-d/ui/FloatingText.js +52 -5
  301. package/dist/two-d/ui/FloatingText.js.map +1 -1
  302. package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
  303. package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
  304. package/dist/two-d/ui/FloatingTextStack.js +89 -18
  305. package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
  306. package/dist/two-d/ui/Layout.d.ts +105 -0
  307. package/dist/two-d/ui/Layout.d.ts.map +1 -0
  308. package/dist/two-d/ui/Layout.js +174 -0
  309. package/dist/two-d/ui/Layout.js.map +1 -0
  310. package/dist/two-d/ui/MarkupText.d.ts +53 -0
  311. package/dist/two-d/ui/MarkupText.d.ts.map +1 -0
  312. package/dist/two-d/ui/MarkupText.js +122 -0
  313. package/dist/two-d/ui/MarkupText.js.map +1 -0
  314. package/dist/two-d/ui/ScrollBox.d.ts +67 -0
  315. package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
  316. package/dist/two-d/ui/ScrollBox.js +127 -0
  317. package/dist/two-d/ui/ScrollBox.js.map +1 -0
  318. package/dist/two-d/ui/Skins.d.ts +59 -0
  319. package/dist/two-d/ui/Skins.d.ts.map +1 -0
  320. package/dist/two-d/ui/Skins.js +77 -0
  321. package/dist/two-d/ui/Skins.js.map +1 -0
  322. package/dist/two-d/ui/Slider.d.ts +91 -0
  323. package/dist/two-d/ui/Slider.d.ts.map +1 -0
  324. package/dist/two-d/ui/Slider.js +170 -0
  325. package/dist/two-d/ui/Slider.js.map +1 -0
  326. package/dist/two-d/ui/Spinner.d.ts +67 -0
  327. package/dist/two-d/ui/Spinner.d.ts.map +1 -0
  328. package/dist/two-d/ui/Spinner.js +137 -0
  329. package/dist/two-d/ui/Spinner.js.map +1 -0
  330. package/dist/two-d/ui/TabbedList.d.ts +118 -0
  331. package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
  332. package/dist/two-d/ui/TabbedList.js +221 -0
  333. package/dist/two-d/ui/TabbedList.js.map +1 -0
  334. package/dist/two-d/ui/TextModel.d.ts +65 -0
  335. package/dist/two-d/ui/TextModel.d.ts.map +1 -0
  336. package/dist/two-d/ui/TextModel.js +126 -0
  337. package/dist/two-d/ui/TextModel.js.map +1 -0
  338. package/dist/two-d/ui/TreeView.d.ts +68 -0
  339. package/dist/two-d/ui/TreeView.d.ts.map +1 -0
  340. package/dist/two-d/ui/TreeView.js +133 -0
  341. package/dist/two-d/ui/TreeView.js.map +1 -0
  342. package/dist/two-d/ui/Window.d.ts +13 -0
  343. package/dist/two-d/ui/Window.d.ts.map +1 -1
  344. package/dist/two-d/ui/Window.js +23 -0
  345. package/dist/two-d/ui/Window.js.map +1 -1
  346. package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
  347. package/dist/two-d/ui/WindowStack.js +2 -0
  348. package/dist/two-d/ui/WindowStack.js.map +1 -1
  349. package/dist/two-d/ui/index.d.ts +29 -3
  350. package/dist/two-d/ui/index.d.ts.map +1 -1
  351. package/dist/two-d/ui/index.js +15 -2
  352. package/dist/two-d/ui/index.js.map +1 -1
  353. package/dist/two-d/ui/markup.d.ts +181 -0
  354. package/dist/two-d/ui/markup.d.ts.map +1 -0
  355. package/dist/two-d/ui/markup.js +370 -0
  356. package/dist/two-d/ui/markup.js.map +1 -0
  357. package/dist/version.d.ts +1 -1
  358. package/dist/version.js +1 -1
  359. package/dist/world/SideTurns.d.ts +115 -0
  360. package/dist/world/SideTurns.d.ts.map +1 -0
  361. package/dist/world/SideTurns.js +138 -0
  362. package/dist/world/SideTurns.js.map +1 -0
  363. package/dist/world/index.d.ts +2 -0
  364. package/dist/world/index.d.ts.map +1 -1
  365. package/dist/world/index.js +1 -0
  366. package/dist/world/index.js.map +1 -1
  367. package/package.json +2 -1
@@ -0,0 +1,162 @@
1
+ /**
2
+ * The numbers behind a decision, for an AI that weighs outcomes instead of matching a behaviour.
3
+ *
4
+ * A rules agent decides from an opaque `perception` the game fills and from its own `state`, and a
5
+ * score exists only inside `alphaBetaSearch`, as the `evaluate` callback the game hands its own
6
+ * search. So a mind that wants to compare attacking against holding has nothing to weigh, and has
7
+ * to re-derive the game's valuation out of the perception blob, which is the duplication the
8
+ * envelope exists to prevent. These functions are that missing half: the framework owns how a view
9
+ * is assembled, the game owns what anything is worth (`scoreOf`), and the mind owns what it cares
10
+ * about (`ScorePersonality`).
11
+ *
12
+ * Both granularities the contract already names (`AIAgentDefinition.scope` is `'actor' |
13
+ * 'controller'`) run the same code and differ in one thing only: the visibility set they are handed.
14
+ * A unit's own sight for an actor, `FactionFog.sees(side)` for a whole side.
15
+ */
16
+ /** A subject as a score view needs it: the game's own handle, its side, and where it stands. */
17
+ export interface ScoreSubject<T> {
18
+ readonly id: T;
19
+ /** who it fights for; sides are compared by name, so allies share one */
20
+ readonly side: string;
21
+ readonly x: number;
22
+ readonly y: number;
23
+ /** its unit type, when the game's world has one (a Wesnoth `[unit] type=`) */
24
+ readonly type?: string;
25
+ /** its role/function, e.g. `leader` or `courier` */
26
+ readonly role?: string;
27
+ /** whether it can recruit, i.e. is a leader; a missing value reads as `false` */
28
+ readonly can_recruit?: boolean;
29
+ /** its own name, when it has one */
30
+ readonly name?: string;
31
+ }
32
+ /** What `subjectsWhere` selects on: the unit attributes a `ScoreSubject` may carry, each optional. */
33
+ export interface ScoreSubjectFilter {
34
+ readonly side?: string;
35
+ readonly type?: string;
36
+ readonly role?: string;
37
+ readonly can_recruit?: boolean;
38
+ readonly name?: string;
39
+ }
40
+ /**
41
+ * The subjects a filter selects, matching only the attributes the filter names.
42
+ *
43
+ * This is how a mind finds "the enemy leader" without re-deriving it from ids, the gap a bare
44
+ * `ScoreSubject` left: `subjectsWhere(world, { side: 'red', can_recruit: true })`. `can_recruit`
45
+ * reads a missing value as `false`, so `{ can_recruit: false }` selects everyone who is not a
46
+ * leader, and `{ role: 'courier' }` selects a named function.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { subjectsWhere } from '@datamoc/mw_games/ai';
51
+ *
52
+ * const world = [
53
+ * { id: 'hero', side: 'blue', x: 0, y: 0, role: 'leader', can_recruit: true },
54
+ * { id: 'grunt', side: 'blue', x: 1, y: 0 },
55
+ * ];
56
+ * console.log(subjectsWhere(world, { can_recruit: true }).map((subject) => subject.id)); // ['hero']
57
+ * ```
58
+ */
59
+ export declare function subjectsWhere<T>(world: readonly ScoreSubject<T>[], filter: ScoreSubjectFilter): ScoreSubject<T>[];
60
+ /**
61
+ * What one mind can see, and what it is worth.
62
+ *
63
+ * The totals stay separate because which of them matter, and how much, is the mind's business -
64
+ * see `scoreWith`. Plain numbers, so a view crosses the AI boundary like any other `AIValue`.
65
+ */
66
+ export interface ScoreView {
67
+ /** the subject's own score; 0 for a whole side, which has no body of its own */
68
+ readonly own: number;
69
+ /** the summed score of everyone on the subject's side that it can see, itself excluded */
70
+ readonly allies: number;
71
+ /** the summed score of everyone on another side that it can see */
72
+ readonly enemies: number;
73
+ /** how many subjects it could see at all, itself included: a diagnostic, never a score */
74
+ readonly seen: number;
75
+ }
76
+ /**
77
+ * A personality, as data: how much of each total is its owner's business.
78
+ *
79
+ * Weights rather than code, on purpose. A selfish scout is `{ own: 1, allies: 0, enemies: 0 }` and
80
+ * a loyal one `{ own: 0.5, allies: 1, enemies: 0 }`, both authored as content, and neither of them
81
+ * needing an AI implementation of its own. An enemy weight is usually negative, since an enemy's
82
+ * score rising is usually the subject's loss.
83
+ */
84
+ export interface ScorePersonality {
85
+ readonly own: number;
86
+ readonly allies: number;
87
+ readonly enemies: number;
88
+ }
89
+ /**
90
+ * The view one subject has: its own score, and the scores of the allies and enemies it can see.
91
+ *
92
+ * `sees` is the visibility set, injected rather than assumed: a unit's own sight for an actor, the
93
+ * union over a side's units for a whole-side mind. The subject sees its own score whether or not it
94
+ * can see where it stands, so `own` is always read and `seen` always counts it.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * import { personalScoreView, scoreWith } from '@datamoc/mw_games/ai';
99
+ *
100
+ * const hero = { id: 'hero', side: 'blue', x: 2, y: 2 };
101
+ * const world = [
102
+ * hero,
103
+ * { id: 'ally', side: 'blue', x: 3, y: 2 },
104
+ * { id: 'rat', side: 'red', x: 4, y: 2 },
105
+ * { id: 'dragon', side: 'red', x: 9, y: 9 },
106
+ * ];
107
+ * const worth = (id: string) => ({ hero: 10, ally: 4, rat: -2, dragon: -40 })[id] ?? 0;
108
+ *
109
+ * // what a scout with a two-cell reach can see
110
+ * const sees = (x: number, y: number) => Math.abs(x - hero.x) + Math.abs(y - hero.y) <= 2;
111
+ *
112
+ * const view = personalScoreView(hero, world, worth, sees);
113
+ * console.log(view); // { own: 10, allies: 4, enemies: -2, seen: 3 } - the dragon is out of reach
114
+ * console.log(scoreWith(view, { own: 1, allies: 1, enemies: -1 })); // 16 - the rat is a nuisance
115
+ * ```
116
+ */
117
+ export declare function personalScoreView<T>(subject: ScoreSubject<T>, world: readonly ScoreSubject<T>[], scoreOf: (id: T) => number, sees: (x: number, y: number) => boolean): ScoreView;
118
+ /**
119
+ * The view a whole side has: every unit on it that the side can see, and every enemy it can see.
120
+ *
121
+ * `own` is 0, because a side has no body of its own - its units are what `allies` counts. Hand this
122
+ * the union of a side's sight (`FactionFog.sees(side)` after syncing every unit of it) and the same
123
+ * arithmetic that reads for one character reads for the player.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * import { FactionFog } from '@datamoc/mw_games/board';
128
+ * import { scoreWith, sideScoreView } from '@datamoc/mw_games/ai';
129
+ *
130
+ * const fog = new FactionFog(10, 10);
131
+ * const world = [
132
+ * { id: 'scout', side: 'blue', x: 1, y: 1 },
133
+ * { id: 'guard', side: 'blue', x: 7, y: 7 },
134
+ * { id: 'rat', side: 'red', x: 3, y: 1 },
135
+ * ];
136
+ * const worth = (id: string) => ({ scout: 6, guard: 9, rat: -3 })[id] ?? 0;
137
+ *
138
+ * // the side reads what its units see: the scout alone would miss the rat at (3, 1)
139
+ * fog.sync('blue', [{ x: 4, y: 1 }], (source) => [source]);
140
+ * console.log(sideScoreView('blue', world, worth, fog.sees('blue')).enemies); // -3
141
+ * fog.sync('blue', [], () => []); // nobody watching, so nothing is read
142
+ * console.log(sideScoreView('blue', world, worth, fog.sees('blue')).enemies); // 0
143
+ * console.log(scoreWith(sideScoreView('blue', world, worth, fog.sees('blue')), { own: 0, allies: 1, enemies: -1 }));
144
+ * ```
145
+ */
146
+ export declare function sideScoreView<T>(side: string, world: readonly ScoreSubject<T>[], scoreOf: (id: T) => number, sees: (x: number, y: number) => boolean): ScoreView;
147
+ /**
148
+ * A view collapsed into the one number a mind compares, according to what that mind cares about.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * import { scoreWith, type ScoreView } from '@datamoc/mw_games/ai';
153
+ *
154
+ * const view: ScoreView = { own: 10, allies: 4, enemies: -2, seen: 3 };
155
+ *
156
+ * console.log(scoreWith(view, { own: 1, allies: 0, enemies: 0 })); // 10 - out for itself
157
+ * console.log(scoreWith(view, { own: 0, allies: 1, enemies: 0 })); // 4 - holds for the line
158
+ * console.log(scoreWith(view, { own: 1, allies: 1, enemies: -1 })); // 16 - the enemy is the point
159
+ * ```
160
+ */
161
+ export declare function scoreWith(view: ScoreView, personality: ScorePersonality): number;
162
+ //# sourceMappingURL=score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/ai/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gGAAgG;AAChG,MAAM,WAAW,YAAY,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEf,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAEnB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB,iFAAiF;IACjF,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAE/B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sGAAsG;AACtG,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CASjH;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAClC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EACxB,KAAK,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EACjC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EAC1B,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GACrC,SAAS,CAcX;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,EACjC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EAC1B,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GACrC,SAAS,CAaX;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAEhF"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The numbers behind a decision, for an AI that weighs outcomes instead of matching a behaviour.
3
+ *
4
+ * A rules agent decides from an opaque `perception` the game fills and from its own `state`, and a
5
+ * score exists only inside `alphaBetaSearch`, as the `evaluate` callback the game hands its own
6
+ * search. So a mind that wants to compare attacking against holding has nothing to weigh, and has
7
+ * to re-derive the game's valuation out of the perception blob, which is the duplication the
8
+ * envelope exists to prevent. These functions are that missing half: the framework owns how a view
9
+ * is assembled, the game owns what anything is worth (`scoreOf`), and the mind owns what it cares
10
+ * about (`ScorePersonality`).
11
+ *
12
+ * Both granularities the contract already names (`AIAgentDefinition.scope` is `'actor' |
13
+ * 'controller'`) run the same code and differ in one thing only: the visibility set they are handed.
14
+ * A unit's own sight for an actor, `FactionFog.sees(side)` for a whole side.
15
+ */
16
+ /**
17
+ * The subjects a filter selects, matching only the attributes the filter names.
18
+ *
19
+ * This is how a mind finds "the enemy leader" without re-deriving it from ids, the gap a bare
20
+ * `ScoreSubject` left: `subjectsWhere(world, { side: 'red', can_recruit: true })`. `can_recruit`
21
+ * reads a missing value as `false`, so `{ can_recruit: false }` selects everyone who is not a
22
+ * leader, and `{ role: 'courier' }` selects a named function.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { subjectsWhere } from '@datamoc/mw_games/ai';
27
+ *
28
+ * const world = [
29
+ * { id: 'hero', side: 'blue', x: 0, y: 0, role: 'leader', can_recruit: true },
30
+ * { id: 'grunt', side: 'blue', x: 1, y: 0 },
31
+ * ];
32
+ * console.log(subjectsWhere(world, { can_recruit: true }).map((subject) => subject.id)); // ['hero']
33
+ * ```
34
+ */
35
+ export function subjectsWhere(world, filter) {
36
+ return world.filter((subject) => (filter.side === undefined || subject.side === filter.side) &&
37
+ (filter.type === undefined || subject.type === filter.type) &&
38
+ (filter.role === undefined || subject.role === filter.role) &&
39
+ (filter.can_recruit === undefined || (subject.can_recruit ?? false) === filter.can_recruit) &&
40
+ (filter.name === undefined || subject.name === filter.name));
41
+ }
42
+ /**
43
+ * The view one subject has: its own score, and the scores of the allies and enemies it can see.
44
+ *
45
+ * `sees` is the visibility set, injected rather than assumed: a unit's own sight for an actor, the
46
+ * union over a side's units for a whole-side mind. The subject sees its own score whether or not it
47
+ * can see where it stands, so `own` is always read and `seen` always counts it.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { personalScoreView, scoreWith } from '@datamoc/mw_games/ai';
52
+ *
53
+ * const hero = { id: 'hero', side: 'blue', x: 2, y: 2 };
54
+ * const world = [
55
+ * hero,
56
+ * { id: 'ally', side: 'blue', x: 3, y: 2 },
57
+ * { id: 'rat', side: 'red', x: 4, y: 2 },
58
+ * { id: 'dragon', side: 'red', x: 9, y: 9 },
59
+ * ];
60
+ * const worth = (id: string) => ({ hero: 10, ally: 4, rat: -2, dragon: -40 })[id] ?? 0;
61
+ *
62
+ * // what a scout with a two-cell reach can see
63
+ * const sees = (x: number, y: number) => Math.abs(x - hero.x) + Math.abs(y - hero.y) <= 2;
64
+ *
65
+ * const view = personalScoreView(hero, world, worth, sees);
66
+ * console.log(view); // { own: 10, allies: 4, enemies: -2, seen: 3 } - the dragon is out of reach
67
+ * console.log(scoreWith(view, { own: 1, allies: 1, enemies: -1 })); // 16 - the rat is a nuisance
68
+ * ```
69
+ */
70
+ export function personalScoreView(subject, world, scoreOf, sees) {
71
+ let allies = 0;
72
+ let enemies = 0;
73
+ let seen = 1;
74
+ for (const other of world) {
75
+ if (other.id === subject.id)
76
+ continue;
77
+ if (!sees(other.x, other.y))
78
+ continue;
79
+ seen++;
80
+ if (other.side === subject.side)
81
+ allies += scoreOf(other.id);
82
+ else
83
+ enemies += scoreOf(other.id);
84
+ }
85
+ return { own: scoreOf(subject.id), allies, enemies, seen };
86
+ }
87
+ /**
88
+ * The view a whole side has: every unit on it that the side can see, and every enemy it can see.
89
+ *
90
+ * `own` is 0, because a side has no body of its own - its units are what `allies` counts. Hand this
91
+ * the union of a side's sight (`FactionFog.sees(side)` after syncing every unit of it) and the same
92
+ * arithmetic that reads for one character reads for the player.
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * import { FactionFog } from '@datamoc/mw_games/board';
97
+ * import { scoreWith, sideScoreView } from '@datamoc/mw_games/ai';
98
+ *
99
+ * const fog = new FactionFog(10, 10);
100
+ * const world = [
101
+ * { id: 'scout', side: 'blue', x: 1, y: 1 },
102
+ * { id: 'guard', side: 'blue', x: 7, y: 7 },
103
+ * { id: 'rat', side: 'red', x: 3, y: 1 },
104
+ * ];
105
+ * const worth = (id: string) => ({ scout: 6, guard: 9, rat: -3 })[id] ?? 0;
106
+ *
107
+ * // the side reads what its units see: the scout alone would miss the rat at (3, 1)
108
+ * fog.sync('blue', [{ x: 4, y: 1 }], (source) => [source]);
109
+ * console.log(sideScoreView('blue', world, worth, fog.sees('blue')).enemies); // -3
110
+ * fog.sync('blue', [], () => []); // nobody watching, so nothing is read
111
+ * console.log(sideScoreView('blue', world, worth, fog.sees('blue')).enemies); // 0
112
+ * console.log(scoreWith(sideScoreView('blue', world, worth, fog.sees('blue')), { own: 0, allies: 1, enemies: -1 }));
113
+ * ```
114
+ */
115
+ export function sideScoreView(side, world, scoreOf, sees) {
116
+ let allies = 0;
117
+ let enemies = 0;
118
+ let seen = 0;
119
+ for (const other of world) {
120
+ if (!sees(other.x, other.y))
121
+ continue;
122
+ seen++;
123
+ if (other.side === side)
124
+ allies += scoreOf(other.id);
125
+ else
126
+ enemies += scoreOf(other.id);
127
+ }
128
+ return { own: 0, allies, enemies, seen };
129
+ }
130
+ /**
131
+ * A view collapsed into the one number a mind compares, according to what that mind cares about.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import { scoreWith, type ScoreView } from '@datamoc/mw_games/ai';
136
+ *
137
+ * const view: ScoreView = { own: 10, allies: 4, enemies: -2, seen: 3 };
138
+ *
139
+ * console.log(scoreWith(view, { own: 1, allies: 0, enemies: 0 })); // 10 - out for itself
140
+ * console.log(scoreWith(view, { own: 0, allies: 1, enemies: 0 })); // 4 - holds for the line
141
+ * console.log(scoreWith(view, { own: 1, allies: 1, enemies: -1 })); // 16 - the enemy is the point
142
+ * ```
143
+ */
144
+ export function scoreWith(view, personality) {
145
+ return view.own * personality.own + view.allies * personality.allies + view.enemies * personality.enemies;
146
+ }
147
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/ai/score.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,16 @@ export interface LoadAssetsOptions {
29
29
  * own default, which is the SVG's intrinsic size.
30
30
  */
31
31
  resolution?: number;
32
+ /**
33
+ * Paths a game can do without - a portrait variant, an optional decal - loaded separately
34
+ * from the rest of the batch so one missing file never aborts every other asset the batch
35
+ * was loading. A path in here that fails to load is simply left unloaded: `isLoaded` reports
36
+ * `false` for it and `texture`'s fallback argument (or `get`'s) is what a caller reads
37
+ * instead, rather than every caller writing its own try/catch around `load()`.
38
+ */
39
+ optional?: readonly string[];
40
+ /** called once per `optional` path that failed to load, with whatever `Assets.load` threw */
41
+ onMissing?: (path: string, error: unknown) => void;
32
42
  }
33
43
  /**
34
44
  * Loads assets by path, giving each one an alias equal to its path.
@@ -38,10 +48,14 @@ export interface LoadAssetsOptions {
38
48
  * (the original signature) or a `LoadAssetsOptions` object for the resolution option.
39
49
  */
40
50
  export declare function load(paths: string[], options?: AssetProgress | LoadAssetsOptions): Promise<void>;
41
- /** a loaded texture, by the same path it was loaded with */
42
- export declare function texture(path: string): Texture;
43
- /** a loaded asset of any other kind, such as parsed JSON */
44
- export declare function get<T>(path: string): T;
51
+ /**
52
+ * A loaded texture, by the same path it was loaded with. `fallback` is what an `optional`
53
+ * `load()` path was for: pass it (typically `Texture.EMPTY`) to get that back instead of a
54
+ * throw when the path never loaded, rather than every caller writing its own `isLoaded` guard.
55
+ */
56
+ export declare function texture(path: string, fallback?: Texture): Texture;
57
+ /** a loaded asset of any other kind, such as parsed JSON; `fallback` behaves as it does on `texture` */
58
+ export declare function get<T>(path: string, fallback?: T): T;
45
59
  /** true once `load` has resolved for this path and it has not since been `release`d */
46
60
  export declare function isLoaded(path: string): boolean;
47
61
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,OAAO,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,aAAa,CAAC;IAE3B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AASD;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,aAAa,GAAG,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1G;AAED,4DAA4D;AAC5D,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAK7C;AAED,4DAA4D;AAC5D,wBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAKtC;AAED,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5D"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,OAAO,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,aAAa,CAAC;IAE3B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7B,6FAA6F;IAC7F,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AASD;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,aAAa,GAAG,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC1G;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAMjE;AAED,wGAAwG;AACxG,wBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAMpD;AAED,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5D"}
@@ -8,30 +8,59 @@ import { resolve } from './paths.js';
8
8
  * (the original signature) or a `LoadAssetsOptions` object for the resolution option.
9
9
  */
10
10
  export async function load(paths, options = {}) {
11
- const { onProgress, resolution } = typeof options === 'function' ? { onProgress: options, resolution: undefined } : options;
11
+ const { onProgress, resolution, optional, onMissing } = typeof options === 'function'
12
+ ? { onProgress: options, resolution: undefined, optional: undefined, onMissing: undefined }
13
+ : options;
14
+ const optionalPaths = new Set(optional ?? []);
12
15
  const pending = paths.filter((path) => !Assets.cache.has(path));
13
- if (pending.length === 0) {
14
- onProgress?.(1);
15
- return;
16
- }
17
- for (const path of pending) {
16
+ const requiredPending = pending.filter((path) => !optionalPaths.has(path));
17
+ const optionalPending = pending.filter((path) => optionalPaths.has(path));
18
+ const add = (path) => {
18
19
  const descriptor = { alias: path, src: resolve(path) };
19
20
  if (resolution !== undefined)
20
21
  descriptor.data = { resolution };
21
22
  Assets.add(descriptor);
23
+ };
24
+ if (optionalPending.length === 0 && requiredPending.length === 0) {
25
+ onProgress?.(1);
26
+ return;
22
27
  }
23
- await Assets.load(pending, onProgress);
28
+ for (const path of requiredPending)
29
+ add(path);
30
+ const requiredLoad = requiredPending.length > 0 ? Assets.load(requiredPending, onProgress) : Promise.resolve();
31
+ //loaded one at a time and never rejected past this function: one missing optional asset
32
+ //must never take the required batch (or any other optional path) down with it
33
+ const optionalLoads = optionalPending.map(async (path) => {
34
+ add(path);
35
+ try {
36
+ await Assets.load(path);
37
+ }
38
+ catch (error) {
39
+ onMissing?.(path, error);
40
+ }
41
+ });
42
+ await Promise.all([requiredLoad, ...optionalLoads]);
43
+ if (optionalPending.length > 0 && requiredPending.length === 0)
44
+ onProgress?.(1);
24
45
  }
25
- /** a loaded texture, by the same path it was loaded with */
26
- export function texture(path) {
46
+ /**
47
+ * A loaded texture, by the same path it was loaded with. `fallback` is what an `optional`
48
+ * `load()` path was for: pass it (typically `Texture.EMPTY`) to get that back instead of a
49
+ * throw when the path never loaded, rather than every caller writing its own `isLoaded` guard.
50
+ */
51
+ export function texture(path, fallback) {
27
52
  if (!Assets.cache.has(path)) {
53
+ if (fallback !== undefined)
54
+ return fallback;
28
55
  throw new Error(`texture "${path}" has not been loaded - pass it to load() first`);
29
56
  }
30
57
  return Assets.get(path);
31
58
  }
32
- /** a loaded asset of any other kind, such as parsed JSON */
33
- export function get(path) {
59
+ /** a loaded asset of any other kind, such as parsed JSON; `fallback` behaves as it does on `texture` */
60
+ export function get(path, fallback) {
34
61
  if (!Assets.cache.has(path)) {
62
+ if (fallback !== undefined)
63
+ return fallback;
35
64
  throw new Error(`asset "${path}" has not been loaded - pass it to load() first`);
36
65
  }
37
66
  return Assets.get(path);
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAsB,MAAM,YAAY,CAAC;AA0CzD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,KAAe,EAAE,OAAO,GAAsC,EAAE;IAC1F,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAC/B,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAE1F,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACR,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAoB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxE,IAAI,UAAU,KAAK,SAAS;YAAE,UAAU,CAAC,IAAI,GAAG,EAAE,UAAU,EAAE,CAAC;QAC/D,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;IACD,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,OAAO,CAAC,IAAY;IACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,iDAAiD,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAU,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,GAAG,CAAI,IAAY;IAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,iDAAiD,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAI,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,QAAQ,CAAC,IAAY;IACpC,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAe;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAChC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ import type { Sound } from './Sound.ts';
2
+ /** A point in the same 2D space the game's camera works in, in world units. */
3
+ export interface AudioPoint {
4
+ x: number;
5
+ y: number;
6
+ }
7
+ /**
8
+ * How far away a source can be heard from, and how fast it fades.
9
+ *
10
+ * `refDistance` is full volume, `maxDistance` is silence, and `rolloff` shapes the drop
11
+ * between them: 1 is inverse-linear, 2 inverse-square. These are the names the Web Audio
12
+ * `PannerNode` uses for the same three numbers, so a game that later moves to a real panner
13
+ * does not have to re-author them.
14
+ */
15
+ export interface AudioFalloff {
16
+ /** distance at which the source is at full volume; defaults to 1 */
17
+ refDistance?: number;
18
+ /** distance at which the source is silent; defaults to Infinity */
19
+ maxDistance?: number;
20
+ /** exponent of the inverse-distance drop; defaults to 1 */
21
+ rolloff?: number;
22
+ }
23
+ /**
24
+ * The gain a listener at `distance` hears a source at, clamped to [0, 1]: 1 at or inside
25
+ * `refDistance`, 0 at or beyond `maxDistance`, an inverse-distance curve between them.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { audioGain } from '@datamoc/mw_games/audio';
30
+ *
31
+ * audioGain(0, { refDistance: 2 }); // 1 - inside the full-volume radius
32
+ * audioGain(2, { refDistance: 2 }); // 1 - the reference distance itself
33
+ * audioGain(4, { refDistance: 2 }); // 0.5 - one doubling away
34
+ * audioGain(4, { refDistance: 2, maxDistance: 4 }); // 0 - at the edge of hearing
35
+ * ```
36
+ */
37
+ export declare function audioGain(distance: number, falloff?: AudioFalloff): number;
38
+ /**
39
+ * Stereo pan in [-1, 1] for a source: -1 is hard left of the listener, 1 hard right, 0
40
+ * directly ahead or behind. The listener's `facing` is its heading in radians (0 faces +x,
41
+ * increasing clockwise on a screen where y grows downward), so turning the listener turns
42
+ * what counts as "right" with it - a sound to the world's east is centred when the listener
43
+ * faces east and hard right when the listener faces north.
44
+ *
45
+ * A game with a stereo backend applies this itself; the framework has no panner node of its
46
+ * own, so it reports the number rather than pretending to pan.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { audioPan } from '@datamoc/mw_games/audio';
51
+ *
52
+ * const listener = { x: 0, y: 0, facing: 0 }; // facing east
53
+ * audioPan(listener, { x: 10, y: 0 }); // 0 - straight ahead
54
+ * audioPan(listener, { x: 0, y: 10 }); // 1 - to the listener's right
55
+ * audioPan(listener, { x: 0, y: -10 }); // -1 - to its left
56
+ * ```
57
+ */
58
+ export declare function audioPan(listener: AudioPoint & {
59
+ facing: number;
60
+ }, source: AudioPoint): number;
61
+ /**
62
+ * Where sounds are heard from: a game moves one listener to its camera or its party leader
63
+ * each frame, and every `SoundSource` is mixed against it.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import { AudioListener } from '@datamoc/mw_games/audio';
68
+ *
69
+ * const listener = new AudioListener({ x: 40, y: 12 });
70
+ * listener.moveTo(41, 12); // following the camera
71
+ * listener.face(Math.PI / 2); // now facing the world's south
72
+ * ```
73
+ */
74
+ export declare class AudioListener implements AudioPoint {
75
+ x: number;
76
+ y: number;
77
+ /** heading in radians: 0 faces +x, increasing clockwise on a y-down screen */
78
+ facing: number;
79
+ constructor(options?: {
80
+ x?: number;
81
+ y?: number;
82
+ facing?: number;
83
+ });
84
+ moveTo(x: number, y: number): void;
85
+ face(radians: number): void;
86
+ }
87
+ export interface SoundSourceOptions extends AudioFalloff {
88
+ x?: number;
89
+ y?: number;
90
+ }
91
+ /**
92
+ * One positional one-shot: a `Sound` attached to a point in the world, heard from a
93
+ * listener with the distance gain `audioGain` computes. `playFor` applies that gain through
94
+ * `Sound.play(gain)`, and stays silent past `maxDistance` rather than playing at volume 0.
95
+ *
96
+ * Long-running position (a waterfall, an engine) is the game's own loop calling `playFor` on
97
+ * a cadence it chooses; this is the placement and the mix, not a scheduler.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * import { AudioListener, Sound, SoundSource } from '@datamoc/mw_games/audio';
102
+ *
103
+ * const listener = new AudioListener({ x: 0, y: 0 });
104
+ * const arrow = new Sound('sounds/arrow.mp3');
105
+ * const source = new SoundSource(arrow, { x: 6, y: 8, refDistance: 4, maxDistance: 20 });
106
+ *
107
+ * const gain = source.gainTo(listener); // 0.4 at distance 10
108
+ * source.playFor(listener); // plays at that gain, or not at all when silent
109
+ * ```
110
+ */
111
+ export declare class SoundSource implements AudioPoint {
112
+ x: number;
113
+ y: number;
114
+ private readonly sound;
115
+ private readonly falloff;
116
+ constructor(sound: Sound, options?: SoundSourceOptions);
117
+ moveTo(x: number, y: number): void;
118
+ gainTo(listener: AudioPoint): number;
119
+ panTo(listener: AudioPoint & {
120
+ facing: number;
121
+ }): number;
122
+ /** Plays the source at the gain the listener hears it; returns the gain actually used. */
123
+ playFor(listener: AudioPoint): number;
124
+ }
125
+ //# sourceMappingURL=Positional.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Positional.d.ts","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC5B,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAU9E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAW9F;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,UAAU;IAC/C,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IAEV,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,OAAO,GAAE;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,EAIpE;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjC;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1B;CACD;AAED,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACvD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,WAAY,YAAW,UAAU;IAC7C,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IAEV,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IAEvC,YAAY,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,kBAAuB,EASzD;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjC;IAED,MAAM,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAEnC;IAED,KAAK,CAAC,QAAQ,EAAE,UAAU,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEvD;IAED,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAKpC;CACD"}