@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/README.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# mwg
|
|
2
|
+
|
|
3
|
+
A framework for building 2D top-down games that run **from a local file** — no server, no
|
|
4
|
+
install, no runtime to download.
|
|
5
|
+
|
|
6
|
+
Licensed under the [MPL-2.0](LICENSE): games built with `mwg` carry no licence obligation
|
|
7
|
+
of their own; improvements to `mwg`'s own files are shared back.
|
|
8
|
+
|
|
9
|
+
**[Live examples and API docs](https://datamoc.github.io/mwg/)** — every example below,
|
|
10
|
+
playable in the browser with no download, plus the generated API reference.
|
|
11
|
+
|
|
12
|
+
> **Status: early.** The scaffolding, licence and capability spec are in place. The
|
|
13
|
+
> modules below are being built in the order given in [ROADMAP.md](ROADMAP.md).
|
|
14
|
+
|
|
15
|
+
## What it is for
|
|
16
|
+
|
|
17
|
+
Tile-based games with a camera over a grid. Nine existing games mark out the corners of
|
|
18
|
+
what that has to cover:
|
|
19
|
+
|
|
20
|
+
| reference | what it demands that the others do not |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| **[Shattered Pixel Dungeon](https://shatteredpixel.com/shatteredpd/)** | generated dungeons, field of view, energy-cost turn scheduling, permadeath, dense inventory UI |
|
|
23
|
+
| **[ADOM](https://www.adom.de/)** | many persistent maps joined by a world map, hunger and long-running effects, skills and attributes, quests inside a roguelike |
|
|
24
|
+
| **[RPG Maker](https://www.rpgmakerweb.com/) projects** | hand-authored maps, events on tiles, dialogue and cutscenes, a party, menu combat, save slots |
|
|
25
|
+
| **[Pokémon](https://www.pokemon.com/), in its traditional form** | encounter tables by terrain, a roster of creatures with derived stats, an effectiveness matrix, speed-ordered battles, capture and storage |
|
|
26
|
+
| **[Ren'Py](https://www.renpy.org/), and the conversation scenes every RPG borrows from it** | a backdrop with characters standing in front of it, expressions, whoever speaks picked out from the rest, branching written as data |
|
|
27
|
+
| **[The Battle for Wesnoth](https://www.wesnoth.org/)** | hexagonal tactical maps, movement cost and defense by terrain, zone of control, turn-based unit combat with recruiting and upkeep |
|
|
28
|
+
| **[Flare](https://flarerpg.org/)'s Empyrean Campaign** | isometric tile maps, loaded straight from Tiled's own isometric export |
|
|
29
|
+
| **[Dungeon Crawl Stone Soup](https://crawl.develz.org/) (Tiles)** | a branching dungeon of many interconnected levels, and autoexplore pathing to the nearest unseen tile |
|
|
30
|
+
| **[Twine](https://twinery.org/)** | a story as named passages, not one linear list - a choice jumps to another passage by name, which can loop back or braid together, entirely on state and no visual stage at all |
|
|
31
|
+
|
|
32
|
+
Underneath they share almost everything: a grid, a camera following someone across it,
|
|
33
|
+
sprites that need tinting, turn-taking, characters with stats and equipment, an inventory,
|
|
34
|
+
and a great many windows. The differences are narrower than the genre labels suggest — one
|
|
35
|
+
generates its maps and another authors them; one schedules monsters and another schedules
|
|
36
|
+
events; one rolls encounters from the terrain and another places them by hand; one puts its
|
|
37
|
+
conversations in a corner of the map and another gives them the whole screen; one moves in
|
|
38
|
+
four directions on a square grid and another in six on a hex grid.
|
|
39
|
+
|
|
40
|
+
`mwg` provides that shared floor plus each specialism, on top of
|
|
41
|
+
[PixiJS](https://pixijs.com) for rendering and [rot.js](https://ondras.github.io/rot.js/)
|
|
42
|
+
for the classic roguelike algorithms. See [Capability spec](#capability-spec).
|
|
43
|
+
|
|
44
|
+
These are references for *what a finished game of each kind has to do*, and nothing more.
|
|
45
|
+
No code, asset, data table or file format is taken from any of them — see
|
|
46
|
+
[Licence and provenance](#licence-and-provenance).
|
|
47
|
+
|
|
48
|
+
### On being "like RPG Maker"
|
|
49
|
+
|
|
50
|
+
Worth being precise, because RPG Maker is two things and `mwg` is only aiming at one of
|
|
51
|
+
them for now.
|
|
52
|
+
|
|
53
|
+
It is a **runtime** — a tile engine, an event interpreter, a battle system, a message box.
|
|
54
|
+
That is what the capability spec below commits to.
|
|
55
|
+
|
|
56
|
+
It is also an **editor**, and that is what most people actually mean by RPG Maker: drawing
|
|
57
|
+
maps and wiring events without writing code. `mwg` does not have one. What it does instead
|
|
58
|
+
is keep maps, events and dialogue as **plain data** rather than code, so an editor can be
|
|
59
|
+
built against that data later without reworking the runtime — and so that in the meantime
|
|
60
|
+
the data can be written by hand, generated by a script, or exported from
|
|
61
|
+
[Tiled](https://www.mapeditor.org/), which is free and already good at this.
|
|
62
|
+
|
|
63
|
+
That data is loaded exactly like any other asset, which means the `file://` story covers it
|
|
64
|
+
for free: a finished game is still a folder you double-click.
|
|
65
|
+
|
|
66
|
+
## Two ways to use it
|
|
67
|
+
|
|
68
|
+
**With a toolchain**, if you already use a bundler:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
npm install @datamoc/mw_games
|
|
72
|
+
```
|
|
73
|
+
```ts
|
|
74
|
+
import { Game, Scene } from '@datamoc/mw_games/core';
|
|
75
|
+
import { Sprite } from '@datamoc/mw_games/render';
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
No npm registry access (an offline machine, a pinned artifact for reproducible builds)?
|
|
79
|
+
`npm pack @datamoc/mw_games` downloads the exact published tarball; install it by path
|
|
80
|
+
instead of by name:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
npm install ./datamoc-mw_games-0.1.1.tgz
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Without either.** Drop one file next to your page and open it — this path exists because
|
|
87
|
+
the framework's own target is a game you can run by double-clicking it. Download
|
|
88
|
+
`mw_games.global.js` from a [release](https://github.com/datamoc/mwg/releases) (no `npm`,
|
|
89
|
+
no `node_modules`, nothing to install):
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<script src="mw_games.global.js"></script>
|
|
93
|
+
<script>
|
|
94
|
+
const game = new mw_games.Game(document.getElementById('game'));
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Node and npm are developer tools here, in the same sense that a compiler is. Nothing from
|
|
99
|
+
them is present when the game runs: the output is HTML, JavaScript and assets.
|
|
100
|
+
|
|
101
|
+
## Running from `file://`
|
|
102
|
+
|
|
103
|
+
Opening a page from disk takes three capabilities away, and the framework is shaped around
|
|
104
|
+
them rather than pretending otherwise:
|
|
105
|
+
|
|
106
|
+
| what is blocked | consequence | how `mwg` handles it |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| ES modules (CORS) | `<script type="module">` will not run | the standalone build is a classic IIFE |
|
|
109
|
+
| `fetch()` / XHR | no asset can be loaded on demand, no directory can be listed | `tools/compile-resources` turns assets into scripts loaded before the game |
|
|
110
|
+
| cross-origin images | an `<img>` from a sibling file taints a WebGL texture in Chrome | assets travel as `data:` URIs inside those scripts |
|
|
111
|
+
|
|
112
|
+
The practical effect: resources are **compiled at build time**, so at runtime every lookup
|
|
113
|
+
is synchronous. Game code never awaits an asset.
|
|
114
|
+
|
|
115
|
+
## Capability spec
|
|
116
|
+
|
|
117
|
+
The definition of done for 1.0, drawn from what each of the nine references actually
|
|
118
|
+
demands. The shared floor is what all of them need; the sections after it are the parts
|
|
119
|
+
only some do.
|
|
120
|
+
|
|
121
|
+
### Shared floor
|
|
122
|
+
|
|
123
|
+
| area | capability | provided by |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| **core** | fixed-step game loop, scenes, timing | `mwg/core` |
|
|
126
|
+
| | signals and listeners | `mwg/core` |
|
|
127
|
+
| | deterministic seeded RNG, reproducible across machines | `mwg/core` |
|
|
128
|
+
| | named, versioned save slots with a preview | `mwg/core` |
|
|
129
|
+
| **render** | sprite batching at thousands of tiles | PixiJS |
|
|
130
|
+
| | per-sprite colour transform: multiply **and** add | `mwg/render` |
|
|
131
|
+
| | animated sprites driven by named frame sets | `mwg/render` |
|
|
132
|
+
| | dense tile maps, multi-layer, with per-cell visibility | `mwg/render` |
|
|
133
|
+
| | hexagonal tile maps, alongside square, as a second grid shape | `mwg/render` |
|
|
134
|
+
| | camera with follow, pan, shake and zoom | `mwg/render` |
|
|
135
|
+
| | particle effects | `mwg/render` |
|
|
136
|
+
| | screen transitions: fade, flash, tint | `mwg/render` |
|
|
137
|
+
| **ui** | windows, lists, tooltips | `mwg/ui` |
|
|
138
|
+
| | text and fonts, including non-latin fallback | PixiJS |
|
|
139
|
+
| | pointer, keyboard and gamepad input with rebinding | `mwg/core` |
|
|
140
|
+
| **text** | message tables per language, compiled at build time | `mwg/i18n` |
|
|
141
|
+
| | plurals, gendered forms and interpolation | `mwg/i18n` |
|
|
142
|
+
| | left-to-right, right-to-left and vertical writing | `mwg/i18n` |
|
|
143
|
+
| | interface mirrored for right-to-left languages | `mwg/ui` |
|
|
144
|
+
| | a missing translation falls back rather than showing a key | `mwg/i18n` |
|
|
145
|
+
| **audio** | sound effects with pooling, music with crossfade | `mwg/audio` |
|
|
146
|
+
|
|
147
|
+
### World
|
|
148
|
+
|
|
149
|
+
Shared by everything past a single screen, and the thing ADOM needs most.
|
|
150
|
+
|
|
151
|
+
| capability | provided by |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| many maps in one world, joined by transitions | `mwg/world` |
|
|
154
|
+
| maps that persist when left and returned to | `mwg/world` |
|
|
155
|
+
| an overworld map with locations on it | `mwg/world` |
|
|
156
|
+
| a turn clock driving hunger, poison and other long effects | `mwg/world` |
|
|
157
|
+
|
|
158
|
+
### Roguelike
|
|
159
|
+
|
|
160
|
+
| capability | provided by |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| field of view and lighting | rot.js + `mwg/roguelike` |
|
|
163
|
+
| pathfinding over a passability map | rot.js + `mwg/roguelike` |
|
|
164
|
+
| turn scheduling by energy cost | `mwg/roguelike` |
|
|
165
|
+
| level generation from composable room builders | `mwg/roguelike` |
|
|
166
|
+
| autoexplore: pathing to the nearest unexplored cell | `mwg/roguelike` |
|
|
167
|
+
|
|
168
|
+
### Tactical maps (hex)
|
|
169
|
+
|
|
170
|
+
The Wesnoth-shaped half: a grid whose shape is a parameter, not a parallel implementation.
|
|
171
|
+
|
|
172
|
+
| capability | provided by |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| hexagonal tile maps, addressed by axial or offset coordinates | `mwg/render` |
|
|
175
|
+
| movement cost and defense bonus by terrain, hex or square alike | `mwg/roguelike` |
|
|
176
|
+
| zone of control: a hex a unit cannot move through, only into | `mwg/roguelike` |
|
|
177
|
+
| field of view and pathfinding over a hex grid, not just square | `mwg/roguelike` |
|
|
178
|
+
| isometric (and staggered) projection, alongside orthogonal and hex | `mwg/render` |
|
|
179
|
+
|
|
180
|
+
A game picks a grid shape once; the camera, field of view, pathfinding and turn scheduler
|
|
181
|
+
work the same way over either, rather than a hex game needing its own copy of each. Between
|
|
182
|
+
them, orthogonal, isometric and hex cover every map orientation
|
|
183
|
+
[Tiled](https://www.mapeditor.org/) itself supports — a Tiled map loads and renders through
|
|
184
|
+
the same `TileMap`, whichever orientation it was drawn in, rather than mwg reading only the
|
|
185
|
+
one shape it happens to render natively. Flare's Empyrean Campaign is the isometric-shaped
|
|
186
|
+
reference, the same way Wesnoth is the hex-shaped one.
|
|
187
|
+
|
|
188
|
+
### RPG
|
|
189
|
+
|
|
190
|
+
| capability | provided by |
|
|
191
|
+
| --- | --- |
|
|
192
|
+
| maps loaded as data, in any of Tiled's map orientations | `mwg/rpg` |
|
|
193
|
+
| events placed on tiles, with pages selected by conditions | `mwg/rpg` |
|
|
194
|
+
| event triggers: action, touch, autorun, parallel | `mwg/rpg` |
|
|
195
|
+
| a command interpreter for cutscenes: move routes, waits, branches, calls | `mwg/rpg` |
|
|
196
|
+
| global switches and variables, saved with the game | `mwg/rpg` |
|
|
197
|
+
| message box with portraits, choices and typewriter reveal | `mwg/rpg` + `mwg/ui` |
|
|
198
|
+
| grid movement tweened between tiles, with a walk cycle | `mwg/rpg` |
|
|
199
|
+
| a dialogue stage: backdrop, characters, expressions, speaker focus | `mwg/stage` |
|
|
200
|
+
| scenes written as a list of commands, awaited as one call | `mwg/stage` |
|
|
201
|
+
| named passages a choice can jump between, for a story that is a graph, not a line | `mwg/stage` |
|
|
202
|
+
| named save slots with a preview | `mwg/core` |
|
|
203
|
+
|
|
204
|
+
### Characters, equipment and stats
|
|
205
|
+
|
|
206
|
+
All four references have these, and they are what a game changes most, so they are data
|
|
207
|
+
rather than classes.
|
|
208
|
+
|
|
209
|
+
| capability | provided by |
|
|
210
|
+
| --- | --- |
|
|
211
|
+
| a stat block: base attributes, derived values, and the rules that derive them | `mwg/actors` |
|
|
212
|
+
| levels, experience and growth curves, all replaceable | `mwg/actors` |
|
|
213
|
+
| skills and proficiencies, checked against a difficulty | `mwg/actors` |
|
|
214
|
+
| equipment slots defined per game, not fixed by the framework | `mwg/actors` |
|
|
215
|
+
| modifiers from equipment, buffs and states, resolved in a stated order | `mwg/actors` |
|
|
216
|
+
| an inventory with stacking, weight and containers | `mwg/actors` |
|
|
217
|
+
| item identification, and cursed or blessed states | `mwg/actors` |
|
|
218
|
+
| a layered character sprite, so worn equipment is visible | `mwg/render` |
|
|
219
|
+
|
|
220
|
+
That last row is why `tools/make-example-assets.mjs` draws its character in parts. A figure
|
|
221
|
+
assembled from skin, eyes, hair and garments is one palette away from being a second
|
|
222
|
+
character — and one *layer* away from showing the armour it just put on. A single flat
|
|
223
|
+
sprite per character can do neither.
|
|
224
|
+
|
|
225
|
+
### Creatures and battles
|
|
226
|
+
|
|
227
|
+
The Pokémon-shaped half, and the part `mwg` deliberately keeps generic.
|
|
228
|
+
|
|
229
|
+
| capability | provided by |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| species defined as data, with per-individual stats derived from them | `mwg/battle` |
|
|
232
|
+
| a party with a roster and off-party storage | `mwg/battle` |
|
|
233
|
+
| an effectiveness matrix between arbitrary types | `mwg/battle` |
|
|
234
|
+
| turn order by speed, with move priority overriding it | `mwg/battle` |
|
|
235
|
+
| moves as data: cost, target shape, effects | `mwg/battle` |
|
|
236
|
+
| encounter tables per map region, weighted, with a rate per step | `mwg/world` |
|
|
237
|
+
| capture, experience, levelling and evolution as replaceable rules | `mwg/battle` |
|
|
238
|
+
|
|
239
|
+
`mwg` supplies the *shape*: a stat block, a type matrix, a turn queue. It supplies no
|
|
240
|
+
formulas, no type chart and no species — those are a game's own design, and copying any
|
|
241
|
+
particular game's would be both wrong and useless to anyone else.
|
|
242
|
+
|
|
243
|
+
All of these specialisms share the tile map, the camera, the windows, the turn clock and
|
|
244
|
+
the save system, which is why they sit in one framework rather than four.
|
|
245
|
+
|
|
246
|
+
### Why per-sprite "multiply and add"
|
|
247
|
+
|
|
248
|
+
The single most load-bearing rendering feature in either genre is the colour transform
|
|
249
|
+
`texel × M + A`. Darkness outside the field of view, tinting a poisoned enemy, flashing
|
|
250
|
+
white on a hit, a room lit by a fireplace, a screen-wide tint for a night scene — all of it
|
|
251
|
+
is that one operation.
|
|
252
|
+
|
|
253
|
+
Pixi's built-in `tint` is multiply-only, which can only ever darken. The additive term is
|
|
254
|
+
what `mwg/render` adds, in the batch shader rather than as a per-object filter, so it costs
|
|
255
|
+
nothing per sprite. See `examples/colour-transform`.
|
|
256
|
+
|
|
257
|
+
### Why maps and events are data, not code
|
|
258
|
+
|
|
259
|
+
An RPG's content is enormous and repetitive, and almost none of it deserves to be written
|
|
260
|
+
by hand in TypeScript. Keeping maps, events, dialogue and item tables as data means they
|
|
261
|
+
can be authored in a spreadsheet, generated by a script, exported from Tiled, or eventually
|
|
262
|
+
edited in a proper editor — without any of those options requiring changes to the runtime.
|
|
263
|
+
|
|
264
|
+
It also keeps the content out of the bundle: `tools/compile-resources` treats a map file
|
|
265
|
+
exactly like a sprite sheet, so adding a hundred maps does not touch the build at all.
|
|
266
|
+
|
|
267
|
+
### On writing direction
|
|
268
|
+
|
|
269
|
+
Supporting more than one language is mostly bookkeeping. Supporting more than one writing
|
|
270
|
+
*direction* is not, and the three cases are genuinely different work:
|
|
271
|
+
|
|
272
|
+
- **Left-to-right** is what everything assumes by default.
|
|
273
|
+
- **Right-to-left** — Arabic, Hebrew — is two problems at once. The text itself the browser
|
|
274
|
+
can handle: canvas applies the Unicode bidirectional algorithm and shapes the glyphs, so
|
|
275
|
+
a label mostly comes out right once its direction is declared. The *interface* is the
|
|
276
|
+
harder half, because a right-to-left reader expects it mirrored: lists indent from the
|
|
277
|
+
right, a back arrow points the other way, a progress bar fills the other way. `mwg/ui`
|
|
278
|
+
lays widgets out against a direction rather than against "left" so this can be flipped,
|
|
279
|
+
and a game only has to mark which of its own icons must not be mirrored.
|
|
280
|
+
- **Vertical**, top to bottom — traditional Chinese, Japanese, Mongolian — gets no help at
|
|
281
|
+
all. Canvas has no vertical writing mode, so the text has to be laid out glyph by glyph,
|
|
282
|
+
with its own rules for which characters rotate and which stand upright. This is real work
|
|
283
|
+
and it is scheduled as such, not assumed to fall out of the other two.
|
|
284
|
+
|
|
285
|
+
Message tables are compiled at build time, the same way every other resource is, so adding
|
|
286
|
+
a language costs nothing at runtime and a missing string falls back to the base language
|
|
287
|
+
rather than showing a raw key to the player.
|
|
288
|
+
|
|
289
|
+
## Roadmap
|
|
290
|
+
|
|
291
|
+
See [ROADMAP.md](ROADMAP.md) for the full, numbered build order — 85 items, 74 shipped and
|
|
292
|
+
eleven open (3D rendering broken into a nine-step build-up plus an engine choice, all
|
|
293
|
+
logged at low priority; see that file for why). Each module ships in the order given there;
|
|
294
|
+
later ones build on the
|
|
295
|
+
modules before them.
|
|
296
|
+
|
|
297
|
+
## Licence and provenance
|
|
298
|
+
|
|
299
|
+
`mwg` is MPL-2.0. Its dependencies are permissive and compatible: PixiJS is MIT, rot.js is
|
|
300
|
+
BSD-3-Clause.
|
|
301
|
+
|
|
302
|
+
`tools/vendored/rgssad-wasm` is a build of the `rgssad-wasm` crate from
|
|
303
|
+
<https://github.com/nathaniel-daniel/rgssad-rs>, used under its MIT licence
|
|
304
|
+
option (© 2022 Nathaniel Daniel) — see `tools/vendored/rgssad-wasm/README.md`.
|
|
305
|
+
It is a developer-side archive tool only, not part of the framework or any game.
|
|
306
|
+
|
|
307
|
+
Shattered Pixel Dungeon (GPL-3, © Oleg Dolya and Evan Debenham), The Battle for Wesnoth
|
|
308
|
+
(GPL-2.0-or-later, © the Battle for Wesnoth contributors), Flare's Empyrean Campaign
|
|
309
|
+
(GPL-3, © the Flare project), and Dungeon Crawl Stone Soup (GPL-2.0, © the Dungeon Crawl
|
|
310
|
+
Stone Soup development team) are referenced only as design studies — a list of what a
|
|
311
|
+
finished roguelike, a finished hex-based tactical game, a finished isometric one, and a
|
|
312
|
+
finished branching dungeon each have to do. None of their code, assets, maps, unit
|
|
313
|
+
definitions or text is included here, and `mwg` is not a derivative work of any of them.
|
|
314
|
+
|
|
315
|
+
ADOM, RPG Maker, Pokémon, Ren'Py and Twine are likewise references for a *shape of game*, not
|
|
316
|
+
sources of anything. `mwg` implements none of their file formats, reads none of their projects or save
|
|
317
|
+
data, and includes none of their runtimes, assets, text or data tables — no type chart, no
|
|
318
|
+
species list, no stat formula. Those are each game's own design work. Where a file format
|
|
319
|
+
is needed, `mwg` uses Tiled's, which is open and documented.
|
|
320
|
+
|
|
321
|
+
Game mechanics are not themselves protected, which is why a framework may offer "a turn
|
|
322
|
+
queue ordered by speed" or "an effectiveness matrix". Particular numbers, names and
|
|
323
|
+
artwork are another matter, and none appear here.
|
|
324
|
+
|
|
325
|
+
The assets under `examples/assets` are generated by `tools/make-example-assets.mjs` and
|
|
326
|
+
carry the project's own licence. Nothing else in this repository was downloaded from
|
|
327
|
+
anywhere, with the sole exception of `tools/vendored/rgssad-wasm` above.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiered specialization: level-gated tiers that grant points, offer a
|
|
3
|
+
* mutually-exclusive branch choice, or offer a capstone choice.
|
|
4
|
+
*
|
|
5
|
+
* The shape a subclass system and an armor-ability slot share: most tiers just add
|
|
6
|
+
* points a game spends elsewhere (through `SkillPoints`, typically), one tier asks the
|
|
7
|
+
* player to commit to exactly one of several branches for the rest of the run, and a
|
|
8
|
+
* late tier grants exactly one capstone. `mwg` names none of the options itself - a
|
|
9
|
+
* game's own track definition does, the same way `QuestLog` takes quest definitions.
|
|
10
|
+
*
|
|
11
|
+
* Points are deliberately only a ledger here, not a spend rule: what a point buys is a
|
|
12
|
+
* game's own design (a stat rank, a talent node), so spending stays game-side the way
|
|
13
|
+
* `skillCheck` is a dice roll and nothing about who is rolling it.
|
|
14
|
+
*/
|
|
15
|
+
export type AdvancementTierKind = 'points' | 'branch' | 'capstone';
|
|
16
|
+
export interface AdvancementOption {
|
|
17
|
+
id: string;
|
|
18
|
+
/** shown in a choice UI; `mwg` never reads this itself */
|
|
19
|
+
description?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AdvancementTier {
|
|
22
|
+
/** the level at which this tier opens */
|
|
23
|
+
threshold: number;
|
|
24
|
+
kind: AdvancementTierKind;
|
|
25
|
+
/** points tiers: how many ledger points opening this tier grants in total */
|
|
26
|
+
points?: number;
|
|
27
|
+
/** branch/capstone tiers: the mutually exclusive options, exactly one may be taken */
|
|
28
|
+
options?: readonly AdvancementOption[];
|
|
29
|
+
}
|
|
30
|
+
export interface AdvancementTrack {
|
|
31
|
+
tiers: readonly AdvancementTier[];
|
|
32
|
+
}
|
|
33
|
+
export declare class Advancement {
|
|
34
|
+
private track;
|
|
35
|
+
/** how many tiers have had their points granted so far */
|
|
36
|
+
private grantedTiers;
|
|
37
|
+
private balance;
|
|
38
|
+
private choices;
|
|
39
|
+
constructor(track: AdvancementTrack);
|
|
40
|
+
/** unspent ledger points */
|
|
41
|
+
get points(): number;
|
|
42
|
+
/** tier indices whose threshold the given level has reached, in order */
|
|
43
|
+
openTiers(level: number): number[];
|
|
44
|
+
/**
|
|
45
|
+
* Opens every tier up to `level`, granting each newly opened points tier's points.
|
|
46
|
+
*
|
|
47
|
+
* @returns how many points were granted - 0 when nothing new opened, so a game can
|
|
48
|
+
* tell "level up with no new tier" from a real unlock
|
|
49
|
+
*/
|
|
50
|
+
grant(level: number): number;
|
|
51
|
+
/** spends ledger points; false, spending nothing, when the balance is short */
|
|
52
|
+
spend(points: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Takes one option of an open branch/capstone tier - permanently. Throws for a points
|
|
55
|
+
* tier, a tier that has not opened yet, an unknown option, or a tier already decided,
|
|
56
|
+
* so a game cannot accidentally offer a choice twice.
|
|
57
|
+
*/
|
|
58
|
+
choose(tierIndex: number, optionId: string, level: number): void;
|
|
59
|
+
/** the option taken at a branch/capstone tier, or null when undecided */
|
|
60
|
+
choice(tierIndex: number): string | null;
|
|
61
|
+
toJSON(): {
|
|
62
|
+
grantedTiers: number;
|
|
63
|
+
balance: number;
|
|
64
|
+
choices: [number, string][];
|
|
65
|
+
};
|
|
66
|
+
/** rebuilds advancement from save data - the track itself is supplied fresh, the same as `QuestLog` definitions */
|
|
67
|
+
static fromJSON(track: AdvancementTrack, data: {
|
|
68
|
+
grantedTiers: number;
|
|
69
|
+
balance: number;
|
|
70
|
+
choices: [number, string][];
|
|
71
|
+
}): Advancement;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=Advancement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Advancement.d.ts","sourceRoot":"","sources":["../../src/actors/Advancement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEnE,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,MAAM,CAAC;IAEX,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,EAAE,mBAAmB,CAAC;IAE1B,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,sFAAsF;IACtF,OAAO,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CAClC;AAED,qBAAa,WAAW;IACvB,OAAO,CAAC,KAAK,CAAmB;IAEhC,0DAA0D;IAC1D,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAA6B;IAE5C,YAAY,KAAK,EAAE,gBAAgB,EAElC;IAED,4BAA4B;IAC5B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,yEAAyE;IACzE,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAMjC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAW3B;IAED,+EAA+E;IAC/E,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI7B;IAED;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAU/D;IAED,yEAAyE;IACzE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEvC;IAED,MAAM,IAAI;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,CAE/E;IAED,mHAAmH;IACnH,MAAM,CAAC,QAAQ,CACd,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,GAC1E,WAAW,CAMb;CACD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiered specialization: level-gated tiers that grant points, offer a
|
|
3
|
+
* mutually-exclusive branch choice, or offer a capstone choice.
|
|
4
|
+
*
|
|
5
|
+
* The shape a subclass system and an armor-ability slot share: most tiers just add
|
|
6
|
+
* points a game spends elsewhere (through `SkillPoints`, typically), one tier asks the
|
|
7
|
+
* player to commit to exactly one of several branches for the rest of the run, and a
|
|
8
|
+
* late tier grants exactly one capstone. `mwg` names none of the options itself - a
|
|
9
|
+
* game's own track definition does, the same way `QuestLog` takes quest definitions.
|
|
10
|
+
*
|
|
11
|
+
* Points are deliberately only a ledger here, not a spend rule: what a point buys is a
|
|
12
|
+
* game's own design (a stat rank, a talent node), so spending stays game-side the way
|
|
13
|
+
* `skillCheck` is a dice roll and nothing about who is rolling it.
|
|
14
|
+
*/
|
|
15
|
+
export class Advancement {
|
|
16
|
+
constructor(track) {
|
|
17
|
+
/** how many tiers have had their points granted so far */
|
|
18
|
+
this.grantedTiers = 0;
|
|
19
|
+
this.balance = 0;
|
|
20
|
+
this.choices = new Map();
|
|
21
|
+
this.track = track;
|
|
22
|
+
}
|
|
23
|
+
/** unspent ledger points */
|
|
24
|
+
get points() {
|
|
25
|
+
return this.balance;
|
|
26
|
+
}
|
|
27
|
+
/** tier indices whose threshold the given level has reached, in order */
|
|
28
|
+
openTiers(level) {
|
|
29
|
+
const out = [];
|
|
30
|
+
this.track.tiers.forEach((tier, index) => {
|
|
31
|
+
if (level >= tier.threshold)
|
|
32
|
+
out.push(index);
|
|
33
|
+
});
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Opens every tier up to `level`, granting each newly opened points tier's points.
|
|
38
|
+
*
|
|
39
|
+
* @returns how many points were granted - 0 when nothing new opened, so a game can
|
|
40
|
+
* tell "level up with no new tier" from a real unlock
|
|
41
|
+
*/
|
|
42
|
+
grant(level) {
|
|
43
|
+
let granted = 0;
|
|
44
|
+
while (this.grantedTiers < this.track.tiers.length && level >= this.track.tiers[this.grantedTiers].threshold) {
|
|
45
|
+
const tier = this.track.tiers[this.grantedTiers];
|
|
46
|
+
if (tier.kind === 'points') {
|
|
47
|
+
this.balance += tier.points ?? 0;
|
|
48
|
+
granted += tier.points ?? 0;
|
|
49
|
+
}
|
|
50
|
+
this.grantedTiers++;
|
|
51
|
+
}
|
|
52
|
+
return granted;
|
|
53
|
+
}
|
|
54
|
+
/** spends ledger points; false, spending nothing, when the balance is short */
|
|
55
|
+
spend(points) {
|
|
56
|
+
if (this.balance < points)
|
|
57
|
+
return false;
|
|
58
|
+
this.balance -= points;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Takes one option of an open branch/capstone tier - permanently. Throws for a points
|
|
63
|
+
* tier, a tier that has not opened yet, an unknown option, or a tier already decided,
|
|
64
|
+
* so a game cannot accidentally offer a choice twice.
|
|
65
|
+
*/
|
|
66
|
+
choose(tierIndex, optionId, level) {
|
|
67
|
+
const tier = this.track.tiers[tierIndex];
|
|
68
|
+
if (!tier)
|
|
69
|
+
throw new Error(`no such advancement tier: ${tierIndex}`);
|
|
70
|
+
if (tier.kind === 'points')
|
|
71
|
+
throw new Error(`tier ${tierIndex} grants points, it has no choice`);
|
|
72
|
+
if (level < tier.threshold)
|
|
73
|
+
throw new Error(`tier ${tierIndex} has not opened yet`);
|
|
74
|
+
if (this.choices.has(tierIndex))
|
|
75
|
+
throw new Error(`tier ${tierIndex} is already decided`);
|
|
76
|
+
if (!(tier.options ?? []).some((option) => option.id === optionId)) {
|
|
77
|
+
throw new Error(`tier ${tierIndex} has no option "${optionId}"`);
|
|
78
|
+
}
|
|
79
|
+
this.choices.set(tierIndex, optionId);
|
|
80
|
+
}
|
|
81
|
+
/** the option taken at a branch/capstone tier, or null when undecided */
|
|
82
|
+
choice(tierIndex) {
|
|
83
|
+
return this.choices.get(tierIndex) ?? null;
|
|
84
|
+
}
|
|
85
|
+
toJSON() {
|
|
86
|
+
return { grantedTiers: this.grantedTiers, balance: this.balance, choices: [...this.choices] };
|
|
87
|
+
}
|
|
88
|
+
/** rebuilds advancement from save data - the track itself is supplied fresh, the same as `QuestLog` definitions */
|
|
89
|
+
static fromJSON(track, data) {
|
|
90
|
+
const advancement = new Advancement(track);
|
|
91
|
+
advancement.grantedTiers = data.grantedTiers;
|
|
92
|
+
advancement.balance = data.balance;
|
|
93
|
+
for (const [tier, option] of data.choices)
|
|
94
|
+
advancement.choices.set(tier, option);
|
|
95
|
+
return advancement;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=Advancement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Advancement.js","sourceRoot":"","sources":["../../src/actors/Advancement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { InventoryItem } from './Inventory.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Named item affixes: enchantments, glyphs, augments, curses - whatever a game's items
|
|
4
|
+
* can carry beyond their upgrade `level`.
|
|
5
|
+
*
|
|
6
|
+
* `mwg` draws the line `ItemState` already drew: `level` is a number any item can have,
|
|
7
|
+
* but what "+1 blazing" *means* is a game's own design. An affix definition therefore
|
|
8
|
+
* carries only the routing information every such system shares - which trigger it
|
|
9
|
+
* answers to (`strike`, `defend`, or a `passive` that is always on), how likely it is
|
|
10
|
+
* relative to its table, and whether it is a curse - and the game interprets the id
|
|
11
|
+
* itself when that trigger fires, the same way `Move.effects` is data `mwg` never reads.
|
|
12
|
+
*/
|
|
13
|
+
export type AffixTrigger = 'strike' | 'defend' | 'passive';
|
|
14
|
+
export interface AffixDef {
|
|
15
|
+
id: string;
|
|
16
|
+
trigger: AffixTrigger;
|
|
17
|
+
/** relative likelihood within its own table; 0 never rolls */
|
|
18
|
+
weight: number;
|
|
19
|
+
/** a curse locks the item (see `EquipmentSlots`' lock option) once identified */
|
|
20
|
+
curse?: boolean;
|
|
21
|
+
/** shown in an item description; `mwg` never reads this itself */
|
|
22
|
+
description?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface AffixTable {
|
|
25
|
+
entries: readonly AffixDef[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Weight-picks one affix from a table - the same "roll whether, then weight-pick which"
|
|
29
|
+
* shape `rollLoot` already is, with a single entry reading as "always this one".
|
|
30
|
+
*
|
|
31
|
+
* @returns null when the table is empty or every entry has weight 0
|
|
32
|
+
*/
|
|
33
|
+
export declare function rollAffix(table: AffixTable): AffixDef | null;
|
|
34
|
+
/** the affix an item carries, if any - stored on the item next to its upgrade `level` */
|
|
35
|
+
export declare function affixOf(item: InventoryItem): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Sets an item's affix, replacing any it already had. A curse affix also marks the item
|
|
38
|
+
* `cursed`, so identification and equipment-lock behaviour follow without the game
|
|
39
|
+
* wiring them separately.
|
|
40
|
+
*/
|
|
41
|
+
export declare function applyAffix(item: InventoryItem, affix: AffixDef): void;
|
|
42
|
+
/** removes an item's affix (and its curse mark, if the affix was a curse) */
|
|
43
|
+
export declare function removeAffix(item: InventoryItem): void;
|
|
44
|
+
//# sourceMappingURL=Affix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Affix.d.ts","sourceRoot":"","sources":["../../src/actors/Affix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IAEX,OAAO,EAAE,YAAY,CAAC;IAEtB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IAEf,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAK5D;AAED,yFAAyF;AACzF,wBAAgB,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAGrE;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAGrD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as Random from '../core/Random.js';
|
|
2
|
+
/**
|
|
3
|
+
* Weight-picks one affix from a table - the same "roll whether, then weight-pick which"
|
|
4
|
+
* shape `rollLoot` already is, with a single entry reading as "always this one".
|
|
5
|
+
*
|
|
6
|
+
* @returns null when the table is empty or every entry has weight 0
|
|
7
|
+
*/
|
|
8
|
+
export function rollAffix(table) {
|
|
9
|
+
const live = table.entries.filter((entry) => entry.weight > 0);
|
|
10
|
+
if (live.length === 0)
|
|
11
|
+
return null;
|
|
12
|
+
const index = Random.weighted(live.map((entry) => entry.weight));
|
|
13
|
+
return index === -1 ? null : live[index];
|
|
14
|
+
}
|
|
15
|
+
/** the affix an item carries, if any - stored on the item next to its upgrade `level` */
|
|
16
|
+
export function affixOf(item) {
|
|
17
|
+
return item.affix;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sets an item's affix, replacing any it already had. A curse affix also marks the item
|
|
21
|
+
* `cursed`, so identification and equipment-lock behaviour follow without the game
|
|
22
|
+
* wiring them separately.
|
|
23
|
+
*/
|
|
24
|
+
export function applyAffix(item, affix) {
|
|
25
|
+
item.affix = affix.id;
|
|
26
|
+
if (affix.curse)
|
|
27
|
+
item.cursed = true;
|
|
28
|
+
}
|
|
29
|
+
/** removes an item's affix (and its curse mark, if the affix was a curse) */
|
|
30
|
+
export function removeAffix(item) {
|
|
31
|
+
if (item.affix !== undefined)
|
|
32
|
+
item.cursed = false;
|
|
33
|
+
delete item.affix;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=Affix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Affix.js","sourceRoot":"","sources":["../../src/actors/Affix.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAmC5C;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,KAAiB;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACjE,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,OAAO,CAAC,IAAmB;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAmB,EAAE,KAAe;IAC9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC;IACtB,IAAI,KAAK,CAAC,KAAK;QAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;AACrC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,IAAmB;IAC9C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-run appearance shuffling for unidentified items: which look each kind wears.
|
|
3
|
+
*
|
|
4
|
+
* A game with identification needs this the moment it has more than one unidentified
|
|
5
|
+
* kind in a category - without it, every run's "red potion" would always be the same
|
|
6
|
+
* kind, and identifying one would identify them all forever. The mapping is drawn once
|
|
7
|
+
* per run (a seeded shuffle, so a run's seed fully determines it) and stays fixed until
|
|
8
|
+
* the run ends; revealing a kind's true nature stays the game's own `identify()` call,
|
|
9
|
+
* which keeps reading the mapping for the *unidentified* label only.
|
|
10
|
+
*/
|
|
11
|
+
export interface AppearanceTable {
|
|
12
|
+
/** the item kinds sharing one pool of looks, e.g. every potion kind */
|
|
13
|
+
kinds: readonly string[];
|
|
14
|
+
/** the distinct looks to deal out; must cover every kind, extras stay unused */
|
|
15
|
+
labels: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Deals each kind a distinct label from a shuffled copy of the pool - pure, so a game
|
|
19
|
+
* that wants the shuffle scoped (one seed per run, say) wraps it in `Random.withSeed`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function assignAppearances(table: AppearanceTable): Map<string, string>;
|
|
22
|
+
export declare class Appearances {
|
|
23
|
+
private tables;
|
|
24
|
+
private assigned;
|
|
25
|
+
constructor(tables: Record<string, AppearanceTable>);
|
|
26
|
+
/** the look `kind` wears this run in `category`, drawing the shuffle on first ask */
|
|
27
|
+
appearanceOf(category: string, kind: string): string;
|
|
28
|
+
toJSON(): {
|
|
29
|
+
assigned: [string, [string, string][]][];
|
|
30
|
+
};
|
|
31
|
+
/** rebuilds appearances from save data - the tables themselves are supplied fresh, the same as `QuestLog` definitions */
|
|
32
|
+
static fromJSON(tables: Record<string, AppearanceTable>, data: {
|
|
33
|
+
assigned: [string, [string, string][]][];
|
|
34
|
+
}): Appearances;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=Appearances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Appearances.d.ts","sourceRoot":"","sources":["../../src/actors/Appearances.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,MAAM,WAAW,eAAe;IAC/B,uEAAuE;IACvE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAEzB,gFAAgF;IAChF,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAc7E;AAED,qBAAa,WAAW;IACvB,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,QAAQ,CAA0C;IAE1D,YAAY,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAElD;IAED,qFAAqF;IACrF,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWnD;IAED,MAAM,IAAI;QAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;KAAE,CAErD;IAED,yHAAyH;IACzH,MAAM,CAAC,QAAQ,CACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACvC,IAAI,EAAE;QAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;KAAE,GAChD,WAAW,CAIb;CACD"}
|