@strixit/storyscript 0.0.0-stage → 1.0.0
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/.env +1 -0
- package/CodeSnippets/StoryScriptSnippets.code-snippets +573 -0
- package/LICENSE.txt +21 -0
- package/LiveTemplates/StoryScript.xml +271 -0
- package/README.md +9 -2
- package/baseViteConfig.js +112 -0
- package/clientFiles/currentGameName.js +1 -0
- package/clientFiles/gitignore +12 -0
- package/clientFiles/tsconfig.json +34 -0
- package/clientFiles/vite.config.ts +14 -0
- package/clientFiles/vitest.config.ts +29 -0
- package/dist/src/Engine/Actions/index.d.ts +2 -0
- package/dist/src/Engine/Actions/open.d.ts +6 -0
- package/dist/src/Engine/Actions/openWithKey.d.ts +7 -0
- package/dist/src/Engine/EntityCreatorFunctions.d.ts +18 -0
- package/dist/src/Engine/Interfaces/action.d.ts +37 -0
- package/dist/src/Engine/Interfaces/autoplayStep.d.ts +11 -0
- package/dist/src/Engine/Interfaces/barrier.d.ts +16 -0
- package/dist/src/Engine/Interfaces/barrierAction.d.ts +19 -0
- package/dist/src/Engine/Interfaces/character.d.ts +48 -0
- package/dist/src/Engine/Interfaces/combatSetup.d.ts +9 -0
- package/dist/src/Engine/Interfaces/combatTurn.d.ts +37 -0
- package/dist/src/Engine/Interfaces/combatWinnings.d.ts +6 -0
- package/dist/src/Engine/Interfaces/combinations/activeCombination.d.ts +14 -0
- package/dist/src/Engine/Interfaces/combinations/combinable.d.ts +18 -0
- package/dist/src/Engine/Interfaces/combinations/combinationAction.d.ts +41 -0
- package/dist/src/Engine/Interfaces/combinations/combinationMatchResult.d.ts +14 -0
- package/dist/src/Engine/Interfaces/combinations/combinations.d.ts +17 -0
- package/dist/src/Engine/Interfaces/combinations/combine.d.ts +22 -0
- package/dist/src/Engine/Interfaces/combinations/combineResult.d.ts +18 -0
- package/dist/src/Engine/Interfaces/combinations/gameCombinations.d.ts +40 -0
- package/dist/src/Engine/Interfaces/compiledLocation.d.ts +33 -0
- package/dist/src/Engine/Interfaces/conversations/conversation.d.ts +44 -0
- package/dist/src/Engine/Interfaces/conversations/conversationLogEntry.d.ts +13 -0
- package/dist/src/Engine/Interfaces/conversations/conversationNode.d.ts +22 -0
- package/dist/src/Engine/Interfaces/conversations/conversationReply.d.ts +49 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacter.d.ts +20 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacterAttribute.d.ts +18 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacterAttributeEntry.d.ts +18 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacterQuestion.d.ts +18 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacterQuestionEntry.d.ts +22 -0
- package/dist/src/Engine/Interfaces/createCharacter/createCharacterStep.d.ts +40 -0
- package/dist/src/Engine/Interfaces/customCursor.d.ts +8 -0
- package/dist/src/Engine/Interfaces/defaultEquipment.d.ts +19 -0
- package/dist/src/Engine/Interfaces/definitions.d.ts +40 -0
- package/dist/src/Engine/Interfaces/destination.d.ts +31 -0
- package/dist/src/Engine/Interfaces/dynamicStyle.d.ts +10 -0
- package/dist/src/Engine/Interfaces/enemy.d.ts +46 -0
- package/dist/src/Engine/Interfaces/enumerations/actionStatus.d.ts +18 -0
- package/dist/src/Engine/Interfaces/enumerations/actionType.d.ts +9 -0
- package/dist/src/Engine/Interfaces/enumerations/equipmentType.d.ts +51 -0
- package/dist/src/Engine/Interfaces/enumerations/gameState.d.ts +11 -0
- package/dist/src/Engine/Interfaces/enumerations/playState.d.ts +10 -0
- package/dist/src/Engine/Interfaces/enumerations/targetType.d.ts +9 -0
- package/dist/src/Engine/Interfaces/equipment.d.ts +43 -0
- package/dist/src/Engine/Interfaces/feature.d.ts +37 -0
- package/dist/src/Engine/Interfaces/featureCollection.d.ts +7 -0
- package/dist/src/Engine/Interfaces/game.d.ts +148 -0
- package/dist/src/Engine/Interfaces/gameEvents.d.ts +7 -0
- package/dist/src/Engine/Interfaces/groupableItem.d.ts +32 -0
- package/dist/src/Engine/Interfaces/helpers.d.ts +50 -0
- package/dist/src/Engine/Interfaces/index.d.ts +78 -0
- package/dist/src/Engine/Interfaces/interfaceTexts.d.ts +140 -0
- package/dist/src/Engine/Interfaces/item.d.ts +96 -0
- package/dist/src/Engine/Interfaces/key.d.ts +16 -0
- package/dist/src/Engine/Interfaces/location.d.ts +78 -0
- package/dist/src/Engine/Interfaces/maps/map.d.ts +45 -0
- package/dist/src/Engine/Interfaces/maps/mapLocation.d.ts +23 -0
- package/dist/src/Engine/Interfaces/party.d.ts +33 -0
- package/dist/src/Engine/Interfaces/person.d.ts +25 -0
- package/dist/src/Engine/Interfaces/quest.d.ts +51 -0
- package/dist/src/Engine/Interfaces/rules/characterRules.d.ts +84 -0
- package/dist/src/Engine/Interfaces/rules/combatRules.d.ts +46 -0
- package/dist/src/Engine/Interfaces/rules/combinationRules.d.ts +15 -0
- package/dist/src/Engine/Interfaces/rules/demoMode.d.ts +15 -0
- package/dist/src/Engine/Interfaces/rules/encounterRules.d.ts +4 -0
- package/dist/src/Engine/Interfaces/rules/explorationRules.d.ts +42 -0
- package/dist/src/Engine/Interfaces/rules/generalRules.d.ts +62 -0
- package/dist/src/Engine/Interfaces/rules/rules.d.ts +31 -0
- package/dist/src/Engine/Interfaces/rules/setupRules.d.ts +56 -0
- package/dist/src/Engine/Interfaces/rules/titleScreen.d.ts +16 -0
- package/dist/src/Engine/Interfaces/saveGame.d.ts +33 -0
- package/dist/src/Engine/Interfaces/scoreEntry.d.ts +13 -0
- package/dist/src/Engine/Interfaces/services/autoplayService.d.ts +19 -0
- package/dist/src/Engine/Interfaces/services/characterService.d.ts +17 -0
- package/dist/src/Engine/Interfaces/services/combatService.d.ts +26 -0
- package/dist/src/Engine/Interfaces/services/combinationService.d.ts +9 -0
- package/dist/src/Engine/Interfaces/services/commandService.d.ts +64 -0
- package/dist/src/Engine/Interfaces/services/conversationService.d.ts +5 -0
- package/dist/src/Engine/Interfaces/services/dataSerializer.d.ts +4 -0
- package/dist/src/Engine/Interfaces/services/dataService.d.ts +33 -0
- package/dist/src/Engine/Interfaces/services/dataSynchronizer.d.ts +3 -0
- package/dist/src/Engine/Interfaces/services/gameService.d.ts +10 -0
- package/dist/src/Engine/Interfaces/services/index.d.ts +16 -0
- package/dist/src/Engine/Interfaces/services/itemService.d.ts +14 -0
- package/dist/src/Engine/Interfaces/services/localStorageService.d.ts +6 -0
- package/dist/src/Engine/Interfaces/services/locationService.d.ts +8 -0
- package/dist/src/Engine/Interfaces/services/soundService.d.ts +5 -0
- package/dist/src/Engine/Interfaces/services/tradeService.d.ts +9 -0
- package/dist/src/Engine/Interfaces/soundPlayer.d.ts +30 -0
- package/dist/src/Engine/Interfaces/sprite.d.ts +23 -0
- package/dist/src/Engine/Interfaces/stateList.d.ts +9 -0
- package/dist/src/Engine/Interfaces/statistics.d.ts +13 -0
- package/dist/src/Engine/Interfaces/stock.d.ts +39 -0
- package/dist/src/Engine/Interfaces/trade.d.ts +62 -0
- package/dist/src/Engine/ServiceFactory.d.ts +52 -0
- package/dist/src/Engine/Services/AutoplayService.d.ts +11 -0
- package/dist/src/Engine/Services/CharacterService.d.ts +21 -0
- package/dist/src/Engine/Services/CombatService.d.ts +16 -0
- package/dist/src/Engine/Services/CombinationService.d.ts +15 -0
- package/dist/src/Engine/Services/CommandService.d.ts +24 -0
- package/dist/src/Engine/Services/ConversationService.d.ts +26 -0
- package/dist/src/Engine/Services/DataSerializer.d.ts +17 -0
- package/dist/src/Engine/Services/DataService.d.ts +16 -0
- package/dist/src/Engine/Services/DataSynchronizer.d.ts +12 -0
- package/dist/src/Engine/Services/GameService.d.ts +28 -0
- package/dist/src/Engine/Services/HelperService.d.ts +18 -0
- package/dist/src/Engine/Services/ItemService.d.ts +21 -0
- package/dist/src/Engine/Services/LocalStorageService.d.ts +7 -0
- package/dist/src/Engine/Services/LocationService.d.ts +25 -0
- package/dist/src/Engine/Services/SoundService.d.ts +13 -0
- package/dist/src/Engine/Services/TradeService.d.ts +17 -0
- package/dist/src/Engine/Services/index.d.ts +17 -0
- package/dist/src/Engine/Services/serializationData.d.ts +8 -0
- package/dist/src/Engine/Services/sharedFunctions.d.ts +21 -0
- package/dist/src/Engine/arrayAndFunctionExtensions.d.ts +3 -0
- package/dist/src/Engine/defaultTexts.d.ts +7 -0
- package/dist/src/Engine/gameEvents.d.ts +10 -0
- package/dist/src/Engine/index.d.ts +8 -0
- package/dist/src/Engine/stateProperties.d.ts +6 -0
- package/dist/src/Engine/utilityFunctions.d.ts +25 -0
- package/dist/src/UI/Composables/CustomCursor.d.ts +2 -0
- package/dist/src/UI/Composables/LocationMap.d.ts +26 -0
- package/dist/src/UI/Composables/Sound.d.ts +7 -0
- package/dist/src/UI/Composables/TextFeatures.d.ts +8 -0
- package/dist/src/UI/Composables/VisualFeatures.d.ts +7 -0
- package/dist/src/UI/Composables/index.d.ts +7 -0
- package/dist/src/UI/Composables/playStateWatch.d.ts +2 -0
- package/dist/src/UI/StateStore.d.ts +14256 -0
- package/dist/src/UI/error.d.ts +6 -0
- package/dist/src/UI/helpers.d.ts +3 -0
- package/dist/src/UI/index.d.ts +6 -0
- package/dist/src/UI/main.d.ts +1 -0
- package/dist/src/UI/startup.d.ts +2 -0
- package/dist/src/constants.d.ts +17 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/storyscript.css +9566 -0
- package/dist/storyscript.js +9659 -0
- package/dist/storyscript.js.map +1 -0
- package/dist/storyscript.mjs +9569 -0
- package/dist/storyscript.mjs.map +1 -0
- package/electron.cjs +44 -0
- package/index.html +14 -0
- package/package.json +118 -4
- package/scripts/cli.js +268 -0
- package/scripts/createAsset.js +117 -0
- package/scripts/createGame.js +40 -0
- package/scripts/helpers.js +21 -0
- package/scripts/postbuild.js +179 -0
- package/scripts/setupTesting.js +17 -0
- package/shims-vue.d.ts +1 -0
- package/src/Engine/Actions/index.ts +2 -0
- package/src/Engine/Actions/open.ts +12 -0
- package/src/Engine/Actions/openWithKey.ts +23 -0
- package/src/Engine/EntityCreatorFunctions.ts +602 -0
- package/src/Engine/Interfaces/action.ts +43 -0
- package/src/Engine/Interfaces/autoplayStep.ts +13 -0
- package/src/Engine/Interfaces/barrier.ts +18 -0
- package/src/Engine/Interfaces/barrierAction.ts +21 -0
- package/src/Engine/Interfaces/character.ts +58 -0
- package/src/Engine/Interfaces/combatSetup.ts +10 -0
- package/src/Engine/Interfaces/combatTurn.ts +45 -0
- package/src/Engine/Interfaces/combatWinnings.ts +7 -0
- package/src/Engine/Interfaces/combinations/activeCombination.ts +16 -0
- package/src/Engine/Interfaces/combinations/combinable.ts +21 -0
- package/src/Engine/Interfaces/combinations/combinationAction.ts +45 -0
- package/src/Engine/Interfaces/combinations/combinationMatchResult.ts +16 -0
- package/src/Engine/Interfaces/combinations/combinations.ts +19 -0
- package/src/Engine/Interfaces/combinations/combine.ts +25 -0
- package/src/Engine/Interfaces/combinations/combineResult.ts +21 -0
- package/src/Engine/Interfaces/combinations/gameCombinations.ts +48 -0
- package/src/Engine/Interfaces/compiledLocation.ts +37 -0
- package/src/Engine/Interfaces/conversations/conversation.ts +47 -0
- package/src/Engine/Interfaces/conversations/conversationLogEntry.ts +14 -0
- package/src/Engine/Interfaces/conversations/conversationNode.ts +26 -0
- package/src/Engine/Interfaces/conversations/conversationReply.ts +59 -0
- package/src/Engine/Interfaces/createCharacter/createCharacter.ts +23 -0
- package/src/Engine/Interfaces/createCharacter/createCharacterAttribute.ts +21 -0
- package/src/Engine/Interfaces/createCharacter/createCharacterAttributeEntry.ts +21 -0
- package/src/Engine/Interfaces/createCharacter/createCharacterQuestion.ts +21 -0
- package/src/Engine/Interfaces/createCharacter/createCharacterQuestionEntry.ts +25 -0
- package/src/Engine/Interfaces/createCharacter/createCharacterStep.ts +47 -0
- package/src/Engine/Interfaces/customCursor.ts +5 -0
- package/src/Engine/Interfaces/defaultEquipment.ts +32 -0
- package/src/Engine/Interfaces/definitions.ts +48 -0
- package/src/Engine/Interfaces/destination.ts +37 -0
- package/src/Engine/Interfaces/dynamicStyle.ts +11 -0
- package/src/Engine/Interfaces/enemy.ts +54 -0
- package/src/Engine/Interfaces/enumerations/actionStatus.ts +20 -0
- package/src/Engine/Interfaces/enumerations/actionType.ts +9 -0
- package/src/Engine/Interfaces/enumerations/equipmentType.ts +61 -0
- package/src/Engine/Interfaces/enumerations/gameState.ts +11 -0
- package/src/Engine/Interfaces/enumerations/playState.ts +10 -0
- package/src/Engine/Interfaces/enumerations/targetType.ts +9 -0
- package/src/Engine/Interfaces/equipment.ts +44 -0
- package/src/Engine/Interfaces/feature.ts +43 -0
- package/src/Engine/Interfaces/featureCollection.ts +8 -0
- package/src/Engine/Interfaces/game.ts +201 -0
- package/src/Engine/Interfaces/gameEvents.ts +11 -0
- package/src/Engine/Interfaces/groupableItem.ts +37 -0
- package/src/Engine/Interfaces/helpers.ts +55 -0
- package/src/Engine/Interfaces/index.ts +158 -0
- package/src/Engine/Interfaces/interfaceTexts.ts +142 -0
- package/src/Engine/Interfaces/item.ts +111 -0
- package/src/Engine/Interfaces/key.ts +18 -0
- package/src/Engine/Interfaces/location.ts +92 -0
- package/src/Engine/Interfaces/maps/map.ts +55 -0
- package/src/Engine/Interfaces/maps/mapLocation.ts +28 -0
- package/src/Engine/Interfaces/party.ts +40 -0
- package/src/Engine/Interfaces/person.ts +29 -0
- package/src/Engine/Interfaces/quest.ts +60 -0
- package/src/Engine/Interfaces/rules/characterRules.ts +96 -0
- package/src/Engine/Interfaces/rules/combatRules.ts +52 -0
- package/src/Engine/Interfaces/rules/combinationRules.ts +17 -0
- package/src/Engine/Interfaces/rules/demoMode.ts +18 -0
- package/src/Engine/Interfaces/rules/encounterRules.ts +5 -0
- package/src/Engine/Interfaces/rules/explorationRules.ts +47 -0
- package/src/Engine/Interfaces/rules/generalRules.ts +80 -0
- package/src/Engine/Interfaces/rules/rules.ts +46 -0
- package/src/Engine/Interfaces/rules/setupRules.ts +65 -0
- package/src/Engine/Interfaces/rules/titleScreen.ts +19 -0
- package/src/Engine/Interfaces/saveGame.ts +39 -0
- package/src/Engine/Interfaces/scoreEntry.ts +14 -0
- package/src/Engine/Interfaces/services/autoplayService.ts +23 -0
- package/src/Engine/Interfaces/services/characterService.ts +35 -0
- package/src/Engine/Interfaces/services/combatService.ts +30 -0
- package/src/Engine/Interfaces/services/combinationService.ts +10 -0
- package/src/Engine/Interfaces/services/commandService.ts +75 -0
- package/src/Engine/Interfaces/services/conversationService.ts +7 -0
- package/src/Engine/Interfaces/services/dataSerializer.ts +4 -0
- package/src/Engine/Interfaces/services/dataService.ts +39 -0
- package/src/Engine/Interfaces/services/dataSynchronizer.ts +9 -0
- package/src/Engine/Interfaces/services/gameService.ts +17 -0
- package/src/Engine/Interfaces/services/index.ts +33 -0
- package/src/Engine/Interfaces/services/itemService.ts +25 -0
- package/src/Engine/Interfaces/services/localStorageService.ts +6 -0
- package/src/Engine/Interfaces/services/locationService.ts +13 -0
- package/src/Engine/Interfaces/services/soundService.ts +7 -0
- package/src/Engine/Interfaces/services/tradeService.ts +15 -0
- package/src/Engine/Interfaces/soundPlayer.ts +30 -0
- package/src/Engine/Interfaces/sprite.ts +27 -0
- package/src/Engine/Interfaces/stateList.ts +13 -0
- package/src/Engine/Interfaces/statistics.ts +14 -0
- package/src/Engine/Interfaces/stock.ts +46 -0
- package/src/Engine/Interfaces/trade.ts +72 -0
- package/src/Engine/ServiceFactory.ts +167 -0
- package/src/Engine/Services/AutoplayService.ts +59 -0
- package/src/Engine/Services/CharacterService.ts +291 -0
- package/src/Engine/Services/CombatService.ts +266 -0
- package/src/Engine/Services/CombinationService.ts +197 -0
- package/src/Engine/Services/CommandService.ts +197 -0
- package/src/Engine/Services/ConversationService.ts +406 -0
- package/src/Engine/Services/DataSerializer.ts +326 -0
- package/src/Engine/Services/DataService.ts +93 -0
- package/src/Engine/Services/DataSynchronizer.ts +216 -0
- package/src/Engine/Services/GameService.ts +554 -0
- package/src/Engine/Services/HelperService.ts +94 -0
- package/src/Engine/Services/ItemService.ts +294 -0
- package/src/Engine/Services/LocalStorageService.ts +24 -0
- package/src/Engine/Services/LocationService.ts +380 -0
- package/src/Engine/Services/SoundService.ts +54 -0
- package/src/Engine/Services/TradeService.ts +176 -0
- package/src/Engine/Services/index.ts +17 -0
- package/src/Engine/Services/serializationData.ts +8 -0
- package/src/Engine/Services/sharedFunctions.ts +296 -0
- package/src/Engine/arrayAndFunctionExtensions.ts +269 -0
- package/src/Engine/defaultTexts.ts +162 -0
- package/src/Engine/gameEvents.ts +51 -0
- package/src/Engine/index.ts +9 -0
- package/src/Engine/stateProperties.ts +9 -0
- package/src/Engine/utilityFunctions.ts +238 -0
- package/src/Games/_GameTemplate/character.ts +31 -0
- package/src/Games/_GameTemplate/customTexts.ts +8 -0
- package/src/Games/_GameTemplate/interfaces/action.ts +5 -0
- package/src/Games/_GameTemplate/interfaces/combatSetup.ts +7 -0
- package/src/Games/_GameTemplate/interfaces/combatTurn.ts +8 -0
- package/src/Games/_GameTemplate/interfaces/destination.ts +5 -0
- package/src/Games/_GameTemplate/interfaces/enemy.ts +11 -0
- package/src/Games/_GameTemplate/interfaces/equipment.ts +5 -0
- package/src/Games/_GameTemplate/interfaces/feature.ts +9 -0
- package/src/Games/_GameTemplate/interfaces/game.ts +22 -0
- package/src/Games/_GameTemplate/interfaces/interfaceTexts.ts +5 -0
- package/src/Games/_GameTemplate/interfaces/item.ts +18 -0
- package/src/Games/_GameTemplate/interfaces/key.ts +10 -0
- package/src/Games/_GameTemplate/interfaces/location.ts +22 -0
- package/src/Games/_GameTemplate/interfaces/map.ts +16 -0
- package/src/Games/_GameTemplate/interfaces/party.ts +8 -0
- package/src/Games/_GameTemplate/interfaces/person.ts +11 -0
- package/src/Games/_GameTemplate/interfaces/quest.ts +9 -0
- package/src/Games/_GameTemplate/locations/Start.html +5 -0
- package/src/Games/_GameTemplate/locations/start.ts +12 -0
- package/src/Games/_GameTemplate/rules.ts +60 -0
- package/src/Games/_GameTemplate/types.ts +55 -0
- package/src/Games/_GameTemplate/ui/styles/game.css +3 -0
- package/src/Games/_GameTemplate/webroot/favicon.ico +0 -0
- package/src/Games/_GameTemplate/webroot/gameinfo.json +10 -0
- package/src/Games/_GameTemplate/webroot/logo192.png +0 -0
- package/src/Games/_GameTemplate/webroot/logo512.png +0 -0
- package/src/Tests/Games/_GameTemplate/specs/rules.test.ts +9 -0
- package/src/UI/Components/AppShell.vue +43 -0
- package/src/UI/Components/Autoplay.vue +32 -0
- package/src/UI/Components/Combinations.vue +37 -0
- package/src/UI/Components/Common/Collapsible.vue +50 -0
- package/src/UI/Components/Common/ModalDialog.vue +54 -0
- package/src/UI/Components/Common/Sprite.vue +53 -0
- package/src/UI/Components/Description.vue +23 -0
- package/src/UI/Components/Encounter/Combat/Combat.vue +89 -0
- package/src/UI/Components/Encounter/Combat/CombatActions.vue +26 -0
- package/src/UI/Components/Encounter/Combat/CombatParticipant.vue +22 -0
- package/src/UI/Components/Encounter/Combat/CombatTargetSelect.vue +55 -0
- package/src/UI/Components/Encounter/Combat/CombatWin.vue +33 -0
- package/src/UI/Components/Encounter/Conversation.vue +66 -0
- package/src/UI/Components/Encounter/Encounter.vue +39 -0
- package/src/UI/Components/Encounter/Enemy.vue +30 -0
- package/src/UI/Components/Encounter/Trade/Stock.vue +58 -0
- package/src/UI/Components/Encounter/Trade/Trade.vue +24 -0
- package/src/UI/Components/Exploration/ActionLog.vue +17 -0
- package/src/UI/Components/Exploration/Destination.vue +66 -0
- package/src/UI/Components/Exploration/Exploration.vue +67 -0
- package/src/UI/Components/Exploration/Ground.vue +22 -0
- package/src/UI/Components/Exploration/LocationMap.vue +42 -0
- package/src/UI/Components/Exploration/LocationText.vue +39 -0
- package/src/UI/Components/Exploration/LocationVisual.vue +38 -0
- package/src/UI/Components/GameContainer.vue +49 -0
- package/src/UI/Components/GameMenu.vue +111 -0
- package/src/UI/Components/GameState/GameOver.vue +20 -0
- package/src/UI/Components/GameState/HighScores.vue +22 -0
- package/src/UI/Components/GameState/Intro.vue +17 -0
- package/src/UI/Components/GameState/TitleScreen.vue +42 -0
- package/src/UI/Components/GameState/Victory.vue +28 -0
- package/src/UI/Components/Navigation.vue +94 -0
- package/src/UI/Components/Party/Backpack.vue +68 -0
- package/src/UI/Components/Party/BuildCharacter.vue +64 -0
- package/src/UI/Components/Party/CharacterSheet.vue +57 -0
- package/src/UI/Components/Party/CreateCharacter.vue +46 -0
- package/src/UI/Components/Party/Equipment.vue +48 -0
- package/src/UI/Components/Party/EquipmentSlot.vue +31 -0
- package/src/UI/Components/Party/LevelUp.vue +27 -0
- package/src/UI/Components/Party/Party.vue +29 -0
- package/src/UI/Components/Party/Quests.vue +48 -0
- package/src/UI/Components/Sound.vue +42 -0
- package/src/UI/Composables/CustomCursor.ts +60 -0
- package/src/UI/Composables/LocationMap.ts +315 -0
- package/src/UI/Composables/Sound.ts +111 -0
- package/src/UI/Composables/TextFeatures.ts +148 -0
- package/src/UI/Composables/VisualFeatures.ts +220 -0
- package/src/UI/Composables/index.ts +15 -0
- package/src/UI/Composables/playStateWatch.ts +31 -0
- package/src/UI/StateStore.ts +237 -0
- package/src/UI/error.ts +6 -0
- package/src/UI/helpers.ts +62 -0
- package/src/UI/index.ts +13 -0
- package/src/UI/main.ts +62 -0
- package/src/UI/startup.ts +58 -0
- package/src/UI/styles/bootstrap-storyscript.scss +31 -0
- package/src/UI/styles/empty.css +3 -0
- package/src/UI/styles/lookinglass.png +0 -0
- package/src/UI/styles/storyscript.css +735 -0
- package/typeExtensions.d.ts +25 -0
- package/vite-env.d.ts +1 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EquipmentType,
|
|
3
|
+
ICharacter,
|
|
4
|
+
IEnemy,
|
|
5
|
+
IGame,
|
|
6
|
+
IGroupableItem,
|
|
7
|
+
IInterfaceTexts,
|
|
8
|
+
IItem,
|
|
9
|
+
IItemService,
|
|
10
|
+
IRules,
|
|
11
|
+
removeItemFromItemsAndEquipment
|
|
12
|
+
} from 'storyScript';
|
|
13
|
+
import {getEquipmentType} from "src/Engine/utilityFunctions";
|
|
14
|
+
|
|
15
|
+
export class ItemService implements IItemService {
|
|
16
|
+
|
|
17
|
+
constructor(private _game: IGame, private _rules: IRules, private _texts: IInterfaceTexts) {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getItemName = (item: IItem): string => {
|
|
21
|
+
if (!item) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (this._rules.general.getItemName) {
|
|
26
|
+
return this._rules.general.getItemName(item, this._texts);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const groupableItem = item as IGroupableItem<IItem>
|
|
30
|
+
|
|
31
|
+
if (!groupableItem.members?.length) {
|
|
32
|
+
return item.name;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return this._texts.format(groupableItem.groupName, [(groupableItem.members.length + 1).toString()]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pickupItem = (character: ICharacter, item: IItem): boolean => {
|
|
39
|
+
const isCombining = this._game.combinations?.activeCombination;
|
|
40
|
+
|
|
41
|
+
if (isCombining) {
|
|
42
|
+
this._game.combinations.tryCombine(item)
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (this._rules.character.beforePickup && !this._rules.character.beforePickup(this._game, character, item)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this._game.currentLocation.items.delete(item);
|
|
51
|
+
character.items.add(item);
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
canGroupItem = (character: ICharacter, group: IGroupableItem<IItem>, item: IGroupableItem<IItem>): boolean => {
|
|
57
|
+
if (!item || !item.isGroupable || item.members?.length) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (group) {
|
|
62
|
+
if (!group.isGroupable) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if ((group.members?.length ?? 0) >= group.maxSize - 1) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (group.id !== item.id && (!group.groupTypes || group.groupTypes.indexOf(item.id) === -1)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const anyGroupableItem = character.items.find(i => {
|
|
76
|
+
if (i === item) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const groupable = i as IGroupableItem<IItem>;
|
|
81
|
+
return groupable.isGroupable && (!groupable.maxSize || ((groupable.members?.length ?? 0) < groupable.maxSize - 1))
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (!anyGroupableItem) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this._rules.general.canGroupItem) {
|
|
89
|
+
return this._rules.general.canGroupItem(character, group, item);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return true;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
groupItem = (character: ICharacter, group: IGroupableItem<IItem>, item: IGroupableItem<IItem>): boolean => {
|
|
96
|
+
if (group && group !== item) {
|
|
97
|
+
group.members ??= [];
|
|
98
|
+
group.members.add(item);
|
|
99
|
+
character.items.delete(item);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
splitItemGroup = (character: ICharacter, item: IGroupableItem<IItem>): void => {
|
|
107
|
+
if (item?.members?.length > 0) {
|
|
108
|
+
item.members.forEach((item: IItem) => {
|
|
109
|
+
character.items.add(item);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
item.members = undefined;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
useItem = (character: ICharacter, item: IItem, target?: IEnemy): Promise<void> | void => {
|
|
117
|
+
const useItem = (this._rules.exploration?.onUseItem?.(this._game, character, item) && item.use) ?? item.use;
|
|
118
|
+
|
|
119
|
+
if (useItem) {
|
|
120
|
+
const promise = item.use(this._game, character, item, target);
|
|
121
|
+
|
|
122
|
+
return Promise.resolve(promise).then(() => {
|
|
123
|
+
if (item.charges !== undefined) {
|
|
124
|
+
if (!isNaN(item.charges)) {
|
|
125
|
+
item.charges--;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (item.charges <= 0) {
|
|
129
|
+
removeItemFromItemsAndEquipment(character, item);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
isEquippable = (item: IItem, character?: ICharacter): boolean => {
|
|
137
|
+
if (item.equipmentType === EquipmentType.Miscellaneous) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (this._rules.character.canEquip) {
|
|
142
|
+
return this._rules.character.canEquip(item, character);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return true;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
equipItem = (character: ICharacter, item: IItem): boolean => {
|
|
149
|
+
const equipmentTypes = Array.isArray(item.equipmentType) ? <EquipmentType[]>item.equipmentType : [<EquipmentType>item.equipmentType];
|
|
150
|
+
|
|
151
|
+
const slotsAvailable = this.makeSlotAvailable(character, item, equipmentTypes);
|
|
152
|
+
|
|
153
|
+
if (slotsAvailable.length === 0) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this._rules.character.beforeEquip) {
|
|
158
|
+
if (!this._rules.character.beforeEquip(this._game, character, item)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (item.equip) {
|
|
164
|
+
if (!item.equip(character, item, this._game)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for (const n in slotsAvailable) {
|
|
170
|
+
character.equipment[slotsAvailable[n]] = item;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
character.items.splice(character.items.indexOf(item), 1);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
unequipItem = (character: ICharacter, item: IItem): boolean => {
|
|
178
|
+
return this.unequip(character, item);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
canDrop = (item: IItem): boolean => {
|
|
182
|
+
let canDrop: boolean;
|
|
183
|
+
|
|
184
|
+
if (typeof item.canDrop === 'function') {
|
|
185
|
+
canDrop = item.canDrop(this._game, item);
|
|
186
|
+
} else if (item.canDrop === undefined) {
|
|
187
|
+
canDrop = true;
|
|
188
|
+
} else {
|
|
189
|
+
canDrop = item.canDrop;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return canDrop
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
dropItem = (character: ICharacter, item: IItem): void => {
|
|
196
|
+
if (!item) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let drop = true;
|
|
201
|
+
|
|
202
|
+
if (this._rules.character.beforeDrop) {
|
|
203
|
+
drop = this._rules.character.beforeDrop(this._game, character, item);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (drop) {
|
|
207
|
+
character.items.delete(item);
|
|
208
|
+
this._game.currentLocation.items.add(item);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private makeSlotAvailable(character: ICharacter, item: IItem, equipmentTypes: EquipmentType[]): string[] {
|
|
213
|
+
if (!item.usesMultipleSlots) {
|
|
214
|
+
return this.findAvailableSlot(character, equipmentTypes);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const availableSlots: string[] = [];
|
|
218
|
+
|
|
219
|
+
for (const n in equipmentTypes) {
|
|
220
|
+
const type = getEquipmentType(equipmentTypes[n]);
|
|
221
|
+
const slotItem = character.equipment[type];
|
|
222
|
+
|
|
223
|
+
if (slotItem) {
|
|
224
|
+
const unequipped = this.unequip(character, slotItem);
|
|
225
|
+
|
|
226
|
+
if (!unequipped) {
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
availableSlots.push(type);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return availableSlots;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private findAvailableSlot(character: ICharacter, equipmentTypes: EquipmentType[]) {
|
|
238
|
+
// If the item uses only one of the slots specified, see if a slot is available first.
|
|
239
|
+
const occupiedSlots: string[] = [];
|
|
240
|
+
const emptySlots: string[] = [];
|
|
241
|
+
|
|
242
|
+
for (const n in equipmentTypes) {
|
|
243
|
+
const type = getEquipmentType(equipmentTypes[n]);
|
|
244
|
+
|
|
245
|
+
if (character.equipment[type]) {
|
|
246
|
+
occupiedSlots.push(type);
|
|
247
|
+
} else {
|
|
248
|
+
emptySlots.push(type);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (emptySlots.length === 0) {
|
|
253
|
+
const slotToUnequip = occupiedSlots[occupiedSlots.length - 1];
|
|
254
|
+
const unequipped = this.unequip(character, character.equipment[slotToUnequip]);
|
|
255
|
+
return !unequipped ? [] : [slotToUnequip];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return [emptySlots[0]];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private unequip = (character: ICharacter, equippedItem: IItem): boolean => {
|
|
262
|
+
if (!equippedItem) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this._rules.character.beforeUnequip) {
|
|
267
|
+
if (!this._rules.character.beforeUnequip(this._game, character, equippedItem)) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (equippedItem.unequip) {
|
|
273
|
+
if (!equippedItem.unequip(character, equippedItem, this._game)) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (equippedItem?.equipmentType && character.items.indexOf(equippedItem) < 0) {
|
|
279
|
+
character.items.push(equippedItem);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const slotsToUnEquip = Array.isArray(equippedItem.equipmentType)
|
|
283
|
+
? equippedItem.equipmentType
|
|
284
|
+
: [equippedItem.equipmentType];
|
|
285
|
+
|
|
286
|
+
slotsToUnEquip.forEach(t => {
|
|
287
|
+
const itemType = getEquipmentType(t);
|
|
288
|
+
const slotItem = character.equipment[itemType];
|
|
289
|
+
character.equipment[itemType] = slotItem === equippedItem ? null : slotItem;
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {ILocalStorageService} from 'storyScript';
|
|
2
|
+
|
|
3
|
+
const StoryScriptPrefix: string = 'StoryScript_';
|
|
4
|
+
|
|
5
|
+
export class LocalStorageService implements ILocalStorageService {
|
|
6
|
+
get = (key: string): any => localStorage.getItem(StoryScriptPrefix + key);
|
|
7
|
+
|
|
8
|
+
set = (key: string, value: any): void => localStorage.setItem(StoryScriptPrefix + key, value);
|
|
9
|
+
|
|
10
|
+
remove = (key: string): void => localStorage.removeItem(StoryScriptPrefix + key);
|
|
11
|
+
|
|
12
|
+
getKeys = (prefix: string): string[] => {
|
|
13
|
+
const result = [];
|
|
14
|
+
prefix = StoryScriptPrefix + prefix;
|
|
15
|
+
|
|
16
|
+
Object.keys(localStorage).forEach(k => {
|
|
17
|
+
if (k.startsWith(prefix)) {
|
|
18
|
+
result.push(k.replace(prefix, ''));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActionType,
|
|
3
|
+
gameEvents,
|
|
4
|
+
IAction,
|
|
5
|
+
ICompiledLocation,
|
|
6
|
+
IDefinitions,
|
|
7
|
+
IDestination,
|
|
8
|
+
IGame,
|
|
9
|
+
IGameEvents,
|
|
10
|
+
IKey,
|
|
11
|
+
ILocation,
|
|
12
|
+
ILocationService,
|
|
13
|
+
IRules,
|
|
14
|
+
parseGamePropertiesInTemplate
|
|
15
|
+
} from 'storyScript';
|
|
16
|
+
import {addHtmlSpaces, getId, parseHtmlDocumentFromString} from 'src/Engine/utilityFunctions';
|
|
17
|
+
import {getBasicFeatureData, setDestination} from "src/Engine/EntityCreatorFunctions";
|
|
18
|
+
|
|
19
|
+
export class LocationService implements ILocationService {
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly _definitions: IDefinitions,
|
|
22
|
+
private readonly _rules: IRules,
|
|
23
|
+
private readonly _game: IGame,
|
|
24
|
+
private readonly _gameEvents: IGameEvents,
|
|
25
|
+
) {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
init = (): void => {
|
|
29
|
+
this._game.currentLocation = null;
|
|
30
|
+
this._game.previousLocation = null;
|
|
31
|
+
|
|
32
|
+
if (!this._game.locations) {
|
|
33
|
+
// When we don't have any locations yet, we're starting a new game. Use the definitions to build
|
|
34
|
+
// all the locations. Also build the maps, if present.
|
|
35
|
+
this._game.locations = {};
|
|
36
|
+
this._definitions.locations.forEach(l => this._game.locations[getId(l)] = <ICompiledLocation>l());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!this._game.maps && this._definitions.maps) {
|
|
40
|
+
this._game.maps = {};
|
|
41
|
+
// When we have no maps, it could be that maps were added later and that they are not in the saved
|
|
42
|
+
// data yet. Add the maps available now.
|
|
43
|
+
this._definitions.maps?.forEach(m => this._game.maps[getId(m)] = m());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.setupLocations();
|
|
47
|
+
|
|
48
|
+
this._gameEvents.subscribe(['add-character-items', 'delete-character-items', 'add-location-items'], (game: IGame, _) => {
|
|
49
|
+
game.currentLocation?.destinations.forEach(d => {
|
|
50
|
+
this.addKeyAction(game, d);
|
|
51
|
+
})
|
|
52
|
+
}, false);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
changeLocation = (location: string | (() => ILocation), travel: boolean, game: IGame): void => {
|
|
56
|
+
// Clear the play state on travel.
|
|
57
|
+
game.playState = null;
|
|
58
|
+
this._rules.exploration?.leaveLocation?.(game, game.currentLocation, getId(location), travel);
|
|
59
|
+
this.playEvents(game, 'leaveEvents');
|
|
60
|
+
|
|
61
|
+
// If there is no location, we are starting a new game. We're done here.
|
|
62
|
+
if (!this.switchLocation(game, location)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.processDestinations(game);
|
|
67
|
+
this._game.party.currentLocationId = game.currentLocation.id;
|
|
68
|
+
this._game.party.previousLocationId = game.previousLocation?.id;
|
|
69
|
+
this._rules.exploration?.enterLocation?.(game, game.currentLocation, game.previousLocation?.id, travel);
|
|
70
|
+
this.loadLocationDescriptions(game);
|
|
71
|
+
this.initTrade(game);
|
|
72
|
+
this.playEvents(game, 'enterEvents');
|
|
73
|
+
this.markCurrentLocationAsVisited(game);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
executeAction = (action: [string, IAction]): void => {
|
|
77
|
+
const execute = action[1]?.execute;
|
|
78
|
+
|
|
79
|
+
if (execute) {
|
|
80
|
+
let result = true;
|
|
81
|
+
|
|
82
|
+
if (typeof execute === 'function') {
|
|
83
|
+
const actionResult = execute(this._game);
|
|
84
|
+
result = actionResult === true;
|
|
85
|
+
} else {
|
|
86
|
+
gameEvents.publish(execute, action);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const typeAndIndex = this.getActionIndex(this._game, action);
|
|
90
|
+
|
|
91
|
+
if (!result && typeAndIndex.index !== -1) {
|
|
92
|
+
if (typeAndIndex.type === ActionType.Regular && this._game.currentLocation.actions) {
|
|
93
|
+
const currentAction = this._game.currentLocation.actions[typeAndIndex.index];
|
|
94
|
+
this._game.currentLocation.actions.delete(currentAction);
|
|
95
|
+
} else if (typeAndIndex.type === ActionType.Combat && this._game.currentLocation.combatActions) {
|
|
96
|
+
const currentCombatAction = this._game.currentLocation.combatActions[typeAndIndex.index];
|
|
97
|
+
this._game.currentLocation.combatActions.delete(currentCombatAction);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
loadLocationDescriptions = (game: IGame): void => {
|
|
104
|
+
if (this.selectLocationDescription(game)) {
|
|
105
|
+
parseGamePropertiesInTemplate(game.currentLocation.description, this._game);
|
|
106
|
+
this.processTextFeatures(game.currentLocation);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
initDestinations = (location: ICompiledLocation): void => {
|
|
111
|
+
// Add a proxy to the destination collection add and delete functions, to replace the target function pointers
|
|
112
|
+
// with the target id when adding or deleting destinations at runtime.
|
|
113
|
+
location.destinations.add = location.destinations.add.proxy(this.addDestination, this._game);
|
|
114
|
+
|
|
115
|
+
Object.defineProperty(location, 'activeDestinations', {
|
|
116
|
+
get: function () {
|
|
117
|
+
return location.destinations.filter(e => {
|
|
118
|
+
return !e.inactive;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
processDestinations = (game: IGame) => {
|
|
125
|
+
if (game.previousLocation?.destinations.length) {
|
|
126
|
+
// Remove the isPreviousLocation and visited markers from the previous location's destinations.
|
|
127
|
+
game.previousLocation.destinations.forEach((d: any) => {
|
|
128
|
+
delete d.isPreviousLocation;
|
|
129
|
+
delete d.visited;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (game.currentLocation.destinations.length) {
|
|
134
|
+
// 1. Mark the previous location in the current location's destinations to allow
|
|
135
|
+
// the player to more easily backtrack his last step.
|
|
136
|
+
// 2. Mark the destination as visited when the player has already visited the location it leads to.
|
|
137
|
+
// 3. Check if the user has the key for one or more barriers at this location, and add the key actions
|
|
138
|
+
// if that is the case.
|
|
139
|
+
game.currentLocation.destinations.forEach((d: any) => {
|
|
140
|
+
if (d.target == game.previousLocation?.id) {
|
|
141
|
+
d.isPreviousLocation = true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const targetLocation = game.locations[d.target];
|
|
145
|
+
const visitedRule = this._rules.exploration?.hasVisitedLocation;
|
|
146
|
+
|
|
147
|
+
if (targetLocation && visitedRule) {
|
|
148
|
+
d.visited = visitedRule(game, targetLocation);
|
|
149
|
+
} else {
|
|
150
|
+
d.visited = targetLocation?.hasVisited;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.addKeyAction(game, d);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private readonly setupLocations = () => {
|
|
159
|
+
Object.values(this._game.locations).forEach(l => {
|
|
160
|
+
const compiledLocation = <ICompiledLocation>l;
|
|
161
|
+
this.initDestinations(compiledLocation);
|
|
162
|
+
let selector = compiledLocation.descriptionSelector;
|
|
163
|
+
|
|
164
|
+
Object.defineProperty(compiledLocation, 'descriptionSelector', {
|
|
165
|
+
enumerable: true,
|
|
166
|
+
get: () => selector,
|
|
167
|
+
set: (value) => {
|
|
168
|
+
selector = value;
|
|
169
|
+
this.selectLocationDescription(this._game);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
this.addLocationGet(this._game.locations);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private readonly addLocationGet = (locations: Record<string, ICompiledLocation>) => {
|
|
178
|
+
Object.defineProperty(locations, 'get', {
|
|
179
|
+
enumerable: false,
|
|
180
|
+
value: function (id?: string | (() => ILocation) | ICompiledLocation): ICompiledLocation {
|
|
181
|
+
if (!id) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (typeof id === 'string') {
|
|
186
|
+
return locations[id.toLowerCase()];
|
|
187
|
+
} else if (typeof id === 'function') {
|
|
188
|
+
return locations[id.name.toLowerCase()];
|
|
189
|
+
} else {
|
|
190
|
+
return locations[id.id]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private readonly switchLocation = (game: IGame, location: string | (() => ILocation)): boolean => {
|
|
197
|
+
let presentLocation: ICompiledLocation;
|
|
198
|
+
|
|
199
|
+
// If no location is specified, go to the previous location.
|
|
200
|
+
if (!location) {
|
|
201
|
+
const tempLocation = game.currentLocation;
|
|
202
|
+
game.currentLocation = game.previousLocation;
|
|
203
|
+
game.previousLocation = tempLocation;
|
|
204
|
+
presentLocation = game.currentLocation;
|
|
205
|
+
}
|
|
206
|
+
// If currently at a location, make this the previous location.
|
|
207
|
+
else if (game.currentLocation) {
|
|
208
|
+
game.previousLocation = game.currentLocation;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!location && !presentLocation) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const key = getId(location) ?? presentLocation.id;
|
|
216
|
+
game.currentLocation = game.locations.get(key);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private readonly markCurrentLocationAsVisited = (game: IGame): void => {
|
|
221
|
+
if (!game.currentLocation.hasVisited) {
|
|
222
|
+
game.currentLocation.hasVisited = true;
|
|
223
|
+
game.statistics.LocationsVisited = game.statistics.LocationsVisited || 0;
|
|
224
|
+
game.statistics.LocationsVisited += 1;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private readonly initTrade = (game: IGame): void => {
|
|
229
|
+
if (game.currentLocation.trade?.length > 0) {
|
|
230
|
+
game.currentLocation.trade.forEach(t => {
|
|
231
|
+
if (!game.currentLocation.actions.find(([k, v]) => v.actionType === ActionType.Trade && k === t.id)) {
|
|
232
|
+
game.currentLocation.actions.add([t.id, {
|
|
233
|
+
text: t.name,
|
|
234
|
+
actionType: ActionType.Trade,
|
|
235
|
+
execute: 'trade'
|
|
236
|
+
}]);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private readonly addDestination = (originalScope: any, originalFunction: Function, destination: IDestination, game: IGame): void => {
|
|
243
|
+
setDestination(destination);
|
|
244
|
+
this.addKeyAction(game, destination);
|
|
245
|
+
originalFunction.call(originalScope, destination);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private readonly playEvents = (game: IGame, eventProperty: string): void => {
|
|
249
|
+
if (!game.currentLocation?.[eventProperty]) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Keep a reference to the location being processed. When the location is changed in the
|
|
254
|
+
// event, we want to still update the events in the originating location.
|
|
255
|
+
const location = game.currentLocation;
|
|
256
|
+
const events = [...location[eventProperty]];
|
|
257
|
+
|
|
258
|
+
events.forEach(e => {
|
|
259
|
+
const result = e[1]?.(game);
|
|
260
|
+
|
|
261
|
+
if (!result) {
|
|
262
|
+
location[eventProperty].delete(e);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private readonly processTextFeatures = (location: ICompiledLocation): void => {
|
|
268
|
+
if (!location.description) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const htmlDoc = parseHtmlDocumentFromString(location.description);
|
|
273
|
+
const featureNodes = <HTMLCollectionOf<HTMLElement>>htmlDoc.getElementsByTagName('feature');
|
|
274
|
+
|
|
275
|
+
for (const element of featureNodes) {
|
|
276
|
+
const feature = getBasicFeatureData(location, element);
|
|
277
|
+
|
|
278
|
+
// If the feature is not present in code, clean the node html as the feature is either
|
|
279
|
+
// not yet added (the feature tag is a placeholder for a feature added at runtime) or it
|
|
280
|
+
// was deleted. Clean the node html to not show the feature text in case it was deleted.
|
|
281
|
+
if (!feature) {
|
|
282
|
+
element.innerHTML = '';
|
|
283
|
+
} else {
|
|
284
|
+
feature.description = element.innerHTML || feature.description;
|
|
285
|
+
element.innerHTML = addHtmlSpaces(feature.description);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
location.description = htmlDoc.body.innerHTML;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
private readonly selectLocationDescription = (game: IGame): boolean => {
|
|
294
|
+
let selector = null;
|
|
295
|
+
|
|
296
|
+
if (!game.currentLocation.descriptions) {
|
|
297
|
+
game.currentLocation.description = null;
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let description: string;
|
|
302
|
+
const defaultDescription = game.currentLocation.descriptions['default'] || game.currentLocation.descriptions[Object.keys(game.currentLocation.descriptions)[0]];
|
|
303
|
+
|
|
304
|
+
// A location can specify how to select the proper selection using a descriptor selection function. If it is not specified,
|
|
305
|
+
// use the default description selector function.
|
|
306
|
+
if (game.currentLocation.descriptionSelector) {
|
|
307
|
+
selector = typeof game.currentLocation.descriptionSelector == 'function' ? game.currentLocation.descriptionSelector(game) : game.currentLocation.descriptionSelector;
|
|
308
|
+
description = game.currentLocation.descriptions[selector];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!description && this._rules.exploration?.descriptionSelector && (selector = this._rules.exploration.descriptionSelector(game))) {
|
|
312
|
+
description = game.currentLocation.descriptions[selector];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
description ??= defaultDescription;
|
|
316
|
+
game.currentLocation.description = description;
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private readonly addKeyAction = (game: IGame, destination: IDestination) => {
|
|
321
|
+
destination.barriers?.forEach(([_, b]) => {
|
|
322
|
+
if (b.key) {
|
|
323
|
+
const key = typeof b.key === 'function' ?
|
|
324
|
+
b.key()
|
|
325
|
+
: <IKey>this._definitions.items.get(b.key)();
|
|
326
|
+
|
|
327
|
+
let existingAction = null;
|
|
328
|
+
|
|
329
|
+
if (b.actions) {
|
|
330
|
+
b.actions.forEach(([k, v]) => {
|
|
331
|
+
if (k === key.id) {
|
|
332
|
+
existingAction = v;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
} else {
|
|
336
|
+
b.actions = [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (existingAction) {
|
|
340
|
+
b.actions.splice(b.actions.indexOf(existingAction), 1);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
let partyKey = null;
|
|
344
|
+
|
|
345
|
+
game.party.characters.forEach(c => {
|
|
346
|
+
partyKey = partyKey ?? c.items.get(key.id);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const barrierKey = <IKey>(partyKey || game.currentLocation.items.get(key.id));
|
|
350
|
+
|
|
351
|
+
if (barrierKey) {
|
|
352
|
+
b.actions.push([barrierKey.id, barrierKey.open]);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private getActionIndex = (game: IGame, action: [string, IAction]): { type: ActionType, index: number } => {
|
|
359
|
+
let index = -1;
|
|
360
|
+
let type = ActionType.Regular;
|
|
361
|
+
|
|
362
|
+
game.currentLocation.actions.forEach(([k, v], i) => {
|
|
363
|
+
if (k === action[0]) {
|
|
364
|
+
index = i;
|
|
365
|
+
type = ActionType.Regular;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
if (index == -1) {
|
|
370
|
+
game.currentLocation.combatActions.forEach(([k, v], i) => {
|
|
371
|
+
if (k === action[0]) {
|
|
372
|
+
index = i;
|
|
373
|
+
type = ActionType.Combat;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return {type, index};
|
|
379
|
+
}
|
|
380
|
+
}
|