@datamoc/mw_games 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +359 -0
- package/README.md +7 -7
- 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/Shop.d.ts.map +1 -1
- package/dist/actors/Shop.js +4 -1
- package/dist/actors/Shop.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 +240 -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/lua.d.ts +21 -0
- package/dist/ai/lua.d.ts.map +1 -1
- package/dist/ai/lua.js +21 -0
- package/dist/ai/lua.js.map +1 -1
- package/dist/ai/score.d.ts +162 -0
- package/dist/ai/score.d.ts.map +1 -0
- package/dist/ai/score.js +147 -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/Classics.d.ts.map +1 -1
- package/dist/board/Classics.js +51 -39
- package/dist/board/Classics.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/board/HexSkirmish.d.ts.map +1 -1
- package/dist/board/HexSkirmish.js +69 -20
- package/dist/board/HexSkirmish.js.map +1 -1
- package/dist/board/Tactics.d.ts +7 -0
- package/dist/board/Tactics.d.ts.map +1 -1
- package/dist/board/Tactics.js +2 -2
- package/dist/board/Tactics.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 +53 -7
- package/dist/core/Achievements.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/actors.d.ts +46 -2
- package/dist/mwl/actors.d.ts.map +1 -1
- package/dist/mwl/actors.js +46 -2
- package/dist/mwl/actors.js.map +1 -1
- 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 +86 -0
- package/dist/mwl/carryover.d.ts.map +1 -0
- package/dist/mwl/carryover.js +70 -0
- package/dist/mwl/carryover.js.map +1 -0
- package/dist/mwl/catalog.d.ts +10 -1
- package/dist/mwl/catalog.d.ts.map +1 -1
- package/dist/mwl/catalog.js +10 -1
- package/dist/mwl/catalog.js.map +1 -1
- package/dist/mwl/compiler.d.ts +70 -3
- package/dist/mwl/compiler.d.ts.map +1 -1
- package/dist/mwl/compiler.js +70 -3
- package/dist/mwl/compiler.js.map +1 -1
- package/dist/mwl/conditions.d.ts +10 -1
- package/dist/mwl/conditions.d.ts.map +1 -1
- package/dist/mwl/conditions.js +10 -1
- package/dist/mwl/conditions.js.map +1 -1
- package/dist/mwl/content.d.ts +21 -0
- package/dist/mwl/content.d.ts.map +1 -1
- package/dist/mwl/content.js +19 -0
- package/dist/mwl/content.js.map +1 -1
- package/dist/mwl/expression.d.ts +21 -0
- package/dist/mwl/expression.d.ts.map +1 -1
- package/dist/mwl/expression.js +21 -0
- package/dist/mwl/expression.js.map +1 -1
- package/dist/mwl/fengari.d.ts +12 -1
- package/dist/mwl/fengari.d.ts.map +1 -1
- package/dist/mwl/fengari.js +12 -1
- package/dist/mwl/fengari.js.map +1 -1
- package/dist/mwl/grammar.d.ts +45 -1
- package/dist/mwl/grammar.d.ts.map +1 -1
- package/dist/mwl/grammar.js +45 -1
- package/dist/mwl/grammar.js.map +1 -1
- package/dist/mwl/hooks.d.ts +51 -6
- package/dist/mwl/hooks.d.ts.map +1 -1
- package/dist/mwl/hooks.js +45 -1
- package/dist/mwl/hooks.js.map +1 -1
- package/dist/mwl/index.d.ts +9 -3
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +5 -2
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/persistence.d.ts +32 -0
- package/dist/mwl/persistence.d.ts.map +1 -1
- package/dist/mwl/persistence.js +32 -0
- package/dist/mwl/persistence.js.map +1 -1
- package/dist/mwl/readers.d.ts +24 -2
- package/dist/mwl/readers.d.ts.map +1 -1
- package/dist/mwl/readers.js +27 -4
- package/dist/mwl/readers.js.map +1 -1
- package/dist/mwl/report.d.ts +21 -2
- package/dist/mwl/report.d.ts.map +1 -1
- package/dist/mwl/report.js +21 -2
- package/dist/mwl/report.js.map +1 -1
- package/dist/mwl/runtime.d.ts +212 -7
- package/dist/mwl/runtime.d.ts.map +1 -1
- package/dist/mwl/runtime.js +682 -90
- package/dist/mwl/runtime.js.map +1 -1
- package/dist/mwl/schema.d.ts +57 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/schema.js +181 -21
- package/dist/mwl/schema.js.map +1 -1
- package/dist/mwl/scripts.d.ts +12 -1
- package/dist/mwl/scripts.d.ts.map +1 -1
- package/dist/mwl/scripts.js +12 -1
- package/dist/mwl/scripts.js.map +1 -1
- package/dist/mwl/utils.d.ts +2 -0
- package/dist/mwl/utils.d.ts.map +1 -1
- package/dist/mwl/utils.js +4 -1
- package/dist/mwl/utils.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/rpg/GameState.d.ts +2 -2
- package/dist/rpg/GameState.js +2 -2
- 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/ColorTransformBatcher.d.ts +7 -1
- package/dist/two-d/render/ColorTransformBatcher.d.ts.map +1 -1
- package/dist/two-d/render/ColorTransformBatcher.js +10 -1
- package/dist/two-d/render/ColorTransformBatcher.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 +454 -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/TerrainGraphicsLayer.d.ts +55 -0
- package/dist/two-d/render/TerrainGraphicsLayer.d.ts.map +1 -0
- package/dist/two-d/render/TerrainGraphicsLayer.js +54 -0
- package/dist/two-d/render/TerrainGraphicsLayer.js.map +1 -0
- package/dist/two-d/render/TintedSprite.js +2 -2
- package/dist/two-d/render/TintedSprite.js.map +1 -1
- package/dist/two-d/render/index.d.ts +15 -3
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +7 -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/MarkupText.d.ts +53 -0
- package/dist/two-d/ui/MarkupText.d.ts.map +1 -0
- package/dist/two-d/ui/MarkupText.js +122 -0
- package/dist/two-d/ui/MarkupText.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 +29 -3
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +15 -2
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/two-d/ui/markup.d.ts +181 -0
- package/dist/two-d/ui/markup.d.ts.map +1 -0
- package/dist/two-d/ui/markup.js +370 -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 +2 -1
|
@@ -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;AAKH,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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnitSelector.d.ts","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;IAC7C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1E;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,YAAY;IACxB,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgE;IAE1F,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,UAAU,CAAK;IAEvB,YAAY,OAAO,EAAE,mBAAmB,EAKvC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,QAAQ,IAAI,cAAc,GAAG,IAAI,CAEpC;IAED,IAAI,MAAM,IAAI,cAAc,GAAG,IAAI,CAElC;IAED,+DAA+D;IAC/D,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,mDAAmD;IACnD,IAAI,UAAU,IAAI,SAAS,cAAc,EAAE,CAI1C;IAED,+EAA+E;IAC/E,IAAI,OAAO,IAAI,SAAS,cAAc,EAAE,CAUvC;IAED,wDAAwD;IACxD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,WAAW,IAAI,cAAc,GAAG,IAAI,CAGvC;IAED,kFAAkF;IAClF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKxB;IAED,yFAAyF;IACzF,MAAM,IAAI,OAAO,CAYhB;IAED,0EAA0E;IAC1E,IAAI,IAAI,IAAI,CASX;IAED,KAAK,IAAI,IAAI,CAMZ;IAED,OAAO,CAAC,MAAM;CAGd"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.js';
|
|
2
|
+
/**
|
|
3
|
+
* The two-step unit selector an attack starts with: pick who attacks, then pick what they attack.
|
|
4
|
+
*
|
|
5
|
+
* Renderer-free, so the choosing rules are tested without a board: `candidates` are the enabled
|
|
6
|
+
* units on the selecting side, `targets` are the enabled units that pass `canTarget` once an
|
|
7
|
+
* attacker is chosen, `move` walks the active list and `select` advances a stage. `back` undoes the
|
|
8
|
+
* attacker choice rather than only the target, so a player who picked the wrong attacker lands
|
|
9
|
+
* where they can pick again rather than being stuck one step in.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { UnitSelector } from '@datamoc/mw_games/battle';
|
|
14
|
+
*
|
|
15
|
+
* const selector = new UnitSelector({
|
|
16
|
+
* units: [{ id: 'hero', side: '1' }, { id: 'rat', side: '2' }],
|
|
17
|
+
* side: '1',
|
|
18
|
+
* });
|
|
19
|
+
* selector.select(); // hero attacks
|
|
20
|
+
* console.log(selector.targets.map((unit) => unit.id)); // ['rat']
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class UnitSelector {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.onChange = new Signal();
|
|
26
|
+
this.stage_ = 'attacker';
|
|
27
|
+
this.charge = null;
|
|
28
|
+
this.victim = null;
|
|
29
|
+
this.highlight_ = 0;
|
|
30
|
+
this.units = options.units;
|
|
31
|
+
this.side = options.side;
|
|
32
|
+
this.disabledOf = options.disabled ?? ((unit) => unit.disabled ?? false);
|
|
33
|
+
this.canTarget = options.canTarget ?? (() => true);
|
|
34
|
+
}
|
|
35
|
+
get stage() {
|
|
36
|
+
return this.stage_;
|
|
37
|
+
}
|
|
38
|
+
get attacker() {
|
|
39
|
+
return this.charge;
|
|
40
|
+
}
|
|
41
|
+
get target() {
|
|
42
|
+
return this.victim;
|
|
43
|
+
}
|
|
44
|
+
/** both steps are done, so the caller has an attack to make */
|
|
45
|
+
get done() {
|
|
46
|
+
return this.charge !== null && this.victim !== null;
|
|
47
|
+
}
|
|
48
|
+
/** the units that may be picked as the attacker */
|
|
49
|
+
get candidates() {
|
|
50
|
+
return this.units.filter((unit) => (this.side === undefined || unit.side === this.side) && !this.disabledOf(unit));
|
|
51
|
+
}
|
|
52
|
+
/** the units the chosen attacker may hit; empty until an attacker is chosen */
|
|
53
|
+
get targets() {
|
|
54
|
+
const attacker = this.charge;
|
|
55
|
+
if (!attacker)
|
|
56
|
+
return [];
|
|
57
|
+
return this.units.filter((unit) => unit.id !== attacker.id &&
|
|
58
|
+
!this.disabledOf(unit) &&
|
|
59
|
+
!(attacker.side !== undefined && unit.side === attacker.side) &&
|
|
60
|
+
this.canTarget(attacker, unit));
|
|
61
|
+
}
|
|
62
|
+
/** the index of the highlight within the active list */
|
|
63
|
+
get highlight() {
|
|
64
|
+
return this.highlight_;
|
|
65
|
+
}
|
|
66
|
+
get highlighted() {
|
|
67
|
+
const list = this.active();
|
|
68
|
+
return list[this.highlight_] ?? null;
|
|
69
|
+
}
|
|
70
|
+
/** moves the highlight, wrapping at both ends, within whichever list is active */
|
|
71
|
+
move(delta) {
|
|
72
|
+
const list = this.active();
|
|
73
|
+
if (list.length === 0)
|
|
74
|
+
return;
|
|
75
|
+
this.highlight_ = (((this.highlight_ + delta) % list.length) + list.length) % list.length;
|
|
76
|
+
this.onChange.dispatch();
|
|
77
|
+
}
|
|
78
|
+
/** takes the highlighted unit: on the attacker stage it advances to choosing a target */
|
|
79
|
+
select() {
|
|
80
|
+
const chosen = this.highlighted;
|
|
81
|
+
if (!chosen)
|
|
82
|
+
return false;
|
|
83
|
+
if (this.stage_ === 'attacker') {
|
|
84
|
+
this.charge = chosen;
|
|
85
|
+
this.stage_ = 'target';
|
|
86
|
+
this.highlight_ = 0;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.victim = chosen;
|
|
90
|
+
}
|
|
91
|
+
this.onChange.dispatch();
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/** undoes the attacker choice, so a wrong attacker can be picked again */
|
|
95
|
+
back() {
|
|
96
|
+
if (this.stage_ === 'attacker')
|
|
97
|
+
return;
|
|
98
|
+
const previous = this.charge;
|
|
99
|
+
this.charge = null;
|
|
100
|
+
this.victim = null;
|
|
101
|
+
this.stage_ = 'attacker';
|
|
102
|
+
const index = previous ? this.candidates.findIndex((unit) => unit.id === previous.id) : -1;
|
|
103
|
+
this.highlight_ = index >= 0 ? index : 0;
|
|
104
|
+
this.onChange.dispatch();
|
|
105
|
+
}
|
|
106
|
+
reset() {
|
|
107
|
+
this.charge = null;
|
|
108
|
+
this.victim = null;
|
|
109
|
+
this.stage_ = 'attacker';
|
|
110
|
+
this.highlight_ = 0;
|
|
111
|
+
this.onChange.dispatch();
|
|
112
|
+
}
|
|
113
|
+
active() {
|
|
114
|
+
return this.stage_ === 'attacker' ? this.candidates : this.targets;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=UnitSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnitSelector.js","sourceRoot":"","sources":["../../src/battle/UnitSelector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.ts';
|
|
2
|
+
export interface WhiteboardEntry {
|
|
3
|
+
/** the unit the plan is for; one plan per unit, the way a turn's moves are planned */
|
|
4
|
+
unit: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
|
|
8
|
+
*
|
|
9
|
+
* A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
|
|
10
|
+
* than stacking a second one for the same unit: what is on the board is the turn as it would be
|
|
11
|
+
* played, not the history of how a player got there. Undo pops the last plan onto a redo stack
|
|
12
|
+
* (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
|
|
13
|
+
* caller, which is where the framework stops - actually executing them is the game's turn.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { Whiteboard } from '@datamoc/mw_games/battle';
|
|
18
|
+
*
|
|
19
|
+
* const board = new Whiteboard<{ unit: string; x: number; y: number }>();
|
|
20
|
+
* board.plan({ unit: 'hero', x: 2, y: 3 });
|
|
21
|
+
* board.plan({ unit: 'archer', x: 5, y: 1 });
|
|
22
|
+
* board.undo();
|
|
23
|
+
* console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class Whiteboard<T extends WhiteboardEntry = WhiteboardEntry> {
|
|
27
|
+
readonly onChange: Signal<void>;
|
|
28
|
+
private planned;
|
|
29
|
+
private undone;
|
|
30
|
+
get plans(): readonly T[];
|
|
31
|
+
get isEmpty(): boolean;
|
|
32
|
+
get canUndo(): boolean;
|
|
33
|
+
get canRedo(): boolean;
|
|
34
|
+
/** the plan for a unit, if it has one on the board */
|
|
35
|
+
plannedFor(unit: string): T | undefined;
|
|
36
|
+
/** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
|
|
37
|
+
plan(action: T): void;
|
|
38
|
+
/** takes the last plan off the board, returning it so a caller can put it back */
|
|
39
|
+
undo(): T | null;
|
|
40
|
+
/** puts the last undone plan back, replacing any plan the unit has picked up since */
|
|
41
|
+
redo(): T | null;
|
|
42
|
+
/** empties the board, both the plans and anything undone */
|
|
43
|
+
clear(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
|
|
46
|
+
* The orders are returned in planning order.
|
|
47
|
+
*/
|
|
48
|
+
commit(): T[];
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=Whiteboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Whiteboard.d.ts","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe;IAClE,QAAQ,CAAC,QAAQ,eAAsB;IAEvC,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,MAAM,CAAW;IAEzB,IAAI,KAAK,IAAI,SAAS,CAAC,EAAE,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,sDAAsD;IACtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAEtC;IAED,yFAAyF;IACzF,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAMpB;IAED,kFAAkF;IAClF,IAAI,IAAI,CAAC,GAAG,IAAI,CAMf;IAED,sFAAsF;IACtF,IAAI,IAAI,CAAC,GAAG,IAAI,CAOf;IAED,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAKZ;IAED;;;OAGG;IACH,MAAM,IAAI,CAAC,EAAE,CAMZ;CACD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Signal } from '../core/Signal.js';
|
|
2
|
+
/**
|
|
3
|
+
* The planned-but-uncommitted orders of a turn - Wesnoth's whiteboard - with undo across them.
|
|
4
|
+
*
|
|
5
|
+
* A plan is one entry per unit, so replanning a unit replaces its earlier order in place rather
|
|
6
|
+
* than stacking a second one for the same unit: what is on the board is the turn as it would be
|
|
7
|
+
* played, not the history of how a player got there. Undo pops the last plan onto a redo stack
|
|
8
|
+
* (planning again clears that stack, the usual undo contract), and `commit` hands the plans to the
|
|
9
|
+
* caller, which is where the framework stops - actually executing them is the game's turn.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { Whiteboard } from '@datamoc/mw_games/battle';
|
|
14
|
+
*
|
|
15
|
+
* const board = new Whiteboard<{ unit: string; x: number; y: number }>();
|
|
16
|
+
* board.plan({ unit: 'hero', x: 2, y: 3 });
|
|
17
|
+
* board.plan({ unit: 'archer', x: 5, y: 1 });
|
|
18
|
+
* board.undo();
|
|
19
|
+
* console.log(board.plans); // [{ unit: 'hero', x: 2, y: 3 }]
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class Whiteboard {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.onChange = new Signal();
|
|
25
|
+
this.planned = [];
|
|
26
|
+
this.undone = [];
|
|
27
|
+
}
|
|
28
|
+
get plans() {
|
|
29
|
+
return this.planned;
|
|
30
|
+
}
|
|
31
|
+
get isEmpty() {
|
|
32
|
+
return this.planned.length === 0;
|
|
33
|
+
}
|
|
34
|
+
get canUndo() {
|
|
35
|
+
return this.planned.length > 0;
|
|
36
|
+
}
|
|
37
|
+
get canRedo() {
|
|
38
|
+
return this.undone.length > 0;
|
|
39
|
+
}
|
|
40
|
+
/** the plan for a unit, if it has one on the board */
|
|
41
|
+
plannedFor(unit) {
|
|
42
|
+
return this.planned.find((entry) => entry.unit === unit);
|
|
43
|
+
}
|
|
44
|
+
/** adds or replaces a unit's plan; clears the redo stack, as planning after undo does */
|
|
45
|
+
plan(action) {
|
|
46
|
+
const index = this.planned.findIndex((entry) => entry.unit === action.unit);
|
|
47
|
+
if (index >= 0)
|
|
48
|
+
this.planned[index] = action;
|
|
49
|
+
else
|
|
50
|
+
this.planned.push(action);
|
|
51
|
+
this.undone = [];
|
|
52
|
+
this.onChange.dispatch();
|
|
53
|
+
}
|
|
54
|
+
/** takes the last plan off the board, returning it so a caller can put it back */
|
|
55
|
+
undo() {
|
|
56
|
+
const entry = this.planned.pop();
|
|
57
|
+
if (!entry)
|
|
58
|
+
return null;
|
|
59
|
+
this.undone.push(entry);
|
|
60
|
+
this.onChange.dispatch();
|
|
61
|
+
return entry;
|
|
62
|
+
}
|
|
63
|
+
/** puts the last undone plan back, replacing any plan the unit has picked up since */
|
|
64
|
+
redo() {
|
|
65
|
+
const entry = this.undone.pop();
|
|
66
|
+
if (!entry)
|
|
67
|
+
return null;
|
|
68
|
+
this.planned = this.planned.filter((candidate) => candidate.unit !== entry.unit);
|
|
69
|
+
this.planned.push(entry);
|
|
70
|
+
this.onChange.dispatch();
|
|
71
|
+
return entry;
|
|
72
|
+
}
|
|
73
|
+
/** empties the board, both the plans and anything undone */
|
|
74
|
+
clear() {
|
|
75
|
+
if (this.planned.length === 0 && this.undone.length === 0)
|
|
76
|
+
return;
|
|
77
|
+
this.planned = [];
|
|
78
|
+
this.undone = [];
|
|
79
|
+
this.onChange.dispatch();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Hands the plans to the caller and empties the board - the moment a turn stops being a plan.
|
|
83
|
+
* The orders are returned in planning order.
|
|
84
|
+
*/
|
|
85
|
+
commit() {
|
|
86
|
+
const committed = this.planned;
|
|
87
|
+
this.planned = [];
|
|
88
|
+
this.undone = [];
|
|
89
|
+
if (committed.length > 0)
|
|
90
|
+
this.onChange.dispatch();
|
|
91
|
+
return committed;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=Whiteboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Whiteboard.js","sourceRoot":"","sources":["../../src/battle/Whiteboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAO3C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,UAAU;IAAvB;QACU,aAAQ,GAAG,IAAI,MAAM,EAAQ,CAAC;QAE/B,YAAO,GAAQ,EAAE,CAAC;QAClB,WAAM,GAAQ,EAAE,CAAC;IAsE1B,CAAC;IApEA,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,sDAAsD;IACtD,UAAU,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,yFAAyF;IACzF,IAAI,CAAC,MAAS;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5E,IAAI,KAAK,IAAI,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;;YACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,kFAAkF;IAClF,IAAI;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,sFAAsF;IACtF,IAAI;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;QACjF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,4DAA4D;IAC5D,KAAK;QACJ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAClE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,MAAM;QACL,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC;IAClB,CAAC;CACD"}
|
package/dist/battle/index.d.ts
CHANGED
|
@@ -13,4 +13,14 @@ export { BattleHooks } from './Hooks.ts';
|
|
|
13
13
|
export type { BattleHook } from './Hooks.ts';
|
|
14
14
|
export { Field } from './Field.ts';
|
|
15
15
|
export type { FieldCondition } from './Field.ts';
|
|
16
|
+
export { AttackPreview } from './AttackPreview.ts';
|
|
17
|
+
export { AttackDialog } from './AttackDialog.ts';
|
|
18
|
+
export type { AttackDialogOptions, StrikeNumbers } from './AttackDialog.ts';
|
|
19
|
+
export type { AttackFrame, AttackPreviewOptions, PreviewCombatant } from './AttackPreview.ts';
|
|
20
|
+
export { UnitSelector } from './UnitSelector.ts';
|
|
21
|
+
export type { SelectableUnit, SelectorStage, UnitSelectorOptions } from './UnitSelector.ts';
|
|
22
|
+
export { Whiteboard } from './Whiteboard.ts';
|
|
23
|
+
export type { WhiteboardEntry } from './Whiteboard.ts';
|
|
24
|
+
export { BattleStats } from './BattleStats.ts';
|
|
25
|
+
export type { BattleStatCategory } from './BattleStats.ts';
|
|
16
26
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/battle/index.js
CHANGED
|
@@ -7,4 +7,9 @@ export { StatStages } from './StatStages.js';
|
|
|
7
7
|
export { chooseMove, chooseSwitch } from './BattleAI.js';
|
|
8
8
|
export { BattleHooks } from './Hooks.js';
|
|
9
9
|
export { Field } from './Field.js';
|
|
10
|
+
export { AttackPreview } from './AttackPreview.js';
|
|
11
|
+
export { AttackDialog } from './AttackDialog.js';
|
|
12
|
+
export { UnitSelector } from './UnitSelector.js';
|
|
13
|
+
export { Whiteboard } from './Whiteboard.js';
|
|
14
|
+
export { BattleStats } from './BattleStats.js';
|
|
10
15
|
//# sourceMappingURL=index.js.map
|
package/dist/battle/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Classics.d.ts","sourceRoot":"","sources":["../../src/board/Classics.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Classics.d.ts","sourceRoot":"","sources":["../../src/board/Classics.ts"],"names":[],"mappings":"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"}
|
package/dist/board/Classics.js
CHANGED
|
@@ -196,7 +196,7 @@ export function playGo(state, x, y) {
|
|
|
196
196
|
//tracked directly rather than diffed against the old board afterwards, since the played
|
|
197
197
|
//stone's own cell also differs and diffing can't tell the two apart
|
|
198
198
|
let soleCaptured = null;
|
|
199
|
-
for (const neighbour of
|
|
199
|
+
for (const neighbour of neighbours(state.size, index)) {
|
|
200
200
|
if (board[neighbour] !== enemy || liberties(board, state.size, neighbour) !== 0)
|
|
201
201
|
continue;
|
|
202
202
|
const removed = group(board, state.size, neighbour);
|
|
@@ -264,7 +264,7 @@ export function goScore(state) {
|
|
|
264
264
|
const area = group(state.board, state.size, i);
|
|
265
265
|
const borders = new Set();
|
|
266
266
|
for (const cell of area)
|
|
267
|
-
for (const neighbour of
|
|
267
|
+
for (const neighbour of neighbours(state.size, cell))
|
|
268
268
|
if (state.board[neighbour])
|
|
269
269
|
borders.add(state.board[neighbour]);
|
|
270
270
|
for (const cell of area)
|
|
@@ -280,41 +280,36 @@ function goIndex(state, x, y) {
|
|
|
280
280
|
throw new Error('Go cell is outside the board');
|
|
281
281
|
return y * state.size + x;
|
|
282
282
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
.
|
|
283
|
+
/** the in-bounds orthogonal neighbours of a square-grid index, as indices */
|
|
284
|
+
function neighbours(size, index) {
|
|
285
|
+
const x = index % size;
|
|
286
|
+
const y = Math.floor(index / size);
|
|
287
|
+
const out = [];
|
|
288
|
+
if (x > 0)
|
|
289
|
+
out.push(index - 1);
|
|
290
|
+
if (x < size - 1)
|
|
291
|
+
out.push(index + 1);
|
|
292
|
+
if (y > 0)
|
|
293
|
+
out.push(index - size);
|
|
294
|
+
if (y < size - 1)
|
|
295
|
+
out.push(index + size);
|
|
296
|
+
return out;
|
|
294
297
|
}
|
|
298
|
+
//cells connected to `start` that share its value - a group of one colour's stones, or, when
|
|
299
|
+
//`start` is itself empty, the empty region around it, which is what `goScore` counts as territory
|
|
295
300
|
function group(board, size, start) {
|
|
296
|
-
const
|
|
297
|
-
if (!stone)
|
|
298
|
-
return [];
|
|
301
|
+
const value = board[start];
|
|
299
302
|
const found = [];
|
|
300
303
|
const todo = [start];
|
|
301
304
|
const seen = new Set();
|
|
302
305
|
while (todo.length) {
|
|
303
306
|
const index = todo.pop();
|
|
304
|
-
if (seen.has(index) || board[index] !==
|
|
307
|
+
if (seen.has(index) || board[index] !== value)
|
|
305
308
|
continue;
|
|
306
309
|
seen.add(index);
|
|
307
310
|
found.push(index);
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
for (const [nx, ny] of [
|
|
311
|
-
[x - 1, y],
|
|
312
|
-
[x + 1, y],
|
|
313
|
-
[x, y - 1],
|
|
314
|
-
[x, y + 1],
|
|
315
|
-
])
|
|
316
|
-
if (nx >= 0 && ny >= 0 && nx < size && ny < size)
|
|
317
|
-
todo.push(ny * size + nx);
|
|
311
|
+
for (const next of neighbours(size, index))
|
|
312
|
+
todo.push(next);
|
|
318
313
|
}
|
|
319
314
|
return found;
|
|
320
315
|
}
|
|
@@ -322,16 +317,9 @@ function liberties(board, size, start) {
|
|
|
322
317
|
const cells = group(board, size, start);
|
|
323
318
|
const empty = new Set();
|
|
324
319
|
for (const index of cells) {
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
[x - 1, y],
|
|
329
|
-
[x + 1, y],
|
|
330
|
-
[x, y - 1],
|
|
331
|
-
[x, y + 1],
|
|
332
|
-
])
|
|
333
|
-
if (nx >= 0 && ny >= 0 && nx < size && ny < size && board[ny * size + nx] === null)
|
|
334
|
-
empty.add(ny * size + nx);
|
|
320
|
+
for (const next of neighbours(size, index))
|
|
321
|
+
if (board[next] === null)
|
|
322
|
+
empty.add(next);
|
|
335
323
|
}
|
|
336
324
|
return empty.size;
|
|
337
325
|
}
|
|
@@ -381,6 +369,28 @@ export function rollBackgammonDice() {
|
|
|
381
369
|
*/
|
|
382
370
|
export function backgammonMoves(state, dice) {
|
|
383
371
|
const side = state.turn === 'white' ? 1 : -1;
|
|
372
|
+
//bearing off needs every checker in the home board (18-23 for white, 0-5 for black) and
|
|
373
|
+
//none on the bar; `pips` is the distance from a point to the off edge, so the checkers with
|
|
374
|
+
//the smallest pips are the ones closest to bearing off
|
|
375
|
+
const home = side === 1 ? [18, 23] : [0, 5];
|
|
376
|
+
const pips = (point) => (side === 1 ? 24 - point : point + 1);
|
|
377
|
+
let allHome = true;
|
|
378
|
+
let closest = Infinity;
|
|
379
|
+
for (let point = 0; point < 24; point++) {
|
|
380
|
+
if (state.points[point] * side <= 0)
|
|
381
|
+
continue;
|
|
382
|
+
if (point < home[0] || point > home[1])
|
|
383
|
+
allHome = false;
|
|
384
|
+
closest = Math.min(closest, pips(point));
|
|
385
|
+
}
|
|
386
|
+
//an exact roll bears off any checker; an over-roll only the checker nearest the off edge,
|
|
387
|
+
//since a checker must never skip past another one on its way off
|
|
388
|
+
const canBearOff = (from, die) => {
|
|
389
|
+
if (!allHome)
|
|
390
|
+
return false;
|
|
391
|
+
const needed = pips(from);
|
|
392
|
+
return die === needed || (die > needed && needed === closest);
|
|
393
|
+
};
|
|
384
394
|
const out = [];
|
|
385
395
|
for (const die of dice) {
|
|
386
396
|
if (state.bar[state.turn] > 0) {
|
|
@@ -392,8 +402,10 @@ export function backgammonMoves(state, dice) {
|
|
|
392
402
|
for (let from = 0; from < 24; from++)
|
|
393
403
|
if (state.points[from] * side > 0) {
|
|
394
404
|
const to = from + die * side;
|
|
395
|
-
if (to < 0 || to >= 24)
|
|
396
|
-
|
|
405
|
+
if (to < 0 || to >= 24) {
|
|
406
|
+
if (canBearOff(from, die))
|
|
407
|
+
out.push({ from, to: 'off', die });
|
|
408
|
+
}
|
|
397
409
|
else if (canBackgammonLand(state, to, side))
|
|
398
410
|
out.push({ from, to, die });
|
|
399
411
|
}
|