@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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Achievements: named milestones unlocked by counters crossing a target - monsters
|
|
3
|
+
* slain, gold collected, floors descended, runs won.
|
|
4
|
+
*
|
|
5
|
+
* The shape every badge/achievement list shares: a definition names a counter and the
|
|
6
|
+
* value that earns it, the game increments counters as things happen, and unlocking is
|
|
7
|
+
* derived (a counter at or past its target), never stored separately - so a counter
|
|
8
|
+
* can only ever move one way and an unlocked achievement can never disagree with the
|
|
9
|
+
* count behind it. Descriptions are display text `mwg` never reads; persistence is the
|
|
10
|
+
* usual definitions-fresh, progress-saved split (`QuestLog`'s own convention).
|
|
11
|
+
*/
|
|
12
|
+
export class Achievements {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.definitions = new Map();
|
|
15
|
+
this.counts = new Map();
|
|
16
|
+
/** every achievement id unlocked since the last `drainNew` call, oldest first */
|
|
17
|
+
this.fresh = [];
|
|
18
|
+
}
|
|
19
|
+
define(definition) {
|
|
20
|
+
this.definitions.set(definition.id, definition);
|
|
21
|
+
}
|
|
22
|
+
/** the current value of a counter; 0 for one nothing has touched yet */
|
|
23
|
+
count(counter) {
|
|
24
|
+
return this.counts.get(counter) ?? 0;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Adds to a counter, unlocking whatever that newly earns.
|
|
28
|
+
*
|
|
29
|
+
* @returns the ids unlocked by exactly this increment, so a game can announce each
|
|
30
|
+
* one once ("Achievement unlocked: ...") rather than re-scanning everything
|
|
31
|
+
*/
|
|
32
|
+
increment(counter, amount = 1) {
|
|
33
|
+
const before = this.count(counter);
|
|
34
|
+
this.counts.set(counter, before + amount);
|
|
35
|
+
const earned = [];
|
|
36
|
+
for (const definition of this.definitions.values()) {
|
|
37
|
+
if (definition.counter !== counter)
|
|
38
|
+
continue;
|
|
39
|
+
if (before < definition.target && before + amount >= definition.target) {
|
|
40
|
+
earned.push(definition.id);
|
|
41
|
+
this.fresh.push(definition.id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return earned;
|
|
45
|
+
}
|
|
46
|
+
/** whether an achievement's counter has reached its target - throws for an unknown id */
|
|
47
|
+
unlocked(id) {
|
|
48
|
+
const definition = this.definitions.get(id);
|
|
49
|
+
if (!definition)
|
|
50
|
+
throw new Error(`no such achievement: "${id}"`);
|
|
51
|
+
return this.count(definition.counter) >= definition.target;
|
|
52
|
+
}
|
|
53
|
+
/** progress towards an achievement: current count and target - throws for an unknown id */
|
|
54
|
+
progress(id) {
|
|
55
|
+
const definition = this.definitions.get(id);
|
|
56
|
+
if (!definition)
|
|
57
|
+
throw new Error(`no such achievement: "${id}"`);
|
|
58
|
+
return { count: this.count(definition.counter), target: definition.target };
|
|
59
|
+
}
|
|
60
|
+
/** every id unlocked but not yet announced, clearing the queue as it reads */
|
|
61
|
+
drainNew() {
|
|
62
|
+
const out = this.fresh;
|
|
63
|
+
this.fresh = [];
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
toJSON() {
|
|
67
|
+
return { counts: [...this.counts] };
|
|
68
|
+
}
|
|
69
|
+
/** rebuilds achievements from save data - definitions are supplied fresh, the same as `QuestLog` */
|
|
70
|
+
static fromJSON(definitions, data) {
|
|
71
|
+
const achievements = new Achievements();
|
|
72
|
+
for (const definition of definitions)
|
|
73
|
+
achievements.define(definition);
|
|
74
|
+
for (const [counter, count] of data.counts)
|
|
75
|
+
achievements.counts.set(counter, count);
|
|
76
|
+
//a loaded game announces nothing: whatever was earned was earned before the save
|
|
77
|
+
return achievements;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=Achievements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Achievements.js","sourceRoot":"","sources":["../../src/core/Achievements.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type SaveStorage } from './Save.ts';
|
|
2
|
+
/**
|
|
3
|
+
* One JSON record in a `Collection`: a string id plus whatever fields the game
|
|
4
|
+
* keeps - quest stages, bestiary sightings, achievements.
|
|
5
|
+
*/
|
|
6
|
+
export interface DbRecord {
|
|
7
|
+
id: string;
|
|
8
|
+
[field: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface CollectionOptions {
|
|
11
|
+
/** key prefix, so two games sharing a browser never meet; defaults to the game's name */
|
|
12
|
+
namespace?: string;
|
|
13
|
+
/** defaults to `localStorage`, falling back to memory where it is unavailable */
|
|
14
|
+
storage?: SaveStorage;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A named collection of records, queried and filtered - the shape `SaveSystem`
|
|
18
|
+
* does not cover. A save slot is one blob loaded wholesale; a collection is many
|
|
19
|
+
* small records asked questions: `where((q) => !q.done)` is "everything not yet
|
|
20
|
+
* completed".
|
|
21
|
+
*
|
|
22
|
+
* Every call hits the storage directly - nothing is cached, so there is no copy
|
|
23
|
+
* to go stale, and two `Collection` objects over the same name agree trivially.
|
|
24
|
+
* Records come back in insertion order. Built for logs and bestiaries (hundreds
|
|
25
|
+
* of records), not for anything scanned per frame.
|
|
26
|
+
*/
|
|
27
|
+
export declare class Collection {
|
|
28
|
+
private readonly prefix;
|
|
29
|
+
private readonly storage;
|
|
30
|
+
constructor(name: string, options?: CollectionOptions);
|
|
31
|
+
/** how many records the collection holds */
|
|
32
|
+
get size(): number;
|
|
33
|
+
/** every record, in insertion order */
|
|
34
|
+
all(): DbRecord[];
|
|
35
|
+
get(id: string): DbRecord | undefined;
|
|
36
|
+
/** inserts or replaces the record with the same id */
|
|
37
|
+
put(record: DbRecord): void;
|
|
38
|
+
remove(id: string): void;
|
|
39
|
+
/** the records a predicate keeps - "everything not yet completed" reads exactly like that */
|
|
40
|
+
where(predicate: (record: DbRecord) => boolean): DbRecord[];
|
|
41
|
+
/** empties this collection, and nothing else sharing the storage */
|
|
42
|
+
clear(): void;
|
|
43
|
+
private keys;
|
|
44
|
+
private read;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=Collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collection.d.ts","sourceRoot":"","sources":["../../src/core/Collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IACjC,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IAEtC,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,EAIxD;IAED,4CAA4C;IAC5C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,uCAAuC;IACvC,GAAG,IAAI,QAAQ,EAAE,CAEhB;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAGpC;IAED,sDAAsD;IACtD,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAQ1B;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEvB;IAED,6FAA6F;IAC7F,KAAK,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,OAAO,GAAG,QAAQ,EAAE,CAE1D;IAED,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAEZ;IAED,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,IAAI;CAGZ"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defaultStorage } from './Save.js';
|
|
2
|
+
/**
|
|
3
|
+
* A named collection of records, queried and filtered - the shape `SaveSystem`
|
|
4
|
+
* does not cover. A save slot is one blob loaded wholesale; a collection is many
|
|
5
|
+
* small records asked questions: `where((q) => !q.done)` is "everything not yet
|
|
6
|
+
* completed".
|
|
7
|
+
*
|
|
8
|
+
* Every call hits the storage directly - nothing is cached, so there is no copy
|
|
9
|
+
* to go stale, and two `Collection` objects over the same name agree trivially.
|
|
10
|
+
* Records come back in insertion order. Built for logs and bestiaries (hundreds
|
|
11
|
+
* of records), not for anything scanned per frame.
|
|
12
|
+
*/
|
|
13
|
+
export class Collection {
|
|
14
|
+
constructor(name, options = {}) {
|
|
15
|
+
if (!name)
|
|
16
|
+
throw new Error('a collection needs a name');
|
|
17
|
+
this.prefix = `mwg-db:${options.namespace ?? 'default'}:${name}:`;
|
|
18
|
+
this.storage = options.storage ?? defaultStorage();
|
|
19
|
+
}
|
|
20
|
+
/** how many records the collection holds */
|
|
21
|
+
get size() {
|
|
22
|
+
return this.keys().length;
|
|
23
|
+
}
|
|
24
|
+
/** every record, in insertion order */
|
|
25
|
+
all() {
|
|
26
|
+
return this.keys().map((key) => this.read(key));
|
|
27
|
+
}
|
|
28
|
+
get(id) {
|
|
29
|
+
const raw = this.storage.read(this.prefix + id);
|
|
30
|
+
return raw === null ? undefined : JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
/** inserts or replaces the record with the same id */
|
|
33
|
+
put(record) {
|
|
34
|
+
if (typeof record !== 'object' || record === null || Array.isArray(record)) {
|
|
35
|
+
throw new Error('a record must be an object with a string id');
|
|
36
|
+
}
|
|
37
|
+
if (typeof record.id !== 'string' || record.id === '') {
|
|
38
|
+
throw new Error('a record must be an object with a string id');
|
|
39
|
+
}
|
|
40
|
+
this.storage.write(this.prefix + record.id, JSON.stringify(record));
|
|
41
|
+
}
|
|
42
|
+
remove(id) {
|
|
43
|
+
this.storage.remove(this.prefix + id);
|
|
44
|
+
}
|
|
45
|
+
/** the records a predicate keeps - "everything not yet completed" reads exactly like that */
|
|
46
|
+
where(predicate) {
|
|
47
|
+
return this.all().filter(predicate);
|
|
48
|
+
}
|
|
49
|
+
/** empties this collection, and nothing else sharing the storage */
|
|
50
|
+
clear() {
|
|
51
|
+
for (const key of this.keys())
|
|
52
|
+
this.storage.remove(key);
|
|
53
|
+
}
|
|
54
|
+
keys() {
|
|
55
|
+
return this.storage.keys().filter((key) => key.startsWith(this.prefix));
|
|
56
|
+
}
|
|
57
|
+
read(key) {
|
|
58
|
+
return JSON.parse(this.storage.read(key));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=Collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collection.js","sourceRoot":"","sources":["../../src/core/Collection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAkB7D;;;;;;;;;;GAUG;AACH,MAAM,OAAO,UAAU;IAItB,YAAY,IAAY,EAAE,OAAO,GAAsB,EAAE;QACxD,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,GAAG,UAAU,OAAO,CAAC,SAAS,IAAI,SAAS,IAAI,IAAI,GAAG,CAAC;QAClE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;IACpD,CAAC;IAED,4CAA4C;IAC5C,IAAI,IAAI;QACP,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,uCAAuC;IACvC,GAAG;QACF,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,GAAG,CAAC,EAAU;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAChD,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACjE,CAAC;IAED,sDAAsD;IACtD,GAAG,CAAC,MAAgB;QACnB,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,CAAC,EAAU;QAChB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,6FAA6F;IAC7F,KAAK,CAAC,SAAwC;QAC7C,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,oEAAoE;IACpE,KAAK;QACJ,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAEO,IAAI;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,CAAC;IAEO,IAAI,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAW,CAAa,CAAC;IACjE,CAAC;CACD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Application } from 'pixi.js';
|
|
2
|
+
import type { Scene, SceneClass } from './Scene.ts';
|
|
3
|
+
import { Signal } from './Signal.ts';
|
|
4
|
+
export interface GameOptions {
|
|
5
|
+
/** the canvas to draw into; one is created and appended if omitted */
|
|
6
|
+
canvas?: HTMLCanvasElement;
|
|
7
|
+
/** background colour behind everything, as 0xRRGGBB */
|
|
8
|
+
background?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Longest frame the game will simulate, in seconds.
|
|
11
|
+
*
|
|
12
|
+
* A backgrounded tab reports an enormous delta on its first frame back, which would
|
|
13
|
+
* teleport everything that moves. Frames longer than this are treated as this long,
|
|
14
|
+
* so the game slows down rather than jumping.
|
|
15
|
+
*/
|
|
16
|
+
maxDelta?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Pixel art is never smoothed when scaled - both inside the game (texture sampling)
|
|
19
|
+
* and in the browser's own compositing of the canvas element onto the page, which is a
|
|
20
|
+
* separate step and blurs on its own if left at the default. Set false for a game whose
|
|
21
|
+
* art is not pixel art and should smooth when magnified.
|
|
22
|
+
*/
|
|
23
|
+
pixelArt?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* What the renderer sizes itself to. Defaults to the window.
|
|
26
|
+
*
|
|
27
|
+
* Sizing to the canvas's parent looks tidier but circles: a canvas styled to fill its
|
|
28
|
+
* parent gives the parent no height of its own, so both collapse. Pass an element only
|
|
29
|
+
* when that element has a size the canvas does not depend on.
|
|
30
|
+
*/
|
|
31
|
+
resizeTo?: HTMLElement | Window;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The application: owns the renderer, the loop, and the current scene.
|
|
35
|
+
*
|
|
36
|
+
* Construct it, `await start(FirstScene)`, and the rest is scenes.
|
|
37
|
+
*/
|
|
38
|
+
export declare class Game {
|
|
39
|
+
private static instance;
|
|
40
|
+
readonly app: Application<import("pixi.js").Renderer>;
|
|
41
|
+
/** seconds elapsed in the previous frame, clamped by `maxDelta` */
|
|
42
|
+
elapsed: number;
|
|
43
|
+
/** total seconds since the current scene was created */
|
|
44
|
+
timeTotal: number;
|
|
45
|
+
/** multiplies elapsed time; 0 pauses the game without stopping the renderer */
|
|
46
|
+
timeScale: number;
|
|
47
|
+
/** fires after every frame's update, for systems that are not scene-owned */
|
|
48
|
+
readonly onFrame: Signal<number>;
|
|
49
|
+
private stack;
|
|
50
|
+
private pending;
|
|
51
|
+
private options;
|
|
52
|
+
private started;
|
|
53
|
+
constructor(options?: GameOptions);
|
|
54
|
+
/** the viewport width in css pixels, which is what scenes lay out against */
|
|
55
|
+
get width(): number;
|
|
56
|
+
get height(): number;
|
|
57
|
+
/** the running game, for the few places that genuinely need a global */
|
|
58
|
+
static get current(): Game;
|
|
59
|
+
start(first: SceneClass): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Queues a scene change; it happens at the start of the next frame.
|
|
62
|
+
*
|
|
63
|
+
* The whole stack goes: every scene is destroyed, suspended or not, and the
|
|
64
|
+
* new one starts alone. For a scene that returns, push it instead.
|
|
65
|
+
*/
|
|
66
|
+
switchScene(next: SceneClass): void;
|
|
67
|
+
/**
|
|
68
|
+
* Queues a scene on top of the current one; it starts at the next frame.
|
|
69
|
+
*
|
|
70
|
+
* The scene underneath suspends but is not destroyed: it stops updating and
|
|
71
|
+
* keeps rendering, so the new scene can layer over it or replace it
|
|
72
|
+
* outright, and `popScene` resumes exactly where play left off.
|
|
73
|
+
*/
|
|
74
|
+
pushScene(next: SceneClass): void;
|
|
75
|
+
/**
|
|
76
|
+
* Queues the top scene's removal; it happens at the start of the next frame.
|
|
77
|
+
*
|
|
78
|
+
* @param result reported back to the resumed scene's `onResume`
|
|
79
|
+
*/
|
|
80
|
+
popScene(result?: unknown): void;
|
|
81
|
+
/** the scene currently updating: the top of the stack */
|
|
82
|
+
get currentScene(): Scene | null;
|
|
83
|
+
/**
|
|
84
|
+
* Advances the game by one frame and draws it, without waiting for the browser.
|
|
85
|
+
*
|
|
86
|
+
* The loop normally runs on requestAnimationFrame, which browsers suspend while a tab
|
|
87
|
+
* is not visible. That is right for a game and wrong for a test or a screenshot, so
|
|
88
|
+
* this drives a frame directly.
|
|
89
|
+
*
|
|
90
|
+
* @param dt seconds to advance by
|
|
91
|
+
*/
|
|
92
|
+
step(dt: number): void;
|
|
93
|
+
/**
|
|
94
|
+
* Publishes the running game on the global object, for tools and for the console.
|
|
95
|
+
*
|
|
96
|
+
* `__PIXI_APP__` is the name the PixiJS devtools extension looks for, so declaring it
|
|
97
|
+
* costs nothing and makes the scene graph inspectable. `__MWG__` is the game itself,
|
|
98
|
+
* which is what makes `__MWG__.step(1/60)` possible from a console — the only way to
|
|
99
|
+
* advance a game whose tab the browser has suspended, and the difference between
|
|
100
|
+
* diagnosing a frozen page and guessing at it.
|
|
101
|
+
*
|
|
102
|
+
* Neither is read by the framework. Nothing depends on them existing.
|
|
103
|
+
*/
|
|
104
|
+
private expose;
|
|
105
|
+
private frame;
|
|
106
|
+
private switchNow;
|
|
107
|
+
/** a new scene alone: everything else is destroyed, the clocks restart */
|
|
108
|
+
private applySwitch;
|
|
109
|
+
/** a new scene over the current one, which suspends but survives underneath */
|
|
110
|
+
private applyPush;
|
|
111
|
+
/** the top scene leaves, reporting back to whatever it covered */
|
|
112
|
+
private applyPop;
|
|
113
|
+
destroy(): void;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=Game.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Game.d.ts","sourceRoot":"","sources":["../../src/core/Game.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,SAAS,CAAC;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA2BrC,MAAM,WAAW,WAAW;IAC3B,sEAAsE;IACtE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;CAChC;AAED;;;;GAIG;AACH,qBAAa,IAAI;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAE5C,QAAQ,CAAC,GAAG,0CAAqB;IAEjC,mEAAmE;IACnE,OAAO,SAAK;IAEZ,wDAAwD;IACxD,SAAS,SAAK;IAEd,+EAA+E;IAC/E,SAAS,SAAK;IAEd,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,iBAAwB;IAExC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,OAAO,GAAE,WAAgB,EAuBpC;IAED,6EAA6E;IAC7E,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,wEAAwE;IACxE,MAAM,KAAK,OAAO,IAAI,IAAI,CAGzB;IAEK,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C5C;IAED;;;;;OAKG;IACH,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAElC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEhC;IAED;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAE/B;IAED,yDAAyD;IACzD,IAAI,YAAY,IAAI,KAAK,GAAG,IAAI,CAE/B;IAED;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAGrB;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,SAAS;IAIjB,0EAA0E;IAC1E,OAAO,CAAC,WAAW;IAanB,+EAA+E;IAC/E,OAAO,CAAC,SAAS;IAYjB,kEAAkE;IAClE,OAAO,CAAC,QAAQ;IAMhB,OAAO,IAAI,IAAI,CAMd;CACD"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { Application, TextureSource } from 'pixi.js';
|
|
2
|
+
import { SceneStack } from './SceneStack.js';
|
|
3
|
+
import { Signal } from './Signal.js';
|
|
4
|
+
import { registerColorTransform } from '../render/TintedSprite.js';
|
|
5
|
+
import * as Input from './Input.js';
|
|
6
|
+
const PIXEL_ART_CLASS = 'mwg-pixel-art';
|
|
7
|
+
/**
|
|
8
|
+
* A class beats an inline `canvas.style.imageRendering` because Pixi's own `autoDensity`/
|
|
9
|
+
* `resizeTo` rewrite the canvas's `style` attribute wholesale (see `start()`); this rule
|
|
10
|
+
* lives in the CSSOM instead, in a stylesheet Pixi never touches, so it survives that.
|
|
11
|
+
* Injected once per page, however many `Game`s end up on it.
|
|
12
|
+
*/
|
|
13
|
+
function ensurePixelArtStylesheet() {
|
|
14
|
+
if (document.getElementById(PIXEL_ART_CLASS))
|
|
15
|
+
return;
|
|
16
|
+
const style = document.createElement('style');
|
|
17
|
+
style.id = PIXEL_ART_CLASS;
|
|
18
|
+
style.textContent = `.${PIXEL_ART_CLASS} { image-rendering: pixelated; }`;
|
|
19
|
+
document.head.appendChild(style);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The application: owns the renderer, the loop, and the current scene.
|
|
23
|
+
*
|
|
24
|
+
* Construct it, `await start(FirstScene)`, and the rest is scenes.
|
|
25
|
+
*/
|
|
26
|
+
export class Game {
|
|
27
|
+
static { this.instance = null; }
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
this.app = new Application();
|
|
30
|
+
/** seconds elapsed in the previous frame, clamped by `maxDelta` */
|
|
31
|
+
this.elapsed = 0;
|
|
32
|
+
/** total seconds since the current scene was created */
|
|
33
|
+
this.timeTotal = 0;
|
|
34
|
+
/** multiplies elapsed time; 0 pauses the game without stopping the renderer */
|
|
35
|
+
this.timeScale = 1;
|
|
36
|
+
/** fires after every frame's update, for systems that are not scene-owned */
|
|
37
|
+
this.onFrame = new Signal();
|
|
38
|
+
this.stack = new SceneStack();
|
|
39
|
+
this.pending = [];
|
|
40
|
+
this.started = false;
|
|
41
|
+
this.options = {
|
|
42
|
+
canvas: options.canvas ?? document.createElement('canvas'),
|
|
43
|
+
background: options.background ?? 0x000000,
|
|
44
|
+
maxDelta: options.maxDelta ?? 0.25,
|
|
45
|
+
pixelArt: options.pixelArt ?? true,
|
|
46
|
+
resizeTo: options.resizeTo ?? window,
|
|
47
|
+
};
|
|
48
|
+
if (this.options.pixelArt) {
|
|
49
|
+
//set here rather than in start(), because textures are usually loaded before
|
|
50
|
+
//the game starts and each one takes the default that was current when it was
|
|
51
|
+
//created. nearest sampling is what keeps magnified pixel art crisp - but only
|
|
52
|
+
//inside the game's own rendering; the browser then does a second, entirely
|
|
53
|
+
//separate resize when it composites the canvas element onto the page (its
|
|
54
|
+
//backing buffer is rarely the same size as its CSS display size, especially at
|
|
55
|
+
//a devicePixelRatio other than 1), and that step defaults to smooth
|
|
56
|
+
//interpolation regardless of anything Pixi does - see `start()` for the other
|
|
57
|
+
//half of this, since `app.init()` overwrites whatever style is set here.
|
|
58
|
+
TextureSource.defaultOptions.scaleMode = 'nearest';
|
|
59
|
+
}
|
|
60
|
+
Game.instance = this;
|
|
61
|
+
}
|
|
62
|
+
/** the viewport width in css pixels, which is what scenes lay out against */
|
|
63
|
+
get width() {
|
|
64
|
+
return this.app.renderer.screen.width;
|
|
65
|
+
}
|
|
66
|
+
get height() {
|
|
67
|
+
return this.app.renderer.screen.height;
|
|
68
|
+
}
|
|
69
|
+
/** the running game, for the few places that genuinely need a global */
|
|
70
|
+
static get current() {
|
|
71
|
+
if (!Game.instance)
|
|
72
|
+
throw new Error('no Game has been created yet');
|
|
73
|
+
return Game.instance;
|
|
74
|
+
}
|
|
75
|
+
async start(first) {
|
|
76
|
+
if (this.started)
|
|
77
|
+
throw new Error('this Game has already been started');
|
|
78
|
+
this.started = true;
|
|
79
|
+
//batchers and pipes have to be registered before the renderer is built, so that
|
|
80
|
+
//TintedSprite has somewhere to render to
|
|
81
|
+
registerColorTransform();
|
|
82
|
+
Input.attach();
|
|
83
|
+
await this.app.init({
|
|
84
|
+
canvas: this.options.canvas,
|
|
85
|
+
background: this.options.background,
|
|
86
|
+
resizeTo: this.options.resizeTo,
|
|
87
|
+
antialias: false,
|
|
88
|
+
//the game clears and redraws every frame, so the buffer need not be preserved
|
|
89
|
+
preserveDrawingBuffer: false,
|
|
90
|
+
//drawing at device resolution is what keeps pixel art on whole device pixels
|
|
91
|
+
resolution: window.devicePixelRatio || 1,
|
|
92
|
+
autoDensity: true,
|
|
93
|
+
});
|
|
94
|
+
if (!this.options.canvas.isConnected) {
|
|
95
|
+
document.body.appendChild(this.options.canvas);
|
|
96
|
+
}
|
|
97
|
+
//`autoDensity` (and `resizeTo`, on its own asynchronous schedule) rewrite the canvas
|
|
98
|
+
//element's `style` attribute wholesale to keep its CSS size matching the backing
|
|
99
|
+
//buffer - which loses anything else set through `canvas.style`, including right
|
|
100
|
+
//after `init` and again from inside pixi's own 'resize' event. A class, rather than
|
|
101
|
+
//an inline style, lives in a different attribute entirely and survives that.
|
|
102
|
+
if (this.options.pixelArt) {
|
|
103
|
+
ensurePixelArtStylesheet();
|
|
104
|
+
this.options.canvas.classList.add(PIXEL_ART_CLASS);
|
|
105
|
+
}
|
|
106
|
+
//`screen` is the logical size in css pixels; `renderer.width` is the backing store,
|
|
107
|
+
//which is larger on a hidpi display. Scenes lay out in logical units, so handing
|
|
108
|
+
//them the backing size would push everything they centre off the screen.
|
|
109
|
+
this.app.renderer.on('resize', () => {
|
|
110
|
+
this.stack.resize(this.width, this.height);
|
|
111
|
+
});
|
|
112
|
+
this.expose();
|
|
113
|
+
this.switchNow(first);
|
|
114
|
+
//pixi's ticker drives the loop, so its own systems stay in step with the game
|
|
115
|
+
this.app.ticker.add((ticker) => this.frame(ticker.deltaMS / 1000));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Queues a scene change; it happens at the start of the next frame.
|
|
119
|
+
*
|
|
120
|
+
* The whole stack goes: every scene is destroyed, suspended or not, and the
|
|
121
|
+
* new one starts alone. For a scene that returns, push it instead.
|
|
122
|
+
*/
|
|
123
|
+
switchScene(next) {
|
|
124
|
+
this.pending.push({ kind: 'switch', next });
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Queues a scene on top of the current one; it starts at the next frame.
|
|
128
|
+
*
|
|
129
|
+
* The scene underneath suspends but is not destroyed: it stops updating and
|
|
130
|
+
* keeps rendering, so the new scene can layer over it or replace it
|
|
131
|
+
* outright, and `popScene` resumes exactly where play left off.
|
|
132
|
+
*/
|
|
133
|
+
pushScene(next) {
|
|
134
|
+
this.pending.push({ kind: 'push', next });
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Queues the top scene's removal; it happens at the start of the next frame.
|
|
138
|
+
*
|
|
139
|
+
* @param result reported back to the resumed scene's `onResume`
|
|
140
|
+
*/
|
|
141
|
+
popScene(result) {
|
|
142
|
+
this.pending.push({ kind: 'pop', result });
|
|
143
|
+
}
|
|
144
|
+
/** the scene currently updating: the top of the stack */
|
|
145
|
+
get currentScene() {
|
|
146
|
+
return this.stack.current;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Advances the game by one frame and draws it, without waiting for the browser.
|
|
150
|
+
*
|
|
151
|
+
* The loop normally runs on requestAnimationFrame, which browsers suspend while a tab
|
|
152
|
+
* is not visible. That is right for a game and wrong for a test or a screenshot, so
|
|
153
|
+
* this drives a frame directly.
|
|
154
|
+
*
|
|
155
|
+
* @param dt seconds to advance by
|
|
156
|
+
*/
|
|
157
|
+
step(dt) {
|
|
158
|
+
this.frame(dt);
|
|
159
|
+
this.app.renderer.render(this.app.stage);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Publishes the running game on the global object, for tools and for the console.
|
|
163
|
+
*
|
|
164
|
+
* `__PIXI_APP__` is the name the PixiJS devtools extension looks for, so declaring it
|
|
165
|
+
* costs nothing and makes the scene graph inspectable. `__MWG__` is the game itself,
|
|
166
|
+
* which is what makes `__MWG__.step(1/60)` possible from a console — the only way to
|
|
167
|
+
* advance a game whose tab the browser has suspended, and the difference between
|
|
168
|
+
* diagnosing a frozen page and guessing at it.
|
|
169
|
+
*
|
|
170
|
+
* Neither is read by the framework. Nothing depends on them existing.
|
|
171
|
+
*/
|
|
172
|
+
expose() {
|
|
173
|
+
const target = globalThis;
|
|
174
|
+
target.__PIXI_APP__ = this.app;
|
|
175
|
+
target.__MWG__ = this;
|
|
176
|
+
}
|
|
177
|
+
frame(deltaSeconds) {
|
|
178
|
+
//queued scene changes run first, in order, so a frame never updates a
|
|
179
|
+
//scene that was already asked to leave
|
|
180
|
+
for (const request of this.pending) {
|
|
181
|
+
if (request.kind === 'switch')
|
|
182
|
+
this.applySwitch(request.next);
|
|
183
|
+
else if (request.kind === 'push')
|
|
184
|
+
this.applyPush(request.next);
|
|
185
|
+
else
|
|
186
|
+
this.applyPop(request.result);
|
|
187
|
+
}
|
|
188
|
+
this.pending.length = 0;
|
|
189
|
+
this.elapsed = Math.min(deltaSeconds, this.options.maxDelta) * this.timeScale;
|
|
190
|
+
this.timeTotal += this.elapsed;
|
|
191
|
+
this.stack.update(this.elapsed);
|
|
192
|
+
this.onFrame.dispatch(this.elapsed);
|
|
193
|
+
//after everything has had a chance to poll it, so nothing misses a press
|
|
194
|
+
Input.endFrame();
|
|
195
|
+
}
|
|
196
|
+
switchNow(next) {
|
|
197
|
+
this.applySwitch(next);
|
|
198
|
+
}
|
|
199
|
+
/** a new scene alone: everything else is destroyed, the clocks restart */
|
|
200
|
+
applySwitch(next) {
|
|
201
|
+
const scene = new next();
|
|
202
|
+
this.stack.replace(scene);
|
|
203
|
+
this.app.stage.removeChildren();
|
|
204
|
+
this.app.stage.addChild(scene.stage);
|
|
205
|
+
this.elapsed = 0;
|
|
206
|
+
this.timeTotal = 0;
|
|
207
|
+
this.timeScale = 1;
|
|
208
|
+
scene.resize(this.width, this.height);
|
|
209
|
+
}
|
|
210
|
+
/** a new scene over the current one, which suspends but survives underneath */
|
|
211
|
+
applyPush(next) {
|
|
212
|
+
const scene = new next();
|
|
213
|
+
this.stack.push(scene);
|
|
214
|
+
this.app.stage.addChild(scene.stage);
|
|
215
|
+
this.elapsed = 0;
|
|
216
|
+
this.timeTotal = 0;
|
|
217
|
+
this.timeScale = 1;
|
|
218
|
+
scene.resize(this.width, this.height);
|
|
219
|
+
}
|
|
220
|
+
/** the top scene leaves, reporting back to whatever it covered */
|
|
221
|
+
applyPop(result) {
|
|
222
|
+
const top = this.stack.current;
|
|
223
|
+
this.stack.pop(result);
|
|
224
|
+
if (top)
|
|
225
|
+
this.app.stage.removeChild(top.stage);
|
|
226
|
+
}
|
|
227
|
+
destroy() {
|
|
228
|
+
Input.detach();
|
|
229
|
+
this.stack.destroy();
|
|
230
|
+
this.onFrame.removeAll();
|
|
231
|
+
this.app.destroy(true, { children: true });
|
|
232
|
+
if (Game.instance === this)
|
|
233
|
+
Game.instance = null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=Game.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Game.js","sourceRoot":"","sources":["../../src/core/Game.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
export interface HexCoord {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
}
|
|
20
|
+
/** the six cells sharing an edge with `(x, y)` */
|
|
21
|
+
export declare function hexNeighbors(x: number, y: number): HexCoord[];
|
|
22
|
+
/** the number of hex steps between two cells */
|
|
23
|
+
export declare function hexDistance(a: HexCoord, b: HexCoord): number;
|
|
24
|
+
/**
|
|
25
|
+
* Every cell a straight line crosses from `a` to `b`, both included - the hex-grid analogue
|
|
26
|
+
* of `mwg/roguelike`'s `traceLine`, and what a simple (non-shadowcast) hex field of view is
|
|
27
|
+
* built from: walk the line to a candidate cell and see whether anything on it is opaque.
|
|
28
|
+
*/
|
|
29
|
+
export declare function hexLine(a: HexCoord, b: HexCoord): HexCoord[];
|
|
30
|
+
/** every cell within `radius` hex steps of `center`, `center` itself included */
|
|
31
|
+
export declare function hexRange(center: HexCoord, radius: number): HexCoord[];
|
|
32
|
+
/** the pixel position of a hex cell's centre, for a flat-top tile of the given size */
|
|
33
|
+
export declare function hexToPixel(x: number, y: number, tileWidth: number, tileHeight: number): {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The hex cell under a pixel position - the inverse of `hexToPixel`.
|
|
39
|
+
*
|
|
40
|
+
* Fractional cube coordinates first, rounded only at the end (`cubeRound`), the same way
|
|
41
|
+
* `hexLine` resolves a fractional step to a cell - rounding column and row independently
|
|
42
|
+
* would round to the wrong cell right at a hex's edge.
|
|
43
|
+
*/
|
|
44
|
+
export declare function pixelToHex(px: number, py: number, tileWidth: number, tileHeight: number): HexCoord;
|
|
45
|
+
//# sourceMappingURL=Hex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hex.d.ts","sourceRoot":"","sources":["../../src/core/Hex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,QAAQ;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AA+BD,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,CAG7D;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAI5D;AAoBD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAsB5D;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAYrE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAKhH;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CASlG"}
|