@datamoc/mw_games 0.1.1
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/LICENSE +373 -0
- package/README.md +327 -0
- package/dist/actors/Advancement.d.ts +73 -0
- package/dist/actors/Advancement.d.ts.map +1 -0
- package/dist/actors/Advancement.js +98 -0
- package/dist/actors/Advancement.js.map +1 -0
- package/dist/actors/Affix.d.ts +44 -0
- package/dist/actors/Affix.d.ts.map +1 -0
- package/dist/actors/Affix.js +35 -0
- package/dist/actors/Affix.js.map +1 -0
- package/dist/actors/Appearances.d.ts +36 -0
- package/dist/actors/Appearances.d.ts.map +1 -0
- package/dist/actors/Appearances.js +50 -0
- package/dist/actors/Appearances.js.map +1 -0
- package/dist/actors/Charges.d.ts +31 -0
- package/dist/actors/Charges.d.ts.map +1 -0
- package/dist/actors/Charges.js +35 -0
- package/dist/actors/Charges.js.map +1 -0
- package/dist/actors/Equipment.d.ts +40 -0
- package/dist/actors/Equipment.d.ts.map +1 -0
- package/dist/actors/Equipment.js +57 -0
- package/dist/actors/Equipment.js.map +1 -0
- package/dist/actors/Inventory.d.ts +50 -0
- package/dist/actors/Inventory.d.ts.map +1 -0
- package/dist/actors/Inventory.js +56 -0
- package/dist/actors/Inventory.js.map +1 -0
- package/dist/actors/ItemState.d.ts +21 -0
- package/dist/actors/ItemState.d.ts.map +1 -0
- package/dist/actors/ItemState.js +34 -0
- package/dist/actors/ItemState.js.map +1 -0
- package/dist/actors/Loot.d.ts +24 -0
- package/dist/actors/Loot.d.ts.map +1 -0
- package/dist/actors/Loot.js +14 -0
- package/dist/actors/Loot.js.map +1 -0
- package/dist/actors/Progression.d.ts +30 -0
- package/dist/actors/Progression.d.ts.map +1 -0
- package/dist/actors/Progression.js +39 -0
- package/dist/actors/Progression.js.map +1 -0
- package/dist/actors/Resource.d.ts +23 -0
- package/dist/actors/Resource.d.ts.map +1 -0
- package/dist/actors/Resource.js +28 -0
- package/dist/actors/Resource.js.map +1 -0
- package/dist/actors/Scaling.d.ts +22 -0
- package/dist/actors/Scaling.d.ts.map +1 -0
- package/dist/actors/Scaling.js +9 -0
- package/dist/actors/Scaling.js.map +1 -0
- package/dist/actors/Shop.d.ts +25 -0
- package/dist/actors/Shop.d.ts.map +1 -0
- package/dist/actors/Shop.js +33 -0
- package/dist/actors/Shop.js.map +1 -0
- package/dist/actors/SkillPoints.d.ts +45 -0
- package/dist/actors/SkillPoints.d.ts.map +1 -0
- package/dist/actors/SkillPoints.js +58 -0
- package/dist/actors/SkillPoints.js.map +1 -0
- package/dist/actors/StatBlock.d.ts +52 -0
- package/dist/actors/StatBlock.d.ts.map +1 -0
- package/dist/actors/StatBlock.js +80 -0
- package/dist/actors/StatBlock.js.map +1 -0
- package/dist/actors/StatusEffect.d.ts +38 -0
- package/dist/actors/StatusEffect.d.ts.map +1 -0
- package/dist/actors/StatusEffect.js +28 -0
- package/dist/actors/StatusEffect.js.map +1 -0
- package/dist/actors/craft.d.ts +26 -0
- package/dist/actors/craft.d.ts.map +1 -0
- package/dist/actors/craft.js +34 -0
- package/dist/actors/craft.js.map +1 -0
- package/dist/actors/index.d.ts +33 -0
- package/dist/actors/index.d.ts.map +1 -0
- package/dist/actors/index.js +18 -0
- package/dist/actors/index.js.map +1 -0
- package/dist/actors/skillCheck.d.ts +13 -0
- package/dist/actors/skillCheck.d.ts.map +1 -0
- package/dist/actors/skillCheck.js +16 -0
- package/dist/actors/skillCheck.js.map +1 -0
- package/dist/assets/index.d.ts +37 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +62 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/audio/Music.d.ts +22 -0
- package/dist/audio/Music.d.ts.map +1 -0
- package/dist/audio/Music.js +67 -0
- package/dist/audio/Music.js.map +1 -0
- package/dist/audio/Playable.d.ts +16 -0
- package/dist/audio/Playable.d.ts.map +1 -0
- package/dist/audio/Playable.js +6 -0
- package/dist/audio/Playable.js.map +1 -0
- package/dist/audio/Sound.d.ts +23 -0
- package/dist/audio/Sound.d.ts.map +1 -0
- package/dist/audio/Sound.js +30 -0
- package/dist/audio/Sound.js.map +1 -0
- package/dist/audio/index.d.ts +7 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +4 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/battle/BattleAI.d.ts +24 -0
- package/dist/battle/BattleAI.d.ts.map +1 -0
- package/dist/battle/BattleAI.js +47 -0
- package/dist/battle/BattleAI.js.map +1 -0
- package/dist/battle/Evolution.d.ts +22 -0
- package/dist/battle/Evolution.d.ts.map +1 -0
- package/dist/battle/Evolution.js +25 -0
- package/dist/battle/Evolution.js.map +1 -0
- package/dist/battle/Field.d.ts +25 -0
- package/dist/battle/Field.d.ts.map +1 -0
- package/dist/battle/Field.js +31 -0
- package/dist/battle/Field.js.map +1 -0
- package/dist/battle/Hooks.d.ts +29 -0
- package/dist/battle/Hooks.d.ts.map +1 -0
- package/dist/battle/Hooks.js +20 -0
- package/dist/battle/Hooks.js.map +1 -0
- package/dist/battle/Move.d.ts +32 -0
- package/dist/battle/Move.d.ts.map +1 -0
- package/dist/battle/Move.js +10 -0
- package/dist/battle/Move.js.map +1 -0
- package/dist/battle/Party.d.ts +21 -0
- package/dist/battle/Party.d.ts.map +1 -0
- package/dist/battle/Party.js +49 -0
- package/dist/battle/Party.js.map +1 -0
- package/dist/battle/Species.d.ts +40 -0
- package/dist/battle/Species.d.ts.map +1 -0
- package/dist/battle/Species.js +31 -0
- package/dist/battle/Species.js.map +1 -0
- package/dist/battle/StatStages.d.ts +38 -0
- package/dist/battle/StatStages.d.ts.map +1 -0
- package/dist/battle/StatStages.js +50 -0
- package/dist/battle/StatStages.js.map +1 -0
- package/dist/battle/TypeMatrix.d.ts +14 -0
- package/dist/battle/TypeMatrix.d.ts.map +1 -0
- package/dist/battle/TypeMatrix.js +24 -0
- package/dist/battle/TypeMatrix.js.map +1 -0
- package/dist/battle/index.d.ts +16 -0
- package/dist/battle/index.d.ts.map +1 -0
- package/dist/battle/index.js +10 -0
- package/dist/battle/index.js.map +1 -0
- package/dist/board/Classics.d.ts +123 -0
- package/dist/board/Classics.d.ts.map +1 -0
- package/dist/board/Classics.js +260 -0
- package/dist/board/Classics.js.map +1 -0
- package/dist/board/Engine.d.ts +23 -0
- package/dist/board/Engine.d.ts.map +1 -0
- package/dist/board/Engine.js +87 -0
- package/dist/board/Engine.js.map +1 -0
- package/dist/board/Tactics.d.ts +46 -0
- package/dist/board/Tactics.d.ts.map +1 -0
- package/dist/board/Tactics.js +108 -0
- package/dist/board/Tactics.js.map +1 -0
- package/dist/board/chess.d.ts +67 -0
- package/dist/board/chess.d.ts.map +1 -0
- package/dist/board/chess.js +439 -0
- package/dist/board/chess.js.map +1 -0
- package/dist/board/index.d.ts +9 -0
- package/dist/board/index.d.ts.map +1 -0
- package/dist/board/index.js +5 -0
- package/dist/board/index.js.map +1 -0
- package/dist/core/Achievements.d.ts +53 -0
- package/dist/core/Achievements.d.ts.map +1 -0
- package/dist/core/Achievements.js +80 -0
- package/dist/core/Achievements.js.map +1 -0
- package/dist/core/Collection.d.ts +46 -0
- package/dist/core/Collection.d.ts.map +1 -0
- package/dist/core/Collection.js +61 -0
- package/dist/core/Collection.js.map +1 -0
- package/dist/core/Game.d.ts +115 -0
- package/dist/core/Game.d.ts.map +1 -0
- package/dist/core/Game.js +236 -0
- package/dist/core/Game.js.map +1 -0
- package/dist/core/Hex.d.ts +45 -0
- package/dist/core/Hex.d.ts.map +1 -0
- package/dist/core/Hex.js +120 -0
- package/dist/core/Hex.js.map +1 -0
- package/dist/core/Input.d.ts +41 -0
- package/dist/core/Input.d.ts.map +1 -0
- package/dist/core/Input.js +132 -0
- package/dist/core/Input.js.map +1 -0
- package/dist/core/Log.d.ts +39 -0
- package/dist/core/Log.d.ts.map +1 -0
- package/dist/core/Log.js +50 -0
- package/dist/core/Log.js.map +1 -0
- package/dist/core/Random.d.ts +64 -0
- package/dist/core/Random.d.ts.map +1 -0
- package/dist/core/Random.js +178 -0
- package/dist/core/Random.js.map +1 -0
- package/dist/core/Replay.d.ts +71 -0
- package/dist/core/Replay.d.ts.map +1 -0
- package/dist/core/Replay.js +102 -0
- package/dist/core/Replay.js.map +1 -0
- package/dist/core/Save.d.ts +52 -0
- package/dist/core/Save.d.ts.map +1 -0
- package/dist/core/Save.js +81 -0
- package/dist/core/Save.js.map +1 -0
- package/dist/core/Scene.d.ts +40 -0
- package/dist/core/Scene.d.ts.map +1 -0
- package/dist/core/Scene.js +56 -0
- package/dist/core/Scene.js.map +1 -0
- package/dist/core/SceneStack.d.ts +37 -0
- package/dist/core/SceneStack.d.ts.map +1 -0
- package/dist/core/SceneStack.js +67 -0
- package/dist/core/SceneStack.js.map +1 -0
- package/dist/core/Signal.d.ts +24 -0
- package/dist/core/Signal.d.ts.map +1 -0
- package/dist/core/Signal.js +41 -0
- package/dist/core/Signal.js.map +1 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/i18n/index.d.ts +51 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +74 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/mw_games.global.js +993 -0
- package/dist/render/ActorAnimator.d.ts +60 -0
- package/dist/render/ActorAnimator.d.ts.map +1 -0
- package/dist/render/ActorAnimator.js +76 -0
- package/dist/render/ActorAnimator.js.map +1 -0
- package/dist/render/AnimatedSprite.d.ts +57 -0
- package/dist/render/AnimatedSprite.d.ts.map +1 -0
- package/dist/render/AnimatedSprite.js +105 -0
- package/dist/render/AnimatedSprite.js.map +1 -0
- package/dist/render/Autotile.d.ts +42 -0
- package/dist/render/Autotile.d.ts.map +1 -0
- package/dist/render/Autotile.js +117 -0
- package/dist/render/Autotile.js.map +1 -0
- package/dist/render/Camera.d.ts +88 -0
- package/dist/render/Camera.d.ts.map +1 -0
- package/dist/render/Camera.js +145 -0
- package/dist/render/Camera.js.map +1 -0
- package/dist/render/ColorTransformBatcher.d.ts +57 -0
- package/dist/render/ColorTransformBatcher.d.ts.map +1 -0
- package/dist/render/ColorTransformBatcher.js +212 -0
- package/dist/render/ColorTransformBatcher.js.map +1 -0
- package/dist/render/LayeredSprite.d.ts +27 -0
- package/dist/render/LayeredSprite.d.ts.map +1 -0
- package/dist/render/LayeredSprite.js +53 -0
- package/dist/render/LayeredSprite.js.map +1 -0
- package/dist/render/Projectile.d.ts +37 -0
- package/dist/render/Projectile.d.ts.map +1 -0
- package/dist/render/Projectile.js +50 -0
- package/dist/render/Projectile.js.map +1 -0
- package/dist/render/SpriteSheet.d.ts +38 -0
- package/dist/render/SpriteSheet.d.ts.map +1 -0
- package/dist/render/SpriteSheet.js +79 -0
- package/dist/render/SpriteSheet.js.map +1 -0
- package/dist/render/TileMap.d.ts +188 -0
- package/dist/render/TileMap.d.ts.map +1 -0
- package/dist/render/TileMap.js +488 -0
- package/dist/render/TileMap.js.map +1 -0
- package/dist/render/TintedSprite.d.ts +47 -0
- package/dist/render/TintedSprite.d.ts.map +1 -0
- package/dist/render/TintedSprite.js +173 -0
- package/dist/render/TintedSprite.js.map +1 -0
- package/dist/render/index.d.ts +18 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +11 -0
- package/dist/render/index.js.map +1 -0
- package/dist/roguelike/Blob.d.ts +46 -0
- package/dist/roguelike/Blob.d.ts.map +1 -0
- package/dist/roguelike/Blob.js +98 -0
- package/dist/roguelike/Blob.js.map +1 -0
- package/dist/roguelike/Boss.d.ts +67 -0
- package/dist/roguelike/Boss.d.ts.map +1 -0
- package/dist/roguelike/Boss.js +114 -0
- package/dist/roguelike/Boss.js.map +1 -0
- package/dist/roguelike/Combat.d.ts +23 -0
- package/dist/roguelike/Combat.d.ts.map +1 -0
- package/dist/roguelike/Combat.js +27 -0
- package/dist/roguelike/Combat.js.map +1 -0
- package/dist/roguelike/Doors.d.ts +60 -0
- package/dist/roguelike/Doors.d.ts.map +1 -0
- package/dist/roguelike/Doors.js +102 -0
- package/dist/roguelike/Doors.js.map +1 -0
- package/dist/roguelike/Elevation.d.ts +26 -0
- package/dist/roguelike/Elevation.d.ts.map +1 -0
- package/dist/roguelike/Elevation.js +37 -0
- package/dist/roguelike/Elevation.js.map +1 -0
- package/dist/roguelike/FieldOfView.d.ts +72 -0
- package/dist/roguelike/FieldOfView.d.ts.map +1 -0
- package/dist/roguelike/FieldOfView.js +134 -0
- package/dist/roguelike/FieldOfView.js.map +1 -0
- package/dist/roguelike/Level.d.ts +96 -0
- package/dist/roguelike/Level.d.ts.map +1 -0
- package/dist/roguelike/Level.js +137 -0
- package/dist/roguelike/Level.js.map +1 -0
- package/dist/roguelike/MonsterAI.d.ts +40 -0
- package/dist/roguelike/MonsterAI.d.ts.map +1 -0
- package/dist/roguelike/MonsterAI.js +69 -0
- package/dist/roguelike/MonsterAI.js.map +1 -0
- package/dist/roguelike/Pathfinder.d.ts +82 -0
- package/dist/roguelike/Pathfinder.d.ts.map +1 -0
- package/dist/roguelike/Pathfinder.js +192 -0
- package/dist/roguelike/Pathfinder.js.map +1 -0
- package/dist/roguelike/Scheduler.d.ts +45 -0
- package/dist/roguelike/Scheduler.d.ts.map +1 -0
- package/dist/roguelike/Scheduler.js +82 -0
- package/dist/roguelike/Scheduler.js.map +1 -0
- package/dist/roguelike/Secrets.d.ts +44 -0
- package/dist/roguelike/Secrets.d.ts.map +1 -0
- package/dist/roguelike/Secrets.js +64 -0
- package/dist/roguelike/Secrets.js.map +1 -0
- package/dist/roguelike/Targeting.d.ts +66 -0
- package/dist/roguelike/Targeting.d.ts.map +1 -0
- package/dist/roguelike/Targeting.js +150 -0
- package/dist/roguelike/Targeting.js.map +1 -0
- package/dist/roguelike/generate.d.ts +44 -0
- package/dist/roguelike/generate.d.ts.map +1 -0
- package/dist/roguelike/generate.js +88 -0
- package/dist/roguelike/generate.js.map +1 -0
- package/dist/roguelike/index.d.ts +23 -0
- package/dist/roguelike/index.d.ts.map +1 -0
- package/dist/roguelike/index.js +15 -0
- package/dist/roguelike/index.js.map +1 -0
- package/dist/rpg/Event.d.ts +33 -0
- package/dist/rpg/Event.d.ts.map +1 -0
- package/dist/rpg/Event.js +19 -0
- package/dist/rpg/Event.js.map +1 -0
- package/dist/rpg/EventRunner.d.ts +72 -0
- package/dist/rpg/EventRunner.d.ts.map +1 -0
- package/dist/rpg/EventRunner.js +76 -0
- package/dist/rpg/EventRunner.js.map +1 -0
- package/dist/rpg/GameState.d.ts +22 -0
- package/dist/rpg/GameState.d.ts.map +1 -0
- package/dist/rpg/GameState.js +35 -0
- package/dist/rpg/GameState.js.map +1 -0
- package/dist/rpg/GridMover.d.ts +51 -0
- package/dist/rpg/GridMover.d.ts.map +1 -0
- package/dist/rpg/GridMover.js +91 -0
- package/dist/rpg/GridMover.js.map +1 -0
- package/dist/rpg/Quest.d.ts +67 -0
- package/dist/rpg/Quest.d.ts.map +1 -0
- package/dist/rpg/Quest.js +92 -0
- package/dist/rpg/Quest.js.map +1 -0
- package/dist/rpg/TiledMap.d.ts +107 -0
- package/dist/rpg/TiledMap.d.ts.map +1 -0
- package/dist/rpg/TiledMap.js +123 -0
- package/dist/rpg/TiledMap.js.map +1 -0
- package/dist/rpg/automap.d.ts +40 -0
- package/dist/rpg/automap.d.ts.map +1 -0
- package/dist/rpg/automap.js +81 -0
- package/dist/rpg/automap.js.map +1 -0
- package/dist/rpg/index.d.ts +14 -0
- package/dist/rpg/index.d.ts.map +1 -0
- package/dist/rpg/index.js +8 -0
- package/dist/rpg/index.js.map +1 -0
- package/dist/stage/DialogueStage.d.ts +75 -0
- package/dist/stage/DialogueStage.d.ts.map +1 -0
- package/dist/stage/DialogueStage.js +207 -0
- package/dist/stage/DialogueStage.js.map +1 -0
- package/dist/stage/index.d.ts +7 -0
- package/dist/stage/index.d.ts.map +1 -0
- package/dist/stage/index.js +4 -0
- package/dist/stage/index.js.map +1 -0
- package/dist/stage/script.d.ts +111 -0
- package/dist/stage/script.d.ts.map +1 -0
- package/dist/stage/script.js +133 -0
- package/dist/stage/script.js.map +1 -0
- package/dist/stage/twee.d.ts +42 -0
- package/dist/stage/twee.d.ts.map +1 -0
- package/dist/stage/twee.js +169 -0
- package/dist/stage/twee.js.map +1 -0
- package/dist/ui/IconGrid.d.ts +110 -0
- package/dist/ui/IconGrid.d.ts.map +1 -0
- package/dist/ui/IconGrid.js +284 -0
- package/dist/ui/IconGrid.js.map +1 -0
- package/dist/ui/Label.d.ts +26 -0
- package/dist/ui/Label.d.ts.map +1 -0
- package/dist/ui/Label.js +41 -0
- package/dist/ui/Label.js.map +1 -0
- package/dist/ui/ListView.d.ts +67 -0
- package/dist/ui/ListView.d.ts.map +1 -0
- package/dist/ui/ListView.js +167 -0
- package/dist/ui/ListView.js.map +1 -0
- package/dist/ui/MessageBox.d.ts +66 -0
- package/dist/ui/MessageBox.d.ts.map +1 -0
- package/dist/ui/MessageBox.js +161 -0
- package/dist/ui/MessageBox.js.map +1 -0
- package/dist/ui/NinePatch.d.ts +34 -0
- package/dist/ui/NinePatch.d.ts.map +1 -0
- package/dist/ui/NinePatch.js +45 -0
- package/dist/ui/NinePatch.js.map +1 -0
- package/dist/ui/VerticalLabel.d.ts +46 -0
- package/dist/ui/VerticalLabel.d.ts.map +1 -0
- package/dist/ui/VerticalLabel.js +81 -0
- package/dist/ui/VerticalLabel.js.map +1 -0
- package/dist/ui/Window.d.ts +71 -0
- package/dist/ui/Window.d.ts.map +1 -0
- package/dist/ui/Window.js +126 -0
- package/dist/ui/Window.js.map +1 -0
- package/dist/ui/WindowStack.d.ts +40 -0
- package/dist/ui/WindowStack.d.ts.map +1 -0
- package/dist/ui/WindowStack.js +106 -0
- package/dist/ui/WindowStack.js.map +1 -0
- package/dist/ui/index.d.ts +18 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +10 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/theme.d.ts +50 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +36 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/world/Encounters.d.ts +20 -0
- package/dist/world/Encounters.d.ts.map +1 -0
- package/dist/world/Encounters.js +9 -0
- package/dist/world/Encounters.js.map +1 -0
- package/dist/world/Overworld.d.ts +25 -0
- package/dist/world/Overworld.d.ts.map +1 -0
- package/dist/world/Overworld.js +26 -0
- package/dist/world/Overworld.js.map +1 -0
- package/dist/world/TurnClock.d.ts +25 -0
- package/dist/world/TurnClock.d.ts.map +1 -0
- package/dist/world/TurnClock.js +33 -0
- package/dist/world/TurnClock.js.map +1 -0
- package/dist/world/World.d.ts +50 -0
- package/dist/world/World.d.ts.map +1 -0
- package/dist/world/World.js +77 -0
- package/dist/world/World.js.map +1 -0
- package/dist/world/index.d.ts +8 -0
- package/dist/world/index.d.ts.map +1 -0
- package/dist/world/index.js +5 -0
- package/dist/world/index.js.map +1 -0
- package/package.json +76 -0
- package/tools/compile-resources.mjs +129 -0
package/dist/core/Hex.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flat-top hexagon geometry, addressed the same way a square grid is: `x` the column, `y`
|
|
3
|
+
* the row, both integers - which is what lets `mwg/roguelike`'s `Level` (grid logic) and
|
|
4
|
+
* `mwg/render`'s `TileMap` (pixel positions) each reuse it without depending on the other.
|
|
5
|
+
* It lives in `mwg/core` for exactly that reason: neither of those two modules is allowed
|
|
6
|
+
* to depend on the other, and this needs to sit below both.
|
|
7
|
+
*
|
|
8
|
+
* Internally this converts to and from cube coordinates (`x + y + z = 0`) for every
|
|
9
|
+
* calculation, because the six neighbour directions are then a fixed, orientation-agnostic
|
|
10
|
+
* list rather than a column-parity-dependent table someone has to get right twice. The
|
|
11
|
+
* offset "odd-q" scheme below - odd columns pushed half a row down - is what makes that
|
|
12
|
+
* cube math round-trip back to integers; nothing about it is rot.js's, which is deliberate
|
|
13
|
+
* (see the roadmap: rot.js's own hex `Path` topology is doubled-width coordinates built for
|
|
14
|
+
* *pointy-top* hexagons, and does not match this orientation).
|
|
15
|
+
*/
|
|
16
|
+
function toCube(x, y) {
|
|
17
|
+
const cx = x;
|
|
18
|
+
const cz = y - (x - (x & 1)) / 2;
|
|
19
|
+
return { x: cx, y: -cx - cz, z: cz };
|
|
20
|
+
}
|
|
21
|
+
function fromCube(cube) {
|
|
22
|
+
const x = cube.x;
|
|
23
|
+
const y = cube.z + (cube.x - (cube.x & 1)) / 2;
|
|
24
|
+
return { x, y };
|
|
25
|
+
}
|
|
26
|
+
//the six cube directions - orientation-agnostic, and each other's negation in pairs, which
|
|
27
|
+
//is what makes the neighbour relation below symmetric by construction
|
|
28
|
+
const CUBE_DIRECTIONS = [
|
|
29
|
+
{ x: 1, y: -1, z: 0 },
|
|
30
|
+
{ x: 1, y: 0, z: -1 },
|
|
31
|
+
{ x: 0, y: 1, z: -1 },
|
|
32
|
+
{ x: -1, y: 1, z: 0 },
|
|
33
|
+
{ x: -1, y: 0, z: 1 },
|
|
34
|
+
{ x: 0, y: -1, z: 1 },
|
|
35
|
+
];
|
|
36
|
+
/** the six cells sharing an edge with `(x, y)` */
|
|
37
|
+
export function hexNeighbors(x, y) {
|
|
38
|
+
const cube = toCube(x, y);
|
|
39
|
+
return CUBE_DIRECTIONS.map((d) => fromCube({ x: cube.x + d.x, y: cube.y + d.y, z: cube.z + d.z }));
|
|
40
|
+
}
|
|
41
|
+
/** the number of hex steps between two cells */
|
|
42
|
+
export function hexDistance(a, b) {
|
|
43
|
+
const ca = toCube(a.x, a.y);
|
|
44
|
+
const cb = toCube(b.x, b.y);
|
|
45
|
+
return Math.max(Math.abs(ca.x - cb.x), Math.abs(ca.y - cb.y), Math.abs(ca.z - cb.z));
|
|
46
|
+
}
|
|
47
|
+
function cubeRound(cube) {
|
|
48
|
+
let rx = Math.round(cube.x);
|
|
49
|
+
let ry = Math.round(cube.y);
|
|
50
|
+
let rz = Math.round(cube.z);
|
|
51
|
+
const dx = Math.abs(rx - cube.x);
|
|
52
|
+
const dy = Math.abs(ry - cube.y);
|
|
53
|
+
const dz = Math.abs(rz - cube.z);
|
|
54
|
+
//whichever coordinate drifted furthest from its rounded value is reconstructed from the
|
|
55
|
+
//other two, so x + y + z = 0 still holds exactly
|
|
56
|
+
if (dx > dy && dx > dz)
|
|
57
|
+
rx = -ry - rz;
|
|
58
|
+
else if (dy > dz)
|
|
59
|
+
ry = -rx - rz;
|
|
60
|
+
else
|
|
61
|
+
rz = -rx - ry;
|
|
62
|
+
return { x: rx, y: ry, z: rz };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Every cell a straight line crosses from `a` to `b`, both included - the hex-grid analogue
|
|
66
|
+
* of `mwg/roguelike`'s `traceLine`, and what a simple (non-shadowcast) hex field of view is
|
|
67
|
+
* built from: walk the line to a candidate cell and see whether anything on it is opaque.
|
|
68
|
+
*/
|
|
69
|
+
export function hexLine(a, b) {
|
|
70
|
+
const distance = hexDistance(a, b);
|
|
71
|
+
if (distance === 0)
|
|
72
|
+
return [{ x: a.x, y: a.y }];
|
|
73
|
+
const ca = toCube(a.x, a.y);
|
|
74
|
+
const cb = toCube(b.x, b.y);
|
|
75
|
+
const points = [];
|
|
76
|
+
for (let step = 0; step <= distance; step++) {
|
|
77
|
+
const t = step / distance;
|
|
78
|
+
points.push(fromCube(cubeRound({
|
|
79
|
+
x: ca.x + (cb.x - ca.x) * t,
|
|
80
|
+
y: ca.y + (cb.y - ca.y) * t,
|
|
81
|
+
z: ca.z + (cb.z - ca.z) * t,
|
|
82
|
+
})));
|
|
83
|
+
}
|
|
84
|
+
return points;
|
|
85
|
+
}
|
|
86
|
+
/** every cell within `radius` hex steps of `center`, `center` itself included */
|
|
87
|
+
export function hexRange(center, radius) {
|
|
88
|
+
const cc = toCube(center.x, center.y);
|
|
89
|
+
const out = [];
|
|
90
|
+
for (let dx = -radius; dx <= radius; dx++) {
|
|
91
|
+
for (let dy = Math.max(-radius, -dx - radius); dy <= Math.min(radius, -dx + radius); dy++) {
|
|
92
|
+
const dz = -dx - dy;
|
|
93
|
+
out.push(fromCube({ x: cc.x + dx, y: cc.y + dy, z: cc.z + dz }));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
/** the pixel position of a hex cell's centre, for a flat-top tile of the given size */
|
|
99
|
+
export function hexToPixel(x, y, tileWidth, tileHeight) {
|
|
100
|
+
return {
|
|
101
|
+
x: x * tileWidth * 0.75 + tileWidth / 2,
|
|
102
|
+
y: y * tileHeight + (x & 1) * (tileHeight / 2) + tileHeight / 2,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The hex cell under a pixel position - the inverse of `hexToPixel`.
|
|
107
|
+
*
|
|
108
|
+
* Fractional cube coordinates first, rounded only at the end (`cubeRound`), the same way
|
|
109
|
+
* `hexLine` resolves a fractional step to a cell - rounding column and row independently
|
|
110
|
+
* would round to the wrong cell right at a hex's edge.
|
|
111
|
+
*/
|
|
112
|
+
export function pixelToHex(px, py, tileWidth, tileHeight) {
|
|
113
|
+
const relativeX = px - tileWidth / 2;
|
|
114
|
+
const relativeY = py - tileHeight / 2;
|
|
115
|
+
const cx = relativeX / (tileWidth * 0.75);
|
|
116
|
+
const cz = relativeY / tileHeight - 0.5 * cx;
|
|
117
|
+
const cy = -cx - cz;
|
|
118
|
+
return fromCube(cubeRound({ x: cx, y: cy, z: cz }));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=Hex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hex.js","sourceRoot":"","sources":["../../src/core/Hex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Signal } from './Signal.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Keyboard input, bound to named actions.
|
|
4
|
+
*
|
|
5
|
+
* Game code asks about `'confirm'`, never about `'Enter'`. That indirection is what makes
|
|
6
|
+
* rebinding possible at all, and it is far easier to put in from the start than to retrofit
|
|
7
|
+
* once a hundred call sites know about key codes.
|
|
8
|
+
*
|
|
9
|
+
* Keys are identified by `KeyboardEvent.code` — the physical key — so a binding to `KeyZ`
|
|
10
|
+
* lands on the same place under AZERTY as under QWERTY, which is what a player actually
|
|
11
|
+
* wants from a movement key.
|
|
12
|
+
*/
|
|
13
|
+
export type Action = string;
|
|
14
|
+
/** fires when an action starts; a listener returning true stops it reaching anything else */
|
|
15
|
+
export declare const onAction: Signal<string>;
|
|
16
|
+
/** fires for every keydown, for the rare case that needs the raw key */
|
|
17
|
+
export declare const onKey: Signal<KeyboardEvent>;
|
|
18
|
+
/** the bindings a game starts with; every one can be replaced */
|
|
19
|
+
export declare const DEFAULT_BINDINGS: Readonly<Record<Action, readonly string[]>>;
|
|
20
|
+
export declare function bind(action: Action, keys: readonly string[]): void;
|
|
21
|
+
export declare function unbind(action: Action): void;
|
|
22
|
+
export declare function keysFor(action: Action): string[];
|
|
23
|
+
/** every binding, in a shape that can be written to a settings file and read back */
|
|
24
|
+
export declare function exportBindings(): Record<Action, string[]>;
|
|
25
|
+
export declare function importBindings(saved: Readonly<Record<Action, readonly string[]>>): void;
|
|
26
|
+
export declare function resetBindings(): void;
|
|
27
|
+
/** true for as long as the key is held */
|
|
28
|
+
export declare function isDown(action: Action): boolean;
|
|
29
|
+
/** true only on the frame the action began, for menus and single steps */
|
|
30
|
+
export declare function justPressed(action: Action): boolean;
|
|
31
|
+
export declare function justReleased(action: Action): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Clears the one-frame state.
|
|
34
|
+
*
|
|
35
|
+
* Called by `Game` at the end of every frame. It has to run after the scene's update, or
|
|
36
|
+
* a `justPressed` would be missed by whatever polls it later in the same frame.
|
|
37
|
+
*/
|
|
38
|
+
export declare function endFrame(): void;
|
|
39
|
+
export declare function attach(target?: EventTarget): void;
|
|
40
|
+
export declare function detach(target?: EventTarget): void;
|
|
41
|
+
//# sourceMappingURL=Input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/core/Input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAO5B,6FAA6F;AAC7F,eAAO,MAAM,QAAQ,gBAA2B,CAAC;AAEjD,wEAAwE;AACxE,eAAO,MAAM,KAAK,uBAAkC,CAAC;AAIrD,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAaxE,CAAC;AAEF,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAElE;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhD;AAED,qFAAqF;AACrF,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAIzD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,CAGvF;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAeD,0CAA0C;AAC1C,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAO9C;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,IAAI,IAAI,CAG/B;AA+BD,wBAAgB,MAAM,CAAC,MAAM,GAAE,WAAoB,GAAG,IAAI,CAOzD;AAED,wBAAgB,MAAM,CAAC,MAAM,GAAE,WAAoB,GAAG,IAAI,CAQzD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Signal } from './Signal.js';
|
|
2
|
+
const bindings = new Map();
|
|
3
|
+
const held = new Set();
|
|
4
|
+
const pressedThisFrame = new Set();
|
|
5
|
+
const releasedThisFrame = new Set();
|
|
6
|
+
/** fires when an action starts; a listener returning true stops it reaching anything else */
|
|
7
|
+
export const onAction = new Signal(true);
|
|
8
|
+
/** fires for every keydown, for the rare case that needs the raw key */
|
|
9
|
+
export const onKey = new Signal(true);
|
|
10
|
+
let attached = false;
|
|
11
|
+
/** the bindings a game starts with; every one can be replaced */
|
|
12
|
+
export const DEFAULT_BINDINGS = {
|
|
13
|
+
up: ['ArrowUp', 'KeyW', 'Numpad8'],
|
|
14
|
+
down: ['ArrowDown', 'KeyS', 'Numpad2'],
|
|
15
|
+
left: ['ArrowLeft', 'KeyA', 'Numpad4'],
|
|
16
|
+
right: ['ArrowRight', 'KeyD', 'Numpad6'],
|
|
17
|
+
upLeft: ['Numpad7'],
|
|
18
|
+
upRight: ['Numpad9'],
|
|
19
|
+
downLeft: ['Numpad1'],
|
|
20
|
+
downRight: ['Numpad3'],
|
|
21
|
+
wait: ['Numpad5', 'Period'],
|
|
22
|
+
confirm: ['Enter', 'Space', 'NumpadEnter'],
|
|
23
|
+
cancel: ['Escape', 'Backspace'],
|
|
24
|
+
menu: ['KeyI', 'Tab'],
|
|
25
|
+
};
|
|
26
|
+
export function bind(action, keys) {
|
|
27
|
+
bindings.set(action, new Set(keys));
|
|
28
|
+
}
|
|
29
|
+
export function unbind(action) {
|
|
30
|
+
bindings.delete(action);
|
|
31
|
+
}
|
|
32
|
+
export function keysFor(action) {
|
|
33
|
+
return [...(bindings.get(action) ?? [])];
|
|
34
|
+
}
|
|
35
|
+
/** every binding, in a shape that can be written to a settings file and read back */
|
|
36
|
+
export function exportBindings() {
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const [action, keys] of bindings)
|
|
39
|
+
out[action] = [...keys];
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
export function importBindings(saved) {
|
|
43
|
+
bindings.clear();
|
|
44
|
+
for (const [action, keys] of Object.entries(saved))
|
|
45
|
+
bind(action, keys);
|
|
46
|
+
}
|
|
47
|
+
export function resetBindings() {
|
|
48
|
+
importBindings(DEFAULT_BINDINGS);
|
|
49
|
+
}
|
|
50
|
+
//installed as soon as this module loads, so a game may add or replace a binding before it
|
|
51
|
+
//starts without that being mistaken for "this game defines all its own keys". Deferring
|
|
52
|
+
//this to attach() cost every default the moment a game bound one action of its own.
|
|
53
|
+
resetBindings();
|
|
54
|
+
function actionsFor(code) {
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const [action, keys] of bindings) {
|
|
57
|
+
if (keys.has(code))
|
|
58
|
+
out.push(action);
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** true for as long as the key is held */
|
|
63
|
+
export function isDown(action) {
|
|
64
|
+
const keys = bindings.get(action);
|
|
65
|
+
if (!keys)
|
|
66
|
+
return false;
|
|
67
|
+
for (const key of keys) {
|
|
68
|
+
if (held.has(key))
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
/** true only on the frame the action began, for menus and single steps */
|
|
74
|
+
export function justPressed(action) {
|
|
75
|
+
return pressedThisFrame.has(action);
|
|
76
|
+
}
|
|
77
|
+
export function justReleased(action) {
|
|
78
|
+
return releasedThisFrame.has(action);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Clears the one-frame state.
|
|
82
|
+
*
|
|
83
|
+
* Called by `Game` at the end of every frame. It has to run after the scene's update, or
|
|
84
|
+
* a `justPressed` would be missed by whatever polls it later in the same frame.
|
|
85
|
+
*/
|
|
86
|
+
export function endFrame() {
|
|
87
|
+
pressedThisFrame.clear();
|
|
88
|
+
releasedThisFrame.clear();
|
|
89
|
+
}
|
|
90
|
+
function handleKeyDown(event) {
|
|
91
|
+
//a held key repeats; the action already started, so only the raw signal repeats
|
|
92
|
+
if (event.repeat) {
|
|
93
|
+
onKey.dispatch(event);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
held.add(event.code);
|
|
97
|
+
for (const action of actionsFor(event.code)) {
|
|
98
|
+
pressedThisFrame.add(action);
|
|
99
|
+
onAction.dispatch(action);
|
|
100
|
+
}
|
|
101
|
+
onKey.dispatch(event);
|
|
102
|
+
}
|
|
103
|
+
function handleKeyUp(event) {
|
|
104
|
+
held.delete(event.code);
|
|
105
|
+
for (const action of actionsFor(event.code)) {
|
|
106
|
+
releasedThisFrame.add(action);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function handleBlur() {
|
|
110
|
+
//a key held while the window loses focus never sends its keyup, and would stay stuck
|
|
111
|
+
held.clear();
|
|
112
|
+
pressedThisFrame.clear();
|
|
113
|
+
releasedThisFrame.clear();
|
|
114
|
+
}
|
|
115
|
+
export function attach(target = window) {
|
|
116
|
+
if (attached)
|
|
117
|
+
return;
|
|
118
|
+
attached = true;
|
|
119
|
+
target.addEventListener('keydown', handleKeyDown);
|
|
120
|
+
target.addEventListener('keyup', handleKeyUp);
|
|
121
|
+
window.addEventListener('blur', handleBlur);
|
|
122
|
+
}
|
|
123
|
+
export function detach(target = window) {
|
|
124
|
+
if (!attached)
|
|
125
|
+
return;
|
|
126
|
+
attached = false;
|
|
127
|
+
target.removeEventListener('keydown', handleKeyDown);
|
|
128
|
+
target.removeEventListener('keyup', handleKeyUp);
|
|
129
|
+
window.removeEventListener('blur', handleBlur);
|
|
130
|
+
handleBlur();
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=Input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/core/Input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What severity a log entry carries. Ordered, so a logger can keep `warn` and
|
|
3
|
+
* above while silencing the chatter below.
|
|
4
|
+
*/
|
|
5
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
6
|
+
export interface LogEntry {
|
|
7
|
+
level: LogLevel;
|
|
8
|
+
category: string;
|
|
9
|
+
message: string;
|
|
10
|
+
data?: unknown;
|
|
11
|
+
time: number;
|
|
12
|
+
}
|
|
13
|
+
export interface LoggerOptions {
|
|
14
|
+
/** entries below this never reach the sink; defaults to `debug` (everything) */
|
|
15
|
+
level?: LogLevel;
|
|
16
|
+
/** where entries go; defaults to the matching console method */
|
|
17
|
+
sink?: (entry: LogEntry) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Categories and severity over bare `console.log`.
|
|
21
|
+
*
|
|
22
|
+
* Marginal on its own - the browser console already exists - which is why this
|
|
23
|
+
* stays small: a named category per system, four levels, a filter, and a sink
|
|
24
|
+
* tests can capture instead of the console.
|
|
25
|
+
*/
|
|
26
|
+
export declare class Logger {
|
|
27
|
+
private readonly category;
|
|
28
|
+
private level;
|
|
29
|
+
private readonly sink;
|
|
30
|
+
constructor(category: string, options?: LoggerOptions);
|
|
31
|
+
/** raises or lowers what reaches the sink from here on */
|
|
32
|
+
setLevel(level: LogLevel): void;
|
|
33
|
+
debug(message: string, data?: unknown): void;
|
|
34
|
+
info(message: string, data?: unknown): void;
|
|
35
|
+
warn(message: string, data?: unknown): void;
|
|
36
|
+
error(message: string, data?: unknown): void;
|
|
37
|
+
private write;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=Log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Log.d.ts","sourceRoot":"","sources":["../../src/core/Log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAI3D,MAAM,WAAW,QAAQ;IACxB,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC7B,gFAAgF;IAChF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,gEAAgE;IAChE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;GAMG;AACH,qBAAa,MAAM;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IAEjD,YAAY,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,EAKxD;IAED,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAE9B;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE3C;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE1C;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE1C;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAE3C;IAED,OAAO,CAAC,KAAK;CAIb"}
|
package/dist/core/Log.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
2
|
+
/**
|
|
3
|
+
* Categories and severity over bare `console.log`.
|
|
4
|
+
*
|
|
5
|
+
* Marginal on its own - the browser console already exists - which is why this
|
|
6
|
+
* stays small: a named category per system, four levels, a filter, and a sink
|
|
7
|
+
* tests can capture instead of the console.
|
|
8
|
+
*/
|
|
9
|
+
export class Logger {
|
|
10
|
+
constructor(category, options = {}) {
|
|
11
|
+
if (!category)
|
|
12
|
+
throw new Error('a logger needs a category');
|
|
13
|
+
this.category = category;
|
|
14
|
+
this.level = options.level ?? 'debug';
|
|
15
|
+
this.sink = options.sink ?? defaultSink;
|
|
16
|
+
}
|
|
17
|
+
/** raises or lowers what reaches the sink from here on */
|
|
18
|
+
setLevel(level) {
|
|
19
|
+
this.level = level;
|
|
20
|
+
}
|
|
21
|
+
debug(message, data) {
|
|
22
|
+
this.write('debug', message, data);
|
|
23
|
+
}
|
|
24
|
+
info(message, data) {
|
|
25
|
+
this.write('info', message, data);
|
|
26
|
+
}
|
|
27
|
+
warn(message, data) {
|
|
28
|
+
this.write('warn', message, data);
|
|
29
|
+
}
|
|
30
|
+
error(message, data) {
|
|
31
|
+
this.write('error', message, data);
|
|
32
|
+
}
|
|
33
|
+
write(level, message, data) {
|
|
34
|
+
if (ORDER[level] < ORDER[this.level])
|
|
35
|
+
return;
|
|
36
|
+
this.sink({ level, category: this.category, message, data, time: Date.now() });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function defaultSink(entry) {
|
|
40
|
+
const line = `[${entry.category}] ${entry.message}`;
|
|
41
|
+
if (entry.level === 'debug')
|
|
42
|
+
console.debug(line, entry.data ?? '');
|
|
43
|
+
else if (entry.level === 'info')
|
|
44
|
+
console.info(line, entry.data ?? '');
|
|
45
|
+
else if (entry.level === 'warn')
|
|
46
|
+
console.warn(line, entry.data ?? '');
|
|
47
|
+
else
|
|
48
|
+
console.error(line, entry.data ?? '');
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=Log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Log.js","sourceRoot":"","sources":["../../src/core/Log.ts"],"names":[],"mappings":"AAMA,MAAM,KAAK,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAiBjF;;;;;;GAMG;AACH,MAAM,OAAO,MAAM;IAKlB,YAAY,QAAgB,EAAE,OAAO,GAAkB,EAAE;QACxD,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IACzC,CAAC;IAED,0DAA0D;IAC1D,QAAQ,CAAC,KAAe;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAAc;QACnC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAc;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAEO,KAAK,CAAC,KAAe,EAAE,OAAe,EAAE,IAAc;QAC7D,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO;QAC7C,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;CACD;AAED,SAAS,WAAW,CAAC,KAAe;IACnC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IACpD,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO;QAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;SAC9D,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;SACjE,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;;QACjE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic random numbers.
|
|
3
|
+
*
|
|
4
|
+
* A roguelike lives or dies on this: the same seed has to produce the same dungeon, on
|
|
5
|
+
* any machine, in any browser, forever. `Math.random()` cannot do that — it is not
|
|
6
|
+
* seedable and its algorithm is not specified.
|
|
7
|
+
*
|
|
8
|
+
* The generator is xoshiro128**, by David Blackman and Sebastiano Vigna, released into the
|
|
9
|
+
* public domain. It is fast, passes the standard statistical test suites, and its state is
|
|
10
|
+
* four 32-bit words, which JavaScript can hold exactly.
|
|
11
|
+
*
|
|
12
|
+
* Generators are kept on a stack. Level generation pushes a seeded one so a floor is
|
|
13
|
+
* reproducible, then pops it, so unrelated rolls elsewhere do not consume from that
|
|
14
|
+
* stream and shift the results.
|
|
15
|
+
*/
|
|
16
|
+
export declare class Generator {
|
|
17
|
+
private s0;
|
|
18
|
+
private s1;
|
|
19
|
+
private s2;
|
|
20
|
+
private s3;
|
|
21
|
+
readonly seed: number;
|
|
22
|
+
constructor(seed?: number);
|
|
23
|
+
/** the raw generator: a uniformly distributed unsigned 32-bit integer */
|
|
24
|
+
nextUint32(): number;
|
|
25
|
+
/** a float in [0, 1), with 32 bits of resolution */
|
|
26
|
+
float(): number;
|
|
27
|
+
/**
|
|
28
|
+
* An integer in [0, bound), without modulo bias.
|
|
29
|
+
*
|
|
30
|
+
* The naive `nextUint32() % bound` favours the low values whenever bound does not
|
|
31
|
+
* divide 2^32; this rejects the unfair tail of the range instead.
|
|
32
|
+
*/
|
|
33
|
+
int(bound: number): number;
|
|
34
|
+
/** captures the generator state, so a save file can resume the same stream */
|
|
35
|
+
getState(): [number, number, number, number];
|
|
36
|
+
setState(state: readonly [number, number, number, number]): void;
|
|
37
|
+
}
|
|
38
|
+
/** starts a reproducible stream; pair every call with `pop()` */
|
|
39
|
+
export declare function push(seed?: number): Generator;
|
|
40
|
+
export declare function pop(): void;
|
|
41
|
+
/** runs `body` with a seeded generator, popping it even if `body` throws */
|
|
42
|
+
export declare function withSeed<T>(seed: number, body: () => T): T;
|
|
43
|
+
export declare function reset(): void;
|
|
44
|
+
/** a float in [0, 1), or [0, max), or [min, max) */
|
|
45
|
+
export declare function float(min?: number, max?: number): number;
|
|
46
|
+
/** an integer in [0, max), or [min, max) */
|
|
47
|
+
export declare function int(min: number, max?: number): number;
|
|
48
|
+
/** an integer in [min, max], both ends included — the usual shape for dice */
|
|
49
|
+
export declare function range(min: number, max: number): number;
|
|
50
|
+
/**
|
|
51
|
+
* A triangular distribution over [min, max], peaking in the middle.
|
|
52
|
+
*
|
|
53
|
+
* Useful wherever a uniform roll feels wrong: damage, room sizes, item quality.
|
|
54
|
+
*/
|
|
55
|
+
export declare function normalRange(min: number, max: number): number;
|
|
56
|
+
export declare function chance(probability: number): boolean;
|
|
57
|
+
export declare function element<T>(items: readonly T[]): T | undefined;
|
|
58
|
+
/** an index into `weights`, each index drawn in proportion to its weight */
|
|
59
|
+
export declare function weighted(weights: readonly number[]): number;
|
|
60
|
+
/** a key from `weights`, drawn in proportion to the value it maps to */
|
|
61
|
+
export declare function weightedKey<K>(weights: ReadonlyMap<K, number>): K | undefined;
|
|
62
|
+
/** Fisher-Yates, in place */
|
|
63
|
+
export declare function shuffle<T>(items: T[]): T[];
|
|
64
|
+
//# sourceMappingURL=Random.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Random.d.ts","sourceRoot":"","sources":["../../src/core/Random.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAcH,qBAAa,SAAS;IACrB,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IAEf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YAAY,IAAI,CAAC,EAAE,MAAM,EAcxB;IAED,yEAAyE;IACzE,UAAU,IAAI,MAAM,CAanB;IAED,oDAAoD;IACpD,KAAK,IAAI,MAAM,CAEd;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASzB;IAED,8EAA8E;IAC9E,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAE3C;IAED,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAE/D;CACD;AAUD,iEAAiE;AACjE,wBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAI7C;AAED,wBAAgB,GAAG,IAAI,IAAI,CAK1B;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAO1D;AAED,wBAAgB,KAAK,IAAI,IAAI,CAG5B;AAED,oDAAoD;AACpD,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,4CAA4C;AAC5C,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,CAE7D;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAW3D;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAI7E;AAED,6BAA6B;AAC7B,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAM1C"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic random numbers.
|
|
3
|
+
*
|
|
4
|
+
* A roguelike lives or dies on this: the same seed has to produce the same dungeon, on
|
|
5
|
+
* any machine, in any browser, forever. `Math.random()` cannot do that — it is not
|
|
6
|
+
* seedable and its algorithm is not specified.
|
|
7
|
+
*
|
|
8
|
+
* The generator is xoshiro128**, by David Blackman and Sebastiano Vigna, released into the
|
|
9
|
+
* public domain. It is fast, passes the standard statistical test suites, and its state is
|
|
10
|
+
* four 32-bit words, which JavaScript can hold exactly.
|
|
11
|
+
*
|
|
12
|
+
* Generators are kept on a stack. Level generation pushes a seeded one so a floor is
|
|
13
|
+
* reproducible, then pops it, so unrelated rolls elsewhere do not consume from that
|
|
14
|
+
* stream and shift the results.
|
|
15
|
+
*/
|
|
16
|
+
/** splitmix32, used to expand a single seed into the four words of generator state */
|
|
17
|
+
function splitmix32(seed) {
|
|
18
|
+
let a = seed >>> 0;
|
|
19
|
+
return () => {
|
|
20
|
+
a = (a + 0x9e3779b9) >>> 0;
|
|
21
|
+
let t = a;
|
|
22
|
+
t = Math.imul(t ^ (t >>> 16), 0x21f0aaad);
|
|
23
|
+
t = Math.imul(t ^ (t >>> 15), 0x735a2d97);
|
|
24
|
+
return (t ^ (t >>> 15)) >>> 0;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export class Generator {
|
|
28
|
+
constructor(seed) {
|
|
29
|
+
this.s0 = 0;
|
|
30
|
+
this.s1 = 0;
|
|
31
|
+
this.s2 = 0;
|
|
32
|
+
this.s3 = 0;
|
|
33
|
+
//an unseeded generator still has to be deterministic once created, so a random seed
|
|
34
|
+
//is drawn once and kept, rather than the state being seeded from entropy directly
|
|
35
|
+
this.seed = seed === undefined ? (Math.random() * 0x100000000) >>> 0 : seed >>> 0;
|
|
36
|
+
const next = splitmix32(this.seed);
|
|
37
|
+
this.s0 = next();
|
|
38
|
+
this.s1 = next();
|
|
39
|
+
this.s2 = next();
|
|
40
|
+
this.s3 = next();
|
|
41
|
+
//an all-zero state is a fixed point of the generator; splitmix never produces one,
|
|
42
|
+
//but a future change to the seeding must not either
|
|
43
|
+
if ((this.s0 | this.s1 | this.s2 | this.s3) === 0)
|
|
44
|
+
this.s0 = 1;
|
|
45
|
+
}
|
|
46
|
+
/** the raw generator: a uniformly distributed unsigned 32-bit integer */
|
|
47
|
+
nextUint32() {
|
|
48
|
+
const result = (Math.imul(rotl(Math.imul(this.s1, 5), 7), 9) >>> 0) >>> 0;
|
|
49
|
+
const t = (this.s1 << 9) >>> 0;
|
|
50
|
+
this.s2 ^= this.s0;
|
|
51
|
+
this.s3 ^= this.s1;
|
|
52
|
+
this.s1 ^= this.s2;
|
|
53
|
+
this.s0 ^= this.s3;
|
|
54
|
+
this.s2 ^= t;
|
|
55
|
+
this.s3 = rotl(this.s3, 11);
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/** a float in [0, 1), with 32 bits of resolution */
|
|
59
|
+
float() {
|
|
60
|
+
return this.nextUint32() / 0x100000000;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* An integer in [0, bound), without modulo bias.
|
|
64
|
+
*
|
|
65
|
+
* The naive `nextUint32() % bound` favours the low values whenever bound does not
|
|
66
|
+
* divide 2^32; this rejects the unfair tail of the range instead.
|
|
67
|
+
*/
|
|
68
|
+
int(bound) {
|
|
69
|
+
if (bound <= 0)
|
|
70
|
+
return 0;
|
|
71
|
+
const limit = 0x100000000 - (0x100000000 % bound);
|
|
72
|
+
let value = this.nextUint32();
|
|
73
|
+
while (value >= limit) {
|
|
74
|
+
value = this.nextUint32();
|
|
75
|
+
}
|
|
76
|
+
return value % bound;
|
|
77
|
+
}
|
|
78
|
+
/** captures the generator state, so a save file can resume the same stream */
|
|
79
|
+
getState() {
|
|
80
|
+
return [this.s0, this.s1, this.s2, this.s3];
|
|
81
|
+
}
|
|
82
|
+
setState(state) {
|
|
83
|
+
[this.s0, this.s1, this.s2, this.s3] = state;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function rotl(x, k) {
|
|
87
|
+
return ((x << k) | (x >>> (32 - k))) >>> 0;
|
|
88
|
+
}
|
|
89
|
+
const stack = [new Generator()];
|
|
90
|
+
const current = () => stack[stack.length - 1];
|
|
91
|
+
/** starts a reproducible stream; pair every call with `pop()` */
|
|
92
|
+
export function push(seed) {
|
|
93
|
+
const generator = new Generator(seed);
|
|
94
|
+
stack.push(generator);
|
|
95
|
+
return generator;
|
|
96
|
+
}
|
|
97
|
+
export function pop() {
|
|
98
|
+
if (stack.length === 1) {
|
|
99
|
+
throw new Error('the base random generator cannot be popped');
|
|
100
|
+
}
|
|
101
|
+
stack.pop();
|
|
102
|
+
}
|
|
103
|
+
/** runs `body` with a seeded generator, popping it even if `body` throws */
|
|
104
|
+
export function withSeed(seed, body) {
|
|
105
|
+
push(seed);
|
|
106
|
+
try {
|
|
107
|
+
return body();
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
pop();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export function reset() {
|
|
114
|
+
stack.length = 0;
|
|
115
|
+
stack.push(new Generator());
|
|
116
|
+
}
|
|
117
|
+
/** a float in [0, 1), or [0, max), or [min, max) */
|
|
118
|
+
export function float(min, max) {
|
|
119
|
+
if (min === undefined)
|
|
120
|
+
return current().float();
|
|
121
|
+
if (max === undefined)
|
|
122
|
+
return current().float() * min;
|
|
123
|
+
return min + current().float() * (max - min);
|
|
124
|
+
}
|
|
125
|
+
/** an integer in [0, max), or [min, max) */
|
|
126
|
+
export function int(min, max) {
|
|
127
|
+
if (max === undefined)
|
|
128
|
+
return current().int(min);
|
|
129
|
+
return min + current().int(max - min);
|
|
130
|
+
}
|
|
131
|
+
/** an integer in [min, max], both ends included — the usual shape for dice */
|
|
132
|
+
export function range(min, max) {
|
|
133
|
+
return min + current().int(max - min + 1);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A triangular distribution over [min, max], peaking in the middle.
|
|
137
|
+
*
|
|
138
|
+
* Useful wherever a uniform roll feels wrong: damage, room sizes, item quality.
|
|
139
|
+
*/
|
|
140
|
+
export function normalRange(min, max) {
|
|
141
|
+
return min + Math.floor(((current().float() + current().float()) * (max - min + 1)) / 2);
|
|
142
|
+
}
|
|
143
|
+
export function chance(probability) {
|
|
144
|
+
return current().float() < probability;
|
|
145
|
+
}
|
|
146
|
+
export function element(items) {
|
|
147
|
+
return items.length > 0 ? items[current().int(items.length)] : undefined;
|
|
148
|
+
}
|
|
149
|
+
/** an index into `weights`, each index drawn in proportion to its weight */
|
|
150
|
+
export function weighted(weights) {
|
|
151
|
+
let total = 0;
|
|
152
|
+
for (const w of weights)
|
|
153
|
+
total += w;
|
|
154
|
+
if (total <= 0)
|
|
155
|
+
return -1;
|
|
156
|
+
let value = current().float() * total;
|
|
157
|
+
for (let i = 0; i < weights.length; i++) {
|
|
158
|
+
value -= weights[i];
|
|
159
|
+
if (value < 0)
|
|
160
|
+
return i;
|
|
161
|
+
}
|
|
162
|
+
return weights.length - 1;
|
|
163
|
+
}
|
|
164
|
+
/** a key from `weights`, drawn in proportion to the value it maps to */
|
|
165
|
+
export function weightedKey(weights) {
|
|
166
|
+
const keys = [...weights.keys()];
|
|
167
|
+
const index = weighted(keys.map((k) => weights.get(k) ?? 0));
|
|
168
|
+
return index === -1 ? undefined : keys[index];
|
|
169
|
+
}
|
|
170
|
+
/** Fisher-Yates, in place */
|
|
171
|
+
export function shuffle(items) {
|
|
172
|
+
for (let i = items.length - 1; i > 0; i--) {
|
|
173
|
+
const j = current().int(i + 1);
|
|
174
|
+
[items[i], items[j]] = [items[j], items[i]];
|
|
175
|
+
}
|
|
176
|
+
return items;
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=Random.js.map
|