@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
package/CHANGELOG.md CHANGED
@@ -5,6 +5,365 @@ All notable changes to `mwg` are documented here. Format follows
5
5
  [Semantic Versioning](https://semver.org/) as of this first release - a 0.y.z version means
6
6
  the public API may still change between minor versions.
7
7
 
8
+ ## [0.7.8] - 2026-09-12
9
+
10
+ ### Added
11
+
12
+ - Unit identity usable by the AI. MWL units now carry their own `name`, `role`/function and
13
+ `can_recruit` leader flag: `[unit]` sets them, a side's own leader is `can_recruit`, `[role]`
14
+ stamps the role onto the units it matches, `[store_unit]`/save keep them, and `unitMatchesFilter`
15
+ reads all three - which also wires up the `can_recruit` the `[filter]` schema already allowed but
16
+ the runtime ignored. On the AI side, `ScoreSubject` and `HeuristicCandidate` carry
17
+ `type`/`role`/`can_recruit`/`name`, and the new `subjectsWhere`/`ScoreSubjectFilter` select a world
18
+ on any of them, so a mind can find "the enemy leader" without re-deriving it from ids.
19
+ - Leader identity on the unit (item 296). An autospawned `[side] leader=` unit carries `leader: true`
20
+ beside its `can_recruit`, `[store_unit]`/unstore and a save keep it, and `unitMatchesFilter` reads
21
+ it, so `[filter] leader=yes` finds the side's own leader without recomputing
22
+ `sides[id].leader === id`.
23
+ - One variable-path resolver for every reader (item 295). `$name` resolution, `[condition]`/
24
+ `[filter_condition]` variable reads, message interpolation and the bare `$name` copy all resolve
25
+ through the same path walker `set_variable` writes with, so a dotted name like `a.b` reads what
26
+ `[set_variable] name=a.b` wrote. Array indices are in scope (`a[0].b` reads the node `a.0.b` or
27
+ `a[0].b` wrote), an index that is not a whole number is refused by name rather than becoming a
28
+ literal key, and the `id` schema type accepts brackets so such a name compiles.
29
+ - `TerrainGraphicsLayer` (item 257): the renderer half of `[terrain_graphics]`, drawing
30
+ `resolveTerrainGraphics`'s placements as one `Sprite2D` per placement, in `layer` order (a stable
31
+ sort, so the rule pass's own row-major walk survives within a layer) at the pixel position a
32
+ caller-supplied `project` callback reports, with images resolved through the asset resolver.
33
+ `setPlacements` redraws in place.
34
+ - The canvas backend for inline markup, closing the three pieces item 258's acceptance still
35
+ named as open: `positionMarkupLines` places `layoutMarkupLines`'s lines into positioned
36
+ `PositionedMarkupSpan` runs under a `MarkupLayout`'s `direction`/`align`, so an `rtl` line flows
37
+ right to left and alignment defaults to the direction's own edge, and `MarkupText` draws them as
38
+ the counterpart to `RichLabel`'s HTML text - one `Text2D` per styled run, one `Sprite2D` per
39
+ `<img>` span resolved through the asset resolver, so an image is drawn rather than left to the
40
+ caller to position. An RTL sample is now covered by `tests/markup.test.ts`.
41
+
42
+ ### Fixed
43
+
44
+ - One rule for the `id` value type, shared by the schema and `mwl.readers`. The schema accepts a
45
+ bracketed path like `a[0].b` as an `id` (a variable name legitimately carries index brackets),
46
+ but `readAttributes`' `id` and `id-list` kept a stricter copy of the pattern, so an adapter
47
+ reading a variable-name attribute raised `MWL_FIELD_TYPE` for a name the compiler had already
48
+ accepted. Both now call the exported `isMwlId`. One test in `tests/mwl.test.ts`.
49
+ - `actors.sell` is transactional again. It ignored the result of `Inventory.add`, so selling into
50
+ a shop stock with no room paid the seller and lost the item: two potions sold into a
51
+ capacity-1 stock produced 10 gold from nothing and left the potions nowhere. It now rolls the
52
+ bag back and refuses, exactly as `buy` already did for a full bag. One test in
53
+ `tests/shop.test.ts`.
54
+ - `board.goScore` counts territory again. Its `group` helper returned nothing for an empty
55
+ square, so the area-scoring loop never saw an enclosed empty region and only stones were
56
+ scored: four stones ringing a 3x3 board reported 4 instead of 9. `group` now groups connected
57
+ cells by value with `null` included, which leaves `liberties`/`playGo` unchanged because they
58
+ only ever pass a stone. One test, plus new coverage for `rollBackgammonDice`, a foundation
59
+ move from a tableau column, and `DiceCup.clearKept`, in `tests/classics.test.ts`.
60
+ - `board.addTacticalUnit` remembers each unit's own action budget, so `endTacticalTurn` refreshes
61
+ `actions` to it instead of a hardcoded two. A unit created with `actions: 3` was silently reset
62
+ to 2 every turn; the per-turn maximum is now `TacticalUnit.maxActions`, filled from the initial
63
+ `actions` when the caller does not set it. Six tests in `tests/tactics.test.ts`, which also
64
+ cover the overwatch reaction and attack paths that had none.
65
+ - `board.backgammonMoves` follows the bearing-off rules. It offered a bear-off from any point
66
+ whose roll reached past the off edge, so at the opening position a 6 came off from point 18
67
+ while checkers still sat on 0, 11 and 16. A bear-off now needs every checker in the home
68
+ board with none on the bar; an exact roll still takes any home checker, and an over-roll takes
69
+ only the checker nearest the off edge, since a checker must never skip past another. Three
70
+ tests in `tests/classics.test.ts`.
71
+ - An `[if]` branch no longer tries to execute its own `[condition]` child. The schema allows a
72
+ branch to carry one, but the executor ran every child, so an `[if]` whose condition held threw
73
+ `unknown MWL command: condition` instead of running its body; a false condition hid it because
74
+ the body never ran. `[if]`/`[else]` now run their command children only, the same rule
75
+ `[while]` already followed. Two tests in `tests/mwl-conditions.test.ts`.
76
+ - An `[else]` following an `[if]` is that branch's other half, so only one of the two runs. A
77
+ taken `[if]` used to run its own body and then fall through to the `[else]` as well, so both
78
+ branches executed; the `[else]` is now skipped when the `[if]` was taken, and run as the
79
+ fallback when it was not. Independent pairs still work, and a free-standing `[else]` with no
80
+ `[if]` before it still runs. Two tests in `tests/mwl-conditions.test.ts`.
81
+ - `[while]` had the same defect as `[if]`, so a loop body carrying a `[condition]` child threw.
82
+ It now runs its command children too. One test in `tests/mwl-variables.test.ts`.
83
+ - The variable-path readers item 295 named are now complete, closing three that were still flat:
84
+ a dialogue `[choice]`'s `variable=` gate, `[store_unit]`/`[unstore_unit]`/`[recall]`'s stored
85
+ list, and the hook host's `setVariable`, plus the public `execute()`'s `set_variable`. An
86
+ indexed path now builds a real array (`a[0]`, `a[1]`), so a stored list and an indexed write
87
+ agree on their shape. One test each in `tests/mwl-dialogue.test.ts`, `tests/mwl-actions.test.ts`
88
+ and `tests/mwl.test.ts`, and the `a[0].b` test now asserts the array.
89
+
90
+ ### Changed
91
+
92
+ - `board.skirmishMoves` computes every reachable cell from one Dijkstra pass over the map
93
+ instead of one per candidate cell. The old per-cell search also re-sorted its own frontier
94
+ every step and `shift()`ed it, so it went quadratic in path length; the pass now uses a
95
+ binary min-heap. Behaviour is unchanged, verified by a differential run of the old and new
96
+ implementations over 58 randomised terrain maps. A `[complexity]` test keeps 20 calls on a
97
+ 40x40 map under a ceiling far below the old cost, and a test pins that a cell held by
98
+ another unit is never offered as a move.
99
+
100
+ ## [0.7.7] - 2026-09-11
101
+
102
+ ### Added
103
+
104
+ - Heuristic AI (item 269): `Aspects`, `Difficulty`, `Goals`, `RecruitmentPattern`, and a
105
+ `HeuristicAI` candidate/stage pipeline with `defaultWeigh`/`keepAwayScore`/`goalScore`. Aspects
106
+ ship no values; the numbers stay content, and `keep_away` is a real penalty.
107
+ - Achievements and battle statistics (item 273): `core.Achievements` gained sub-achievements
108
+ (multi-criterion unlocks via `AchievementDef.criteria`, read back with `subProgress`), and
109
+ `battle.BattleStats` tracks recruits/recalls/advances/kills/deaths/damage dealt/damage taken by
110
+ unit type for a `PlayerStats`/`RunHistory` summary to fold in.
111
+ - Free map rotation (item 286): `Camera.rotateTo`/`animateRotationTo` turn the view to any angle,
112
+ not only a grid's whole steps, sharing 285's layer-level transform and taking the shorter way
113
+ around a full turn when animated.
114
+ - Battle UI models (item 265): `AttackPreview` (damage totals and an animated frame timeline from
115
+ the game's own numbers), `AttackDialog` (the selector plus the preview and its clock),
116
+ `UnitSelector` (attacker then target), and `Whiteboard` (planned orders with undo/redo). All
117
+ renderer-free; the dialog's pixels are `Bar`/`Label` a game composes.
118
+ - Story screens (item 264): `StoryScreen` (a full-screen backdrop, title and text advanced by a
119
+ click) over the renderer-free `StorySequence` (`advance`/`back`/`goTo`/`skip`/`restart`, with the
120
+ current beat's `music` reported as a signal). `StoryBeat` matches `MwlWorld.story`'s shape.
121
+ - Data-driven shell layout and skins (item 263): `Layout` (`resolveAnchor`/`anchorAlign` over nine
122
+ named anchors plus `fill`, and a `Grid` of `size`-or-`grow` tracks) and `Skins` (per-widget,
123
+ per-state looks with a widget-state -> widget-idle -> wildcard fallback chain, and `Skins.from`
124
+ for plain data). Both renderer-free.
125
+ - The missing UI widgets (item 261): `Slider` (`sliderFraction`/`sliderValueAt`), `Checkbox`,
126
+ `Spinner` (`spinValue`), `Dropdown`, `TextModel`, `DataTable`, `TreeView` and `ScrollBox`
127
+ (`scrollOffset`). The rule-bearing parts are pure functions or renderer-free models tested
128
+ headlessly, the drawing is a thin theme-driven shell, and text fields pair `TextModel` with a
129
+ `Label` rather than a separate `TextArea`.
130
+ - Fixed-angle view rotation on `Camera` (item 285): `grid: 'square' | 'hex'` sets four quarter turns
131
+ or six 60-degree steps, `setRotationStep`/`rotate` move through them, `toScreen`/`toWorld` invert
132
+ the turn, `view` reports the box around the turned viewport for culling, and `uprightRotation`
133
+ keeps a label drawn into the world upright.
134
+ - WML action vocabulary in `[event]` (item 250): `fire_event`, `store_unit`/`unstore_unit`/`recall`,
135
+ `modify_unit`/`heal_unit`, `set_terrain`, `capture_village`, `clear_shroud`, and the scenario-level
136
+ `[role]`/`[object]`/`[story]`, backed by `MwlWorld.villages`/`clearedShroud`/`roles`/`objects`/
137
+ `story` (all saved). WML's scenario `[item]` is deliberately not added: the tag already means an
138
+ inventory item definition.
139
+ - `blendPixels`/`rotatePixels` in `ImageModifiers.ts`: `~BLEND` and `~ROTATE` moved from a
140
+ runtime sprite-property/`ColorMatrixFilter` approximation to an exact, baked-once per-pixel
141
+ operation in `applyTextureModifiers` (`~ROTATE` in particular now rotates the source pixels
142
+ and expands the surface, which a sprite's own `rotation` cannot do - needed for terrain and
143
+ anything else that must keep tiling after the rotation). `blendMatrix` stays available for a
144
+ caller that explicitly wants the cheaper live approximation instead.
145
+ - `PaletteRemapMode` (`'exact'` | `'nearest'`) on `remapPixels`/`recolorTexture`, defaulting to
146
+ `'exact'`: a pixel is now repainted only on an exact match to a `from` colour unless
147
+ `'nearest'` is asked for explicitly. The old always-nearest behaviour silently recoloured an
148
+ entire image the first time `~RC`/`~PAL` met a short, specific palette instead of a full
149
+ covering; `paletteRangeMapping`'s own gradient usage opts into `'nearest'` explicitly, since
150
+ that is the one case it is correct for.
151
+ - `ImageTextureProbe.resolveColor` and the exported `parseColorPairs`/`parsePaletteLists`: `~RC`
152
+ and `~PAL` now accept a named colour (`~RC(magenta>red)`), not hex only, and `~PAL`'s two
153
+ comma-separated colour lists parse correctly instead of only the first colour of each list
154
+ (`parseImagePath`'s own comma split does not respect that list's internal boundary, which
155
+ `parsePaletteLists` now reconstructs).
156
+ - `~BLIT`/`~MASK` now hand `resolveTexture` the argument exactly as written, nested modifiers
157
+ included (`~BLIT(unit.png~RC(magenta>red),0,0)` calls it with the full string, not a bare
158
+ path with the modifier silently dropped).
159
+ - `withTextureCanvas` is now exported from `two-d/render`, so a caller building its own
160
+ texture-level modifier can reuse the same canvas bookkeeping `recolorTexture`/`~BLIT`/`~MASK`/
161
+ `~BLEND`/`~ROTATE` all share instead of duplicating it.
162
+
163
+ - `mwl.parseMapFile`/`MwlMapFile` (item 284): a Wesnoth-shaped `.map` loader. The `key=value`
164
+ header is split off and kept (keys not interpreted), and the comma-separated grid goes through
165
+ the same `parseTerrain` an inline `[map] terrain=` uses.
166
+ - `actors.craft` category-shaped ingredients (item 289): `Ingredient` now accepts `id` as a string
167
+ or a list, a `category` matched against the item definition's new `InventoryItem.category`
168
+ (kind-level, so it stays out of saves), or a `matches(item)` predicate. `craft` allocates against
169
+ a working copy so two flexible ingredients cannot count one stack twice.
170
+ - `two-d/render/SpriteAttachment.ts`: `SpriteAttachment` (item 291), ties a second sprite's
171
+ position to a first one's - `follow(x, y)` applies an offset, an optional `duration` makes
172
+ `update(dt)` report `done` once it elapses, so a permanent shadow and a temporary status icon
173
+ are the same class with different options. Renderer-neutral like `Projectile`/`LightningArc`.
174
+
175
+ - `two-d/render/LightningArc.ts`: `LightningArc` (item 292), the position data for a jittered
176
+ line between two points - a lightning bolt, a tether, a chain-lightning link - geometry only,
177
+ drawn by the caller through `Shape2D`'s `Graphics`. `retarget` moves either endpoint for a
178
+ tether following two moving units; an optional `flickerInterval` re-rolls the jitter on a
179
+ timer instead of holding one fixed shape.
180
+ - `assets.load`'s `optional`/`onMissing` options (item 287): paths a game can do without load
181
+ separately from the required batch, so one missing file never aborts the rest; `texture`/`get`
182
+ take a `fallback` value returned instead of a throw for a path that never loaded.
183
+
184
+ - `MultiTurnBeam` fronts, `blocker`, `onCell` and saved shape identity (item 278): a beam is now a
185
+ sequence of per-turn fronts rather than one captured cell per turn, so a game-supplied
186
+ `fronts(previous, turn)` expresses a cone, burst, fork or moving front. `BeamBlocker` replaces
187
+ the implicit blocker flags with one policy, `BeamStep.cells` reports every reached cell, and a
188
+ save carries the shape name so `fromJSON` refuses a mismatched shape; pre-fronts saves still load.
189
+ - `two-d/render/PaletteRemap.ts`: `remapPixels`/`paletteRangeMapping`/`recolorTexture` (item
190
+ 256), a nearest-colour palette remap for team-colour-by-range - `paletteRangeMapping` places a
191
+ reference palette's own lightest-to-darkest order along a `min -> mid -> max` gradient,
192
+ `remapPixels` is the renderer-free pixel core, and `recolorTexture` (via the new shared
193
+ `withTextureCanvas` helper) is the canvas-backed wrapper.
194
+ - Eleven more `image~MOD` suffixes in `ImageModifiers.ts` (item 255): `~O`, `~R`/`~G`/`~B`,
195
+ `~BLEND` and `~CHAN` join `~FL`/`~SCALE`/`~GS`/`~CS` as sprite-property/`ColorMatrixFilter`
196
+ operations on `applyImageModifiers`; `~ROTATE` sets the sprite's own rotation. `~RC`, `~PAL`,
197
+ `~BLIT` and `~MASK` needed real pixel access or a sibling texture, so they are the new
198
+ `applyTextureModifiers`, built on 256's `withTextureCanvas`. `~GS` no longer replaces a filter
199
+ already on the sprite (was clobbering, now appends).
200
+ - `two-d/render/TerrainGraphics.ts`: `resolveTerrainGraphics`/`TerrainRule`/`matchTerrainRule`/
201
+ `squareRotate`/`hexRotate` (item 257), a rule-driven `[terrain_graphics]`-style transition pass
202
+ generalising `Autotile`'s fixed 47-shape blob table: arbitrary flag conditions at arbitrary
203
+ offsets, multi-image placement (so a piece bigger than one cell is one rule's own data, not
204
+ something `TileMap`'s one-sprite-per-cell grid has to hold), rotation and probability. Returns
205
+ plain placement data; drawing it through a renderer is still open.
206
+ - `markupToHtml` now renders colour and size as an inline style; `markupAccessibilityText` is a
207
+ proper accessibility projection for markup (an image becomes a caller-described string instead
208
+ of its raw path); `layoutMarkupLines` wraps already-parsed spans word by word, each word
209
+ measured under its own span's style, so a bold or larger run wraps where its own wider glyphs
210
+ actually land (item 258's remaining acceptance, in part - see ROADMAP for what is still open).
211
+
212
+ - `ParticleEmitter` spawn bounds (item 279): `ParticleSpawnArea` is an optional `spawn` on the
213
+ emitter's options, a `rect` or `ellipse` in local space so a burst spreads across an extent
214
+ instead of every particle starting at the emitter's single origin (a forge mouth, a flame
215
+ column, rain across a room). A point emitter draws nothing extra, so the seeded sequence an
216
+ existing replay recorded is unchanged.
217
+ - `roguelike.TargetingController` (item 280): the input-facing half of targeting, renderer-free.
218
+ A cursor moved by `move(dx, dy)` or a caller-resolved `moveTo(cell)`, range and line-of-sight
219
+ validation with an optional `validate` hook, a `preview()` of the shape's cells and a
220
+ `confirm()`/`cancel()` result carrying cells only, so damage, legality details and drawing stay
221
+ with the game. Hex levels step by their own six neighbours and measure in hex distance.
222
+ - `AudioListener`/`SoundSource`/`audioGain`/`audioPan`/`AudioFalloff` (item 271): positional
223
+ audio, renderer-free. A listener the game moves and turns, a `Sound` placed at a world point,
224
+ and the distance gain and stereo pan between them. `SoundSource.playFor(listener)` applies the
225
+ gain through `Sound.play`, which now takes an optional gain argument.
226
+ - `Input.onText`/`Input.onComposition`/`Input.textFromKey`/`Input.dispatchText`/
227
+ `Input.dispatchComposition` (item 262): the character a key press produces, and the three
228
+ phases of an input-method composition, so a free text field can be built. `onText` is a
229
+ stack-mode signal a focused field can consume.
230
+ - `MersenneTwister`/`MersenneTwisterState`/`RandomStreams` (item 266): MT19937 with the reference
231
+ `mt_rng`'s `seed`/`discard`/`discardCount` bookkeeping (verified against the standard test
232
+ vector) and named, independent streams derived from one base seed, so per-entity and per-usage
233
+ draws never shift each other. C++'s `uniform_int_distribution` is implementation-defined, so the
234
+ int mapping is MWG's own and documented as such.
235
+ - `i18n.parsePo`/`PoOptions` (item 270): a gettext `.po` loader into the same `Catalog` surface
236
+ as `parseFTL`, with `msgctxt`, `msgstr[N]` mapped onto the locale's CLDR categories,
237
+ untranslated entries left out for base fallback, and gettext `domain`-prefixed keys.
238
+ - `world.SideTurns`/`SideTurn`/`TimeOfDay`/`TimeArea`/`Alignment`/`alignmentBonus` (item 267): the
239
+ reference's outer turn model, sides in order with a schedule that steps per round, and a per-hex
240
+ `lawfulBonusAt` where a `TimeArea` overrides the global time of day.
241
+ - `ui.TabbedList`/`ListTab`/`TabbedListOptions` (item 281): a renderer-free model for a tabbed,
242
+ filtered, paged list with selection and a detail/close state, over caller-supplied rows and
243
+ predicates. The page is derived from the selection, so the two cannot disagree.
244
+ - `simulation.EventPresentation`/`EventPresentationOptions` (item 282): the documented recipe
245
+ tying a `SimulationRuntime` to a `PresentationQueue` - command result, animation lock,
246
+ scheduled secondary actor, cancellation, and save/load that resumes idle.
247
+ - `MwlWorld.sideStatus` and per-side `[victory]`/`[defeat]` under `[side]` (item 283): a side's
248
+ own condition is evaluated after the scenario-wide `[objectives]` ones, its result recorded by
249
+ side id, and `[win]`/`[lose]` record the side they name too. `MwlCommand`'s `win`/`lose` gained an
250
+ optional `side`.
251
+ - `simulation.CampaignSave`/`CampaignSaveState`/`CampaignSaveParts` (item 249): one `SaveSystem`
252
+ slot for a whole campaign, holding the campaign, world and simulation snapshots together, with
253
+ the world payload left opaque.
254
+ - `core.stateChecksum`/`core.SyncGuard` (item 272): a key-order-stable 32-bit checksum of JSON
255
+ state and a guard comparing the checksums peers compute per tick, so a lockstep run can notice
256
+ and locate a divergence.
257
+ - `ai.personalScoreView`/`ai.sideScoreView`/`ai.scoreWith`, over `ScoreSubject`/`ScoreView`/
258
+ `ScorePersonality` (items 274-276): the numbers a mind needs when a search is the wrong tool.
259
+ The game supplies what anything is worth, the framework assembles the view (own, allies and
260
+ enemies kept apart, with a `seen` count), and a personality is weights over the three, so a
261
+ selfish scout and a loyal one are content rather than two AI implementations. A unit's sight and a
262
+ whole side's read through the same two functions and differ only in the visibility set they are
263
+ handed, and `board.FactionFog.sees(side)` is that set as a predicate: it reads the shroud as it is
264
+ when called, not as it was when the predicate was made.
265
+ - `Animation`/`AnimatedSprite` frame timing (item 254): a frame is now a texture or
266
+ `{ texture, duration, offsetX, offsetY }`, so a frame carries its own time and its own place, as
267
+ Wesnoth's `image=a.png:120,b.png:80` does, and `AnimationOptions.startTime` is signed the way
268
+ Wesnoth writes it: positive holds the first frame, negative starts partway in (`start_time=-450`
269
+ over frames of 100ms opens on the fifth, which is how a swing is lined up with its damage frame).
270
+ `Animation.frameAt`/`frameIndexAt` are the rule, the sprite advances on its own elapsed time
271
+ rather than a leftover timer, and a frame's offset is reported through `AnimatedSprite.frameOffset`
272
+ for the caller to add where it already positions the sprite.
273
+ - `FactionFog.share(factions)` (item 268): factions put on one map, what is lit now and the shroud
274
+ they remember alike, which is what Wesnoth's `share_vision` means. Nothing shares until asked,
275
+ growing a group widens it rather than replacing it, and a share declared after a `sync` still
276
+ counts because the group is read when a cell is asked about. `sees(side)` follows it, so a side's
277
+ score view reads the team's eyes.
278
+ - `campaignChain` (item 247): a `[campaign]` pointed at `simulation.Campaign`. `first_scenario` opens
279
+ it, each `[scenario]`'s `next_scenario` is where it goes when it is won, and the chain ends where a
280
+ scenario has no next one. The order is content and the playing stays the game's, since the runner
281
+ is a callback; a scenario that decides for itself keeps its decision, which is where a runtime
282
+ `[endlevel]` will hook in. Malformed chains (no scenarios, one id twice, an unknown
283
+ `first_scenario`) throw by name. The `[campaign]` schema now accepts `first_scenario`, and
284
+ `contentCatalog` exposes each campaign's scenario links.
285
+ - `[endlevel]` and carry-over (item 248): a scenario ends with `result=victory|defeat`, and what it
286
+ hands on is `endLevelCarryover` - `bonus` plus a share of the side's gold (`carryover_percentage`,
287
+ 80% when unset, which is the reference's own default rather than an invented one), the units of
288
+ that side still standing as the recall list, and `next_scenario` for where the campaign goes (the
289
+ hook `campaignChain` already honours). `carryoverIntoScenario` is the other half of the rule: the
290
+ carried share is added to what the next scenario declares when `carryover_add` asks for it, and is
291
+ otherwise a floor under it. `MWL_DEFAULT_CARRYOVER_PERCENTAGE` names the default.
292
+ - `[kill]` as a filter (item 251): naming a unit that is not there still throws, while a `[kill]`
293
+ whose attributes are a filter over the world's units is a no-op when it matches nobody, as WML's
294
+ own `[kill]` is. It reads the same attributes an event filter does, an empty filter matches every
295
+ unit (there as here), and the schema entry is open on attributes so a filter can say what it
296
+ means.
297
+ - A scenario turn limit, as a native condition (item 253): `[game] turn_limit=N` makes the runtime
298
+ set `time_over` as a world variable and fire the `time_over` event once the turn counter passes N.
299
+ Content tests it like any variable and answers it like any event, `[endlevel]` included, because a
300
+ limit is usually a defeat and sometimes the whole scenario.
301
+ - An inline-markup contract, first half of item 258: `MarkupSpan` plus `parseMarkup`/`stripMarkup`/
302
+ `markupToHtml`/`escapeHtml` in `src/two-d/ui/markup.ts`. Nested emphasis, named and hex colours, a
303
+ size, a line break, an image span carrying a path, `$name` interpolation supplied by the caller,
304
+ and the five entities as escapes. Unknown or malformed tags and unset variables stay literal
305
+ rather than vanishing, and output text is escaped so no raw HTML can leak. What the item's
306
+ acceptance still wants (backend equivalence, wrapping after styling, images through the asset
307
+ resolver, an accessibility projection) is recorded on the item rather than implied here.
308
+ - The `[side]` surface, and one key of it with behaviour (item 252): the Wesnoth keys `team_name`,
309
+ `user_team_name`, `share_vision`, `village_gold`, `heal`, `fog`, `shroud`, `hidden` and `flag` are
310
+ read onto `MwlWorld.sides` as written (`yes`/`no` as booleans), and `sideVisionGroups` turns
311
+ `team_name` with `share_vision` into the groups `FactionFog.share` takes.
312
+ - Hex projection options, first half of item 259: `hexToPixel`/`pixelToHex` take
313
+ `HexShape`/`HexOrientation`/`HexOffset`, so a grid can be flat-top or pointy-top with either
314
+ offset parity, and the default is the flat-top odd-q layout the module always had. The inverse is
315
+ the nearest cell centre, which cannot disagree with the projection at a hex's edge.
316
+ - `Halo` (item 260): the glow around a unit, an aura, a shrine's light. An `AnimatedSprite` that
317
+ `follow(x, y)`s a target with its own offset applied once, additive by default, with z-order left
318
+ to the caller. `[halo_frame]` needed nothing new after 254 gave frames their own timing.
319
+
320
+ ### Fixed
321
+
322
+ - `FloatingTextStack` stacked the wrong way round: it moved the **newcomer** down by
323
+ `height + 1`, where Java's `FloatingText.push()` anchors the newcomer on the target and lifts
324
+ the lines already there to `below.top - height - 4`. A second pop-up on one target in one turn
325
+ therefore landed *below* the target instead of above the first - found by a consumer measuring
326
+ it, not by the tests, which asserted the offset's magnitude and never its direction.
327
+ `floatingTextStackOffset` is replaced by `floatingTextStackLift` (the position the older line
328
+ must take, rather than an offset the caller adds, so the sign cannot be got wrong quietly) and
329
+ by `floatingTextStackMoves`, the whole policy: which lines move, newest first, where each one
330
+ ends up, and what age each is forced to. The loop is arithmetic now, so it is checked as
331
+ arithmetic rather than through a rendered label. `FLOATING_TEXT_STACK_GAP` names Java's 4px gap.
332
+ - The lift survived exactly one frame. `FloatingText.update` wrote its own `y` from a base captured
333
+ on the first frame, so a line the stack had just moved snapped back on the next one: measured, a
334
+ line lifted to 166.6 was back at 194.4 beside the newcomer at 200, still overlapping it. The rise
335
+ now moves the pop-up's inner layer and never its position, which belongs to the caller and to the
336
+ stack; `baseY` is gone. A consumer repositioning a pop-up mid-flight no longer loses the position
337
+ on the next frame either.
338
+ - A pop-up scaled *after* `push` was measured before the scale, because a `FloatingText`'s `height`
339
+ includes its own scale. A port rasterising at 21px and drawing at 7 therefore spaced lifted lines
340
+ 33.4 world pixels apart for lines 9.8 tall. `push` now takes a `scale`, applied before the pop-up
341
+ is measured, so the entry records the size the line is actually drawn at.
342
+
343
+ ### Changed
344
+
345
+ - `FloatingText.shortenLife(seconds)` becomes `FloatingText.ageAtLeast(seconds)`, which does what
346
+ Java's rule says rather than something close: `above.timeLeft = Math.min(above.timeLeft,
347
+ LIFESPAN - numBelow / 5f)` caps what is *left*, and a cap on what is left is a floor under the
348
+ age. A line that has already lived past the floor keeps the age it has, where subtracting the
349
+ floor shortened it a second time. `floatingTextAgeAtLeast` is that arithmetic as a pure function,
350
+ so the difference is checked by a test; `floatingTextStackLifePenalty(linesBelow)` stays the
351
+ floor itself, a fifth of a second per line below.
352
+ - A stack keys on `key` alone, as Java's `stacks.get(key)` does. The old rule wanted the same key
353
+ *and* the same origin, which this framework had invented. A caller that reused one key for two
354
+ different targets now sees their lines stacked together, and has to give each target its own key.
355
+ - One side identity in `MwlWorld` (item 277): `unit.side`, `MwlMessage.side`, `MwlMap.starts` keys
356
+ and every `side`/`side_filter` attribute now hold the string `id` `[side]` declares, so a named
357
+ side (`id=rebels`) works throughout. `MwlSideRef` is just that id. The `[side] id` and the other
358
+ side-identifying schema attributes accept a string (numbers still validate), and the map
359
+ `<side> <code>` keep marker accepts a name.
360
+
361
+ ### Fixed
362
+
363
+ - `ui.Window` (item 290): `closed` is now a getter to guard a caller's reference after `close()`,
364
+ `close()` is idempotent, input and layout on a closed window are no-ops rather than throws on
365
+ freed Pixi internals, and `WindowStack.push` refuses a closed window with a named error.
366
+
8
367
  ## [0.7.6] - 2026-09-11
9
368
 
10
369
  ### Added
package/README.md CHANGED
@@ -12,12 +12,12 @@ of their own; improvements to `mwg`'s own files are shared back.
12
12
  playable in the browser with no download, plus the generated API reference.
13
13
 
14
14
  **[AI project prompt](https://datamoc.github.io/mwg/ai-prompt/)**: a copy-ready prompt for
15
- planning or porting a demanding game with mwg, with links to the [mwg reference](REFERENCE.md)
15
+ planning or porting a demanding game with mwg, with links to the [mwg reference](https://github.com/datamoc/mwg/blob/main/REFERENCE.md)
16
16
  and the [mwg Pixel Dungeon study](https://datamoc.github.io/mwg-pixel-dungeon/).
17
17
 
18
- > **Status: pre-alpha (v0.7.4).** Every module in the shared floor below, plus optional
18
+ > **Status: pre-alpha (v0.7.7).** Every module in the shared floor below, plus optional
19
19
  > 3D, mobile (Capacitor) and desktop (WebView2) packaging, is built and tested - see
20
- > [ROADMAP.md](ROADMAP.md) for the full, numbered history.
20
+ > [ROADMAP.md](https://github.com/datamoc/mwg/blob/main/ROADMAP.md) for the full, numbered history.
21
21
  >
22
22
  > 0.4.0 was the reshaping release: the renderer moved out of `mwg/core`, `render`/`ui`/`stage`
23
23
  > became `mwg/two-d`, and a set of names that meant several things each were made to mean one.
@@ -29,8 +29,8 @@ and the [mwg Pixel Dungeon study](https://datamoc.github.io/mwg-pixel-dungeon/).
29
29
  > a name beginning with A, 2.0 one beginning with B, and so on. None of the names are chosen
30
30
  > yet, and nothing depends on them until they are.
31
31
  >
32
- > **API stability:** everything documented in [REFERENCE.md](REFERENCE.md) and
33
- > [API_REPORT.md](API_REPORT.md) is meant to be stable from 1.0 on. Anything that is not carries
32
+ > **API stability:** everything documented in [REFERENCE.md](https://github.com/datamoc/mwg/blob/main/REFERENCE.md) and
33
+ > [API_REPORT.md](https://github.com/datamoc/mwg/blob/main/API_REPORT.md) is meant to be stable from 1.0 on. Anything that is not carries
34
34
  > an `@experimental` tag in its own doc comment, and is called out as experimental in the release
35
35
  > notes that introduce it, so it can still change or disappear without a major version. A rename
36
36
  > or a removal is deprecated first: the old name keeps working, its doc comment carries
@@ -143,7 +143,7 @@ them rather than pretending otherwise:
143
143
  The practical effect: resources are **compiled at build time**, so at runtime every lookup
144
144
  is synchronous. Game code never awaits an asset. The developer-side scripts behind this
145
145
  and the other workflows (translation editing, benchmarks, packaging) are listed in
146
- [tools.md](tools.md).
146
+ [tools.md](https://github.com/datamoc/mwg/blob/main/tools.md).
147
147
 
148
148
  ## Capability spec
149
149
 
@@ -387,7 +387,7 @@ with `advanceToInput`.
387
387
 
388
388
  ## Roadmap
389
389
 
390
- See [ROADMAP.md](ROADMAP.md) for the full, numbered build order and implementation notes.
390
+ See [ROADMAP.md](https://github.com/datamoc/mwg/blob/main/ROADMAP.md) for the full, numbered build order and implementation notes.
391
391
  The optional 3D group is now implemented without changing the existing 2D entry point.
392
392
 
393
393
  ## MWL
@@ -24,6 +24,12 @@ export interface InventoryItem {
24
24
  quantity: number;
25
25
  stackable?: boolean;
26
26
  weight?: number;
27
+ /**
28
+ * A kind-level grouping - `'herb'`, `'runestone'`, `'potion'` - so a recipe can ask for "any
29
+ * herb" rather than one exact id. Like `stackable` and `weight` it describes the item's kind,
30
+ * so it comes from the game's item definitions on load and is not part of a save.
31
+ */
32
+ category?: string;
27
33
  /**
28
34
  * Distinguishes otherwise-identical instances of the same item id - two `"sword"`s, one
29
35
  * enchanted and one not, or two enchanted differently - so they never silently merge into
@@ -95,7 +101,7 @@ export declare class Inventory {
95
101
  static fromJSON(defs: ReadonlyMap<string, ItemDefinition>, data: SavedInventory): Inventory;
96
102
  }
97
103
  /** the kind-level fields a game's own item table supplies, rather than the save file */
98
- export type ItemDefinition = Pick<InventoryItem, 'stackable' | 'weight'>;
104
+ export type ItemDefinition = Pick<InventoryItem, 'stackable' | 'weight' | 'category'>;
99
105
  /** one slot as saved: instance state only, no kind-level fields */
100
106
  export interface SavedInventoryItem {
101
107
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Inventory.d.ts","sourceRoot":"","sources":["../../src/actors/Inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,aAAa;IAC7B,mGAAmG;IACnG,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,SAAS;IACrB,OAAO,CAAC,KAAK,CAAuB;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,YAAY,OAAO,GAAE,gBAAqB,EAEzC;IAED,IAAI,KAAK,IAAI,SAAS,aAAa,EAAE,CAEpC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,CAAC,QAAQ;IAIhB,8FAA8F;IAC9F,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAI/D;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAmBhC;IAED,0FAA0F;IAC1F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAU/D;IAED;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAc7E;IAED;;;;;;;;;;;OAWG;IACH,MAAM,IAAI,cAAc,CAiBvB;IAED;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,CAsB1F;CACD;AAED,wFAAwF;AACxF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,QAAQ,CAAC,CAAC;AAEzE,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC5B"}
1
+ {"version":3,"file":"Inventory.d.ts","sourceRoot":"","sources":["../../src/actors/Inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,aAAa;IAC7B,mGAAmG;IACnG,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,SAAS;IACrB,OAAO,CAAC,KAAK,CAAuB;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,YAAY,OAAO,GAAE,gBAAqB,EAEzC;IAED,IAAI,KAAK,IAAI,SAAS,aAAa,EAAE,CAEpC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,CAAC,QAAQ;IAIhB,8FAA8F;IAC9F,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAI/D;IAED;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAmBhC;IAED,0FAA0F;IAC1F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAU/D;IAED;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAI,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAc7E;IAED;;;;;;;;;;;OAWG;IACH,MAAM,IAAI,cAAc,CAiBvB;IAED;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,CAsB1F;CACD;AAED,wFAAwF;AACxF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC,CAAC;AAEtF,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"Inventory.js","sourceRoot":"","sources":["../../src/actors/Inventory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Inventory.js","sourceRoot":"","sources":["../../src/actors/Inventory.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Shop.d.ts","sourceRoot":"","sources":["../../src/actors/Shop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,KAAK;IACrB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC3B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CACnC;AAED,kGAAkG;AAClG,wBAAgB,GAAG,CAClB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GAClB,OAAO,CAkBT;AAED,iGAAiG;AACjG,wBAAgB,IAAI,CACnB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GAClB,OAAO,CAWT"}
1
+ {"version":3,"file":"Shop.d.ts","sourceRoot":"","sources":["../../src/actors/Shop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,KAAK;IACrB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC3B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CACnC;AAED,kGAAkG;AAClG,wBAAgB,GAAG,CAClB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GAClB,OAAO,CAkBT;AAED,iGAAiG;AACjG,wBAAgB,IAAI,CACnB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,WAAW,GAClB,OAAO,CAcT"}
@@ -26,7 +26,10 @@ export function sell(wallet, stock, bag, id, quantity, options) {
26
26
  if (!item || item.quantity < quantity)
27
27
  return false;
28
28
  bag.remove(id, quantity);
29
- stock.add({ ...item, quantity });
29
+ if (!stock.add({ ...item, quantity })) {
30
+ bag.add({ ...item, quantity }); //the shop's stock had no room - put the item back
31
+ return false;
32
+ }
30
33
  wallet.setBase(options.currency, wallet.base(options.currency) + price.sell * quantity);
31
34
  return true;
32
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Shop.js","sourceRoot":"","sources":["../../src/actors/Shop.ts"],"names":[],"mappings":"AAsCA,kGAAkG;AAClG,MAAM,UAAU,GAAG,CAClB,MAAiB,EACjB,KAAgB,EAChB,GAAc,EACd,EAAU,EACV,QAAgB,EAChB,OAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,GAAG,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE1D,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC;IAClC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC;IAEvD,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,kDAAkD;QACvF,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC;AACb,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,IAAI,CACnB,MAAiB,EACjB,KAAgB,EAChB,GAAc,EACd,EAAU,EACV,QAAgB,EAChB,OAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,QAAQ;QAAE,OAAO,KAAK,CAAC;IAEpD,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACzB,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IACxF,OAAO,IAAI,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"Shop.js","sourceRoot":"","sources":["../../src/actors/Shop.ts"],"names":[],"mappings":"AAsCA,kGAAkG;AAClG,MAAM,UAAU,GAAG,CAClB,MAAiB,EACjB,KAAgB,EAChB,GAAc,EACd,EAAU,EACV,QAAgB,EAChB,OAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,GAAG,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE1D,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC;IAClC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC;IAEvD,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,kDAAkD;QACvF,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC;AACb,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,IAAI,CACnB,MAAiB,EACjB,KAAgB,EAChB,GAAc,EACd,EAAU,EACV,QAAgB,EAChB,OAAoB;IAEpB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,QAAQ;QAAE,OAAO,KAAK,CAAC;IAEpD,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACzB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,kDAAkD;QAClF,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IACxF,OAAO,IAAI,CAAC;AACb,CAAC"}
@@ -1,10 +1,23 @@
1
1
  import type { Inventory, InventoryItem } from './Inventory.ts';
2
+ /**
3
+ * What one recipe ingredient consumes. `id` is the simple case: one exact item, or any of
4
+ * several. `category` asks for any item of a kind ("any herb plus any runestone"), matching the
5
+ * `category` an item's definition carries. `matches` is the escape hatch when neither fits.
6
+ * Give exactly one of the three.
7
+ */
8
+ export interface Ingredient {
9
+ /** one exact item id, or any of several */
10
+ readonly id?: string | readonly string[];
11
+ /** any item whose `category` is this */
12
+ readonly category?: string;
13
+ /** full control: an item this returns true for */
14
+ readonly matches?: (item: InventoryItem) => boolean;
15
+ /** how many items matching this the recipe needs */
16
+ readonly quantity: number;
17
+ }
2
18
  export interface Recipe {
3
- /** what gets consumed, by id and how much of each */
4
- ingredients: Array<{
5
- id: string;
6
- quantity: number;
7
- }>;
19
+ /** what gets consumed, by exact id, by category, or by predicate */
20
+ ingredients: Ingredient[];
8
21
  /** what one crafting resolves to - a full item, since it needs its own weight/stackable */
9
22
  result: InventoryItem;
10
23
  }
@@ -15,10 +28,15 @@ export interface Recipe {
15
28
  * adds/removes what a game already hands it; nothing there turns one stack of items into a
16
29
  * different one, which is the entire gap this closes.
17
30
  *
18
- * All or nothing: if any ingredient is missing or too few, nothing is touched. If every
19
- * ingredient is present but the result would not fit (`Inventory`'s own capacity, unrelated
20
- * to crafting itself), the ingredients are put back exactly as they were rather than being
21
- * spent for nothing.
31
+ * An ingredient may name an exact `id` (or any of several), a `category` ("any herb", matched
32
+ * against the item definition's own `category`), or a `matches` predicate, and a quantity is
33
+ * taken from as many matching stacks as it spans.
34
+ *
35
+ * All or nothing: if any ingredient is missing or too few, nothing is touched. The allocation
36
+ * runs against a working copy of the stacks first, so two ingredients that could both take the
37
+ * same stack cannot each count it. If every ingredient is present but the result would not fit
38
+ * (`Inventory`'s own capacity, unrelated to crafting itself), the ingredients are put back
39
+ * exactly as they were rather than being spent for nothing.
22
40
  *
23
41
  * @returns whether the recipe resolved
24
42
  *
@@ -27,15 +45,18 @@ export interface Recipe {
27
45
  * import { craft, Inventory, type Recipe } from '@datamoc/mw_games/actors';
28
46
  *
29
47
  * const bag = new Inventory();
30
- * bag.add({ id: 'wood', quantity: 3, stackable: true });
31
- * bag.add({ id: 'iron', quantity: 1, stackable: true });
48
+ * bag.add({ id: 'sage', quantity: 2, stackable: true, category: 'herb' });
49
+ * bag.add({ id: 'ember', quantity: 1, stackable: true, category: 'runestone' });
32
50
  *
33
51
  * const recipe: Recipe = {
34
- * ingredients: [{ id: 'wood', quantity: 2 }, { id: 'iron', quantity: 1 }],
35
- * result: { id: 'torch', quantity: 1 },
52
+ * ingredients: [
53
+ * { category: 'herb', quantity: 2 },
54
+ * { category: 'runestone', quantity: 1 },
55
+ * ],
56
+ * result: { id: 'elixir', quantity: 1 },
36
57
  * };
37
58
  *
38
- * const made = craft(bag, recipe); // true - both ingredients present, consumed, torch added
59
+ * const made = craft(bag, recipe); // true - any herb plus any runestone becomes an elixir
39
60
  * ```
40
61
  */
41
62
  export declare function craft(inventory: Inventory, recipe: Recipe): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"craft.d.ts","sourceRoot":"","sources":["../../src/actors/craft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/D,MAAM,WAAW,MAAM;IACtB,qDAAqD;IACrD,WAAW,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAErD,2FAA2F;IAC3F,MAAM,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAqBnE"}
1
+ {"version":3,"file":"craft.d.ts","sourceRoot":"","sources":["../../src/actors/craft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACzC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC;IAEpD,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACtB,oEAAoE;IACpE,WAAW,EAAE,UAAU,EAAE,CAAC;IAE1B,2FAA2F;IAC3F,MAAM,EAAE,aAAa,CAAC;CACtB;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CA+BnE"}