@datamoc/mw_games 0.7.4 → 0.7.7

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 (288) hide show
  1. package/CHANGELOG.md +287 -2
  2. package/README.md +15 -2
  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/craft.d.ts +35 -14
  7. package/dist/actors/craft.d.ts.map +1 -1
  8. package/dist/actors/craft.js +56 -24
  9. package/dist/actors/craft.js.map +1 -1
  10. package/dist/actors/index.d.ts +1 -1
  11. package/dist/actors/index.d.ts.map +1 -1
  12. package/dist/ai/Heuristics.d.ts +232 -0
  13. package/dist/ai/Heuristics.d.ts.map +1 -0
  14. package/dist/ai/Heuristics.js +298 -0
  15. package/dist/ai/Heuristics.js.map +1 -0
  16. package/dist/ai/index.d.ts +4 -0
  17. package/dist/ai/index.d.ts.map +1 -1
  18. package/dist/ai/index.js +2 -0
  19. package/dist/ai/index.js.map +1 -1
  20. package/dist/ai/score.d.ts +126 -0
  21. package/dist/ai/score.d.ts.map +1 -0
  22. package/dist/ai/score.js +121 -0
  23. package/dist/ai/score.js.map +1 -0
  24. package/dist/assets/loader.d.ts +18 -4
  25. package/dist/assets/loader.d.ts.map +1 -1
  26. package/dist/assets/loader.js +40 -11
  27. package/dist/assets/loader.js.map +1 -1
  28. package/dist/audio/Positional.d.ts +125 -0
  29. package/dist/audio/Positional.d.ts.map +1 -0
  30. package/dist/audio/Positional.js +135 -0
  31. package/dist/audio/Positional.js.map +1 -0
  32. package/dist/audio/Sound.d.ts +7 -1
  33. package/dist/audio/Sound.d.ts.map +1 -1
  34. package/dist/audio/Sound.js +8 -2
  35. package/dist/audio/Sound.js.map +1 -1
  36. package/dist/audio/index.d.ts +2 -0
  37. package/dist/audio/index.d.ts.map +1 -1
  38. package/dist/audio/index.js +1 -0
  39. package/dist/audio/index.js.map +1 -1
  40. package/dist/battle/AttackDialog.d.ts +75 -0
  41. package/dist/battle/AttackDialog.d.ts.map +1 -0
  42. package/dist/battle/AttackDialog.js +115 -0
  43. package/dist/battle/AttackDialog.js.map +1 -0
  44. package/dist/battle/AttackPreview.d.ts +70 -0
  45. package/dist/battle/AttackPreview.d.ts.map +1 -0
  46. package/dist/battle/AttackPreview.js +78 -0
  47. package/dist/battle/AttackPreview.js.map +1 -0
  48. package/dist/battle/BattleStats.d.ts +45 -0
  49. package/dist/battle/BattleStats.d.ts.map +1 -0
  50. package/dist/battle/BattleStats.js +63 -0
  51. package/dist/battle/BattleStats.js.map +1 -0
  52. package/dist/battle/UnitSelector.d.ts +72 -0
  53. package/dist/battle/UnitSelector.d.ts.map +1 -0
  54. package/dist/battle/UnitSelector.js +117 -0
  55. package/dist/battle/UnitSelector.js.map +1 -0
  56. package/dist/battle/Whiteboard.d.ts +50 -0
  57. package/dist/battle/Whiteboard.d.ts.map +1 -0
  58. package/dist/battle/Whiteboard.js +94 -0
  59. package/dist/battle/Whiteboard.js.map +1 -0
  60. package/dist/battle/index.d.ts +10 -0
  61. package/dist/battle/index.d.ts.map +1 -1
  62. package/dist/battle/index.js +5 -0
  63. package/dist/battle/index.js.map +1 -1
  64. package/dist/board/FogOfWar.d.ts +32 -2
  65. package/dist/board/FogOfWar.d.ts.map +1 -1
  66. package/dist/board/FogOfWar.js +70 -6
  67. package/dist/board/FogOfWar.js.map +1 -1
  68. package/dist/core/Achievements.d.ts +40 -7
  69. package/dist/core/Achievements.d.ts.map +1 -1
  70. package/dist/core/Achievements.js +51 -7
  71. package/dist/core/Achievements.js.map +1 -1
  72. package/dist/core/Blob.d.ts +13 -2
  73. package/dist/core/Blob.d.ts.map +1 -1
  74. package/dist/core/Blob.js +16 -2
  75. package/dist/core/Blob.js.map +1 -1
  76. package/dist/core/Hex.d.ts +26 -6
  77. package/dist/core/Hex.d.ts.map +1 -1
  78. package/dist/core/Hex.js +40 -13
  79. package/dist/core/Hex.js.map +1 -1
  80. package/dist/core/Input.d.ts +36 -0
  81. package/dist/core/Input.d.ts.map +1 -1
  82. package/dist/core/Input.js +63 -1
  83. package/dist/core/Input.js.map +1 -1
  84. package/dist/core/Random.d.ts +93 -0
  85. package/dist/core/Random.d.ts.map +1 -1
  86. package/dist/core/Random.js +177 -0
  87. package/dist/core/Random.js.map +1 -1
  88. package/dist/core/SyncGuard.d.ts +57 -0
  89. package/dist/core/SyncGuard.d.ts.map +1 -0
  90. package/dist/core/SyncGuard.js +116 -0
  91. package/dist/core/SyncGuard.js.map +1 -0
  92. package/dist/core/index.d.ts +3 -1
  93. package/dist/core/index.d.ts.map +1 -1
  94. package/dist/core/index.js +2 -1
  95. package/dist/core/index.js.map +1 -1
  96. package/dist/i18n/Po.d.ts +51 -0
  97. package/dist/i18n/Po.d.ts.map +1 -0
  98. package/dist/i18n/Po.js +176 -0
  99. package/dist/i18n/Po.js.map +1 -0
  100. package/dist/i18n/index.d.ts +2 -0
  101. package/dist/i18n/index.d.ts.map +1 -1
  102. package/dist/i18n/index.js +1 -0
  103. package/dist/i18n/index.js.map +1 -1
  104. package/dist/mw_games.global.js +104 -98
  105. package/dist/mwl/MapFile.d.ts +41 -0
  106. package/dist/mwl/MapFile.d.ts.map +1 -0
  107. package/dist/mwl/MapFile.js +43 -0
  108. package/dist/mwl/MapFile.js.map +1 -0
  109. package/dist/mwl/campaign.d.ts +51 -0
  110. package/dist/mwl/campaign.d.ts.map +1 -0
  111. package/dist/mwl/campaign.js +58 -0
  112. package/dist/mwl/campaign.js.map +1 -0
  113. package/dist/mwl/carryover.d.ts +79 -0
  114. package/dist/mwl/carryover.d.ts.map +1 -0
  115. package/dist/mwl/carryover.js +63 -0
  116. package/dist/mwl/carryover.js.map +1 -0
  117. package/dist/mwl/content.d.ts +10 -0
  118. package/dist/mwl/content.d.ts.map +1 -1
  119. package/dist/mwl/content.js +8 -0
  120. package/dist/mwl/content.js.map +1 -1
  121. package/dist/mwl/hooks.d.ts +6 -5
  122. package/dist/mwl/hooks.d.ts.map +1 -1
  123. package/dist/mwl/hooks.js.map +1 -1
  124. package/dist/mwl/index.d.ts +8 -2
  125. package/dist/mwl/index.d.ts.map +1 -1
  126. package/dist/mwl/index.js +4 -1
  127. package/dist/mwl/index.js.map +1 -1
  128. package/dist/mwl/runtime.d.ts +140 -7
  129. package/dist/mwl/runtime.d.ts.map +1 -1
  130. package/dist/mwl/runtime.js +427 -33
  131. package/dist/mwl/runtime.js.map +1 -1
  132. package/dist/mwl/schema.d.ts.map +1 -1
  133. package/dist/mwl/schema.js +97 -18
  134. package/dist/mwl/schema.js.map +1 -1
  135. package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
  136. package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
  137. package/dist/roguelike/MultiTurnBeam.js +100 -53
  138. package/dist/roguelike/MultiTurnBeam.js.map +1 -1
  139. package/dist/roguelike/Targeting.d.ts +94 -0
  140. package/dist/roguelike/Targeting.d.ts.map +1 -1
  141. package/dist/roguelike/Targeting.js +123 -0
  142. package/dist/roguelike/Targeting.js.map +1 -1
  143. package/dist/roguelike/index.d.ts +3 -1
  144. package/dist/roguelike/index.d.ts.map +1 -1
  145. package/dist/roguelike/index.js +1 -0
  146. package/dist/roguelike/index.js.map +1 -1
  147. package/dist/simulation/CampaignSave.d.ts +68 -0
  148. package/dist/simulation/CampaignSave.d.ts.map +1 -0
  149. package/dist/simulation/CampaignSave.js +54 -0
  150. package/dist/simulation/CampaignSave.js.map +1 -0
  151. package/dist/simulation/EventPresentation.d.ts +111 -0
  152. package/dist/simulation/EventPresentation.d.ts.map +1 -0
  153. package/dist/simulation/EventPresentation.js +120 -0
  154. package/dist/simulation/EventPresentation.js.map +1 -0
  155. package/dist/simulation/index.d.ts +4 -0
  156. package/dist/simulation/index.d.ts.map +1 -1
  157. package/dist/simulation/index.js +2 -0
  158. package/dist/simulation/index.js.map +1 -1
  159. package/dist/two-d/pixi-interop.d.ts +18 -6
  160. package/dist/two-d/pixi-interop.d.ts.map +1 -1
  161. package/dist/two-d/pixi-interop.js +18 -6
  162. package/dist/two-d/pixi-interop.js.map +1 -1
  163. package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
  164. package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
  165. package/dist/two-d/render/AnimatedSprite.js +88 -26
  166. package/dist/two-d/render/AnimatedSprite.js.map +1 -1
  167. package/dist/two-d/render/Camera.d.ts +64 -4
  168. package/dist/two-d/render/Camera.d.ts.map +1 -1
  169. package/dist/two-d/render/Camera.js +132 -11
  170. package/dist/two-d/render/Camera.js.map +1 -1
  171. package/dist/two-d/render/Halo.d.ts +58 -0
  172. package/dist/two-d/render/Halo.d.ts.map +1 -0
  173. package/dist/two-d/render/Halo.js +48 -0
  174. package/dist/two-d/render/Halo.js.map +1 -0
  175. package/dist/two-d/render/ImageModifiers.d.ts +174 -0
  176. package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
  177. package/dist/two-d/render/ImageModifiers.js +438 -1
  178. package/dist/two-d/render/ImageModifiers.js.map +1 -1
  179. package/dist/two-d/render/LightningArc.d.ts +57 -0
  180. package/dist/two-d/render/LightningArc.d.ts.map +1 -0
  181. package/dist/two-d/render/LightningArc.js +91 -0
  182. package/dist/two-d/render/LightningArc.js.map +1 -0
  183. package/dist/two-d/render/PaletteRemap.d.ts +135 -0
  184. package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
  185. package/dist/two-d/render/PaletteRemap.js +181 -0
  186. package/dist/two-d/render/PaletteRemap.js.map +1 -0
  187. package/dist/two-d/render/Particles.d.ts +26 -0
  188. package/dist/two-d/render/Particles.d.ts.map +1 -1
  189. package/dist/two-d/render/Particles.js +23 -2
  190. package/dist/two-d/render/Particles.js.map +1 -1
  191. package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
  192. package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
  193. package/dist/two-d/render/SpriteAttachment.js +60 -0
  194. package/dist/two-d/render/SpriteAttachment.js.map +1 -0
  195. package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
  196. package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
  197. package/dist/two-d/render/TerrainGraphics.js +161 -0
  198. package/dist/two-d/render/TerrainGraphics.js.map +1 -0
  199. package/dist/two-d/render/index.d.ts +13 -3
  200. package/dist/two-d/render/index.d.ts.map +1 -1
  201. package/dist/two-d/render/index.js +6 -1
  202. package/dist/two-d/render/index.js.map +1 -1
  203. package/dist/two-d/stage/StoryScreen.d.ts +110 -0
  204. package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
  205. package/dist/two-d/stage/StoryScreen.js +178 -0
  206. package/dist/two-d/stage/StoryScreen.js.map +1 -0
  207. package/dist/two-d/stage/index.d.ts +2 -0
  208. package/dist/two-d/stage/index.d.ts.map +1 -1
  209. package/dist/two-d/stage/index.js +1 -0
  210. package/dist/two-d/stage/index.js.map +1 -1
  211. package/dist/two-d/ui/Checkbox.d.ts +44 -0
  212. package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
  213. package/dist/two-d/ui/Checkbox.js +89 -0
  214. package/dist/two-d/ui/Checkbox.js.map +1 -0
  215. package/dist/two-d/ui/DataTable.d.ts +79 -0
  216. package/dist/two-d/ui/DataTable.d.ts.map +1 -0
  217. package/dist/two-d/ui/DataTable.js +164 -0
  218. package/dist/two-d/ui/DataTable.js.map +1 -0
  219. package/dist/two-d/ui/Dropdown.d.ts +72 -0
  220. package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
  221. package/dist/two-d/ui/Dropdown.js +126 -0
  222. package/dist/two-d/ui/Dropdown.js.map +1 -0
  223. package/dist/two-d/ui/FloatingText.d.ts +43 -4
  224. package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
  225. package/dist/two-d/ui/FloatingText.js +52 -5
  226. package/dist/two-d/ui/FloatingText.js.map +1 -1
  227. package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
  228. package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
  229. package/dist/two-d/ui/FloatingTextStack.js +89 -18
  230. package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
  231. package/dist/two-d/ui/Layout.d.ts +105 -0
  232. package/dist/two-d/ui/Layout.d.ts.map +1 -0
  233. package/dist/two-d/ui/Layout.js +174 -0
  234. package/dist/two-d/ui/Layout.js.map +1 -0
  235. package/dist/two-d/ui/ScrollBox.d.ts +67 -0
  236. package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
  237. package/dist/two-d/ui/ScrollBox.js +127 -0
  238. package/dist/two-d/ui/ScrollBox.js.map +1 -0
  239. package/dist/two-d/ui/Skins.d.ts +59 -0
  240. package/dist/two-d/ui/Skins.d.ts.map +1 -0
  241. package/dist/two-d/ui/Skins.js +77 -0
  242. package/dist/two-d/ui/Skins.js.map +1 -0
  243. package/dist/two-d/ui/Slider.d.ts +91 -0
  244. package/dist/two-d/ui/Slider.d.ts.map +1 -0
  245. package/dist/two-d/ui/Slider.js +170 -0
  246. package/dist/two-d/ui/Slider.js.map +1 -0
  247. package/dist/two-d/ui/Spinner.d.ts +67 -0
  248. package/dist/two-d/ui/Spinner.d.ts.map +1 -0
  249. package/dist/two-d/ui/Spinner.js +137 -0
  250. package/dist/two-d/ui/Spinner.js.map +1 -0
  251. package/dist/two-d/ui/TabbedList.d.ts +118 -0
  252. package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
  253. package/dist/two-d/ui/TabbedList.js +221 -0
  254. package/dist/two-d/ui/TabbedList.js.map +1 -0
  255. package/dist/two-d/ui/TextModel.d.ts +65 -0
  256. package/dist/two-d/ui/TextModel.d.ts.map +1 -0
  257. package/dist/two-d/ui/TextModel.js +126 -0
  258. package/dist/two-d/ui/TextModel.js.map +1 -0
  259. package/dist/two-d/ui/TreeView.d.ts +68 -0
  260. package/dist/two-d/ui/TreeView.d.ts.map +1 -0
  261. package/dist/two-d/ui/TreeView.js +133 -0
  262. package/dist/two-d/ui/TreeView.js.map +1 -0
  263. package/dist/two-d/ui/Window.d.ts +13 -0
  264. package/dist/two-d/ui/Window.d.ts.map +1 -1
  265. package/dist/two-d/ui/Window.js +23 -0
  266. package/dist/two-d/ui/Window.js.map +1 -1
  267. package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
  268. package/dist/two-d/ui/WindowStack.js +2 -0
  269. package/dist/two-d/ui/WindowStack.js.map +1 -1
  270. package/dist/two-d/ui/index.d.ts +27 -3
  271. package/dist/two-d/ui/index.d.ts.map +1 -1
  272. package/dist/two-d/ui/index.js +14 -2
  273. package/dist/two-d/ui/index.js.map +1 -1
  274. package/dist/two-d/ui/markup.d.ts +127 -0
  275. package/dist/two-d/ui/markup.d.ts.map +1 -0
  276. package/dist/two-d/ui/markup.js +322 -0
  277. package/dist/two-d/ui/markup.js.map +1 -0
  278. package/dist/version.d.ts +1 -1
  279. package/dist/version.js +1 -1
  280. package/dist/world/SideTurns.d.ts +115 -0
  281. package/dist/world/SideTurns.d.ts.map +1 -0
  282. package/dist/world/SideTurns.js +138 -0
  283. package/dist/world/SideTurns.js.map +1 -0
  284. package/dist/world/index.d.ts +2 -0
  285. package/dist/world/index.d.ts.map +1 -1
  286. package/dist/world/index.js +1 -0
  287. package/dist/world/index.js.map +1 -1
  288. package/package.json +8 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnitSelector.d.ts","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;IAC7C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1E;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY;IACxB,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgE;IAE1F,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,UAAU,CAAK;IAEvB,YAAY,OAAO,EAAE,mBAAmB,EAKvC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,QAAQ,IAAI,cAAc,GAAG,IAAI,CAEpC;IAED,IAAI,MAAM,IAAI,cAAc,GAAG,IAAI,CAElC;IAED,+DAA+D;IAC/D,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,mDAAmD;IACnD,IAAI,UAAU,IAAI,SAAS,cAAc,EAAE,CAI1C;IAED,+EAA+E;IAC/E,IAAI,OAAO,IAAI,SAAS,cAAc,EAAE,CAUvC;IAED,wDAAwD;IACxD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,WAAW,IAAI,cAAc,GAAG,IAAI,CAGvC;IAED,kFAAkF;IAClF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKxB;IAED,yFAAyF;IACzF,MAAM,IAAI,OAAO,CAYhB;IAED,0EAA0E;IAC1E,IAAI,IAAI,IAAI,CASX;IAED,KAAK,IAAI,IAAI,CAMZ;IAED,OAAO,CAAC,MAAM;CAGd"}
@@ -0,0 +1,117 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * The two-step unit selector an attack starts with: pick who attacks, then pick what they attack.
4
+ *
5
+ * Renderer-free, so the choosing rules are tested without a board: `candidates` are the enabled
6
+ * units on the selecting side, `targets` are the enabled units that pass `canTarget` once an
7
+ * attacker is chosen, `move` walks the active list and `select` advances a stage. `back` undoes the
8
+ * attacker choice rather than only the target, so a player who picked the wrong attacker lands
9
+ * where they can pick again rather than being stuck one step in.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { UnitSelector } from '@datamoc/mw_games/battle';
14
+ *
15
+ * const selector = new UnitSelector({
16
+ * units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
17
+ * side: '1',
18
+ * });
19
+ * selector.select(); // hero attacks
20
+ * console.log(selector.targets.map((unit) => unit.id)); // ['rat']
21
+ * ```
22
+ */
23
+ export class UnitSelector {
24
+ constructor(options) {
25
+ this.onChange = new Signal();
26
+ this.stage_ = 'attacker';
27
+ this.charge = null;
28
+ this.victim = null;
29
+ this.highlight_ = 0;
30
+ this.units = options.units;
31
+ this.side = options.side;
32
+ this.disabledOf = options.disabled ?? ((unit) => unit.disabled ?? false);
33
+ this.canTarget = options.canTarget ?? (() => true);
34
+ }
35
+ get stage() {
36
+ return this.stage_;
37
+ }
38
+ get attacker() {
39
+ return this.charge;
40
+ }
41
+ get target() {
42
+ return this.victim;
43
+ }
44
+ /** both steps are done, so the caller has an attack to make */
45
+ get done() {
46
+ return this.charge !== null && this.victim !== null;
47
+ }
48
+ /** the units that may be picked as the attacker */
49
+ get candidates() {
50
+ return this.units.filter((unit) => (this.side === undefined || unit.side === this.side) && !this.disabledOf(unit));
51
+ }
52
+ /** the units the chosen attacker may hit; empty until an attacker is chosen */
53
+ get targets() {
54
+ const attacker = this.charge;
55
+ if (!attacker)
56
+ return [];
57
+ return this.units.filter((unit) => unit.id !== attacker.id &&
58
+ !this.disabledOf(unit) &&
59
+ !(attacker.side !== undefined && unit.side === attacker.side) &&
60
+ this.canTarget(attacker, unit));
61
+ }
62
+ /** the index of the highlight within the active list */
63
+ get highlight() {
64
+ return this.highlight_;
65
+ }
66
+ get highlighted() {
67
+ const list = this.active();
68
+ return list[this.highlight_] ?? null;
69
+ }
70
+ /** moves the highlight, wrapping at both ends, within whichever list is active */
71
+ move(delta) {
72
+ const list = this.active();
73
+ if (list.length === 0)
74
+ return;
75
+ this.highlight_ = (((this.highlight_ + delta) % list.length) + list.length) % list.length;
76
+ this.onChange.dispatch();
77
+ }
78
+ /** takes the highlighted unit: on the attacker stage it advances to choosing a target */
79
+ select() {
80
+ const chosen = this.highlighted;
81
+ if (!chosen)
82
+ return false;
83
+ if (this.stage_ === 'attacker') {
84
+ this.charge = chosen;
85
+ this.stage_ = 'target';
86
+ this.highlight_ = 0;
87
+ }
88
+ else {
89
+ this.victim = chosen;
90
+ }
91
+ this.onChange.dispatch();
92
+ return true;
93
+ }
94
+ /** undoes the attacker choice, so a wrong attacker can be picked again */
95
+ back() {
96
+ if (this.stage_ === 'attacker')
97
+ return;
98
+ const previous = this.charge;
99
+ this.charge = null;
100
+ this.victim = null;
101
+ this.stage_ = 'attacker';
102
+ const index = previous ? this.candidates.findIndex((unit) => unit.id === previous.id) : -1;
103
+ this.highlight_ = index >= 0 ? index : 0;
104
+ this.onChange.dispatch();
105
+ }
106
+ reset() {
107
+ this.charge = null;
108
+ this.victim = null;
109
+ this.stage_ = 'attacker';
110
+ this.highlight_ = 0;
111
+ this.onChange.dispatch();
112
+ }
113
+ active() {
114
+ return this.stage_ === 'attacker' ? this.candidates : this.targets;
115
+ }
116
+ }
117
+ //# sourceMappingURL=UnitSelector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnitSelector.js","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { Signal } from '../core/Signal.ts';
2
+ export interface WhiteboardEntry {
3
+ /** the unit the plan is for; one plan per unit, the way a turn's moves are planned */
4
+ unit: string;
5
+ }
6
+ /**
7
+ * The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
8
+ *
9
+ * A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
10
+ * than stacking a second one for the same unit: what is on the board is the turn as it would be
11
+ * played, not the history of how a player got there. Undo pops the last plan onto a redo stack
12
+ * (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
13
+ * caller, which is where the framework stops - actually executing them is the game's turn.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Whiteboard } from '@datamoc/mw_games/battle';
18
+ *
19
+ * const board = new Whiteboard<{ unit: string; x: number; y: number }>();
20
+ * board.plan({ unit: 'hero', x: 2, y: 3 });
21
+ * board.plan({ unit: 'archer', x: 5, y: 1 });
22
+ * board.undo();
23
+ * console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
24
+ * ```
25
+ */
26
+ export declare class Whiteboard<T extends WhiteboardEntry = WhiteboardEntry> {
27
+ readonly onChange: Signal<void>;
28
+ private planned;
29
+ private undone;
30
+ get plans(): readonly T[];
31
+ get isEmpty(): boolean;
32
+ get canUndo(): boolean;
33
+ get canRedo(): boolean;
34
+ /** the plan for a unit, if it has one on the board */
35
+ plannedFor(unit: string): T | undefined;
36
+ /** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
37
+ plan(action: T): void;
38
+ /** takes the last plan off the board, returning it so a caller can put it back */
39
+ undo(): T | null;
40
+ /** puts the last undone plan back, replacing any plan the unit has picked up since */
41
+ redo(): T | null;
42
+ /** empties the board, both the plans and anything undone */
43
+ clear(): void;
44
+ /**
45
+ * Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
46
+ * The orders are returned in planning order.
47
+ */
48
+ commit(): T[];
49
+ }
50
+ //# sourceMappingURL=Whiteboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Whiteboard.d.ts","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe;IAClE,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,MAAM,CAAW;IAEzB,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,sDAAsD;IACtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAEtC;IAED,yFAAyF;IACzF,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAMpB;IAED,kFAAkF;IAClF,IAAI,IAAI,CAAC,GAAG,IAAI,CAMf;IAED,sFAAsF;IACtF,IAAI,IAAI,CAAC,GAAG,IAAI,CAOf;IAED,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAKZ;IAED;;;OAGG;IACH,MAAM,IAAI,CAAC,EAAE,CAMZ;CACD"}
@@ -0,0 +1,94 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
4
+ *
5
+ * A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
6
+ * than stacking a second one for the same unit: what is on the board is the turn as it would be
7
+ * played, not the history of how a player got there. Undo pops the last plan onto a redo stack
8
+ * (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
9
+ * caller, which is where the framework stops - actually executing them is the game's turn.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Whiteboard } from '@datamoc/mw_games/battle';
14
+ *
15
+ * const board = new Whiteboard<{ unit: string; x: number; y: number }>();
16
+ * board.plan({ unit: 'hero', x: 2, y: 3 });
17
+ * board.plan({ unit: 'archer', x: 5, y: 1 });
18
+ * board.undo();
19
+ * console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
20
+ * ```
21
+ */
22
+ export class Whiteboard {
23
+ constructor() {
24
+ this.onChange = new Signal();
25
+ this.planned = [];
26
+ this.undone = [];
27
+ }
28
+ get plans() {
29
+ return this.planned;
30
+ }
31
+ get isEmpty() {
32
+ return this.planned.length === 0;
33
+ }
34
+ get canUndo() {
35
+ return this.planned.length > 0;
36
+ }
37
+ get canRedo() {
38
+ return this.undone.length > 0;
39
+ }
40
+ /** the plan for a unit, if it has one on the board */
41
+ plannedFor(unit) {
42
+ return this.planned.find((entry) => entry.unit === unit);
43
+ }
44
+ /** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
45
+ plan(action) {
46
+ const index = this.planned.findIndex((entry) => entry.unit === action.unit);
47
+ if (index >= 0)
48
+ this.planned[index] = action;
49
+ else
50
+ this.planned.push(action);
51
+ this.undone = [];
52
+ this.onChange.dispatch();
53
+ }
54
+ /** takes the last plan off the board, returning it so a caller can put it back */
55
+ undo() {
56
+ const entry = this.planned.pop();
57
+ if (!entry)
58
+ return null;
59
+ this.undone.push(entry);
60
+ this.onChange.dispatch();
61
+ return entry;
62
+ }
63
+ /** puts the last undone plan back, replacing any plan the unit has picked up since */
64
+ redo() {
65
+ const entry = this.undone.pop();
66
+ if (!entry)
67
+ return null;
68
+ this.planned = this.planned.filter((candidate) => candidate.unit !== entry.unit);
69
+ this.planned.push(entry);
70
+ this.onChange.dispatch();
71
+ return entry;
72
+ }
73
+ /** empties the board, both the plans and anything undone */
74
+ clear() {
75
+ if (this.planned.length === 0 && this.undone.length === 0)
76
+ return;
77
+ this.planned = [];
78
+ this.undone = [];
79
+ this.onChange.dispatch();
80
+ }
81
+ /**
82
+ * Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
83
+ * The orders are returned in planning order.
84
+ */
85
+ commit() {
86
+ const committed = this.planned;
87
+ this.planned = [];
88
+ this.undone = [];
89
+ if (committed.length > 0)
90
+ this.onChange.dispatch();
91
+ return committed;
92
+ }
93
+ }
94
+ //# sourceMappingURL=Whiteboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Whiteboard.js","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"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"}
@@ -13,4 +13,14 @@ export { BattleHooks } from './Hooks.ts';
13
13
  export type { BattleHook } from './Hooks.ts';
14
14
  export { Field } from './Field.ts';
15
15
  export type { FieldCondition } from './Field.ts';
16
+ export { AttackPreview } from './AttackPreview.ts';
17
+ export { AttackDialog } from './AttackDialog.ts';
18
+ export type { AttackDialogOptions, StrikeNumbers } from './AttackDialog.ts';
19
+ export type { AttackFrame, AttackPreviewOptions, PreviewCombatant } from './AttackPreview.ts';
20
+ export { UnitSelector } from './UnitSelector.ts';
21
+ export type { SelectableUnit, SelectorStage, UnitSelectorOptions } from './UnitSelector.ts';
22
+ export { Whiteboard } from './Whiteboard.ts';
23
+ export type { WhiteboardEntry } from './Whiteboard.ts';
24
+ export { BattleStats } from './BattleStats.ts';
25
+ export type { BattleStatCategory } from './BattleStats.ts';
16
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -7,4 +7,9 @@ export { StatStages } from './StatStages.js';
7
7
  export { chooseMove, chooseSwitch } from './BattleAI.js';
8
8
  export { BattleHooks } from './Hooks.js';
9
9
  export { Field } from './Field.js';
10
+ export { AttackPreview } from './AttackPreview.js';
11
+ export { AttackDialog } from './AttackDialog.js';
12
+ export { UnitSelector } from './UnitSelector.js';
13
+ export { Whiteboard } from './Whiteboard.js';
14
+ export { BattleStats } from './BattleStats.js';
10
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -6,6 +6,11 @@ export interface VisionCell {
6
6
  * Unions the visible cells of several units for each faction and retains explored memory.
7
7
  * The caller supplies visibility because board games differ in terrain, range, and blockers.
8
8
  *
9
+ * Factions that `share` see through one another's eyes - one map for the group, what is lit now
10
+ * and what they remember having seen, which is what Wesnoth's `share_vision` means. Nothing shares
11
+ * until asked, and sharing is a property of the sides rather than of any unit, so it survives every
12
+ * `sync`.
13
+ *
9
14
  * @example
10
15
  * ```ts
11
16
  * import { FactionFog } from '@datamoc/mw_games/board';
@@ -21,9 +26,12 @@ export interface VisionCell {
21
26
  * console.log(fog.isVisible('blue', 3, 2)); // true - lit by the scout right now
22
27
  * console.log(fog.isVisible('blue', 5, 5)); // false - never seen
23
28
  *
29
+ * fog.share(['blue', 'green']); // the two now see one map
30
+ * console.log(fog.isVisible('green', 3, 2)); // true - blue's scout is watching for both
31
+ *
24
32
  * fog.sync('blue', [], () => []); // the scout moved away, nothing visible this turn
25
- * console.log(fog.isVisible('blue', 3, 2)); // false - no longer in sight
26
- * console.log(fog.isExplored('blue', 3, 2)); // true - stays remembered after leaving
33
+ * console.log(fog.isVisible('green', 3, 2)); // false - no longer in sight, for either of them
34
+ * console.log(fog.isExplored('green', 3, 2)); // true - stays remembered, for both
27
35
  * ```
28
36
  */
29
37
  export declare class FactionFog {
@@ -31,7 +39,18 @@ export declare class FactionFog {
31
39
  readonly height: number;
32
40
  private visible;
33
41
  private explored;
42
+ /** faction to the factions it shares vision with, itself included. Absent means it shares with nobody. */
43
+ private readonly shared;
34
44
  constructor(width: number, height: number);
45
+ /**
46
+ * Makes these factions see with one pair of eyes: each one's cells count as the others', both
47
+ * for what is visible now and for the shroud they remember.
48
+ *
49
+ * Calling it again widens the group rather than replacing it, so `share(['blue', 'green'])`
50
+ * after `share(['green', 'teal'])` leaves all three on one map. A side may also be told to share
51
+ * with itself, or with nobody at all, without harm.
52
+ */
53
+ share(factions: readonly string[]): void;
35
54
  sync(faction: string, sources: readonly VisionCell[], cells: (source: VisionCell) => Iterable<VisionCell>): void;
36
55
  /**
37
56
  * Mark cells explored without changing what is currently visible: the
@@ -40,9 +59,20 @@ export declare class FactionFog {
40
59
  */
41
60
  reveal(faction: string, cells: Iterable<VisionCell>): void;
42
61
  isVisible(faction: string, x: number, y: number): boolean;
62
+ /**
63
+ * One faction's sight as a predicate, ready to hand to anything that asks what a side can see -
64
+ * `ai`'s score views, for one. It reads the shroud as it is when called, not as it was when the
65
+ * predicate was made, so a caller holding one across a `sync` sees the update, and it follows
66
+ * whatever `share` the faction later joins.
67
+ */
68
+ sees(faction: string): (x: number, y: number) => boolean;
43
69
  isExplored(faction: string, x: number, y: number): boolean;
44
70
  visibleCells(faction: string): readonly number[];
45
71
  exploredCells(faction: string): readonly number[];
72
+ /** one cell, as the faction or anyone it shares with sees it */
73
+ private seenBy;
74
+ /** one faction's cells, or the union over the group it shares with */
75
+ private cellsSeenBy;
46
76
  private inside;
47
77
  private index;
48
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FogOfWar.d.ts","sourceRoot":"","sources":["../../src/board/FogOfWar.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,UAAU;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAAkC;IAElD,YAAY,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAIxC;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAW/G;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAOzD;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;IAED,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE/C;IACD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEhD;IAED,OAAO,CAAC,MAAM;IAGd,OAAO,CAAC,KAAK;CAGb"}
1
+ {"version":3,"file":"FogOfWar.d.ts","sourceRoot":"","sources":["../../src/board/FogOfWar.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,UAAU;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAAkC;IAElD,0GAA0G;IAC1G,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IAEzD,YAAY,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAIxC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CASvC;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAW/G;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAOzD;IAED,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAExD;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAEvD;IAED,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE/C;IACD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEhD;IAED,gEAAgE;IAChE,OAAO,CAAC,MAAM;IASd,sEAAsE;IACtE,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,MAAM;IAGd,OAAO,CAAC,KAAK;CAGb"}
@@ -2,6 +2,11 @@
2
2
  * Unions the visible cells of several units for each faction and retains explored memory.
3
3
  * The caller supplies visibility because board games differ in terrain, range, and blockers.
4
4
  *
5
+ * Factions that `share` see through one another's eyes - one map for the group, what is lit now
6
+ * and what they remember having seen, which is what Wesnoth's `share_vision` means. Nothing shares
7
+ * until asked, and sharing is a property of the sides rather than of any unit, so it survives every
8
+ * `sync`.
9
+ *
5
10
  * @example
6
11
  * ```ts
7
12
  * import { FactionFog } from '@datamoc/mw_games/board';
@@ -17,20 +22,45 @@
17
22
  * console.log(fog.isVisible('blue', 3, 2)); // true - lit by the scout right now
18
23
  * console.log(fog.isVisible('blue', 5, 5)); // false - never seen
19
24
  *
25
+ * fog.share(['blue', 'green']); // the two now see one map
26
+ * console.log(fog.isVisible('green', 3, 2)); // true - blue's scout is watching for both
27
+ *
20
28
  * fog.sync('blue', [], () => []); // the scout moved away, nothing visible this turn
21
- * console.log(fog.isVisible('blue', 3, 2)); // false - no longer in sight
22
- * console.log(fog.isExplored('blue', 3, 2)); // true - stays remembered after leaving
29
+ * console.log(fog.isVisible('green', 3, 2)); // false - no longer in sight, for either of them
30
+ * console.log(fog.isExplored('green', 3, 2)); // true - stays remembered, for both
23
31
  * ```
24
32
  */
25
33
  export class FactionFog {
26
34
  constructor(width, height) {
27
35
  this.visible = new Map();
28
36
  this.explored = new Map();
37
+ /** faction to the factions it shares vision with, itself included. Absent means it shares with nobody. */
38
+ this.shared = new Map();
29
39
  if (width < 1 || height < 1)
30
40
  throw new Error('fog needs positive dimensions');
31
41
  this.width = width;
32
42
  this.height = height;
33
43
  }
44
+ /**
45
+ * Makes these factions see with one pair of eyes: each one's cells count as the others', both
46
+ * for what is visible now and for the shroud they remember.
47
+ *
48
+ * Calling it again widens the group rather than replacing it, so `share(['blue', 'green'])`
49
+ * after `share(['green', 'teal'])` leaves all three on one map. A side may also be told to share
50
+ * with itself, or with nobody at all, without harm.
51
+ */
52
+ share(factions) {
53
+ const named = [...new Set(factions)].filter((faction) => Boolean(faction));
54
+ if (named.length === 0)
55
+ return;
56
+ const group = new Set(named);
57
+ for (const faction of named) {
58
+ for (const mate of this.shared.get(faction) ?? [])
59
+ group.add(mate);
60
+ }
61
+ for (const faction of group)
62
+ this.shared.set(faction, group);
63
+ }
34
64
  sync(faction, sources, cells) {
35
65
  if (!faction)
36
66
  throw new Error('fog needs a faction id');
@@ -62,16 +92,50 @@ export class FactionFog {
62
92
  this.explored.set(faction, memory);
63
93
  }
64
94
  isVisible(faction, x, y) {
65
- return this.visible.get(faction)?.has(this.index(x, y)) ?? false;
95
+ return this.seenBy(this.visible, faction, this.index(x, y));
96
+ }
97
+ /**
98
+ * One faction's sight as a predicate, ready to hand to anything that asks what a side can see -
99
+ * `ai`'s score views, for one. It reads the shroud as it is when called, not as it was when the
100
+ * predicate was made, so a caller holding one across a `sync` sees the update, and it follows
101
+ * whatever `share` the faction later joins.
102
+ */
103
+ sees(faction) {
104
+ return (x, y) => this.isVisible(faction, x, y);
66
105
  }
67
106
  isExplored(faction, x, y) {
68
- return this.explored.get(faction)?.has(this.index(x, y)) ?? false;
107
+ return this.seenBy(this.explored, faction, this.index(x, y));
69
108
  }
70
109
  visibleCells(faction) {
71
- return [...(this.visible.get(faction) ?? [])];
110
+ return this.cellsSeenBy(this.visible, faction);
72
111
  }
73
112
  exploredCells(faction) {
74
- return [...(this.explored.get(faction) ?? [])];
113
+ return this.cellsSeenBy(this.explored, faction);
114
+ }
115
+ /** one cell, as the faction or anyone it shares with sees it */
116
+ seenBy(cells, faction, cell) {
117
+ const group = this.shared.get(faction);
118
+ if (!group)
119
+ return cells.get(faction)?.has(cell) ?? false;
120
+ for (const mate of group) {
121
+ if (cells.get(mate)?.has(cell))
122
+ return true;
123
+ }
124
+ return false;
125
+ }
126
+ /** one faction's cells, or the union over the group it shares with */
127
+ cellsSeenBy(cells, faction) {
128
+ const group = this.shared.get(faction);
129
+ if (!group)
130
+ return [...(cells.get(faction) ?? [])];
131
+ const union = new Set();
132
+ for (const mate of group) {
133
+ for (const cell of cells.get(mate) ?? [])
134
+ union.add(cell);
135
+ }
136
+ //sorted because a union of sets has no order of its own, and a caller comparing two of these
137
+ //should not have to care which of the group was synced first
138
+ return [...union].sort((a, b) => a - b);
75
139
  }
76
140
  inside(x, y) {
77
141
  return x >= 0 && y >= 0 && x < this.width && y < this.height;
@@ -1 +1 @@
1
- {"version":3,"file":"FogOfWar.js","sourceRoot":"","sources":["../../src/board/FogOfWar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FogOfWar.js","sourceRoot":"","sources":["../../src/board/FogOfWar.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,13 @@
9
9
  * count behind it. Descriptions are display text `mwg` never reads; persistence is the
10
10
  * usual definitions-fresh, progress-saved split (`QuestLog`'s own convention).
11
11
  *
12
+ * An achievement can also name several criteria instead of one - Wesnoth's own
13
+ * "sub-achievements" shape, such as "recruit one of every unit type" being six counters
14
+ * that must each reach 1 - and it unlocks only once every one of them has. A single
15
+ * `counter`/`target` is shorthand for a one-criterion achievement; both forms share the
16
+ * same unlock, progress and save code, since a one-element criteria list behaves
17
+ * identically to the shorthand.
18
+ *
12
19
  * @example
13
20
  * ```ts
14
21
  * import { Achievements } from '@datamoc/mw_games/core';
@@ -16,6 +23,13 @@
16
23
  * const achievements = new Achievements();
17
24
  * achievements.define({ id: 'first-blood', counter: 'kills', target: 1 });
18
25
  * achievements.define({ id: 'slayer', counter: 'kills', target: 100 });
26
+ * achievements.define({
27
+ * id: 'diverse-army',
28
+ * criteria: [
29
+ * { counter: 'recruited-archer', target: 1 },
30
+ * { counter: 'recruited-knight', target: 1 },
31
+ * ],
32
+ * });
19
33
  *
20
34
  * const unlocked = achievements.increment('kills', 1);
21
35
  * console.log(unlocked); // ['first-blood']
@@ -24,12 +38,20 @@
24
38
  * const toast = achievements.drainNew();
25
39
  * ```
26
40
  */
27
- export interface AchievementDef {
28
- id: string;
29
- /** the counter this watches, incremented by the game as things happen */
41
+ export interface AchievementCriterion {
42
+ /** the counter this criterion watches, incremented by the game as things happen */
30
43
  counter: string;
31
- /** the counter value that earns this */
44
+ /** the counter value that satisfies this criterion */
32
45
  target: number;
46
+ }
47
+ export interface AchievementDef {
48
+ id: string;
49
+ /** shorthand for a single-criterion achievement; mutually exclusive with `criteria` */
50
+ counter?: string;
51
+ /** shorthand for a single-criterion achievement; mutually exclusive with `criteria` */
52
+ target?: number;
53
+ /** every criterion here must be met before this achievement unlocks; mutually exclusive with `counter`/`target` */
54
+ criteria?: AchievementCriterion[];
33
55
  /** shown on an achievement screen; `mwg` never reads this itself */
34
56
  description?: string;
35
57
  }
@@ -42,19 +64,30 @@ export declare class Achievements {
42
64
  /** the current value of a counter; 0 for one nothing has touched yet */
43
65
  count(counter: string): number;
44
66
  /**
45
- * Adds to a counter, unlocking whatever that newly earns.
67
+ * Adds to a counter, unlocking whatever that newly earns - a multi-criteria achievement
68
+ * unlocks only on the increment that leaves every one of its criteria met.
46
69
  *
47
70
  * @returns the ids unlocked by exactly this increment, so a game can announce each
48
71
  * one once ("Achievement unlocked: ...") rather than re-scanning everything
49
72
  */
50
73
  increment(counter: string, amount?: number): string[];
51
- /** whether an achievement's counter has reached its target - throws for an unknown id */
74
+ /** whether every one of an achievement's criteria has reached its target - throws for an unknown id */
52
75
  unlocked(id: string): boolean;
53
- /** progress towards an achievement: current count and target - throws for an unknown id */
76
+ /**
77
+ * Progress towards a single-criterion achievement: current count and target - throws for
78
+ * an unknown id or a multi-criteria one (use `subProgress` there instead).
79
+ */
54
80
  progress(id: string): {
55
81
  count: number;
56
82
  target: number;
57
83
  };
84
+ /** progress towards each of an achievement's criteria, in definition order - throws for an unknown id */
85
+ subProgress(id: string): readonly {
86
+ counter: string;
87
+ count: number;
88
+ target: number;
89
+ met: boolean;
90
+ }[];
58
91
  /** every id unlocked but not yet announced, clearing the queue as it reads */
59
92
  drainNew(): string[];
60
93
  toJSON(): {
@@ -1 +1 @@
1
- {"version":3,"file":"Achievements.d.ts","sourceRoot":"","sources":["../../src/core/Achievements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,MAAM,CAAC;IAEX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IAEf,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,YAAY;IACxB,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,MAAM,CAA6B;IAE3C,iFAAiF;IACjF,OAAO,CAAC,KAAK,CAAgB;IAE7B,MAAM,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAEvC;IAED,wEAAwE;IACxE,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,EAAE,CAa/C;IAED,yFAAyF;IACzF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAI5B;IAED,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAItD;IAED,8EAA8E;IAC9E,QAAQ,IAAI,MAAM,EAAE,CAInB;IAED,MAAM,IAAI;QAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,CAEvC;IAED,oGAAoG;IACpG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,GAAG,YAAY,CAMjG;CACD"}
1
+ {"version":3,"file":"Achievements.d.ts","sourceRoot":"","sources":["../../src/core/Achievements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,MAAM,WAAW,oBAAoB;IACpC,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAEhB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,MAAM,CAAC;IAEX,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,mHAAmH;IACnH,QAAQ,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAElC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAUD,qBAAa,YAAY;IACxB,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,MAAM,CAA6B;IAE3C,iFAAiF;IACjF,OAAO,CAAC,KAAK,CAAgB;IAE7B,MAAM,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,CAEvC;IAED,wEAAwE;IACxE,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,EAAE,CAmB/C;IAED,uGAAuG;IACvG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAI5B;IAED;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAMtD;IAED,yGAAyG;IACzG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,CAOnG;IAED,8EAA8E;IAC9E,QAAQ,IAAI,MAAM,EAAE,CAInB;IAED,MAAM,IAAI;QAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,CAEvC;IAED,oGAAoG;IACpG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,GAAG,YAAY,CAMjG;CACD"}