@datamoc/mw_games 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +42 -17
  2. package/dist/actors/Aura.d.ts +29 -0
  3. package/dist/actors/Aura.d.ts.map +1 -0
  4. package/dist/actors/Aura.js +69 -0
  5. package/dist/actors/Aura.js.map +1 -0
  6. package/dist/actors/ItemStatusEffect.d.ts +27 -0
  7. package/dist/actors/ItemStatusEffect.d.ts.map +1 -0
  8. package/dist/actors/ItemStatusEffect.js +35 -0
  9. package/dist/actors/ItemStatusEffect.js.map +1 -0
  10. package/dist/actors/Support.d.ts +32 -0
  11. package/dist/actors/Support.d.ts.map +1 -0
  12. package/dist/actors/Support.js +60 -0
  13. package/dist/actors/Support.js.map +1 -0
  14. package/dist/actors/Traits.d.ts +29 -0
  15. package/dist/actors/Traits.d.ts.map +1 -0
  16. package/dist/actors/Traits.js +21 -0
  17. package/dist/actors/Traits.js.map +1 -0
  18. package/dist/actors/index.d.ts +8 -0
  19. package/dist/actors/index.d.ts.map +1 -1
  20. package/dist/actors/index.js +4 -0
  21. package/dist/actors/index.js.map +1 -1
  22. package/dist/assets/Streaming.d.ts +40 -0
  23. package/dist/assets/Streaming.d.ts.map +1 -0
  24. package/dist/assets/Streaming.js +79 -0
  25. package/dist/assets/Streaming.js.map +1 -0
  26. package/dist/assets/index.d.ts +13 -0
  27. package/dist/assets/index.d.ts.map +1 -1
  28. package/dist/assets/index.js +19 -0
  29. package/dist/assets/index.js.map +1 -1
  30. package/dist/audio/Captions.d.ts +15 -0
  31. package/dist/audio/Captions.d.ts.map +1 -0
  32. package/dist/audio/Captions.js +4 -0
  33. package/dist/audio/Captions.js.map +1 -0
  34. package/dist/audio/Midi.d.ts +75 -0
  35. package/dist/audio/Midi.d.ts.map +1 -0
  36. package/dist/audio/Midi.js +186 -0
  37. package/dist/audio/Midi.js.map +1 -0
  38. package/dist/audio/Orchestrator.d.ts +40 -0
  39. package/dist/audio/Orchestrator.d.ts.map +1 -0
  40. package/dist/audio/Orchestrator.js +48 -0
  41. package/dist/audio/Orchestrator.js.map +1 -0
  42. package/dist/audio/Sound.d.ts +3 -0
  43. package/dist/audio/Sound.d.ts.map +1 -1
  44. package/dist/audio/Sound.js +4 -0
  45. package/dist/audio/Sound.js.map +1 -1
  46. package/dist/audio/Synth.d.ts +35 -0
  47. package/dist/audio/Synth.d.ts.map +1 -0
  48. package/dist/audio/Synth.js +96 -0
  49. package/dist/audio/Synth.js.map +1 -0
  50. package/dist/audio/index.d.ts +8 -0
  51. package/dist/audio/index.d.ts.map +1 -1
  52. package/dist/audio/index.js +4 -0
  53. package/dist/audio/index.js.map +1 -1
  54. package/dist/board/Army.d.ts +17 -0
  55. package/dist/board/Army.d.ts.map +1 -0
  56. package/dist/board/Army.js +48 -0
  57. package/dist/board/Army.js.map +1 -0
  58. package/dist/board/FogOfWar.d.ts +23 -0
  59. package/dist/board/FogOfWar.d.ts.map +1 -0
  60. package/dist/board/FogOfWar.js +40 -0
  61. package/dist/board/FogOfWar.js.map +1 -0
  62. package/dist/board/Tactics.d.ts +2 -0
  63. package/dist/board/Tactics.d.ts.map +1 -1
  64. package/dist/board/Tactics.js +29 -7
  65. package/dist/board/Tactics.js.map +1 -1
  66. package/dist/board/index.d.ts +5 -1
  67. package/dist/board/index.d.ts.map +1 -1
  68. package/dist/board/index.js +3 -1
  69. package/dist/board/index.js.map +1 -1
  70. package/dist/core/Feedback.d.ts +23 -0
  71. package/dist/core/Feedback.d.ts.map +1 -0
  72. package/dist/core/Feedback.js +35 -0
  73. package/dist/core/Feedback.js.map +1 -0
  74. package/dist/core/Game.d.ts +11 -0
  75. package/dist/core/Game.d.ts.map +1 -1
  76. package/dist/core/Game.js +54 -0
  77. package/dist/core/Game.js.map +1 -1
  78. package/dist/core/Input.d.ts +58 -0
  79. package/dist/core/Input.d.ts.map +1 -1
  80. package/dist/core/Input.js +135 -0
  81. package/dist/core/Input.js.map +1 -1
  82. package/dist/core/Loading.d.ts +48 -0
  83. package/dist/core/Loading.d.ts.map +1 -0
  84. package/dist/core/Loading.js +102 -0
  85. package/dist/core/Loading.js.map +1 -0
  86. package/dist/core/News.d.ts +46 -0
  87. package/dist/core/News.d.ts.map +1 -0
  88. package/dist/core/News.js +79 -0
  89. package/dist/core/News.js.map +1 -0
  90. package/dist/core/PlayerInput.d.ts +38 -0
  91. package/dist/core/PlayerInput.d.ts.map +1 -0
  92. package/dist/core/PlayerInput.js +57 -0
  93. package/dist/core/PlayerInput.js.map +1 -0
  94. package/dist/core/RunHistory.d.ts +43 -0
  95. package/dist/core/RunHistory.d.ts.map +1 -0
  96. package/dist/core/RunHistory.js +41 -0
  97. package/dist/core/RunHistory.js.map +1 -0
  98. package/dist/core/Sanitize.d.ts +56 -0
  99. package/dist/core/Sanitize.d.ts.map +1 -0
  100. package/dist/core/Sanitize.js +87 -0
  101. package/dist/core/Sanitize.js.map +1 -0
  102. package/dist/core/Save.d.ts +31 -7
  103. package/dist/core/Save.d.ts.map +1 -1
  104. package/dist/core/Save.js +56 -0
  105. package/dist/core/Save.js.map +1 -1
  106. package/dist/core/SaveSync.d.ts +26 -0
  107. package/dist/core/SaveSync.d.ts.map +1 -0
  108. package/dist/core/SaveSync.js +52 -0
  109. package/dist/core/SaveSync.js.map +1 -0
  110. package/dist/core/Scramble.d.ts +13 -0
  111. package/dist/core/Scramble.d.ts.map +1 -0
  112. package/dist/core/Scramble.js +44 -0
  113. package/dist/core/Scramble.js.map +1 -0
  114. package/dist/core/Spawner.d.ts +48 -0
  115. package/dist/core/Spawner.d.ts.map +1 -0
  116. package/dist/core/Spawner.js +65 -0
  117. package/dist/core/Spawner.js.map +1 -0
  118. package/dist/core/Tween.d.ts +25 -0
  119. package/dist/core/Tween.d.ts.map +1 -0
  120. package/dist/core/Tween.js +60 -0
  121. package/dist/core/Tween.js.map +1 -0
  122. package/dist/core/UndoHistory.d.ts +37 -0
  123. package/dist/core/UndoHistory.d.ts.map +1 -0
  124. package/dist/core/UndoHistory.js +49 -0
  125. package/dist/core/UndoHistory.js.map +1 -0
  126. package/dist/core/index.d.ts +20 -0
  127. package/dist/core/index.d.ts.map +1 -1
  128. package/dist/core/index.js +11 -0
  129. package/dist/core/index.js.map +1 -1
  130. package/dist/i18n/Fluent.d.ts +7 -0
  131. package/dist/i18n/Fluent.d.ts.map +1 -0
  132. package/dist/i18n/Fluent.js +86 -0
  133. package/dist/i18n/Fluent.js.map +1 -0
  134. package/dist/i18n/index.d.ts +15 -1
  135. package/dist/i18n/index.d.ts.map +1 -1
  136. package/dist/i18n/index.js +17 -2
  137. package/dist/i18n/index.js.map +1 -1
  138. package/dist/index.d.ts +1 -0
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +1 -0
  141. package/dist/index.js.map +1 -1
  142. package/dist/mw_games.global.js +351 -79
  143. package/dist/render/Camera.d.ts +29 -2
  144. package/dist/render/Camera.d.ts.map +1 -1
  145. package/dist/render/Camera.js +40 -11
  146. package/dist/render/Camera.js.map +1 -1
  147. package/dist/render/Capabilities.d.ts +51 -0
  148. package/dist/render/Capabilities.d.ts.map +1 -0
  149. package/dist/render/Capabilities.js +56 -0
  150. package/dist/render/Capabilities.js.map +1 -0
  151. package/dist/render/ColorBlindness.d.ts +16 -0
  152. package/dist/render/ColorBlindness.d.ts.map +1 -0
  153. package/dist/render/ColorBlindness.js +41 -0
  154. package/dist/render/ColorBlindness.js.map +1 -0
  155. package/dist/render/Minimap.d.ts +52 -0
  156. package/dist/render/Minimap.d.ts.map +1 -0
  157. package/dist/render/Minimap.js +95 -0
  158. package/dist/render/Minimap.js.map +1 -0
  159. package/dist/render/Viewport.d.ts +46 -0
  160. package/dist/render/Viewport.d.ts.map +1 -0
  161. package/dist/render/Viewport.js +52 -0
  162. package/dist/render/Viewport.js.map +1 -0
  163. package/dist/render/index.d.ts +9 -1
  164. package/dist/render/index.d.ts.map +1 -1
  165. package/dist/render/index.js +5 -1
  166. package/dist/render/index.js.map +1 -1
  167. package/dist/roguelike/Stealth.d.ts +34 -0
  168. package/dist/roguelike/Stealth.d.ts.map +1 -0
  169. package/dist/roguelike/Stealth.js +35 -0
  170. package/dist/roguelike/Stealth.js.map +1 -0
  171. package/dist/roguelike/index.d.ts +2 -0
  172. package/dist/roguelike/index.d.ts.map +1 -1
  173. package/dist/roguelike/index.js +1 -0
  174. package/dist/roguelike/index.js.map +1 -1
  175. package/dist/rpg/Collision.d.ts +42 -0
  176. package/dist/rpg/Collision.d.ts.map +1 -0
  177. package/dist/rpg/Collision.js +77 -0
  178. package/dist/rpg/Collision.js.map +1 -0
  179. package/dist/rpg/FreeMover.d.ts +45 -0
  180. package/dist/rpg/FreeMover.d.ts.map +1 -0
  181. package/dist/rpg/FreeMover.js +68 -0
  182. package/dist/rpg/FreeMover.js.map +1 -0
  183. package/dist/rpg/Marshal.d.ts +65 -0
  184. package/dist/rpg/Marshal.d.ts.map +1 -0
  185. package/dist/rpg/Marshal.js +393 -0
  186. package/dist/rpg/Marshal.js.map +1 -0
  187. package/dist/rpg/Quest.d.ts +41 -0
  188. package/dist/rpg/Quest.d.ts.map +1 -1
  189. package/dist/rpg/Quest.js +39 -6
  190. package/dist/rpg/Quest.js.map +1 -1
  191. package/dist/rpg/index.d.ts +7 -1
  192. package/dist/rpg/index.d.ts.map +1 -1
  193. package/dist/rpg/index.js +3 -0
  194. package/dist/rpg/index.js.map +1 -1
  195. package/dist/stage/DialogueStage.d.ts +1 -2
  196. package/dist/stage/DialogueStage.d.ts.map +1 -1
  197. package/dist/stage/DialogueStage.js +7 -22
  198. package/dist/stage/DialogueStage.js.map +1 -1
  199. package/dist/stage/index.d.ts +1 -1
  200. package/dist/stage/index.d.ts.map +1 -1
  201. package/dist/stage/script.d.ts +29 -0
  202. package/dist/stage/script.d.ts.map +1 -1
  203. package/dist/stage/script.js +0 -0
  204. package/dist/stage/script.js.map +1 -1
  205. package/dist/three-d/Character3D.d.ts +48 -0
  206. package/dist/three-d/Character3D.d.ts.map +1 -0
  207. package/dist/three-d/Character3D.js +96 -0
  208. package/dist/three-d/Character3D.js.map +1 -0
  209. package/dist/three-d/Engine3D.d.ts +23 -0
  210. package/dist/three-d/Engine3D.d.ts.map +1 -0
  211. package/dist/three-d/Engine3D.js +45 -0
  212. package/dist/three-d/Engine3D.js.map +1 -0
  213. package/dist/three-d/Grid.d.ts +14 -0
  214. package/dist/three-d/Grid.d.ts.map +1 -0
  215. package/dist/three-d/Grid.js +13 -0
  216. package/dist/three-d/Grid.js.map +1 -0
  217. package/dist/three-d/Heightmap.d.ts +35 -0
  218. package/dist/three-d/Heightmap.d.ts.map +1 -0
  219. package/dist/three-d/Heightmap.js +29 -0
  220. package/dist/three-d/Heightmap.js.map +1 -0
  221. package/dist/three-d/Models.d.ts +12 -0
  222. package/dist/three-d/Models.d.ts.map +1 -0
  223. package/dist/three-d/Models.js +14 -0
  224. package/dist/three-d/Models.js.map +1 -0
  225. package/dist/three-d/TileGrid3D.d.ts +21 -0
  226. package/dist/three-d/TileGrid3D.d.ts.map +1 -0
  227. package/dist/three-d/TileGrid3D.js +65 -0
  228. package/dist/three-d/TileGrid3D.js.map +1 -0
  229. package/dist/three-d/Vox.d.ts +24 -0
  230. package/dist/three-d/Vox.d.ts.map +1 -0
  231. package/dist/three-d/Vox.js +93 -0
  232. package/dist/three-d/Vox.js.map +1 -0
  233. package/dist/three-d/index.d.ts +13 -0
  234. package/dist/three-d/index.d.ts.map +1 -0
  235. package/dist/three-d/index.js +7 -0
  236. package/dist/three-d/index.js.map +1 -0
  237. package/dist/ui/Bar.d.ts +49 -0
  238. package/dist/ui/Bar.d.ts.map +1 -0
  239. package/dist/ui/Bar.js +70 -0
  240. package/dist/ui/Bar.js.map +1 -0
  241. package/dist/ui/BitmapLabel.d.ts +42 -0
  242. package/dist/ui/BitmapLabel.d.ts.map +1 -0
  243. package/dist/ui/BitmapLabel.js +59 -0
  244. package/dist/ui/BitmapLabel.js.map +1 -0
  245. package/dist/ui/Button.d.ts +52 -0
  246. package/dist/ui/Button.d.ts.map +1 -0
  247. package/dist/ui/Button.js +147 -0
  248. package/dist/ui/Button.js.map +1 -0
  249. package/dist/ui/FloatingText.d.ts +28 -0
  250. package/dist/ui/FloatingText.d.ts.map +1 -0
  251. package/dist/ui/FloatingText.js +39 -0
  252. package/dist/ui/FloatingText.js.map +1 -0
  253. package/dist/ui/HelpScreen.d.ts +29 -0
  254. package/dist/ui/HelpScreen.d.ts.map +1 -0
  255. package/dist/ui/HelpScreen.js +39 -0
  256. package/dist/ui/HelpScreen.js.map +1 -0
  257. package/dist/ui/IconGrid.d.ts +8 -0
  258. package/dist/ui/IconGrid.d.ts.map +1 -1
  259. package/dist/ui/IconGrid.js +27 -1
  260. package/dist/ui/IconGrid.js.map +1 -1
  261. package/dist/ui/Label.d.ts +9 -0
  262. package/dist/ui/Label.d.ts.map +1 -1
  263. package/dist/ui/Label.js +24 -1
  264. package/dist/ui/Label.js.map +1 -1
  265. package/dist/ui/ListView.d.ts +11 -0
  266. package/dist/ui/ListView.d.ts.map +1 -1
  267. package/dist/ui/ListView.js +55 -1
  268. package/dist/ui/ListView.js.map +1 -1
  269. package/dist/ui/LoadingScreen.d.ts +31 -0
  270. package/dist/ui/LoadingScreen.d.ts.map +1 -0
  271. package/dist/ui/LoadingScreen.js +60 -0
  272. package/dist/ui/LoadingScreen.js.map +1 -0
  273. package/dist/ui/MessageBox.d.ts +26 -0
  274. package/dist/ui/MessageBox.d.ts.map +1 -1
  275. package/dist/ui/MessageBox.js +62 -13
  276. package/dist/ui/MessageBox.js.map +1 -1
  277. package/dist/ui/RebindScreen.d.ts +55 -0
  278. package/dist/ui/RebindScreen.d.ts.map +1 -0
  279. package/dist/ui/RebindScreen.js +114 -0
  280. package/dist/ui/RebindScreen.js.map +1 -0
  281. package/dist/ui/Toast.d.ts +44 -0
  282. package/dist/ui/Toast.d.ts.map +1 -0
  283. package/dist/ui/Toast.js +89 -0
  284. package/dist/ui/Toast.js.map +1 -0
  285. package/dist/ui/VerticalLabel.d.ts +5 -0
  286. package/dist/ui/VerticalLabel.d.ts.map +1 -1
  287. package/dist/ui/VerticalLabel.js +18 -7
  288. package/dist/ui/VerticalLabel.js.map +1 -1
  289. package/dist/ui/Window.d.ts +6 -0
  290. package/dist/ui/Window.d.ts.map +1 -1
  291. package/dist/ui/Window.js +16 -1
  292. package/dist/ui/Window.js.map +1 -1
  293. package/dist/ui/WindowStack.d.ts +1 -0
  294. package/dist/ui/WindowStack.d.ts.map +1 -1
  295. package/dist/ui/WindowStack.js +4 -1
  296. package/dist/ui/WindowStack.js.map +1 -1
  297. package/dist/ui/index.d.ts +17 -1
  298. package/dist/ui/index.d.ts.map +1 -1
  299. package/dist/ui/index.js +9 -1
  300. package/dist/ui/index.js.map +1 -1
  301. package/dist/ui/theme.d.ts +21 -0
  302. package/dist/ui/theme.d.ts.map +1 -1
  303. package/dist/ui/theme.js +42 -0
  304. package/dist/ui/theme.js.map +1 -1
  305. package/dist/version.d.ts +13 -0
  306. package/dist/version.d.ts.map +1 -0
  307. package/dist/version.js +13 -0
  308. package/dist/version.js.map +1 -0
  309. package/dist/world/Environment.d.ts +35 -0
  310. package/dist/world/Environment.d.ts.map +1 -0
  311. package/dist/world/Environment.js +55 -0
  312. package/dist/world/Environment.js.map +1 -0
  313. package/dist/world/index.d.ts +2 -0
  314. package/dist/world/index.d.ts.map +1 -1
  315. package/dist/world/index.js +1 -0
  316. package/dist/world/index.js.map +1 -1
  317. package/package.json +40 -4
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # mwg
2
2
 
3
- A framework for building 2D top-down games that run **from a local file**: no server, no
4
- install, no runtime to download.
3
+ A framework for building primarily 2D top-down games that run **from a local file**: no
4
+ server, no install, no runtime to download. An optional Babylon.js module supports 3D maps.
5
5
 
6
6
  Licensed under the [MPL-2.0](LICENSE): games built with `mwg` carry no licence obligation
7
7
  of their own; improvements to `mwg`'s own files are shared back.
@@ -9,8 +9,10 @@ of their own; improvements to `mwg`'s own files are shared back.
9
9
  **[Live examples and API docs](https://datamoc.github.io/mwg/)**: every example below,
10
10
  playable in the browser with no download, plus the generated API reference.
11
11
 
12
- > **Status: early.** The scaffolding, licence and capability spec are in place. The
13
- > modules below are being built in the order given in [ROADMAP.md](ROADMAP.md).
12
+ > **Status: early release (v0.2.0).** Every module in the shared floor below, plus optional
13
+ > 3D, mobile (Capacitor) and desktop (WebView2) packaging, is built and tested - see
14
+ > [ROADMAP.md](ROADMAP.md) for the full, numbered history. Still `0.y.z`: the "public API"
15
+ > can still change between minor versions, and the wider genre-specific modules keep growing.
14
16
 
15
17
  ## What it is for
16
18
 
@@ -39,7 +41,8 @@ four directions on a square grid and another in six on a hex grid.
39
41
 
40
42
  `mwg` provides that shared floor plus each specialism, on top of
41
43
  [PixiJS](https://pixijs.com) for rendering and [rot.js](https://ondras.github.io/rot.js/)
42
- for the classic roguelike algorithms. See [Capability spec](#capability-spec).
44
+ for the classic roguelike algorithms. Optional 3D scenes use Babylon.js. See
45
+ [Capability spec](#capability-spec).
43
46
 
44
47
  These are references for *what a finished game of each kind has to do*, and nothing more.
45
48
  No code, asset, data table or file format is taken from any of them: see
@@ -139,6 +142,7 @@ only some do.
139
142
  | | pointer, keyboard and gamepad input with rebinding | `mwg/core` |
140
143
  | **text** | message tables per language, compiled at build time | `mwg/i18n` |
141
144
  | | plurals, gendered forms and interpolation | `mwg/i18n` |
145
+ | | Fluent-style FTL catalogs with locale-aware fallback and variants | `mwg/i18n` |
142
146
  | | left-to-right, right-to-left and vertical writing | `mwg/i18n` |
143
147
  | | interface mirrored for right-to-left languages | `mwg/ui` |
144
148
  | | a missing translation falls back rather than showing a key | `mwg/i18n` |
@@ -173,9 +177,10 @@ The Wesnoth-shaped half: a grid whose shape is a parameter, not a parallel imple
173
177
  | --- | --- |
174
178
  | hexagonal tile maps, addressed by axial or offset coordinates | `mwg/render` |
175
179
  | movement cost and defense bonus by terrain, hex or square alike | `mwg/roguelike` |
176
- | zone of control: a hex a unit cannot move through, only into | `mwg/roguelike` |
177
180
  | field of view and pathfinding over a hex grid, not just square | `mwg/roguelike` |
178
181
  | isometric (and staggered) projection, alongside orthogonal and hex | `mwg/render` |
182
+ | zone of control: a hex a unit can only move into, not through, unless already engaged | `mwg/board` |
183
+ | an army economy: recruiting against a currency, recalling from a pool, per-turn upkeep | `mwg/board` |
179
184
 
180
185
  A game picks a grid shape once; the camera, field of view, pathfinding and turn scheduler
181
186
  work the same way over either, rather than a hex game needing its own copy of each. Between
@@ -286,18 +291,34 @@ Message tables are compiled at build time, the same way every other resource is,
286
291
  a language costs nothing at runtime and a missing string falls back to the base language
287
292
  rather than showing a raw key to the player.
288
293
 
294
+ ## Optional Babylon.js 3D
295
+
296
+ `@babylonjs/core`/`@babylonjs/loaders` are peer dependencies, not installed automatically -
297
+ a game that never imports `mwg/3d` never downloads Babylon.js. Add them yourself
298
+ (`npm install @babylonjs/core @babylonjs/loaders`) once a game imports 3D support:
299
+
300
+ ```ts
301
+ import { Engine3D, createTileGrid3D } from '@datamoc/mw_games/3d';
302
+ import { loadModel3D } from '@datamoc/mw_games/3d/models';
303
+ ```
304
+
305
+ `Engine3D` owns a WebGL scene, orbit camera, light, resize handling, and render loop.
306
+ `createTileGrid3D` batches square or flat-top hex tiles and elevation columns with thin
307
+ instances; `createHeightmapTerrain3D` builds continuous terrain from decoded RGBA heightmap
308
+ pixels. `Character3D` moves imported meshes or camera-facing sprites continuously, and can
309
+ play imported animation clips. `parseVox` and `createVoxModel3D` load one MagicaVoxel model;
310
+ `loadModel3D` handles glTF/GLB.
311
+ Run `npm run example:3d` for the live example or `npm run benchmark:3d` for its FPS gate.
312
+
289
313
  ## Roadmap
290
314
 
291
- See [ROADMAP.md](ROADMAP.md) for the full, numbered build order: 85 items, 74 shipped and
292
- eleven open (3D rendering broken into a nine-step build-up plus an engine choice, all
293
- logged at low priority; see that file for why). Each module ships in the order given there;
294
- later ones build on the
295
- modules before them.
315
+ See [ROADMAP.md](ROADMAP.md) for the full, numbered build order and implementation notes.
316
+ The optional 3D group is now implemented without changing the existing 2D entry point.
296
317
 
297
318
  ## Licence and provenance
298
319
 
299
- `mwg` is MPL-2.0. Its dependencies are permissive and compatible: PixiJS is MIT, rot.js is
300
- BSD-3-Clause.
320
+ `mwg` is MPL-2.0. Its dependencies are permissive and compatible: PixiJS and Babylon.js are
321
+ MIT, and rot.js is BSD-3-Clause.
301
322
 
302
323
  `tools/vendored/rgssad-wasm` is a build of the `rgssad-wasm` crate from
303
324
  <https://github.com/nathaniel-daniel/rgssad-rs>, used under its MIT licence
@@ -313,10 +334,14 @@ finished branching dungeon each have to do. None of their code, assets, maps, un
313
334
  definitions or text is included here, and `mwg` is not a derivative work of any of them.
314
335
 
315
336
  ADOM, RPG Maker, Pokémon, Ren'Py and Twine are likewise references for a *shape of game*, not
316
- sources of anything. `mwg` implements none of their file formats, reads none of their projects or save
317
- data, and includes none of their runtimes, assets, text or data tables: no type chart, no
318
- species list, no stat formula. Those are each game's own design work. Where a file format
319
- is needed, `mwg` uses Tiled's, which is open and documented.
337
+ sources of anything. `mwg` includes none of their runtimes, assets, text or data tables: no
338
+ type chart, no species list, no stat formula, no map, no line of dialogue. Those are each
339
+ game's own design work. A loader or writer for one of their file formats is a different
340
+ matter and is not off limits on its own: a format is a container, understood the same way
341
+ any published format is, by reading real files in it to learn its shape; what stays out is
342
+ the media that container holds, someone else's actual assets, text or data tables. Where a
343
+ format already exists and needs no reverse-engineering, `mwg` uses Tiled's, which is open
344
+ and documented.
320
345
 
321
346
  Game mechanics are not themselves protected, which is why a framework may offer "a turn
322
347
  queue ordered by speed" or "an effectiveness matrix". Particular numbers, names and
@@ -0,0 +1,29 @@
1
+ import { StatBlock, type Modifier } from './StatBlock.ts';
2
+ /** "adjacent allies fight better while this unit is nearby" - the modifiers, not the radius */
3
+ export interface AuraDef {
4
+ name: string;
5
+ modifiers: readonly Omit<Modifier, 'source'>[];
6
+ }
7
+ /** anyone who might carry or receive an aura; `aura` absent or `null` means "carries none" */
8
+ export interface AuraParticipant {
9
+ stats: StatBlock;
10
+ aura?: AuraDef | null;
11
+ }
12
+ /**
13
+ * Continuously reapplies auras as who is adjacent to whom changes, unlike `battle.BattleHooks`
14
+ * (triggered once) or `actors.StatusEffect` (expires on a timer) - neither re-checks "is a
15
+ * qualifying unit still adjacent" on its own, which is exactly what a positional aura needs
16
+ * every time anyone moves.
17
+ *
18
+ * Call `update` once per relevant tick with the full roster and an adjacency test; "adjacent"
19
+ * is deliberately left to the caller (square grid, hex grid, board-tactics neighbours all mean
20
+ * something different) rather than assumed here. Each call diffs against who was affected by
21
+ * each carrier last time: a unit that just became adjacent gets the carrier's modifiers added,
22
+ * one that just left loses exactly those modifiers, and one that stays adjacent is left alone
23
+ * rather than having its modifiers reapplied on every tick.
24
+ */
25
+ export declare class AuraField {
26
+ private affected;
27
+ update(participants: readonly AuraParticipant[], isAdjacent: (a: AuraParticipant, b: AuraParticipant) => boolean): void;
28
+ }
29
+ //# sourceMappingURL=Aura.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Aura.d.ts","sourceRoot":"","sources":["../../src/actors/Aura.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1D,+FAA+F;AAC/F,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;CAC/C;AAED,8FAA8F;AAC9F,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,SAAS;IAGrB,OAAO,CAAC,QAAQ,CAA4D;IAE5E,MAAM,CAAC,YAAY,EAAE,SAAS,eAAe,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,KAAK,OAAO,GAAG,IAAI,CA6CtH;CACD"}
@@ -0,0 +1,69 @@
1
+ import { StatBlock } from './StatBlock.js';
2
+ /**
3
+ * Continuously reapplies auras as who is adjacent to whom changes, unlike `battle.BattleHooks`
4
+ * (triggered once) or `actors.StatusEffect` (expires on a timer) - neither re-checks "is a
5
+ * qualifying unit still adjacent" on its own, which is exactly what a positional aura needs
6
+ * every time anyone moves.
7
+ *
8
+ * Call `update` once per relevant tick with the full roster and an adjacency test; "adjacent"
9
+ * is deliberately left to the caller (square grid, hex grid, board-tactics neighbours all mean
10
+ * something different) rather than assumed here. Each call diffs against who was affected by
11
+ * each carrier last time: a unit that just became adjacent gets the carrier's modifiers added,
12
+ * one that just left loses exactly those modifiers, and one that stays adjacent is left alone
13
+ * rather than having its modifiers reapplied on every tick.
14
+ */
15
+ export class AuraField {
16
+ constructor() {
17
+ //per carrier, which participants currently carry that carrier's modifiers and under
18
+ //what source symbol - a unit inside two carriers' auras at once tracks both independently
19
+ this.affected = new Map();
20
+ }
21
+ update(participants, isAdjacent) {
22
+ const roster = new Set(participants);
23
+ const carriers = participants.filter((p) => !!p.aura);
24
+ const carrierSet = new Set(carriers);
25
+ for (const carrier of carriers) {
26
+ let currentlyAffected = this.affected.get(carrier);
27
+ if (!currentlyAffected) {
28
+ currentlyAffected = new Map();
29
+ this.affected.set(carrier, currentlyAffected);
30
+ }
31
+ for (const other of participants) {
32
+ if (other === carrier)
33
+ continue;
34
+ const adjacent = isAdjacent(carrier, other);
35
+ const source = currentlyAffected.get(other);
36
+ if (adjacent && !source) {
37
+ const newSource = Symbol(`aura:${carrier.aura.name}`);
38
+ for (const modifier of carrier.aura.modifiers)
39
+ other.stats.addModifier({ ...modifier, source: newSource });
40
+ currentlyAffected.set(other, newSource);
41
+ }
42
+ else if (!adjacent && source) {
43
+ other.stats.removeModifiersFrom(source);
44
+ currentlyAffected.delete(other);
45
+ }
46
+ }
47
+ //a target affected last call but absent from this call's roster entirely (died,
48
+ //was removed) is never visited by the loop above, since that only walks
49
+ //`participants` - left alone, its modifiers and its own strong reference here
50
+ //would both persist forever
51
+ for (const [other, source] of [...currentlyAffected]) {
52
+ if (roster.has(other))
53
+ continue;
54
+ other.stats.removeModifiersFrom(source);
55
+ currentlyAffected.delete(other);
56
+ }
57
+ }
58
+ //a carrier that died, lost its aura, or simply is not in this call's roster any more
59
+ //stops affecting anyone it was still affecting, rather than leaving stale modifiers
60
+ for (const [carrier, currentlyAffected] of [...this.affected]) {
61
+ if (carrierSet.has(carrier))
62
+ continue;
63
+ for (const [other, source] of currentlyAffected)
64
+ other.stats.removeModifiersFrom(source);
65
+ this.affected.delete(carrier);
66
+ }
67
+ }
68
+ }
69
+ //# sourceMappingURL=Aura.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Aura.js","sourceRoot":"","sources":["../../src/actors/Aura.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AAc1D;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,SAAS;IAAtB;QACC,oFAAoF;QACpF,0FAA0F;QAClF,aAAQ,GAAG,IAAI,GAAG,EAAiD,CAAC;IAgD7E,CAAC;IA9CA,MAAM,CAAC,YAAwC,EAAE,UAA+D;QAC/G,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAA4C,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChG,MAAM,UAAU,GAAG,IAAI,GAAG,CAAkB,QAAQ,CAAC,CAAC;QAEtD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAChC,IAAI,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACnD,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACxB,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAC;gBAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;YAC/C,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBAClC,IAAI,KAAK,KAAK,OAAO;oBAAE,SAAS;gBAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAE5C,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;oBACzB,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBACtD,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS;wBAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;oBAC3G,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;gBACzC,CAAC;qBAAM,IAAI,CAAC,QAAQ,IAAI,MAAM,EAAE,CAAC;oBAChC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;oBACxC,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACjC,CAAC;YACF,CAAC;YAED,gFAAgF;YAChF,wEAAwE;YACxE,8EAA8E;YAC9E,4BAA4B;YAC5B,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,EAAE,CAAC;gBACtD,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBAChC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;gBACxC,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;QACF,CAAC;QAED,qFAAqF;QACrF,oFAAoF;QACpF,KAAK,MAAM,CAAC,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/D,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YACtC,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,iBAAiB;gBAAE,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YACzF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACF,CAAC;CACD"}
@@ -0,0 +1,27 @@
1
+ import type { EffectClock } from './StatusEffect.ts';
2
+ export interface ItemStatusEffectOptions<T> {
3
+ /** fields applied to the item for the duration, restored to their prior value on expiry */
4
+ fields: Partial<T>;
5
+ /** turns until the fields are restored */
6
+ duration: number;
7
+ /** called once per turn the effect is active, such as a poison coating's own tick */
8
+ tick?: (turn: number) => void;
9
+ }
10
+ /** ends an `ItemStatusEffect` early, restoring the item's fields immediately rather than at expiry */
11
+ export interface ItemStatusEffectHandle {
12
+ cancel(): void;
13
+ }
14
+ /**
15
+ * A temporary status on an item itself - a weapon coated in poison for a fixed number of
16
+ * turns, a shield reinforced until it wears off, a ring blessed only "for this floor" - the
17
+ * item-targeted counterpart to `applyStatusEffect`, which only ever targets a `StatBlock`.
18
+ * Today's item-level fields (`cursed`, `blessed`, `level`, `affix`) are all permanent until
19
+ * a game explicitly changes them; this is what expires one instead.
20
+ *
21
+ * Applies `fields` onto `item`, remembering each field's prior value (not merely deleting
22
+ * it), and restores exactly that value once `clock` expires the effect or `cancel()` is
23
+ * called early - the same "never has to remember to remove what it added" guarantee
24
+ * `applyStatusEffect` already gives a `StatBlock`.
25
+ */
26
+ export declare function applyItemStatusEffect<T extends object>(item: T, clock: EffectClock, options: ItemStatusEffectOptions<T>): ItemStatusEffectHandle;
27
+ //# sourceMappingURL=ItemStatusEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemStatusEffect.d.ts","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACzC,2FAA2F;IAC3F,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IAEjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,sGAAsG;AACtG,MAAM,WAAW,sBAAsB;IACtC,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACrD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,sBAAsB,CAuBxB"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A temporary status on an item itself - a weapon coated in poison for a fixed number of
3
+ * turns, a shield reinforced until it wears off, a ring blessed only "for this floor" - the
4
+ * item-targeted counterpart to `applyStatusEffect`, which only ever targets a `StatBlock`.
5
+ * Today's item-level fields (`cursed`, `blessed`, `level`, `affix`) are all permanent until
6
+ * a game explicitly changes them; this is what expires one instead.
7
+ *
8
+ * Applies `fields` onto `item`, remembering each field's prior value (not merely deleting
9
+ * it), and restores exactly that value once `clock` expires the effect or `cancel()` is
10
+ * called early - the same "never has to remember to remove what it added" guarantee
11
+ * `applyStatusEffect` already gives a `StatBlock`.
12
+ */
13
+ export function applyItemStatusEffect(item, clock, options) {
14
+ const previous = new Map();
15
+ for (const key of Object.keys(options.fields)) {
16
+ previous.set(key, item[key]);
17
+ item[key] = options.fields[key];
18
+ }
19
+ const restore = () => {
20
+ for (const [key, value] of previous)
21
+ item[key] = value;
22
+ };
23
+ const id = clock.add({
24
+ duration: options.duration,
25
+ tick: (turn) => options.tick?.(turn),
26
+ onExpire: restore,
27
+ });
28
+ return {
29
+ cancel: () => {
30
+ clock.remove(id);
31
+ restore();
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=ItemStatusEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemStatusEffect.js","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAO,EACP,KAAkB,EAClB,OAAmC;IAEnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAgB,EAAE,CAAC;QAC9D,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAe,CAAC;IAC/C,CAAC;IAED,MAAM,OAAO,GAAG,GAAS,EAAE;QAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;QACpC,QAAQ,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,OAAO;QACN,MAAM,EAAE,GAAG,EAAE;YACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjB,OAAO,EAAE,CAAC;QACX,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ /** A thresholded bond level between two named units. */
2
+ export interface SupportLevel {
3
+ id: string;
4
+ threshold: number;
5
+ /** Optional game-facing bonus or dialogue key unlocked at this level. */
6
+ bonus?: string;
7
+ }
8
+ export interface SupportChange {
9
+ a: string;
10
+ b: string;
11
+ points: number;
12
+ previousLevel: SupportLevel | null;
13
+ level: SupportLevel | null;
14
+ }
15
+ export interface SupportSave {
16
+ pairs: Array<[string, string, number]>;
17
+ }
18
+ /**
19
+ * Stores persistent progress for a relationship between a specific pair of units.
20
+ * Pair order is ignored, so `add('alice', 'bob', 1)` and the reverse address one bond.
21
+ */
22
+ export declare class SupportLedger {
23
+ private levels;
24
+ private points;
25
+ constructor(levels: readonly SupportLevel[]);
26
+ get(a: string, b: string): number;
27
+ level(a: string, b: string): SupportLevel | null;
28
+ add(a: string, b: string, amount: number): SupportChange;
29
+ save(): SupportSave;
30
+ static restore(levels: readonly SupportLevel[], data: SupportSave): SupportLedger;
31
+ }
32
+ //# sourceMappingURL=Support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Support.d.ts","sourceRoot":"","sources":["../../src/actors/Support.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACvC;AAED;;;GAGG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAA6B;IAE3C,YAAY,MAAM,EAAE,SAAS,YAAY,EAAE,EAK1C;IAED,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhC;IAED,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQ/C;IAED,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAQvD;IAED,IAAI,IAAI,WAAW,CAMlB;IAED,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,GAAG,aAAa,CAShF;CACD"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Stores persistent progress for a relationship between a specific pair of units.
3
+ * Pair order is ignored, so `add('alice', 'bob', 1)` and the reverse address one bond.
4
+ */
5
+ export class SupportLedger {
6
+ constructor(levels) {
7
+ this.points = new Map();
8
+ if (levels.some((level) => !level.id || !Number.isFinite(level.threshold) || level.threshold < 0)) {
9
+ throw new Error('support levels need an id and a non-negative threshold');
10
+ }
11
+ this.levels = [...levels].sort((a, b) => a.threshold - b.threshold);
12
+ }
13
+ get(a, b) {
14
+ return this.points.get(pairKey(a, b)) ?? 0;
15
+ }
16
+ level(a, b) {
17
+ const points = this.get(a, b);
18
+ let found = null;
19
+ for (const level of this.levels) {
20
+ if (level.threshold > points)
21
+ break;
22
+ found = level;
23
+ }
24
+ return found;
25
+ }
26
+ add(a, b, amount) {
27
+ if (!a || !b || a === b)
28
+ throw new Error('support needs two different named units');
29
+ if (!Number.isFinite(amount))
30
+ throw new Error(`support amount must be finite, got ${amount}`);
31
+ const previousLevel = this.level(a, b);
32
+ const key = pairKey(a, b);
33
+ const points = Math.max(0, (this.points.get(key) ?? 0) + amount);
34
+ this.points.set(key, points);
35
+ return { a, b, points, previousLevel, level: this.level(a, b) };
36
+ }
37
+ save() {
38
+ const pairs = [...this.points].map(([key, points]) => {
39
+ const [a, b] = key.split('\u0000');
40
+ return [a, b, points];
41
+ });
42
+ return { pairs };
43
+ }
44
+ static restore(levels, data) {
45
+ const ledger = new SupportLedger(levels);
46
+ for (const [a, b, points] of data.pairs) {
47
+ if (!a || !b || a === b || !Number.isFinite(points) || points < 0)
48
+ throw new Error('invalid support save data');
49
+ const key = pairKey(a, b);
50
+ if (ledger.points.has(key))
51
+ throw new Error(`invalid support save data: duplicate pair "${a}" / "${b}"`);
52
+ ledger.points.set(key, points);
53
+ }
54
+ return ledger;
55
+ }
56
+ }
57
+ function pairKey(a, b) {
58
+ return [a, b].sort().join('\u0000');
59
+ }
60
+ //# sourceMappingURL=Support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Support.js","sourceRoot":"","sources":["../../src/actors/Support.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { StatBlock, type Modifier } from './StatBlock.ts';
2
+ /**
3
+ * One entry in a shared pool a creature or unit can draw from at creation - "born strong",
4
+ * "nocturnal", "unlucky". Distinct from `actors.Affix` (item-side, one per item, weight-picked
5
+ * at generation) and `StatusEffect` (temporary, expires): a trait is permanent once assigned,
6
+ * never chosen by the player, and belongs to the creature rather than anything it carries.
7
+ */
8
+ export interface TraitDef {
9
+ name: string;
10
+ modifiers: readonly Omit<Modifier, 'source'>[];
11
+ /** shown in a character sheet; `mwg` never reads this itself */
12
+ description?: string;
13
+ }
14
+ /** an assigned trait's modifiers can be found again later via `removeModifiersFrom` */
15
+ export interface AssignedTrait {
16
+ trait: TraitDef;
17
+ source: symbol;
18
+ }
19
+ /**
20
+ * Draws `count` distinct traits at random from `pool` and applies their modifiers to `stats`
21
+ * permanently - no clock, no trigger, nothing removes them automatically. Each trait gets its
22
+ * own `source` symbol so a game that genuinely needs to strip one later still can, via
23
+ * `StatBlock.removeModifiersFrom`, even though nothing here ever calls that itself.
24
+ *
25
+ * @param count clamped to `pool.length` - asking for more traits than exist in the pool
26
+ * assigns every one of them rather than throwing
27
+ */
28
+ export declare function assignTraits(stats: StatBlock, pool: readonly TraitDef[], count: number): AssignedTrait[];
29
+ //# sourceMappingURL=Traits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Traits.d.ts","sourceRoot":"","sources":["../../src/actors/Traits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1D;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IAE/C,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uFAAuF;AACvF,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAOxG"}
@@ -0,0 +1,21 @@
1
+ import { StatBlock } from './StatBlock.js';
2
+ import * as Random from '../core/Random.js';
3
+ /**
4
+ * Draws `count` distinct traits at random from `pool` and applies their modifiers to `stats`
5
+ * permanently - no clock, no trigger, nothing removes them automatically. Each trait gets its
6
+ * own `source` symbol so a game that genuinely needs to strip one later still can, via
7
+ * `StatBlock.removeModifiersFrom`, even though nothing here ever calls that itself.
8
+ *
9
+ * @param count clamped to `pool.length` - asking for more traits than exist in the pool
10
+ * assigns every one of them rather than throwing
11
+ */
12
+ export function assignTraits(stats, pool, count) {
13
+ const picked = Random.shuffle([...pool]).slice(0, Math.min(count, pool.length));
14
+ return picked.map((trait) => {
15
+ const source = Symbol(`trait:${trait.name}`);
16
+ for (const modifier of trait.modifiers)
17
+ stats.addModifier({ ...modifier, source });
18
+ return { trait, source };
19
+ });
20
+ }
21
+ //# sourceMappingURL=Traits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Traits.js","sourceRoot":"","sources":["../../src/actors/Traits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAsB5C;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,KAAgB,EAAE,IAAyB,EAAE,KAAa;IACtF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7C,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS;YAAE,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACnF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -14,6 +14,8 @@ export type { Recipe } from './craft.ts';
14
14
  export { applyStatusEffect } from './StatusEffect.ts';
15
15
  export type { EffectClock, StatusEffectOptions, StatusEffectHandle } from './StatusEffect.ts';
16
16
  export { identify, enchant, damageItem, repairItem } from './ItemState.ts';
17
+ export { applyItemStatusEffect } from './ItemStatusEffect.ts';
18
+ export type { ItemStatusEffectOptions, ItemStatusEffectHandle } from './ItemStatusEffect.ts';
17
19
  export { Charges } from './Charges.ts';
18
20
  export type { ChargesOptions } from './Charges.ts';
19
21
  export { rollLoot } from './Loot.ts';
@@ -30,4 +32,10 @@ export { buy, sell } from './Shop.ts';
30
32
  export type { Price, ShopOptions } from './Shop.ts';
31
33
  export { canAfford, spend } from './Resource.ts';
32
34
  export type { ResourceCost } from './Resource.ts';
35
+ export { assignTraits } from './Traits.ts';
36
+ export type { TraitDef, AssignedTrait } from './Traits.ts';
37
+ export { AuraField } from './Aura.ts';
38
+ export type { AuraDef, AuraParticipant } from './Aura.ts';
39
+ export { SupportLedger } from './Support.ts';
40
+ export type { SupportLevel, SupportChange, SupportSave } from './Support.ts';
33
41
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAClH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actors/index.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export { Inventory } from './Inventory.js';
7
7
  export { craft } from './craft.js';
8
8
  export { applyStatusEffect } from './StatusEffect.js';
9
9
  export { identify, enchant, damageItem, repairItem } from './ItemState.js';
10
+ export { applyItemStatusEffect } from './ItemStatusEffect.js';
10
11
  export { Charges } from './Charges.js';
11
12
  export { rollLoot } from './Loot.js';
12
13
  export { Advancement } from './Advancement.js';
@@ -15,4 +16,7 @@ export { scaledModifiers } from './Scaling.js';
15
16
  export { assignAppearances, Appearances } from './Appearances.js';
16
17
  export { buy, sell } from './Shop.js';
17
18
  export { canAfford, spend } from './Resource.js';
19
+ export { assignTraits } from './Traits.js';
20
+ export { AuraField } from './Aura.js';
21
+ export { SupportLedger } from './Support.js';
18
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/actors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/actors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,40 @@
1
+ export interface AssetBundle {
2
+ id: string;
3
+ paths: readonly string[];
4
+ priority?: number;
5
+ /** caller-supplied estimate, used only for eviction accounting */
6
+ estimatedBytes?: number;
7
+ }
8
+ export interface AssetStreamOptions {
9
+ budgetBytes?: number;
10
+ load?: (paths: string[]) => Promise<void>;
11
+ release?: (paths: string[]) => Promise<void>;
12
+ }
13
+ /**
14
+ * Game-directed background asset staging with bounded, least-recently-used eviction.
15
+ *
16
+ * It deliberately does not guess a player's next map: the game supplies bundles it considers
17
+ * likely. This works with compiled data URIs as a decode/GPU warm-up and with server or
18
+ * desktop hosts as ordinary asynchronous streaming.
19
+ */
20
+ export declare class AssetStream {
21
+ private readonly entries;
22
+ private readonly budgetBytes;
23
+ private readonly loadAssets;
24
+ private readonly releaseAssets;
25
+ private clock;
26
+ constructor(options?: AssetStreamOptions);
27
+ /** loads one bundle now, then evicts older ready bundles if its budget requires it */
28
+ preload(bundle: AssetBundle): Promise<void>;
29
+ /** preloads bundles in highest-priority-first order; callers may intentionally not await it */
30
+ preloadLikely(bundles: readonly AssetBundle[]): Promise<void>;
31
+ /** marks a ready bundle as recently used at the moment a scene adopts it */
32
+ use(id: string): boolean;
33
+ isReady(id: string): boolean;
34
+ /** explicitly unloads one bundle, even when the configured budget has room */
35
+ unload(id: string): Promise<void>;
36
+ get estimatedBytes(): number;
37
+ private enforceBudget;
38
+ private isRetained;
39
+ }
40
+ //# sourceMappingURL=Streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../src/assets/Streaming.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAOD;;;;;;GAMG;AACH,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqC;IAChE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IACnE,OAAO,CAAC,KAAK,CAAK;IAElB,YAAY,OAAO,GAAE,kBAAuB,EAK3C;IAED,sFAAsF;IAChF,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhD;IAED,+FAA+F;IACzF,aAAa,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;IAED,4EAA4E;IAC5E,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAKvB;IAED,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE3B;IAED,8EAA8E;IACxE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtC;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;YAEa,aAAa;IAU3B,OAAO,CAAC,UAAU;CAGlB"}