@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.
- package/CHANGELOG.md +287 -2
- package/README.md +15 -2
- package/dist/actors/Inventory.d.ts +7 -1
- package/dist/actors/Inventory.d.ts.map +1 -1
- package/dist/actors/Inventory.js.map +1 -1
- package/dist/actors/craft.d.ts +35 -14
- package/dist/actors/craft.d.ts.map +1 -1
- package/dist/actors/craft.js +56 -24
- package/dist/actors/craft.js.map +1 -1
- package/dist/actors/index.d.ts +1 -1
- package/dist/actors/index.d.ts.map +1 -1
- package/dist/ai/Heuristics.d.ts +232 -0
- package/dist/ai/Heuristics.d.ts.map +1 -0
- package/dist/ai/Heuristics.js +298 -0
- package/dist/ai/Heuristics.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +2 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/score.d.ts +126 -0
- package/dist/ai/score.d.ts.map +1 -0
- package/dist/ai/score.js +121 -0
- package/dist/ai/score.js.map +1 -0
- package/dist/assets/loader.d.ts +18 -4
- package/dist/assets/loader.d.ts.map +1 -1
- package/dist/assets/loader.js +40 -11
- package/dist/assets/loader.js.map +1 -1
- package/dist/audio/Positional.d.ts +125 -0
- package/dist/audio/Positional.d.ts.map +1 -0
- package/dist/audio/Positional.js +135 -0
- package/dist/audio/Positional.js.map +1 -0
- package/dist/audio/Sound.d.ts +7 -1
- package/dist/audio/Sound.d.ts.map +1 -1
- package/dist/audio/Sound.js +8 -2
- package/dist/audio/Sound.js.map +1 -1
- package/dist/audio/index.d.ts +2 -0
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +1 -0
- package/dist/audio/index.js.map +1 -1
- package/dist/battle/AttackDialog.d.ts +75 -0
- package/dist/battle/AttackDialog.d.ts.map +1 -0
- package/dist/battle/AttackDialog.js +115 -0
- package/dist/battle/AttackDialog.js.map +1 -0
- package/dist/battle/AttackPreview.d.ts +70 -0
- package/dist/battle/AttackPreview.d.ts.map +1 -0
- package/dist/battle/AttackPreview.js +78 -0
- package/dist/battle/AttackPreview.js.map +1 -0
- package/dist/battle/BattleStats.d.ts +45 -0
- package/dist/battle/BattleStats.d.ts.map +1 -0
- package/dist/battle/BattleStats.js +63 -0
- package/dist/battle/BattleStats.js.map +1 -0
- package/dist/battle/UnitSelector.d.ts +72 -0
- package/dist/battle/UnitSelector.d.ts.map +1 -0
- package/dist/battle/UnitSelector.js +117 -0
- package/dist/battle/UnitSelector.js.map +1 -0
- package/dist/battle/Whiteboard.d.ts +50 -0
- package/dist/battle/Whiteboard.d.ts.map +1 -0
- package/dist/battle/Whiteboard.js +94 -0
- package/dist/battle/Whiteboard.js.map +1 -0
- package/dist/battle/index.d.ts +10 -0
- package/dist/battle/index.d.ts.map +1 -1
- package/dist/battle/index.js +5 -0
- package/dist/battle/index.js.map +1 -1
- package/dist/board/FogOfWar.d.ts +32 -2
- package/dist/board/FogOfWar.d.ts.map +1 -1
- package/dist/board/FogOfWar.js +70 -6
- package/dist/board/FogOfWar.js.map +1 -1
- package/dist/core/Achievements.d.ts +40 -7
- package/dist/core/Achievements.d.ts.map +1 -1
- package/dist/core/Achievements.js +51 -7
- package/dist/core/Achievements.js.map +1 -1
- package/dist/core/Blob.d.ts +13 -2
- package/dist/core/Blob.d.ts.map +1 -1
- package/dist/core/Blob.js +16 -2
- package/dist/core/Blob.js.map +1 -1
- package/dist/core/Hex.d.ts +26 -6
- package/dist/core/Hex.d.ts.map +1 -1
- package/dist/core/Hex.js +40 -13
- package/dist/core/Hex.js.map +1 -1
- package/dist/core/Input.d.ts +36 -0
- package/dist/core/Input.d.ts.map +1 -1
- package/dist/core/Input.js +63 -1
- package/dist/core/Input.js.map +1 -1
- package/dist/core/Random.d.ts +93 -0
- package/dist/core/Random.d.ts.map +1 -1
- package/dist/core/Random.js +177 -0
- package/dist/core/Random.js.map +1 -1
- package/dist/core/SyncGuard.d.ts +57 -0
- package/dist/core/SyncGuard.d.ts.map +1 -0
- package/dist/core/SyncGuard.js +116 -0
- package/dist/core/SyncGuard.js.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/i18n/Po.d.ts +51 -0
- package/dist/i18n/Po.d.ts.map +1 -0
- package/dist/i18n/Po.js +176 -0
- package/dist/i18n/Po.js.map +1 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/index.js.map +1 -1
- package/dist/mw_games.global.js +104 -98
- package/dist/mwl/MapFile.d.ts +41 -0
- package/dist/mwl/MapFile.d.ts.map +1 -0
- package/dist/mwl/MapFile.js +43 -0
- package/dist/mwl/MapFile.js.map +1 -0
- package/dist/mwl/campaign.d.ts +51 -0
- package/dist/mwl/campaign.d.ts.map +1 -0
- package/dist/mwl/campaign.js +58 -0
- package/dist/mwl/campaign.js.map +1 -0
- package/dist/mwl/carryover.d.ts +79 -0
- package/dist/mwl/carryover.d.ts.map +1 -0
- package/dist/mwl/carryover.js +63 -0
- package/dist/mwl/carryover.js.map +1 -0
- package/dist/mwl/content.d.ts +10 -0
- package/dist/mwl/content.d.ts.map +1 -1
- package/dist/mwl/content.js +8 -0
- package/dist/mwl/content.js.map +1 -1
- package/dist/mwl/hooks.d.ts +6 -5
- package/dist/mwl/hooks.d.ts.map +1 -1
- package/dist/mwl/hooks.js.map +1 -1
- package/dist/mwl/index.d.ts +8 -2
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +4 -1
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/runtime.d.ts +140 -7
- package/dist/mwl/runtime.d.ts.map +1 -1
- package/dist/mwl/runtime.js +427 -33
- package/dist/mwl/runtime.js.map +1 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/schema.js +97 -18
- package/dist/mwl/schema.js.map +1 -1
- package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
- package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
- package/dist/roguelike/MultiTurnBeam.js +100 -53
- package/dist/roguelike/MultiTurnBeam.js.map +1 -1
- package/dist/roguelike/Targeting.d.ts +94 -0
- package/dist/roguelike/Targeting.d.ts.map +1 -1
- package/dist/roguelike/Targeting.js +123 -0
- package/dist/roguelike/Targeting.js.map +1 -1
- package/dist/roguelike/index.d.ts +3 -1
- package/dist/roguelike/index.d.ts.map +1 -1
- package/dist/roguelike/index.js +1 -0
- package/dist/roguelike/index.js.map +1 -1
- package/dist/simulation/CampaignSave.d.ts +68 -0
- package/dist/simulation/CampaignSave.d.ts.map +1 -0
- package/dist/simulation/CampaignSave.js +54 -0
- package/dist/simulation/CampaignSave.js.map +1 -0
- package/dist/simulation/EventPresentation.d.ts +111 -0
- package/dist/simulation/EventPresentation.d.ts.map +1 -0
- package/dist/simulation/EventPresentation.js +120 -0
- package/dist/simulation/EventPresentation.js.map +1 -0
- package/dist/simulation/index.d.ts +4 -0
- package/dist/simulation/index.d.ts.map +1 -1
- package/dist/simulation/index.js +2 -0
- package/dist/simulation/index.js.map +1 -1
- package/dist/two-d/pixi-interop.d.ts +18 -6
- package/dist/two-d/pixi-interop.d.ts.map +1 -1
- package/dist/two-d/pixi-interop.js +18 -6
- package/dist/two-d/pixi-interop.js.map +1 -1
- package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
- package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
- package/dist/two-d/render/AnimatedSprite.js +88 -26
- package/dist/two-d/render/AnimatedSprite.js.map +1 -1
- package/dist/two-d/render/Camera.d.ts +64 -4
- package/dist/two-d/render/Camera.d.ts.map +1 -1
- package/dist/two-d/render/Camera.js +132 -11
- package/dist/two-d/render/Camera.js.map +1 -1
- package/dist/two-d/render/Halo.d.ts +58 -0
- package/dist/two-d/render/Halo.d.ts.map +1 -0
- package/dist/two-d/render/Halo.js +48 -0
- package/dist/two-d/render/Halo.js.map +1 -0
- package/dist/two-d/render/ImageModifiers.d.ts +174 -0
- package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
- package/dist/two-d/render/ImageModifiers.js +438 -1
- package/dist/two-d/render/ImageModifiers.js.map +1 -1
- package/dist/two-d/render/LightningArc.d.ts +57 -0
- package/dist/two-d/render/LightningArc.d.ts.map +1 -0
- package/dist/two-d/render/LightningArc.js +91 -0
- package/dist/two-d/render/LightningArc.js.map +1 -0
- package/dist/two-d/render/PaletteRemap.d.ts +135 -0
- package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
- package/dist/two-d/render/PaletteRemap.js +181 -0
- package/dist/two-d/render/PaletteRemap.js.map +1 -0
- package/dist/two-d/render/Particles.d.ts +26 -0
- package/dist/two-d/render/Particles.d.ts.map +1 -1
- package/dist/two-d/render/Particles.js +23 -2
- package/dist/two-d/render/Particles.js.map +1 -1
- package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
- package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
- package/dist/two-d/render/SpriteAttachment.js +60 -0
- package/dist/two-d/render/SpriteAttachment.js.map +1 -0
- package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
- package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
- package/dist/two-d/render/TerrainGraphics.js +161 -0
- package/dist/two-d/render/TerrainGraphics.js.map +1 -0
- package/dist/two-d/render/index.d.ts +13 -3
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +6 -1
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/two-d/stage/StoryScreen.d.ts +110 -0
- package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
- package/dist/two-d/stage/StoryScreen.js +178 -0
- package/dist/two-d/stage/StoryScreen.js.map +1 -0
- package/dist/two-d/stage/index.d.ts +2 -0
- package/dist/two-d/stage/index.d.ts.map +1 -1
- package/dist/two-d/stage/index.js +1 -0
- package/dist/two-d/stage/index.js.map +1 -1
- package/dist/two-d/ui/Checkbox.d.ts +44 -0
- package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
- package/dist/two-d/ui/Checkbox.js +89 -0
- package/dist/two-d/ui/Checkbox.js.map +1 -0
- package/dist/two-d/ui/DataTable.d.ts +79 -0
- package/dist/two-d/ui/DataTable.d.ts.map +1 -0
- package/dist/two-d/ui/DataTable.js +164 -0
- package/dist/two-d/ui/DataTable.js.map +1 -0
- package/dist/two-d/ui/Dropdown.d.ts +72 -0
- package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
- package/dist/two-d/ui/Dropdown.js +126 -0
- package/dist/two-d/ui/Dropdown.js.map +1 -0
- package/dist/two-d/ui/FloatingText.d.ts +43 -4
- package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
- package/dist/two-d/ui/FloatingText.js +52 -5
- package/dist/two-d/ui/FloatingText.js.map +1 -1
- package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
- package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
- package/dist/two-d/ui/FloatingTextStack.js +89 -18
- package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
- package/dist/two-d/ui/Layout.d.ts +105 -0
- package/dist/two-d/ui/Layout.d.ts.map +1 -0
- package/dist/two-d/ui/Layout.js +174 -0
- package/dist/two-d/ui/Layout.js.map +1 -0
- package/dist/two-d/ui/ScrollBox.d.ts +67 -0
- package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
- package/dist/two-d/ui/ScrollBox.js +127 -0
- package/dist/two-d/ui/ScrollBox.js.map +1 -0
- package/dist/two-d/ui/Skins.d.ts +59 -0
- package/dist/two-d/ui/Skins.d.ts.map +1 -0
- package/dist/two-d/ui/Skins.js +77 -0
- package/dist/two-d/ui/Skins.js.map +1 -0
- package/dist/two-d/ui/Slider.d.ts +91 -0
- package/dist/two-d/ui/Slider.d.ts.map +1 -0
- package/dist/two-d/ui/Slider.js +170 -0
- package/dist/two-d/ui/Slider.js.map +1 -0
- package/dist/two-d/ui/Spinner.d.ts +67 -0
- package/dist/two-d/ui/Spinner.d.ts.map +1 -0
- package/dist/two-d/ui/Spinner.js +137 -0
- package/dist/two-d/ui/Spinner.js.map +1 -0
- package/dist/two-d/ui/TabbedList.d.ts +118 -0
- package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
- package/dist/two-d/ui/TabbedList.js +221 -0
- package/dist/two-d/ui/TabbedList.js.map +1 -0
- package/dist/two-d/ui/TextModel.d.ts +65 -0
- package/dist/two-d/ui/TextModel.d.ts.map +1 -0
- package/dist/two-d/ui/TextModel.js +126 -0
- package/dist/two-d/ui/TextModel.js.map +1 -0
- package/dist/two-d/ui/TreeView.d.ts +68 -0
- package/dist/two-d/ui/TreeView.d.ts.map +1 -0
- package/dist/two-d/ui/TreeView.js +133 -0
- package/dist/two-d/ui/TreeView.js.map +1 -0
- package/dist/two-d/ui/Window.d.ts +13 -0
- package/dist/two-d/ui/Window.d.ts.map +1 -1
- package/dist/two-d/ui/Window.js +23 -0
- package/dist/two-d/ui/Window.js.map +1 -1
- package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
- package/dist/two-d/ui/WindowStack.js +2 -0
- package/dist/two-d/ui/WindowStack.js.map +1 -1
- package/dist/two-d/ui/index.d.ts +27 -3
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +14 -2
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/two-d/ui/markup.d.ts +127 -0
- package/dist/two-d/ui/markup.d.ts.map +1 -0
- package/dist/two-d/ui/markup.js +322 -0
- package/dist/two-d/ui/markup.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/world/SideTurns.d.ts +115 -0
- package/dist/world/SideTurns.d.ts.map +1 -0
- package/dist/world/SideTurns.js +138 -0
- package/dist/world/SideTurns.js.map +1 -0
- package/dist/world/index.d.ts +2 -0
- package/dist/world/index.d.ts.map +1 -1
- package/dist/world/index.js +1 -0
- package/dist/world/index.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Positional.js","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"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"}
|
package/dist/audio/Sound.d.ts
CHANGED
|
@@ -28,7 +28,13 @@ export declare class Sound {
|
|
|
28
28
|
private caption?;
|
|
29
29
|
volume: number;
|
|
30
30
|
constructor(path: string, options?: SoundOptions);
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Plays one instance from the pool.
|
|
33
|
+
*
|
|
34
|
+
* @param gain multiplied into the sound's own volume, for a distance-attenuated one-shot
|
|
35
|
+
* (`Positional.SoundSource.playFor`); 1 leaves it at `volume`.
|
|
36
|
+
*/
|
|
37
|
+
play(gain?: number): void;
|
|
32
38
|
stopAll(): void;
|
|
33
39
|
}
|
|
34
40
|
//# sourceMappingURL=Sound.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sound.d.ts","sourceRoot":"","sources":["../../src/audio/Sound.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG3D,MAAM,WAAW,YAAY;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IAEpC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,EAMnD;IAED,IAAI,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"Sound.d.ts","sourceRoot":"","sources":["../../src/audio/Sound.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG3D,MAAM,WAAW,YAAY;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IAEpC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,EAMnD;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,SAAI,GAAG,IAAI,CAYnB;IAED,OAAO,IAAI,IAAI,CAKd;CACD"}
|
package/dist/audio/Sound.js
CHANGED
|
@@ -23,10 +23,16 @@ export class Sound {
|
|
|
23
23
|
this.caption = options.caption;
|
|
24
24
|
this.pool = Array.from({ length: size }, () => create(path));
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Plays one instance from the pool.
|
|
28
|
+
*
|
|
29
|
+
* @param gain multiplied into the sound's own volume, for a distance-attenuated one-shot
|
|
30
|
+
* (`Positional.SoundSource.playFor`); 1 leaves it at `volume`.
|
|
31
|
+
*/
|
|
32
|
+
play(gain = 1) {
|
|
27
33
|
const audio = this.pool[this.next];
|
|
28
34
|
this.next = (this.next + 1) % this.pool.length;
|
|
29
|
-
audio.volume = this.volume;
|
|
35
|
+
audio.volume = this.volume * gain;
|
|
30
36
|
audio.currentTime = 0;
|
|
31
37
|
// play() can return a Promise that rejects if this reuse interrupts its own prior,
|
|
32
38
|
// still-loading play() (a real browser, not the fakes tests supply) - swallow it the
|
package/dist/audio/Sound.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sound.js","sourceRoot":"","sources":["../../src/audio/Sound.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAc1C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,KAAK;IAMjB,YAAY,IAAY,EAAE,OAAO,GAAiB,EAAE;QAJ5C,SAAI,GAAG,CAAC,CAAC;QAKhB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI;
|
|
1
|
+
{"version":3,"file":"Sound.js","sourceRoot":"","sources":["../../src/audio/Sound.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAc1C;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,KAAK;IAMjB,YAAY,IAAY,EAAE,OAAO,GAAiB,EAAE;QAJ5C,SAAI,GAAG,CAAC,CAAC;QAKhB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,GAAG,CAAC;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAE/C,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QAClC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;QACtB,mFAAmF;QACnF,qFAAqF;QACrF,wFAAwF;QACxF,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEnD,IAAI,IAAI,CAAC,OAAO;YAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO;QACN,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD"}
|
package/dist/audio/index.d.ts
CHANGED
|
@@ -12,4 +12,6 @@ export { synthesizeTone, playTone } from './Synth.ts';
|
|
|
12
12
|
export type { Waveform, ToneOptions } from './Synth.ts';
|
|
13
13
|
export { parseMidi, scheduleMidi, noteToFrequency, MidiPlayer } from './Midi.ts';
|
|
14
14
|
export type { MidiFile, MidiEvent, MidiNoteEvent, MidiTempoEvent, ScheduledNote, MidiPlayerOptions } from './Midi.ts';
|
|
15
|
+
export { AudioListener, SoundSource, audioGain, audioPan } from './Positional.ts';
|
|
16
|
+
export type { AudioPoint, AudioFalloff, SoundSourceOptions } from './Positional.ts';
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACjF,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACtH,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClF,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/audio/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { createAudio } from './Playable.js';
|
|
|
5
5
|
export { Orchestrator } from './Orchestrator.js';
|
|
6
6
|
export { synthesizeTone, playTone } from './Synth.js';
|
|
7
7
|
export { parseMidi, scheduleMidi, noteToFrequency, MidiPlayer } from './Midi.js';
|
|
8
|
+
export { AudioListener, SoundSource, audioGain, audioPan } from './Positional.js';
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
package/dist/audio/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.ts';
|
|
2
|
+
import { AttackPreview, type AttackFrame } from './AttackPreview.ts';
|
|
3
|
+
import { UnitSelector, type SelectableUnit, type SelectorStage } from './UnitSelector.ts';
|
|
4
|
+
/** The per-strike numbers a game's own rules produce for one attacker/target pair. */
|
|
5
|
+
export interface StrikeNumbers {
|
|
6
|
+
damage: number;
|
|
7
|
+
strikes: number;
|
|
8
|
+
chanceToHit?: number;
|
|
9
|
+
hits?: readonly boolean[];
|
|
10
|
+
}
|
|
11
|
+
export interface AttackDialogOptions {
|
|
12
|
+
units: readonly SelectableUnit[];
|
|
13
|
+
side?: string;
|
|
14
|
+
disabled?: (unit: SelectableUnit) => boolean;
|
|
15
|
+
canTarget?: (attacker: SelectableUnit, target: SelectableUnit) => boolean;
|
|
16
|
+
/** the game's damage rules, called once the attacker and target are both chosen */
|
|
17
|
+
damageFor: (attacker: SelectableUnit, target: SelectableUnit) => StrikeNumbers;
|
|
18
|
+
/** seconds between strikes in the preview animation */
|
|
19
|
+
strikeDuration?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The attack dialog's whole state, with no renderer: the unit selector, the damage preview the
|
|
23
|
+
* game's numbers build, and the animation clock the preview is sampled on.
|
|
24
|
+
*
|
|
25
|
+
* The order of business is the one a player sees - choose an attacker, choose a target, and the
|
|
26
|
+
* dialog shows a blow that lands over time - so the clock is here rather than in a widget: `update`
|
|
27
|
+
* takes the frame's `dt` and returns the preview frame to draw, and `finished` says when the
|
|
28
|
+
* animation has run out and the caller may apply the result. `damageFor` is where the game's own
|
|
29
|
+
* rules live; this model never invents damage.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { AttackDialog } from '@datamoc/mw_games/battle';
|
|
34
|
+
*
|
|
35
|
+
* const dialog = new AttackDialog({
|
|
36
|
+
* units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
|
|
37
|
+
* side: '1',
|
|
38
|
+
* damageFor: () => ({ damage: 4, strikes: 2 }),
|
|
39
|
+
* strikeDuration: 0.25,
|
|
40
|
+
* });
|
|
41
|
+
* dialog.select();
|
|
42
|
+
* dialog.select();
|
|
43
|
+
* console.log(dialog.update(0.3)?.defenderHp); // the defender after the second strike
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class AttackDialog {
|
|
47
|
+
readonly onChange: Signal<void>;
|
|
48
|
+
readonly selector: UnitSelector;
|
|
49
|
+
private readonly damageFor;
|
|
50
|
+
private readonly strikeDuration;
|
|
51
|
+
private built;
|
|
52
|
+
private elapsed_;
|
|
53
|
+
constructor(options: AttackDialogOptions);
|
|
54
|
+
get stage(): SelectorStage;
|
|
55
|
+
get attacker(): SelectableUnit | null;
|
|
56
|
+
get target(): SelectableUnit | null;
|
|
57
|
+
/** the damage preview, built once both choices are made */
|
|
58
|
+
get preview(): AttackPreview | null;
|
|
59
|
+
/** how long the animation has been playing, in seconds */
|
|
60
|
+
get elapsed(): number;
|
|
61
|
+
/** whether the animation has reached the end of the preview */
|
|
62
|
+
get finished(): boolean;
|
|
63
|
+
/** the frame to draw right now, or `null` before both choices are made */
|
|
64
|
+
get frame(): AttackFrame | null;
|
|
65
|
+
move(delta: number): void;
|
|
66
|
+
select(): boolean;
|
|
67
|
+
back(): void;
|
|
68
|
+
/** advances the animation, returning the frame to draw */
|
|
69
|
+
update(dt: number): AttackFrame | null;
|
|
70
|
+
/** skips the animation to its end, the click-through a player makes */
|
|
71
|
+
finish(): void;
|
|
72
|
+
reset(): void;
|
|
73
|
+
private readonly handleSelectorChange;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=AttackDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttackDialog.d.ts","sourceRoot":"","sources":["../../src/battle/AttackDialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE1F,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;IAC7C,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;IAC1E,mFAAmF;IACnF,SAAS,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,KAAK,aAAa,CAAC;IAC/E,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,YAAY;IACxB,QAAQ,CAAC,QAAQ,eAAsB;IACvC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsE;IAChG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,QAAQ,CAAK;IAErB,YAAY,OAAO,EAAE,mBAAmB,EAUvC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,QAAQ,IAAI,cAAc,GAAG,IAAI,CAEpC;IAED,IAAI,MAAM,IAAI,cAAc,GAAG,IAAI,CAElC;IAED,2DAA2D;IAC3D,IAAI,OAAO,IAAI,aAAa,GAAG,IAAI,CAElC;IAED,0DAA0D;IAC1D,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,+DAA+D;IAC/D,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,0EAA0E;IAC1E,IAAI,KAAK,IAAI,WAAW,GAAG,IAAI,CAE9B;IAED,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAExB;IAED,MAAM,IAAI,OAAO,CAEhB;IAED,IAAI,IAAI,IAAI,CAEX;IAED,0DAA0D;IAC1D,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAIrC;IAED,uEAAuE;IACvE,MAAM,IAAI,IAAI,CAEb;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAiBnC;CACF"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.js';
|
|
2
|
+
import { AttackPreview } from './AttackPreview.js';
|
|
3
|
+
import { UnitSelector } from './UnitSelector.js';
|
|
4
|
+
/**
|
|
5
|
+
* The attack dialog's whole state, with no renderer: the unit selector, the damage preview the
|
|
6
|
+
* game's numbers build, and the animation clock the preview is sampled on.
|
|
7
|
+
*
|
|
8
|
+
* The order of business is the one a player sees - choose an attacker, choose a target, and the
|
|
9
|
+
* dialog shows a blow that lands over time - so the clock is here rather than in a widget: `update`
|
|
10
|
+
* takes the frame's `dt` and returns the preview frame to draw, and `finished` says when the
|
|
11
|
+
* animation has run out and the caller may apply the result. `damageFor` is where the game's own
|
|
12
|
+
* rules live; this model never invents damage.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { AttackDialog } from '@datamoc/mw_games/battle';
|
|
17
|
+
*
|
|
18
|
+
* const dialog = new AttackDialog({
|
|
19
|
+
* units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
|
|
20
|
+
* side: '1',
|
|
21
|
+
* damageFor: () => ({ damage: 4, strikes: 2 }),
|
|
22
|
+
* strikeDuration: 0.25,
|
|
23
|
+
* });
|
|
24
|
+
* dialog.select();
|
|
25
|
+
* dialog.select();
|
|
26
|
+
* console.log(dialog.update(0.3)?.defenderHp); // the defender after the second strike
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class AttackDialog {
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.onChange = new Signal();
|
|
32
|
+
this.built = null;
|
|
33
|
+
this.elapsed_ = 0;
|
|
34
|
+
this.handleSelectorChange = () => {
|
|
35
|
+
if (this.selector.done && this.attacker && this.target) {
|
|
36
|
+
const numbers = this.damageFor(this.attacker, this.target);
|
|
37
|
+
this.built = new AttackPreview({
|
|
38
|
+
attacker: { hp: this.attacker.hp ?? 0, name: this.attacker.id },
|
|
39
|
+
defender: { hp: this.target.hp ?? 0, name: this.target.id },
|
|
40
|
+
damage: numbers.damage,
|
|
41
|
+
strikes: numbers.strikes,
|
|
42
|
+
...(numbers.chanceToHit === undefined ? {} : { chanceToHit: numbers.chanceToHit }),
|
|
43
|
+
...(numbers.hits === undefined ? {} : { hits: numbers.hits }),
|
|
44
|
+
strikeDuration: this.strikeDuration,
|
|
45
|
+
});
|
|
46
|
+
this.elapsed_ = 0;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.built = null;
|
|
50
|
+
}
|
|
51
|
+
this.onChange.dispatch();
|
|
52
|
+
};
|
|
53
|
+
this.damageFor = options.damageFor;
|
|
54
|
+
this.strikeDuration = options.strikeDuration ?? 0;
|
|
55
|
+
this.selector = new UnitSelector({
|
|
56
|
+
units: options.units,
|
|
57
|
+
...(options.side === undefined ? {} : { side: options.side }),
|
|
58
|
+
...(options.disabled === undefined ? {} : { disabled: options.disabled }),
|
|
59
|
+
...(options.canTarget === undefined ? {} : { canTarget: options.canTarget }),
|
|
60
|
+
});
|
|
61
|
+
this.selector.onChange.add(this.handleSelectorChange);
|
|
62
|
+
}
|
|
63
|
+
get stage() {
|
|
64
|
+
return this.selector.stage;
|
|
65
|
+
}
|
|
66
|
+
get attacker() {
|
|
67
|
+
return this.selector.attacker;
|
|
68
|
+
}
|
|
69
|
+
get target() {
|
|
70
|
+
return this.selector.target;
|
|
71
|
+
}
|
|
72
|
+
/** the damage preview, built once both choices are made */
|
|
73
|
+
get preview() {
|
|
74
|
+
return this.built;
|
|
75
|
+
}
|
|
76
|
+
/** how long the animation has been playing, in seconds */
|
|
77
|
+
get elapsed() {
|
|
78
|
+
return this.elapsed_;
|
|
79
|
+
}
|
|
80
|
+
/** whether the animation has reached the end of the preview */
|
|
81
|
+
get finished() {
|
|
82
|
+
return this.built !== null && this.elapsed_ >= this.built.duration;
|
|
83
|
+
}
|
|
84
|
+
/** the frame to draw right now, or `null` before both choices are made */
|
|
85
|
+
get frame() {
|
|
86
|
+
return this.built ? this.built.sampleAt(this.elapsed_) : null;
|
|
87
|
+
}
|
|
88
|
+
move(delta) {
|
|
89
|
+
this.selector.move(delta);
|
|
90
|
+
}
|
|
91
|
+
select() {
|
|
92
|
+
return this.selector.select();
|
|
93
|
+
}
|
|
94
|
+
back() {
|
|
95
|
+
this.selector.back();
|
|
96
|
+
}
|
|
97
|
+
/** advances the animation, returning the frame to draw */
|
|
98
|
+
update(dt) {
|
|
99
|
+
if (!this.built)
|
|
100
|
+
return null;
|
|
101
|
+
this.elapsed_ = Math.min(this.built.duration, this.elapsed_ + Math.max(0, dt));
|
|
102
|
+
return this.frame;
|
|
103
|
+
}
|
|
104
|
+
/** skips the animation to its end, the click-through a player makes */
|
|
105
|
+
finish() {
|
|
106
|
+
if (this.built)
|
|
107
|
+
this.elapsed_ = this.built.duration;
|
|
108
|
+
}
|
|
109
|
+
reset() {
|
|
110
|
+
this.selector.reset();
|
|
111
|
+
this.built = null;
|
|
112
|
+
this.elapsed_ = 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=AttackDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttackDialog.js","sourceRoot":"","sources":["../../src/battle/AttackDialog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface PreviewCombatant {
|
|
2
|
+
hp: number;
|
|
3
|
+
maxHp?: number;
|
|
4
|
+
name?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AttackPreviewOptions {
|
|
7
|
+
attacker: PreviewCombatant;
|
|
8
|
+
defender: PreviewCombatant;
|
|
9
|
+
/** damage per strike, from the game's own formula - `mwg` supplies none */
|
|
10
|
+
damage: number;
|
|
11
|
+
strikes: number;
|
|
12
|
+
/** chance to hit, 0 to 1; 1 (always hits) when omitted */
|
|
13
|
+
chanceToHit?: number;
|
|
14
|
+
/** which strikes land; every strike when omitted, for the maximum-damage preview */
|
|
15
|
+
hits?: readonly boolean[];
|
|
16
|
+
/** seconds between strikes in the animation; 0 when there is no animation */
|
|
17
|
+
strikeDuration?: number;
|
|
18
|
+
}
|
|
19
|
+
/** One moment of the attack animation: the board after `strike` strikes. */
|
|
20
|
+
export interface AttackFrame {
|
|
21
|
+
strike: number;
|
|
22
|
+
time: number;
|
|
23
|
+
attackerHp: number;
|
|
24
|
+
defenderHp: number;
|
|
25
|
+
/** hp taken off the defender by the strikes so far */
|
|
26
|
+
defenderDamage: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The numbers an attack dialog shows and animates: the attacker and defender's hp over the course
|
|
30
|
+
* of a blow, plus the totals the labels print.
|
|
31
|
+
*
|
|
32
|
+
* It deliberately computes no damage of its own - this framework supplies no damage formula, so a
|
|
33
|
+
* game hands in the per-strike `damage` exactly as its own rules worked it out. What the preview
|
|
34
|
+
* adds is the part a dialog needs and a formula does not: the *timeline* (one frame per strike,
|
|
35
|
+
* `sampleAt` the animation's own clock) and the two totals (the maximum, `damage * strikes`, and
|
|
36
|
+
* the expected value once `chanceToHit` is weighed). Which strikes actually land is `hits`, so a
|
|
37
|
+
* preview can show the maximum by default or a known outcome a replay already rolled.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { AttackPreview } from '@datamoc/mw_games/battle';
|
|
42
|
+
*
|
|
43
|
+
* const preview = new AttackPreview({
|
|
44
|
+
* attacker: { hp: 20 },
|
|
45
|
+
* defender: { hp: 12 },
|
|
46
|
+
* damage: 4,
|
|
47
|
+
* strikes: 3,
|
|
48
|
+
* chanceToHit: 0.6,
|
|
49
|
+
* strikeDuration: 0.2,
|
|
50
|
+
* });
|
|
51
|
+
* console.log(preview.totalDamage); // 12
|
|
52
|
+
* console.log(preview.sampleAt(0.25).defenderHp); // 8, after the second strike
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare class AttackPreview {
|
|
56
|
+
readonly frames: readonly AttackFrame[];
|
|
57
|
+
readonly totalDamage: number;
|
|
58
|
+
readonly expectedDamage: number;
|
|
59
|
+
readonly chanceToHit: number;
|
|
60
|
+
private readonly strikeDuration;
|
|
61
|
+
private readonly defenderHp0;
|
|
62
|
+
constructor(options: AttackPreviewOptions);
|
|
63
|
+
/** how long the animation runs, in seconds */
|
|
64
|
+
get duration(): number;
|
|
65
|
+
/** whether the defender would be at 0 hp once every landing strike has been shown */
|
|
66
|
+
get defenderKilled(): boolean;
|
|
67
|
+
/** the frame the animation shows at `time`, clamped to its own start and end */
|
|
68
|
+
sampleAt(time: number): AttackFrame;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=AttackPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttackPreview.d.ts","sourceRoot":"","sources":["../../src/battle/AttackPreview.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,aAAa;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,YAAY,OAAO,EAAE,oBAAoB,EAoBxC;IAED,8CAA8C;IAC9C,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,qFAAqF;IACrF,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAWlC;CACD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The numbers an attack dialog shows and animates: the attacker and defender's hp over the course
|
|
3
|
+
* of a blow, plus the totals the labels print.
|
|
4
|
+
*
|
|
5
|
+
* It deliberately computes no damage of its own - this framework supplies no damage formula, so a
|
|
6
|
+
* game hands in the per-strike `damage` exactly as its own rules worked it out. What the preview
|
|
7
|
+
* adds is the part a dialog needs and a formula does not: the *timeline* (one frame per strike,
|
|
8
|
+
* `sampleAt` the animation's own clock) and the two totals (the maximum, `damage * strikes`, and
|
|
9
|
+
* the expected value once `chanceToHit` is weighed). Which strikes actually land is `hits`, so a
|
|
10
|
+
* preview can show the maximum by default or a known outcome a replay already rolled.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { AttackPreview } from '@datamoc/mw_games/battle';
|
|
15
|
+
*
|
|
16
|
+
* const preview = new AttackPreview({
|
|
17
|
+
* attacker: { hp: 20 },
|
|
18
|
+
* defender: { hp: 12 },
|
|
19
|
+
* damage: 4,
|
|
20
|
+
* strikes: 3,
|
|
21
|
+
* chanceToHit: 0.6,
|
|
22
|
+
* strikeDuration: 0.2,
|
|
23
|
+
* });
|
|
24
|
+
* console.log(preview.totalDamage); // 12
|
|
25
|
+
* console.log(preview.sampleAt(0.25).defenderHp); // 8, after the second strike
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class AttackPreview {
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.chanceToHit = clamp01(options.chanceToHit ?? 1);
|
|
31
|
+
this.strikeDuration = Math.max(0, options.strikeDuration ?? 0);
|
|
32
|
+
this.totalDamage = Math.max(0, options.damage) * Math.max(0, options.strikes);
|
|
33
|
+
this.expectedDamage = this.totalDamage * this.chanceToHit;
|
|
34
|
+
this.defenderHp0 = options.defender.hp;
|
|
35
|
+
const frames = [];
|
|
36
|
+
let defenderHp = options.defender.hp;
|
|
37
|
+
for (let strike = 0; strike <= options.strikes; strike++) {
|
|
38
|
+
if (strike > 0 && (options.hits?.[strike - 1] ?? true))
|
|
39
|
+
defenderHp -= Math.max(0, options.damage);
|
|
40
|
+
frames.push({
|
|
41
|
+
strike,
|
|
42
|
+
time: strike * this.strikeDuration,
|
|
43
|
+
attackerHp: options.attacker.hp,
|
|
44
|
+
defenderHp: Math.max(0, defenderHp),
|
|
45
|
+
defenderDamage: this.defenderHp0 - Math.max(0, defenderHp),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
this.frames = frames;
|
|
49
|
+
}
|
|
50
|
+
/** how long the animation runs, in seconds */
|
|
51
|
+
get duration() {
|
|
52
|
+
return this.strikeDuration * (this.frames.length - 1);
|
|
53
|
+
}
|
|
54
|
+
/** whether the defender would be at 0 hp once every landing strike has been shown */
|
|
55
|
+
get defenderKilled() {
|
|
56
|
+
return this.frames[this.frames.length - 1].defenderHp === 0;
|
|
57
|
+
}
|
|
58
|
+
/** the frame the animation shows at `time`, clamped to its own start and end */
|
|
59
|
+
sampleAt(time) {
|
|
60
|
+
const last = this.frames.length - 1;
|
|
61
|
+
if (this.strikeDuration <= 0)
|
|
62
|
+
return this.frames[last];
|
|
63
|
+
//compare frame times rather than dividing, so a float strike duration does not land on the
|
|
64
|
+
//frame before the one its time names (0.4 / 0.2 can read just under 2)
|
|
65
|
+
let index = 0;
|
|
66
|
+
for (let frame = 0; frame <= last; frame++) {
|
|
67
|
+
if (this.frames[frame].time <= time + 1e-9)
|
|
68
|
+
index = frame;
|
|
69
|
+
else
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
return this.frames[index];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function clamp01(value) {
|
|
76
|
+
return Math.max(0, Math.min(1, value));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=AttackPreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttackPreview.js","sourceRoot":"","sources":["../../src/battle/AttackPreview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-run battle statistics breakdown by category and unit type - recruits, recalls,
|
|
3
|
+
* advances, kills, deaths, damage dealt, damage taken - the shape Wesnoth's own
|
|
4
|
+
* statistics dialog shows and a bare `core.PlayerStats<T>` cannot give a game for free,
|
|
5
|
+
* since `T` there is an opaque summary the game must already know how to combine. Here
|
|
6
|
+
* the categories and the per-unit-type breakdown are the primitive: a game records one
|
|
7
|
+
* event at a time as it happens and reads either a category's total or its breakdown by
|
|
8
|
+
* unit type, then folds `toJSON()` into a `core.RunHistory` entry or a `core.PlayerStats`
|
|
9
|
+
* total the way any other run summary would.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { BattleStats } from '@datamoc/mw_games/battle';
|
|
14
|
+
*
|
|
15
|
+
* const stats = new BattleStats();
|
|
16
|
+
* stats.record('kills', 'orc-grunt');
|
|
17
|
+
* stats.record('kills', 'orc-grunt');
|
|
18
|
+
* stats.record('damageDealt', 'elvish-archer', 12);
|
|
19
|
+
*
|
|
20
|
+
* console.log(stats.total('kills')); // 2
|
|
21
|
+
* console.log(stats.breakdown('kills')); // [{ unitType: 'orc-grunt', count: 2 }]
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export type BattleStatCategory = 'recruits' | 'recalls' | 'advances' | 'kills' | 'deaths' | 'damageDealt' | 'damageTaken';
|
|
25
|
+
export declare class BattleStats {
|
|
26
|
+
private counts;
|
|
27
|
+
/** adds `amount` (default 1) to a category's count for one unit type */
|
|
28
|
+
record(category: BattleStatCategory, unitType: string, amount?: number): void;
|
|
29
|
+
/** one category's count for one unit type; 0 for a combination nothing has recorded yet */
|
|
30
|
+
forType(category: BattleStatCategory, unitType: string): number;
|
|
31
|
+
/** a category's total across every unit type */
|
|
32
|
+
total(category: BattleStatCategory): number;
|
|
33
|
+
/** every unit type a category has recorded, with its count - the rows a stats screen breaks a category into */
|
|
34
|
+
breakdown(category: BattleStatCategory): readonly {
|
|
35
|
+
unitType: string;
|
|
36
|
+
count: number;
|
|
37
|
+
}[];
|
|
38
|
+
toJSON(): {
|
|
39
|
+
counts: [BattleStatCategory, [string, number][]][];
|
|
40
|
+
};
|
|
41
|
+
static fromJSON(data: {
|
|
42
|
+
counts: [BattleStatCategory, [string, number][]][];
|
|
43
|
+
}): BattleStats;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=BattleStats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BattleStats.d.ts","sourceRoot":"","sources":["../../src/battle/BattleStats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,kBAAkB,GAC3B,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,QAAQ,GACR,aAAa,GACb,aAAa,CAAC;AAEjB,qBAAa,WAAW;IACvB,OAAO,CAAC,MAAM,CAAsD;IAEpE,wEAAwE;IACxE,MAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,IAAI,CAIvE;IAED,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9D;IAED,gDAAgD;IAChD,KAAK,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAM1C;IAED,+GAA+G;IAC/G,SAAS,CAAC,QAAQ,EAAE,kBAAkB,GAAG,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAGtF;IAED,MAAM,IAAI;QAAE,MAAM,EAAE,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;KAAE,CAE/D;IAED,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;KAAE,GAAG,WAAW,CAIzF;CACD"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A per-run battle statistics breakdown by category and unit type - recruits, recalls,
|
|
3
|
+
* advances, kills, deaths, damage dealt, damage taken - the shape Wesnoth's own
|
|
4
|
+
* statistics dialog shows and a bare `core.PlayerStats<T>` cannot give a game for free,
|
|
5
|
+
* since `T` there is an opaque summary the game must already know how to combine. Here
|
|
6
|
+
* the categories and the per-unit-type breakdown are the primitive: a game records one
|
|
7
|
+
* event at a time as it happens and reads either a category's total or its breakdown by
|
|
8
|
+
* unit type, then folds `toJSON()` into a `core.RunHistory` entry or a `core.PlayerStats`
|
|
9
|
+
* total the way any other run summary would.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { BattleStats } from '@datamoc/mw_games/battle';
|
|
14
|
+
*
|
|
15
|
+
* const stats = new BattleStats();
|
|
16
|
+
* stats.record('kills', 'orc-grunt');
|
|
17
|
+
* stats.record('kills', 'orc-grunt');
|
|
18
|
+
* stats.record('damageDealt', 'elvish-archer', 12);
|
|
19
|
+
*
|
|
20
|
+
* console.log(stats.total('kills')); // 2
|
|
21
|
+
* console.log(stats.breakdown('kills')); // [{ unitType: 'orc-grunt', count: 2 }]
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class BattleStats {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.counts = new Map();
|
|
27
|
+
}
|
|
28
|
+
/** adds `amount` (default 1) to a category's count for one unit type */
|
|
29
|
+
record(category, unitType, amount = 1) {
|
|
30
|
+
const byType = this.counts.get(category) ?? new Map();
|
|
31
|
+
byType.set(unitType, (byType.get(unitType) ?? 0) + amount);
|
|
32
|
+
this.counts.set(category, byType);
|
|
33
|
+
}
|
|
34
|
+
/** one category's count for one unit type; 0 for a combination nothing has recorded yet */
|
|
35
|
+
forType(category, unitType) {
|
|
36
|
+
return this.counts.get(category)?.get(unitType) ?? 0;
|
|
37
|
+
}
|
|
38
|
+
/** a category's total across every unit type */
|
|
39
|
+
total(category) {
|
|
40
|
+
const byType = this.counts.get(category);
|
|
41
|
+
if (!byType)
|
|
42
|
+
return 0;
|
|
43
|
+
let sum = 0;
|
|
44
|
+
for (const count of byType.values())
|
|
45
|
+
sum += count;
|
|
46
|
+
return sum;
|
|
47
|
+
}
|
|
48
|
+
/** every unit type a category has recorded, with its count - the rows a stats screen breaks a category into */
|
|
49
|
+
breakdown(category) {
|
|
50
|
+
const byType = this.counts.get(category);
|
|
51
|
+
return byType ? [...byType.entries()].map(([unitType, count]) => ({ unitType, count })) : [];
|
|
52
|
+
}
|
|
53
|
+
toJSON() {
|
|
54
|
+
return { counts: [...this.counts].map(([category, byType]) => [category, [...byType]]) };
|
|
55
|
+
}
|
|
56
|
+
static fromJSON(data) {
|
|
57
|
+
const stats = new BattleStats();
|
|
58
|
+
for (const [category, entries] of data.counts)
|
|
59
|
+
stats.counts.set(category, new Map(entries));
|
|
60
|
+
return stats;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=BattleStats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BattleStats.js","sourceRoot":"","sources":["../../src/battle/BattleStats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAWH,MAAM,OAAO,WAAW;IAAxB;QACS,WAAM,GAAG,IAAI,GAAG,EAA2C,CAAC;IAsCrE,CAAC;IApCA,wEAAwE;IACxE,MAAM,CAAC,QAA4B,EAAE,QAAgB,EAAE,MAAM,GAAG,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;QACtE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,2FAA2F;IAC3F,OAAO,CAAC,QAA4B,EAAE,QAAgB;QACrD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,gDAAgD;IAChD,KAAK,CAAC,QAA4B;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC;QACtB,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,IAAI,KAAK,CAAC;QAClD,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,+GAA+G;IAC/G,SAAS,CAAC,QAA4B;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,CAAC;IAED,MAAM;QACL,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,IAA4D;QAC3E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5F,OAAO,KAAK,CAAC;IACd,CAAC;CACD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.ts';
|
|
2
|
+
export interface SelectableUnit {
|
|
3
|
+
id: string;
|
|
4
|
+
side?: string;
|
|
5
|
+
/** current hp, so an attack dialog can preview it; the selector itself never reads it */
|
|
6
|
+
hp?: number;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UnitSelectorOptions {
|
|
10
|
+
units: readonly SelectableUnit[];
|
|
11
|
+
/** only units on this side may attack; every enabled unit when omitted */
|
|
12
|
+
side?: string;
|
|
13
|
+
/** further narrows who may be chosen at all (a unit that has already acted, say) */
|
|
14
|
+
disabled?: (unit: SelectableUnit) => boolean;
|
|
15
|
+
/** narrows the targets once an attacker is chosen (adjacency, range, fog) */
|
|
16
|
+
canTarget?: (attacker: SelectableUnit, target: SelectableUnit) => boolean;
|
|
17
|
+
}
|
|
18
|
+
export type SelectorStage = 'attacker' | 'target';
|
|
19
|
+
/**
|
|
20
|
+
* The two-step unit selector an attack starts with: pick who attacks, then pick what they attack.
|
|
21
|
+
*
|
|
22
|
+
* Renderer-free, so the choosing rules are tested without a board: `candidates` are the enabled
|
|
23
|
+
* units on the selecting side, `targets` are the enabled units that pass `canTarget` once an
|
|
24
|
+
* attacker is chosen, `move` walks the active list and `select` advances a stage. `back` undoes the
|
|
25
|
+
* attacker choice rather than only the target, so a player who picked the wrong attacker lands
|
|
26
|
+
* where they can pick again rather than being stuck one step in.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { UnitSelector } from '@datamoc/mw_games/battle';
|
|
31
|
+
*
|
|
32
|
+
* const selector = new UnitSelector({
|
|
33
|
+
* units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
|
|
34
|
+
* side: '1',
|
|
35
|
+
* });
|
|
36
|
+
* selector.select(); // hero attacks
|
|
37
|
+
* console.log(selector.targets.map((unit) => unit.id)); // ['rat']
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class UnitSelector {
|
|
41
|
+
readonly onChange: Signal<void>;
|
|
42
|
+
private readonly units;
|
|
43
|
+
private readonly side?;
|
|
44
|
+
private readonly disabledOf;
|
|
45
|
+
private readonly canTarget;
|
|
46
|
+
private stage_;
|
|
47
|
+
private charge;
|
|
48
|
+
private victim;
|
|
49
|
+
private highlight_;
|
|
50
|
+
constructor(options: UnitSelectorOptions);
|
|
51
|
+
get stage(): SelectorStage;
|
|
52
|
+
get attacker(): SelectableUnit | null;
|
|
53
|
+
get target(): SelectableUnit | null;
|
|
54
|
+
/** both steps are done, so the caller has an attack to make */
|
|
55
|
+
get done(): boolean;
|
|
56
|
+
/** the units that may be picked as the attacker */
|
|
57
|
+
get candidates(): readonly SelectableUnit[];
|
|
58
|
+
/** the units the chosen attacker may hit; empty until an attacker is chosen */
|
|
59
|
+
get targets(): readonly SelectableUnit[];
|
|
60
|
+
/** the index of the highlight within the active list */
|
|
61
|
+
get highlight(): number;
|
|
62
|
+
get highlighted(): SelectableUnit | null;
|
|
63
|
+
/** moves the highlight, wrapping at both ends, within whichever list is active */
|
|
64
|
+
move(delta: number): void;
|
|
65
|
+
/** takes the highlighted unit: on the attacker stage it advances to choosing a target */
|
|
66
|
+
select(): boolean;
|
|
67
|
+
/** undoes the attacker choice, so a wrong attacker can be picked again */
|
|
68
|
+
back(): void;
|
|
69
|
+
reset(): void;
|
|
70
|
+
private active;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=UnitSelector.d.ts.map
|