@datamoc/mw_games 0.7.6 → 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 (283) hide show
  1. package/CHANGELOG.md +270 -0
  2. package/dist/actors/Inventory.d.ts +7 -1
  3. package/dist/actors/Inventory.d.ts.map +1 -1
  4. package/dist/actors/Inventory.js.map +1 -1
  5. package/dist/actors/craft.d.ts +35 -14
  6. package/dist/actors/craft.d.ts.map +1 -1
  7. package/dist/actors/craft.js +56 -24
  8. package/dist/actors/craft.js.map +1 -1
  9. package/dist/actors/index.d.ts +1 -1
  10. package/dist/actors/index.d.ts.map +1 -1
  11. package/dist/ai/Heuristics.d.ts +232 -0
  12. package/dist/ai/Heuristics.d.ts.map +1 -0
  13. package/dist/ai/Heuristics.js +298 -0
  14. package/dist/ai/Heuristics.js.map +1 -0
  15. package/dist/ai/index.d.ts +4 -0
  16. package/dist/ai/index.d.ts.map +1 -1
  17. package/dist/ai/index.js +2 -0
  18. package/dist/ai/index.js.map +1 -1
  19. package/dist/ai/score.d.ts +126 -0
  20. package/dist/ai/score.d.ts.map +1 -0
  21. package/dist/ai/score.js +121 -0
  22. package/dist/ai/score.js.map +1 -0
  23. package/dist/assets/loader.d.ts +18 -4
  24. package/dist/assets/loader.d.ts.map +1 -1
  25. package/dist/assets/loader.js +40 -11
  26. package/dist/assets/loader.js.map +1 -1
  27. package/dist/audio/Positional.d.ts +125 -0
  28. package/dist/audio/Positional.d.ts.map +1 -0
  29. package/dist/audio/Positional.js +135 -0
  30. package/dist/audio/Positional.js.map +1 -0
  31. package/dist/audio/Sound.d.ts +7 -1
  32. package/dist/audio/Sound.d.ts.map +1 -1
  33. package/dist/audio/Sound.js +8 -2
  34. package/dist/audio/Sound.js.map +1 -1
  35. package/dist/audio/index.d.ts +2 -0
  36. package/dist/audio/index.d.ts.map +1 -1
  37. package/dist/audio/index.js +1 -0
  38. package/dist/audio/index.js.map +1 -1
  39. package/dist/battle/AttackDialog.d.ts +75 -0
  40. package/dist/battle/AttackDialog.d.ts.map +1 -0
  41. package/dist/battle/AttackDialog.js +115 -0
  42. package/dist/battle/AttackDialog.js.map +1 -0
  43. package/dist/battle/AttackPreview.d.ts +70 -0
  44. package/dist/battle/AttackPreview.d.ts.map +1 -0
  45. package/dist/battle/AttackPreview.js +78 -0
  46. package/dist/battle/AttackPreview.js.map +1 -0
  47. package/dist/battle/BattleStats.d.ts +45 -0
  48. package/dist/battle/BattleStats.d.ts.map +1 -0
  49. package/dist/battle/BattleStats.js +63 -0
  50. package/dist/battle/BattleStats.js.map +1 -0
  51. package/dist/battle/UnitSelector.d.ts +72 -0
  52. package/dist/battle/UnitSelector.d.ts.map +1 -0
  53. package/dist/battle/UnitSelector.js +117 -0
  54. package/dist/battle/UnitSelector.js.map +1 -0
  55. package/dist/battle/Whiteboard.d.ts +50 -0
  56. package/dist/battle/Whiteboard.d.ts.map +1 -0
  57. package/dist/battle/Whiteboard.js +94 -0
  58. package/dist/battle/Whiteboard.js.map +1 -0
  59. package/dist/battle/index.d.ts +10 -0
  60. package/dist/battle/index.d.ts.map +1 -1
  61. package/dist/battle/index.js +5 -0
  62. package/dist/battle/index.js.map +1 -1
  63. package/dist/board/FogOfWar.d.ts +32 -2
  64. package/dist/board/FogOfWar.d.ts.map +1 -1
  65. package/dist/board/FogOfWar.js +70 -6
  66. package/dist/board/FogOfWar.js.map +1 -1
  67. package/dist/core/Achievements.d.ts +40 -7
  68. package/dist/core/Achievements.d.ts.map +1 -1
  69. package/dist/core/Achievements.js +51 -7
  70. package/dist/core/Achievements.js.map +1 -1
  71. package/dist/core/Hex.d.ts +26 -6
  72. package/dist/core/Hex.d.ts.map +1 -1
  73. package/dist/core/Hex.js +40 -13
  74. package/dist/core/Hex.js.map +1 -1
  75. package/dist/core/Input.d.ts +36 -0
  76. package/dist/core/Input.d.ts.map +1 -1
  77. package/dist/core/Input.js +63 -1
  78. package/dist/core/Input.js.map +1 -1
  79. package/dist/core/Random.d.ts +93 -0
  80. package/dist/core/Random.d.ts.map +1 -1
  81. package/dist/core/Random.js +177 -0
  82. package/dist/core/Random.js.map +1 -1
  83. package/dist/core/SyncGuard.d.ts +57 -0
  84. package/dist/core/SyncGuard.d.ts.map +1 -0
  85. package/dist/core/SyncGuard.js +116 -0
  86. package/dist/core/SyncGuard.js.map +1 -0
  87. package/dist/core/index.d.ts +3 -1
  88. package/dist/core/index.d.ts.map +1 -1
  89. package/dist/core/index.js +2 -1
  90. package/dist/core/index.js.map +1 -1
  91. package/dist/i18n/Po.d.ts +51 -0
  92. package/dist/i18n/Po.d.ts.map +1 -0
  93. package/dist/i18n/Po.js +176 -0
  94. package/dist/i18n/Po.js.map +1 -0
  95. package/dist/i18n/index.d.ts +2 -0
  96. package/dist/i18n/index.d.ts.map +1 -1
  97. package/dist/i18n/index.js +1 -0
  98. package/dist/i18n/index.js.map +1 -1
  99. package/dist/mw_games.global.js +104 -98
  100. package/dist/mwl/MapFile.d.ts +41 -0
  101. package/dist/mwl/MapFile.d.ts.map +1 -0
  102. package/dist/mwl/MapFile.js +43 -0
  103. package/dist/mwl/MapFile.js.map +1 -0
  104. package/dist/mwl/campaign.d.ts +51 -0
  105. package/dist/mwl/campaign.d.ts.map +1 -0
  106. package/dist/mwl/campaign.js +58 -0
  107. package/dist/mwl/campaign.js.map +1 -0
  108. package/dist/mwl/carryover.d.ts +79 -0
  109. package/dist/mwl/carryover.d.ts.map +1 -0
  110. package/dist/mwl/carryover.js +63 -0
  111. package/dist/mwl/carryover.js.map +1 -0
  112. package/dist/mwl/content.d.ts +10 -0
  113. package/dist/mwl/content.d.ts.map +1 -1
  114. package/dist/mwl/content.js +8 -0
  115. package/dist/mwl/content.js.map +1 -1
  116. package/dist/mwl/hooks.d.ts +6 -5
  117. package/dist/mwl/hooks.d.ts.map +1 -1
  118. package/dist/mwl/hooks.js.map +1 -1
  119. package/dist/mwl/index.d.ts +8 -2
  120. package/dist/mwl/index.d.ts.map +1 -1
  121. package/dist/mwl/index.js +4 -1
  122. package/dist/mwl/index.js.map +1 -1
  123. package/dist/mwl/runtime.d.ts +140 -7
  124. package/dist/mwl/runtime.d.ts.map +1 -1
  125. package/dist/mwl/runtime.js +427 -33
  126. package/dist/mwl/runtime.js.map +1 -1
  127. package/dist/mwl/schema.d.ts.map +1 -1
  128. package/dist/mwl/schema.js +97 -18
  129. package/dist/mwl/schema.js.map +1 -1
  130. package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
  131. package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
  132. package/dist/roguelike/MultiTurnBeam.js +100 -53
  133. package/dist/roguelike/MultiTurnBeam.js.map +1 -1
  134. package/dist/roguelike/Targeting.d.ts +94 -0
  135. package/dist/roguelike/Targeting.d.ts.map +1 -1
  136. package/dist/roguelike/Targeting.js +123 -0
  137. package/dist/roguelike/Targeting.js.map +1 -1
  138. package/dist/roguelike/index.d.ts +3 -1
  139. package/dist/roguelike/index.d.ts.map +1 -1
  140. package/dist/roguelike/index.js +1 -0
  141. package/dist/roguelike/index.js.map +1 -1
  142. package/dist/simulation/CampaignSave.d.ts +68 -0
  143. package/dist/simulation/CampaignSave.d.ts.map +1 -0
  144. package/dist/simulation/CampaignSave.js +54 -0
  145. package/dist/simulation/CampaignSave.js.map +1 -0
  146. package/dist/simulation/EventPresentation.d.ts +111 -0
  147. package/dist/simulation/EventPresentation.d.ts.map +1 -0
  148. package/dist/simulation/EventPresentation.js +120 -0
  149. package/dist/simulation/EventPresentation.js.map +1 -0
  150. package/dist/simulation/index.d.ts +4 -0
  151. package/dist/simulation/index.d.ts.map +1 -1
  152. package/dist/simulation/index.js +2 -0
  153. package/dist/simulation/index.js.map +1 -1
  154. package/dist/two-d/pixi-interop.d.ts +18 -6
  155. package/dist/two-d/pixi-interop.d.ts.map +1 -1
  156. package/dist/two-d/pixi-interop.js +18 -6
  157. package/dist/two-d/pixi-interop.js.map +1 -1
  158. package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
  159. package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
  160. package/dist/two-d/render/AnimatedSprite.js +88 -26
  161. package/dist/two-d/render/AnimatedSprite.js.map +1 -1
  162. package/dist/two-d/render/Camera.d.ts +64 -4
  163. package/dist/two-d/render/Camera.d.ts.map +1 -1
  164. package/dist/two-d/render/Camera.js +132 -11
  165. package/dist/two-d/render/Camera.js.map +1 -1
  166. package/dist/two-d/render/Halo.d.ts +58 -0
  167. package/dist/two-d/render/Halo.d.ts.map +1 -0
  168. package/dist/two-d/render/Halo.js +48 -0
  169. package/dist/two-d/render/Halo.js.map +1 -0
  170. package/dist/two-d/render/ImageModifiers.d.ts +174 -0
  171. package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
  172. package/dist/two-d/render/ImageModifiers.js +438 -1
  173. package/dist/two-d/render/ImageModifiers.js.map +1 -1
  174. package/dist/two-d/render/LightningArc.d.ts +57 -0
  175. package/dist/two-d/render/LightningArc.d.ts.map +1 -0
  176. package/dist/two-d/render/LightningArc.js +91 -0
  177. package/dist/two-d/render/LightningArc.js.map +1 -0
  178. package/dist/two-d/render/PaletteRemap.d.ts +135 -0
  179. package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
  180. package/dist/two-d/render/PaletteRemap.js +181 -0
  181. package/dist/two-d/render/PaletteRemap.js.map +1 -0
  182. package/dist/two-d/render/Particles.d.ts +26 -0
  183. package/dist/two-d/render/Particles.d.ts.map +1 -1
  184. package/dist/two-d/render/Particles.js +23 -2
  185. package/dist/two-d/render/Particles.js.map +1 -1
  186. package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
  187. package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
  188. package/dist/two-d/render/SpriteAttachment.js +60 -0
  189. package/dist/two-d/render/SpriteAttachment.js.map +1 -0
  190. package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
  191. package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
  192. package/dist/two-d/render/TerrainGraphics.js +161 -0
  193. package/dist/two-d/render/TerrainGraphics.js.map +1 -0
  194. package/dist/two-d/render/index.d.ts +13 -3
  195. package/dist/two-d/render/index.d.ts.map +1 -1
  196. package/dist/two-d/render/index.js +6 -1
  197. package/dist/two-d/render/index.js.map +1 -1
  198. package/dist/two-d/stage/StoryScreen.d.ts +110 -0
  199. package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
  200. package/dist/two-d/stage/StoryScreen.js +178 -0
  201. package/dist/two-d/stage/StoryScreen.js.map +1 -0
  202. package/dist/two-d/stage/index.d.ts +2 -0
  203. package/dist/two-d/stage/index.d.ts.map +1 -1
  204. package/dist/two-d/stage/index.js +1 -0
  205. package/dist/two-d/stage/index.js.map +1 -1
  206. package/dist/two-d/ui/Checkbox.d.ts +44 -0
  207. package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
  208. package/dist/two-d/ui/Checkbox.js +89 -0
  209. package/dist/two-d/ui/Checkbox.js.map +1 -0
  210. package/dist/two-d/ui/DataTable.d.ts +79 -0
  211. package/dist/two-d/ui/DataTable.d.ts.map +1 -0
  212. package/dist/two-d/ui/DataTable.js +164 -0
  213. package/dist/two-d/ui/DataTable.js.map +1 -0
  214. package/dist/two-d/ui/Dropdown.d.ts +72 -0
  215. package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
  216. package/dist/two-d/ui/Dropdown.js +126 -0
  217. package/dist/two-d/ui/Dropdown.js.map +1 -0
  218. package/dist/two-d/ui/FloatingText.d.ts +43 -4
  219. package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
  220. package/dist/two-d/ui/FloatingText.js +52 -5
  221. package/dist/two-d/ui/FloatingText.js.map +1 -1
  222. package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
  223. package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
  224. package/dist/two-d/ui/FloatingTextStack.js +89 -18
  225. package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
  226. package/dist/two-d/ui/Layout.d.ts +105 -0
  227. package/dist/two-d/ui/Layout.d.ts.map +1 -0
  228. package/dist/two-d/ui/Layout.js +174 -0
  229. package/dist/two-d/ui/Layout.js.map +1 -0
  230. package/dist/two-d/ui/ScrollBox.d.ts +67 -0
  231. package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
  232. package/dist/two-d/ui/ScrollBox.js +127 -0
  233. package/dist/two-d/ui/ScrollBox.js.map +1 -0
  234. package/dist/two-d/ui/Skins.d.ts +59 -0
  235. package/dist/two-d/ui/Skins.d.ts.map +1 -0
  236. package/dist/two-d/ui/Skins.js +77 -0
  237. package/dist/two-d/ui/Skins.js.map +1 -0
  238. package/dist/two-d/ui/Slider.d.ts +91 -0
  239. package/dist/two-d/ui/Slider.d.ts.map +1 -0
  240. package/dist/two-d/ui/Slider.js +170 -0
  241. package/dist/two-d/ui/Slider.js.map +1 -0
  242. package/dist/two-d/ui/Spinner.d.ts +67 -0
  243. package/dist/two-d/ui/Spinner.d.ts.map +1 -0
  244. package/dist/two-d/ui/Spinner.js +137 -0
  245. package/dist/two-d/ui/Spinner.js.map +1 -0
  246. package/dist/two-d/ui/TabbedList.d.ts +118 -0
  247. package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
  248. package/dist/two-d/ui/TabbedList.js +221 -0
  249. package/dist/two-d/ui/TabbedList.js.map +1 -0
  250. package/dist/two-d/ui/TextModel.d.ts +65 -0
  251. package/dist/two-d/ui/TextModel.d.ts.map +1 -0
  252. package/dist/two-d/ui/TextModel.js +126 -0
  253. package/dist/two-d/ui/TextModel.js.map +1 -0
  254. package/dist/two-d/ui/TreeView.d.ts +68 -0
  255. package/dist/two-d/ui/TreeView.d.ts.map +1 -0
  256. package/dist/two-d/ui/TreeView.js +133 -0
  257. package/dist/two-d/ui/TreeView.js.map +1 -0
  258. package/dist/two-d/ui/Window.d.ts +13 -0
  259. package/dist/two-d/ui/Window.d.ts.map +1 -1
  260. package/dist/two-d/ui/Window.js +23 -0
  261. package/dist/two-d/ui/Window.js.map +1 -1
  262. package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
  263. package/dist/two-d/ui/WindowStack.js +2 -0
  264. package/dist/two-d/ui/WindowStack.js.map +1 -1
  265. package/dist/two-d/ui/index.d.ts +27 -3
  266. package/dist/two-d/ui/index.d.ts.map +1 -1
  267. package/dist/two-d/ui/index.js +14 -2
  268. package/dist/two-d/ui/index.js.map +1 -1
  269. package/dist/two-d/ui/markup.d.ts +127 -0
  270. package/dist/two-d/ui/markup.d.ts.map +1 -0
  271. package/dist/two-d/ui/markup.js +322 -0
  272. package/dist/two-d/ui/markup.js.map +1 -0
  273. package/dist/version.d.ts +1 -1
  274. package/dist/version.js +1 -1
  275. package/dist/world/SideTurns.d.ts +115 -0
  276. package/dist/world/SideTurns.d.ts.map +1 -0
  277. package/dist/world/SideTurns.js +138 -0
  278. package/dist/world/SideTurns.js.map +1 -0
  279. package/dist/world/index.d.ts +2 -0
  280. package/dist/world/index.d.ts.map +1 -1
  281. package/dist/world/index.js +1 -0
  282. package/dist/world/index.js.map +1 -1
  283. package/package.json +2 -1
@@ -1,10 +1,36 @@
1
1
  import { TintedSprite } from './TintedSprite.ts';
2
2
  import type { Texture2D } from './Types2D.ts';
3
+ /**
4
+ * One frame, with its own timing and its own place.
5
+ *
6
+ * A frame may carry its own duration, which is what Wesnoth writes as `image=a.png:120,b.png:80`: a
7
+ * list of frames with how long each is held. It may also sit a few pixels away from where the sprite
8
+ * is - a recoil, a hit shake, a frame drawn high on purpose.
9
+ */
10
+ export interface AnimationFrame {
11
+ readonly texture: Texture2D;
12
+ /** seconds this frame is held; without it, `AnimationOptions.fps` decides */
13
+ readonly duration?: number;
14
+ /** pixels this frame is drawn away from the sprite's own position */
15
+ readonly offsetX?: number;
16
+ readonly offsetY?: number;
17
+ }
18
+ /** a plain texture is a frame with no timing or offset of its own */
19
+ export type AnimationFrameInput = Texture2D | AnimationFrame;
3
20
  export interface AnimationOptions {
4
- /** frames per second */
21
+ /** frames per second: the duration of every frame that does not carry one of its own */
5
22
  fps?: number;
6
23
  /** whether to start again at the end, or hold on the last frame */
7
24
  loop?: boolean;
25
+ /**
26
+ * Seconds into its own timeline this animation starts at. Positive holds the first frame that
27
+ * much longer, negative skips that much of the leading frames. The negative case is not a quirk:
28
+ * it is how Wesnoth lines an attack animation up with the frame the damage lands on, by starting
29
+ * mid-swing (`start_time=-450` over frames of 100ms each skips four and a half of them). The
30
+ * offset applies once, when playback starts; a looping animation then cycles on the frames' own
31
+ * length, so the delay does not repeat every lap.
32
+ */
33
+ startTime?: number;
8
34
  }
9
35
  /**
10
36
  * @example
@@ -19,11 +45,24 @@ export interface AnimationOptions {
19
45
  * ```
20
46
  */
21
47
  export declare class Animation {
22
- readonly frames: readonly Texture2D[];
48
+ readonly frames: readonly AnimationFrame[];
49
+ /** the duration every frame without one of its own is held for */
23
50
  readonly frameDuration: number;
24
51
  readonly loop: boolean;
25
- constructor(frames: readonly Texture2D[], { fps, loop }?: AnimationOptions);
26
- get duration(): number;
52
+ readonly startTime: number;
53
+ /** how long one pass over the frames takes, `startTime` excluded */
54
+ readonly duration: number;
55
+ /** each frame's resolved duration, in order: `frameAt` walks these rather than the frames */
56
+ private readonly times;
57
+ constructor(frames: readonly AnimationFrameInput[], { fps, loop, startTime }?: AnimationOptions);
58
+ /** the frame playing `seconds` in, with `startTime` and `loop` applied */
59
+ frameAt(seconds: number): AnimationFrame;
60
+ /**
61
+ * Which frame plays `seconds` in. Before it starts the first frame is held, however long that
62
+ * is, and a non-looping animation that has run out stays on its last frame rather than running
63
+ * off the end.
64
+ */
65
+ frameIndexAt(seconds: number): number;
27
66
  }
28
67
  /**
29
68
  * A sprite that plays named animations, and can still be tinted.
@@ -34,6 +73,14 @@ export declare class Animation {
34
73
  * Nothing advances on its own: call `update(dt)` from the scene, or add the sprite to a
35
74
  * `SpriteGroup`, so that pausing the game pauses the animations with it.
36
75
  *
76
+ * Frames may carry their own duration, and the animation may start partway into itself, which is
77
+ * what Wesnoth's `image=a.png:120,b.png:80` and `start_time=-450` mean. A frame may also carry an
78
+ * offset, so a swing recoils a few pixels without a second texture: `frameOffset` reports it, and
79
+ * the *caller* adds it where it already positions the sprite. The framework does not apply it
80
+ * itself, on purpose - this sprite's position belongs to whoever put it there (a `GridMover`, a
81
+ * walk tween, a camera projection), and a sprite that overwrote `y` every frame would undo that
82
+ * every frame. `FloatingText` learned the same rule the hard way.
83
+ *
37
84
  * Reduced motion deliberately does not pause this. A frame cycle is usually game state - a
38
85
  * walking enemy that freezes when the player has asked for less motion is a bug, not an
39
86
  * accommodation, and the article's own "Don't Reduce Too Much" is about exactly this. A game
@@ -54,6 +101,14 @@ export declare class Animation {
54
101
  * hero.add('idle', sheet.pick(0, 0, 0, 1), { fps: 2 });
55
102
  * hero.add('walk', sheet.range(6, 10), { fps: 10 });
56
103
  * hero.add('die', sheet.range(11, 14), { fps: 10, loop: false });
104
+ * hero.add(
105
+ * 'thrust',
106
+ * [
107
+ * { texture: sheet.get(20), duration: 0.4 },
108
+ * { texture: sheet.get(21), duration: 0.1, offsetX: 3 }, // the lunge
109
+ * ],
110
+ * { startTime: -0.2 },
111
+ * );
57
112
  * hero.play('idle');
58
113
  *
59
114
  * hero.onFinish = (name) => console.log(`${name} finished`);
@@ -64,16 +119,27 @@ export declare class AnimatedSprite extends TintedSprite {
64
119
  private animations;
65
120
  private current;
66
121
  private currentName;
67
- private frameIndex;
68
- private timer;
122
+ private elapsed;
69
123
  private finished;
124
+ private readonly offset;
70
125
  /** fires once when a non-looping animation reaches its last frame */
71
126
  onFinish: ((name: string) => void) | null;
72
127
  paused: boolean;
73
- add(name: string, frames: readonly Texture2D[], options?: AnimationOptions): this;
128
+ add(name: string, frames: readonly AnimationFrameInput[], options?: AnimationOptions): this;
74
129
  has(name: string): boolean;
75
130
  get playing(): string | null;
76
131
  get isFinished(): boolean;
132
+ /**
133
+ * Where the current frame is drawn relative to the sprite's own position, in pixels. The caller
134
+ * adds it, as in `sprite.position.set(x + sprite.frameOffset.x, y + sprite.frameOffset.y)`. Both
135
+ * are zero for a frame with no offset of its own.
136
+ */
137
+ get frameOffset(): {
138
+ readonly x: number;
139
+ readonly y: number;
140
+ };
141
+ /** how long the current animation has been running, `startTime` and all */
142
+ get elapsedTime(): number;
77
143
  /**
78
144
  * Starts an animation.
79
145
  *
@@ -83,5 +149,6 @@ export declare class AnimatedSprite extends TintedSprite {
83
149
  play(name: string, restart?: boolean): this;
84
150
  stop(): void;
85
151
  update(dt: number): void;
152
+ private show;
86
153
  }
87
154
  //# sourceMappingURL=AnimatedSprite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnimatedSprite.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/AnimatedSprite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAChC,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,mEAAmE;IACnE,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,SAAS;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB,YAAY,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,GAAQ,EAAE,IAAW,EAAE,GAAE,gBAAqB,EAKzF;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;CACD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC/C,OAAO,CAAC,UAAU,CAAgC;IAElD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAS;IAEzB,qEAAqE;IACrE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAEjD,MAAM,UAAS;IAEf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAGhF;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzB;IAED,IAAI,OAAO,IAAI,MAAM,GAAG,IAAI,CAE3B;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,IAAI,CAcxC;IAED,IAAI,IAAI,IAAI,CAGX;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAuBvB;CACD"}
1
+ {"version":3,"file":"AnimatedSprite.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/AnimatedSprite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAE5B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qEAAqE;AACrE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,cAAc,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAChC,wFAAwF;IACxF,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,mEAAmE;IACnE,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,SAAS;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAE3C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAE1C,YACC,MAAM,EAAE,SAAS,mBAAmB,EAAE,EACtC,EAAE,GAAQ,EAAE,IAAW,EAAE,SAAa,EAAE,GAAE,gBAAqB,EAqB/D;IAED,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEvC;IAED;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAapC;CACD;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC/C,OAAO,CAAC,UAAU,CAAgC;IAElD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,qEAAqE;IACrE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAEjD,MAAM,UAAS;IAEf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,mBAAmB,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAG1F;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzB;IAED,IAAI,OAAO,IAAI,MAAM,GAAG,IAAI,CAE3B;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;OAIG;IACH,IAAI,WAAW,IAAI;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAE5D;IAED,2EAA2E;IAC3E,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,IAAI,CAaxC;IAED,IAAI,IAAI,IAAI,CAGX;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAavB;IAED,OAAO,CAAC,IAAI;CAKZ"}
@@ -12,17 +12,57 @@ import { TintedSprite } from './TintedSprite.js';
12
12
  * ```
13
13
  */
14
14
  export class Animation {
15
- constructor(frames, { fps = 10, loop = true } = {}) {
15
+ constructor(frames, { fps = 10, loop = true, startTime = 0 } = {}) {
16
16
  if (frames.length === 0)
17
17
  throw new Error('an animation needs at least one frame');
18
- this.frames = frames;
18
+ if (!(fps > 0))
19
+ throw new Error(`an animation needs a positive fps, got ${fps}`);
19
20
  this.frameDuration = 1 / fps;
21
+ this.frames = frames.map((frame) => (isFrame(frame) ? frame : { texture: frame }));
22
+ this.times = this.frames.map((frame) => frame.duration ?? this.frameDuration);
20
23
  this.loop = loop;
24
+ this.startTime = startTime;
25
+ //the frames that borrow the fps are multiplied rather than added one by one: ten frames at a
26
+ //tenth of a second are exactly a second, where summing ten copies of 0.1 lands an ulp away
27
+ //from it. This total is what a loop wraps on and what a one-shot animation is timed against
28
+ let uniform = 0;
29
+ let timed = 0;
30
+ for (const frame of this.frames) {
31
+ if (frame.duration === undefined)
32
+ uniform++;
33
+ else
34
+ timed += frame.duration;
35
+ }
36
+ this.duration = uniform * this.frameDuration + timed;
37
+ }
38
+ /** the frame playing `seconds` in, with `startTime` and `loop` applied */
39
+ frameAt(seconds) {
40
+ return this.frames[this.frameIndexAt(seconds)];
21
41
  }
22
- get duration() {
23
- return this.frameDuration * this.frames.length;
42
+ /**
43
+ * Which frame plays `seconds` in. Before it starts the first frame is held, however long that
44
+ * is, and a non-looping animation that has run out stays on its last frame rather than running
45
+ * off the end.
46
+ */
47
+ frameIndexAt(seconds) {
48
+ const elapsed = seconds - this.startTime;
49
+ if (elapsed <= 0)
50
+ return 0;
51
+ const total = this.duration;
52
+ if (total <= 0)
53
+ return this.frames.length - 1;
54
+ let time = this.loop ? elapsed % total : Math.min(elapsed, total);
55
+ for (let index = 0; index < this.times.length; index++) {
56
+ if (time < this.times[index])
57
+ return index;
58
+ time -= this.times[index];
59
+ }
60
+ return this.frames.length - 1;
24
61
  }
25
62
  }
63
+ function isFrame(frame) {
64
+ return typeof frame.texture !== 'undefined';
65
+ }
26
66
  /**
27
67
  * A sprite that plays named animations, and can still be tinted.
28
68
  *
@@ -32,6 +72,14 @@ export class Animation {
32
72
  * Nothing advances on its own: call `update(dt)` from the scene, or add the sprite to a
33
73
  * `SpriteGroup`, so that pausing the game pauses the animations with it.
34
74
  *
75
+ * Frames may carry their own duration, and the animation may start partway into itself, which is
76
+ * what Wesnoth's `image=a.png:120,b.png:80` and `start_time=-450` mean. A frame may also carry an
77
+ * offset, so a swing recoils a few pixels without a second texture: `frameOffset` reports it, and
78
+ * the *caller* adds it where it already positions the sprite. The framework does not apply it
79
+ * itself, on purpose - this sprite's position belongs to whoever put it there (a `GridMover`, a
80
+ * walk tween, a camera projection), and a sprite that overwrote `y` every frame would undo that
81
+ * every frame. `FloatingText` learned the same rule the hard way.
82
+ *
35
83
  * Reduced motion deliberately does not pause this. A frame cycle is usually game state - a
36
84
  * walking enemy that freezes when the player has asked for less motion is a bug, not an
37
85
  * accommodation, and the article's own "Don't Reduce Too Much" is about exactly this. A game
@@ -52,6 +100,14 @@ export class Animation {
52
100
  * hero.add('idle', sheet.pick(0, 0, 0, 1), { fps: 2 });
53
101
  * hero.add('walk', sheet.range(6, 10), { fps: 10 });
54
102
  * hero.add('die', sheet.range(11, 14), { fps: 10, loop: false });
103
+ * hero.add(
104
+ * 'thrust',
105
+ * [
106
+ * { texture: sheet.get(20), duration: 0.4 },
107
+ * { texture: sheet.get(21), duration: 0.1, offsetX: 3 }, // the lunge
108
+ * ],
109
+ * { startTime: -0.2 },
110
+ * );
55
111
  * hero.play('idle');
56
112
  *
57
113
  * hero.onFinish = (name) => console.log(`${name} finished`);
@@ -64,9 +120,9 @@ export class AnimatedSprite extends TintedSprite {
64
120
  this.animations = new Map();
65
121
  this.current = null;
66
122
  this.currentName = null;
67
- this.frameIndex = 0;
68
- this.timer = 0;
123
+ this.elapsed = 0;
69
124
  this.finished = false;
125
+ this.offset = { x: 0, y: 0 };
70
126
  /** fires once when a non-looping animation reaches its last frame */
71
127
  this.onFinish = null;
72
128
  this.paused = false;
@@ -84,6 +140,18 @@ export class AnimatedSprite extends TintedSprite {
84
140
  get isFinished() {
85
141
  return this.finished;
86
142
  }
143
+ /**
144
+ * Where the current frame is drawn relative to the sprite's own position, in pixels. The caller
145
+ * adds it, as in `sprite.position.set(x + sprite.frameOffset.x, y + sprite.frameOffset.y)`. Both
146
+ * are zero for a frame with no offset of its own.
147
+ */
148
+ get frameOffset() {
149
+ return this.offset;
150
+ }
151
+ /** how long the current animation has been running, `startTime` and all */
152
+ get elapsedTime() {
153
+ return this.elapsed;
154
+ }
87
155
  /**
88
156
  * Starts an animation.
89
157
  *
@@ -98,10 +166,9 @@ export class AnimatedSprite extends TintedSprite {
98
166
  throw new Error(`no animation named "${name}" on this sprite`);
99
167
  this.current = animation;
100
168
  this.currentName = name;
101
- this.frameIndex = 0;
102
- this.timer = 0;
169
+ this.elapsed = 0;
103
170
  this.finished = false;
104
- this.texture = animation.frames[0];
171
+ this.show(animation.frameAt(0));
105
172
  return this;
106
173
  }
107
174
  stop() {
@@ -112,24 +179,19 @@ export class AnimatedSprite extends TintedSprite {
112
179
  const animation = this.current;
113
180
  if (!animation || this.paused || this.finished)
114
181
  return;
115
- this.timer += dt;
116
- //a long frame may cross several animation frames, so this catches up rather than
117
- //dropping them, which keeps two sprites started together in step
118
- while (this.timer >= animation.frameDuration) {
119
- this.timer -= animation.frameDuration;
120
- if (this.frameIndex < animation.frames.length - 1) {
121
- this.frameIndex++;
122
- }
123
- else if (animation.loop) {
124
- this.frameIndex = 0;
125
- }
126
- else {
127
- this.finished = true;
128
- this.onFinish?.(this.currentName);
129
- break;
130
- }
182
+ //elapsed rather than a leftover timer: one long frame lands on the right frame instead of
183
+ //catching up through each of them, which keeps two sprites started together in step
184
+ this.elapsed += dt;
185
+ this.show(animation.frameAt(this.elapsed));
186
+ if (!animation.loop && this.elapsed >= animation.startTime + animation.duration) {
187
+ this.finished = true;
188
+ this.onFinish?.(this.currentName);
131
189
  }
132
- this.texture = animation.frames[this.frameIndex];
190
+ }
191
+ show(frame) {
192
+ this.texture = frame.texture;
193
+ this.offset.x = frame.offsetX ?? 0;
194
+ this.offset.y = frame.offsetY ?? 0;
133
195
  }
134
196
  }
135
197
  //# sourceMappingURL=AnimatedSprite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnimatedSprite.js","sourceRoot":"","sources":["../../../src/two-d/render/AnimatedSprite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AnimatedSprite.js","sourceRoot":"","sources":["../../../src/two-d/render/AnimatedSprite.ts"],"names":[],"mappings":"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"}
@@ -4,10 +4,20 @@ import { Container } from 'pixi.js';
4
4
  *
5
5
  * The camera does not move: it moves the world under a fixed viewport, which is what a
6
6
  * renderer actually wants. `world` is the container to put the map and its inhabitants in;
7
- * anything that should stay put on screen (the HUD, a dialogue box) goes outside it.
7
+ * anything that should stay put on screen (the HUD, a dialogue box) goes outside it. The
8
+ * same answers "does rotation turn the camera or the world": the layer turns, once, about
9
+ * the view centre - never a per-tile transform, which is what keeps rotated tiles seamless
10
+ * and the per-frame cost flat regardless of map size.
8
11
  *
9
12
  * Positions are in world units. At `zoom = 3` a 16px tile is 48 screen pixels.
10
13
  *
14
+ * Rotation has two APIs sharing one angle: `setRotationStep`/`rotate` turn in the whole
15
+ * steps a grid closes on (item 285 - four quarter turns for a square map, six 60-degree
16
+ * steps for a hex one), while `rotateTo`/`animateRotationTo` turn to any angle at all (item
17
+ * 286), animating smoothly between two steps rather than only landing on them. `toScreen`/
18
+ * `toWorld`/`view`'s culling box already work at any angle, not only a step's whole
19
+ * multiple, so free rotation needed no change to either.
20
+ *
11
21
  * @example
12
22
  * ```ts
13
23
  * import { Camera, createCamera } from '@datamoc/mw_games/two-d/render';
@@ -28,6 +38,13 @@ import { Container } from 'pixi.js';
28
38
  export interface CameraOptions {
29
39
  /** screen pixels per world unit */
30
40
  zoom?: number;
41
+ /**
42
+ * The grid whose symmetry `rotate`/`setRotationStep` step in: `'square'` (the default)
43
+ * turns in four quarter turns, `'hex'` in six 60-degree steps, because a hex lattice comes
44
+ * back onto itself every 60 degrees. Only the step count depends on this; the layer and its
45
+ * inverse mapping are the same shape either way.
46
+ */
47
+ grid?: 'square' | 'hex';
31
48
  /**
32
49
  * How much of the screen the target may drift across before the camera follows, 0 to 1.
33
50
  *
@@ -91,7 +108,43 @@ export declare class Camera {
91
108
  private shakeY;
92
109
  /** clamps the view to these world bounds when set, so the map's edge is never crossed */
93
110
  private bounds;
111
+ /** how many whole-angle positions a full turn has: 4 for a square grid, 6 for a hex one */
112
+ readonly stepsPerTurn: number;
113
+ private step;
114
+ private _angle;
115
+ private targetAngle;
116
+ private angleIntensity;
94
117
  constructor(options?: CameraOptions);
118
+ /** the rotation step this view is turned to, always in `0 .. stepsPerTurn - 1` */
119
+ get rotationSteps(): number;
120
+ /** the view's rotation, in radians, positive turning the world counter-clockwise */
121
+ get rotation(): number;
122
+ /**
123
+ * The angle that cancels `rotation`: draw a label, health bar or damage number into `world`
124
+ * with this and it stays upright however the view is turned. A half turn would otherwise put
125
+ * every label upside down.
126
+ */
127
+ get uprightRotation(): number;
128
+ /** turns the view to a whole step, wrapping around a full turn */
129
+ setRotationStep(step: number): void;
130
+ /** turns the view by whole steps; `rotate(1)` is the next position, `rotate(-1)` the last */
131
+ rotate(delta?: number): void;
132
+ /**
133
+ * Turns the view to an arbitrary angle immediately, no animation - free rotation, not
134
+ * confined to a grid's whole steps. `rotationSteps` is left as it was: it names where
135
+ * `setRotationStep`/`rotate` last put the view, not this angle, so the two APIs are best
136
+ * used one at a time rather than interleaved.
137
+ */
138
+ rotateTo(angle: number): void;
139
+ /**
140
+ * Eases the view towards an arbitrary angle, taking whichever way around the turn is
141
+ * shorter - so animating from a hex view's fifth step back to its first sweeps the one
142
+ * 60-degree gap between them rather than the long way around. `intensity` behaves like
143
+ * `follow`'s: the remaining angle closes by that fraction each second.
144
+ */
145
+ animateRotationTo(angle: number, intensity?: number): void;
146
+ /** cos/sin of the current rotation, the shared arithmetic `toScreen`/`toWorld`/`view` use */
147
+ private get spin();
95
148
  get zoom(): number;
96
149
  set zoom(value: number);
97
150
  /**
@@ -101,7 +154,14 @@ export declare class Camera {
101
154
  * the screen instead, for a split-screen layout.
102
155
  */
103
156
  setViewport(width: number, height: number, screenX?: number, screenY?: number): void;
104
- /** the visible rectangle, in world units: use it to cull */
157
+ /**
158
+ * The visible region, in world units, as an axis-aligned box: use it to cull.
159
+ *
160
+ * With the view turned, the visible region is the viewport rectangle rotated in world space,
161
+ * so this is the box around its four corners instead of the rectangle itself - over-inclusive
162
+ * rather than clipping tiles that are actually on screen. Unturned, it is the rectangle, at
163
+ * its exact numbers.
164
+ */
105
165
  get view(): {
106
166
  x: number;
107
167
  y: number;
@@ -128,12 +188,12 @@ export declare class Camera {
128
188
  /** @param magnitude world units @param duration seconds */
129
189
  shake(magnitude: number, duration?: number): void;
130
190
  update(dt: number): void;
131
- /** world point to screen pixels */
191
+ /** world point to screen pixels, through the current rotation */
132
192
  toScreen(x: number, y: number): {
133
193
  x: number;
134
194
  y: number;
135
195
  };
136
- /** screen pixels to world point, for turning a click into a tile */
196
+ /** screen pixels to world point, for turning a click into a tile; the inverse of `toScreen` */
137
197
  toWorld(x: number, y: number): {
138
198
  x: number;
139
199
  y: number;
@@ -1 +1 @@
1
- {"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/Camera.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/Camera.ts"],"names":[],"mappings":"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"}