@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,266 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GameState,
|
|
3
|
+
ICharacter,
|
|
4
|
+
ICombatService,
|
|
5
|
+
ICombatSetup,
|
|
6
|
+
ICombatTurn,
|
|
7
|
+
IEnemy,
|
|
8
|
+
IGame,
|
|
9
|
+
IInterfaceTexts,
|
|
10
|
+
IItem,
|
|
11
|
+
IRules,
|
|
12
|
+
PlayState,
|
|
13
|
+
TargetType,
|
|
14
|
+
} from 'storyScript';
|
|
15
|
+
import {StateProperties} from "src/Engine/stateProperties";
|
|
16
|
+
import {addUniqueId} from "src/Engine/arrayAndFunctionExtensions";
|
|
17
|
+
|
|
18
|
+
export class CombatService implements ICombatService {
|
|
19
|
+
constructor(private readonly _game: IGame, private readonly _rules: IRules, private readonly _texts: IInterfaceTexts) {
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
initCombat = (): void => {
|
|
23
|
+
this._game.combatLog.length = 0;
|
|
24
|
+
this._rules.combat?.initCombat?.(this._game, this._game.currentLocation);
|
|
25
|
+
this.initCombatRound(true);
|
|
26
|
+
this._game.playState = PlayState.Combat;
|
|
27
|
+
this._game.combat.enemies.forEach(enemy => enemy.onAttack?.(this._game, enemy));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fight = (combat: ICombatSetup<ICombatTurn>, retaliate?: boolean): Promise<void> | void => {
|
|
31
|
+
if (!this._rules.combat?.fight) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const promise = this._rules.combat.fight(this._game, combat, retaliate);
|
|
36
|
+
|
|
37
|
+
return Promise.resolve(promise).then(() => {
|
|
38
|
+
combat.forEach((s, i) => {
|
|
39
|
+
const defeated = (s.item?.targetType === TargetType.Enemy || (<any>s.target)?.type === TargetType.Enemy.toLowerCase())
|
|
40
|
+
&& s.target?.currentHitpoints <= 0
|
|
41
|
+
&& (s.targetDefeated === undefined || s.targetDefeated);
|
|
42
|
+
|
|
43
|
+
if (defeated) {
|
|
44
|
+
this.enemyDefeated(combat, this._game.party.characters[i], s.target);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (this._game.party.characters.filter(c => c.currentHitpoints > 0).length == 0) {
|
|
49
|
+
this._game.playState = null;
|
|
50
|
+
this._game.state = GameState.GameOver;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (combat.enemies.filter(c => c.currentHitpoints >= 0).length == 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.initCombatRound(false);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isSelectable = (item: IItem): boolean => item?.selectable || item?.selectable === undefined;
|
|
62
|
+
|
|
63
|
+
canTarget = (item: IItem, target: IEnemy | ICharacter, character: ICharacter) => {
|
|
64
|
+
const type = (<any>target).type;
|
|
65
|
+
let canTarget = false;
|
|
66
|
+
|
|
67
|
+
if (type === 'enemy') {
|
|
68
|
+
canTarget = item.targetType === TargetType.Enemy;
|
|
69
|
+
} else {
|
|
70
|
+
switch (item.targetType) {
|
|
71
|
+
case TargetType.Ally:
|
|
72
|
+
canTarget = target !== character;
|
|
73
|
+
break;
|
|
74
|
+
case TargetType.Self:
|
|
75
|
+
canTarget = target === character;
|
|
76
|
+
break;
|
|
77
|
+
case TargetType.AllyOrSelf:
|
|
78
|
+
canTarget = true;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!canTarget || !item.canTarget) {
|
|
84
|
+
return canTarget;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return item.canTarget(this._game, item, target);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private readonly initCombatRound = (newFight: boolean) => {
|
|
91
|
+
this._game.combat = newFight ? <ICombatSetup<ICombatTurn>>[] : this._game.combat;
|
|
92
|
+
|
|
93
|
+
if (!this._game.combat.enemies) {
|
|
94
|
+
this._game.combat.enemies = [];
|
|
95
|
+
|
|
96
|
+
const enemiesPerType = <Record<string, number[]>>{};
|
|
97
|
+
const activeEnemies = this._game.currentLocation.enemies.filter(e => !e.inactive);
|
|
98
|
+
|
|
99
|
+
activeEnemies.forEach((e: any, i) => {
|
|
100
|
+
enemiesPerType[e.id] ??= [];
|
|
101
|
+
e.index = enemiesPerType[e.id].length + 1;
|
|
102
|
+
enemiesPerType[e.id].push(i);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
activeEnemies.forEach(e => {
|
|
106
|
+
// Add a unique id here so we can track multiple enemies of the same type.
|
|
107
|
+
// Combat will end only when the enemies are defeated, at which point they will
|
|
108
|
+
// be assigned a unique id anyway.
|
|
109
|
+
addUniqueId(e);
|
|
110
|
+
const name = this.getTargetName(enemiesPerType, e);
|
|
111
|
+
const copy = {...e};
|
|
112
|
+
copy.name = name;
|
|
113
|
+
copy.currentHitpoints = copy.hitpoints;
|
|
114
|
+
this._game.combat.enemies.push(copy);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this._game.combat.round = newFight ? 1 : ++this._game.combat.round;
|
|
119
|
+
this._game.combat.roundHeader = this._texts.format(this._texts.combatRound, [this._game.combat.round.toString()]);
|
|
120
|
+
this._game.combat.noActionText = this._texts.noCombatAction;
|
|
121
|
+
const enemies = this._game.combat.enemies = this._game.combat.enemies.filter(e => e.currentHitpoints > 0);
|
|
122
|
+
const characters = this._game.combat.characters = this._game.party.characters;
|
|
123
|
+
|
|
124
|
+
characters.forEach((c, i) => {
|
|
125
|
+
const allies = characters.filter(a => a != c);
|
|
126
|
+
const items = this.getItems(c, enemies, allies);
|
|
127
|
+
|
|
128
|
+
// Remember the last item used and enemy attacked and select them when they are still valid.
|
|
129
|
+
let previousItem = this._game.combat[i]?.item;
|
|
130
|
+
previousItem = this.isSelectable(previousItem) ? previousItem : undefined;
|
|
131
|
+
const previousTarget = this._game.combat[i]?.target;
|
|
132
|
+
let newItem = (previousItem && items.find(i => i === previousItem)) ?? items.filter(i => this.isSelectable(i))[0];
|
|
133
|
+
let {targets, newTarget} = this.getTarget(newItem, enemies, allies, previousTarget, previousItem);
|
|
134
|
+
|
|
135
|
+
if (!newTarget) {
|
|
136
|
+
newItem = items.filter(i => this.isSelectable(i) && (!i.canTarget || (newTarget && i.canTarget(this._game, newItem, newTarget))))[0];
|
|
137
|
+
({
|
|
138
|
+
targets,
|
|
139
|
+
newTarget
|
|
140
|
+
} = this.getTarget(newItem, enemies, allies, this._game.combat[i]?.target, previousItem));
|
|
141
|
+
newTarget ??= targets[0];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this._game.combat[i] = <ICombatTurn>{
|
|
145
|
+
character: c,
|
|
146
|
+
targetsAvailable: enemies.concat(allies),
|
|
147
|
+
previousTarget: previousTarget,
|
|
148
|
+
target: newTarget,
|
|
149
|
+
itemsAvailable: items,
|
|
150
|
+
previousItem: previousItem,
|
|
151
|
+
item: newItem
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
this._rules.combat?.initCombatRound?.(this._game, this._game.combat);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private readonly getItems = (character: ICharacter, enemies: IEnemy[], allies: ICharacter[]) => {
|
|
159
|
+
const items = character.combatItems ?? [];
|
|
160
|
+
|
|
161
|
+
Object.keys(character.equipment).forEach(k => {
|
|
162
|
+
const item = <IItem>character.equipment[k];
|
|
163
|
+
|
|
164
|
+
if ((item?.useInCombat || item?.targetType) && items.indexOf(item) === -1) {
|
|
165
|
+
items.push(item)
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
items.forEach(i => {
|
|
170
|
+
if (this._rules.combat.itemIsSelectable) {
|
|
171
|
+
i.selectable = this._rules.combat.itemIsSelectable(this._game, i);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!i.canTarget) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
i.selectable = false;
|
|
179
|
+
let targets;
|
|
180
|
+
|
|
181
|
+
switch (i.targetType) {
|
|
182
|
+
case TargetType.Enemy: {
|
|
183
|
+
targets = enemies;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case TargetType.Ally: {
|
|
187
|
+
targets = allies;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case TargetType.AllyOrSelf: {
|
|
191
|
+
targets = allies.concat([character]);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case TargetType.Self: {
|
|
195
|
+
targets = [character];
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (let x = 0; x < targets.length; x++) {
|
|
201
|
+
const target = targets[x];
|
|
202
|
+
if (i.canTarget(this._game, i, target)) {
|
|
203
|
+
i.selectable = true;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
items.sort((a: IItem, b: IItem) => b.targetType?.localeCompare(a.targetType) || a.name.localeCompare(b.name));
|
|
210
|
+
return items;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private readonly getTarget =
|
|
214
|
+
(newItem: IItem, enemies: IEnemy[], allies: ICharacter[], previousTarget: IEnemy | ICharacter, previousItem?: IItem):
|
|
215
|
+
{ targets: IEnemy[] | ICharacter[], newTarget?: IEnemy | ICharacter } => {
|
|
216
|
+
let targetType = newItem?.targetType ?? TargetType.Enemy;
|
|
217
|
+
let targets = targetType === TargetType.Enemy ? enemies : allies;
|
|
218
|
+
let newTarget = newItem === previousItem && previousTarget ?
|
|
219
|
+
targets.find(i => i === previousTarget && (!newItem?.canTarget || newItem.canTarget(this._game, newItem, i)))
|
|
220
|
+
: undefined;
|
|
221
|
+
return {targets, newTarget};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private readonly getTargetName = (enemiesPerType: Record<string, number[]>, target: any): string => {
|
|
225
|
+
const ofSameType = enemiesPerType[target.id];
|
|
226
|
+
|
|
227
|
+
if (ofSameType.length === 1) {
|
|
228
|
+
return target.name;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return this._texts.format(this._texts.enemyCombatName, [target.name, target.index.toString()]);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private readonly enemyDefeated = (combat: ICombatSetup<ICombatTurn>, character: ICharacter, enemy: IEnemy): void => {
|
|
235
|
+
combat.winnings ??= {
|
|
236
|
+
currency: 0,
|
|
237
|
+
itemsWon: [],
|
|
238
|
+
enemiesDefeated: []
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
if (enemy.items) {
|
|
242
|
+
const items = [...enemy.items];
|
|
243
|
+
|
|
244
|
+
items.forEach((item: IItem) => {
|
|
245
|
+
if (!this._rules.combat?.beforeDrop || this._rules.combat.beforeDrop(this._game, character, enemy, item)) {
|
|
246
|
+
enemy.items.delete(item);
|
|
247
|
+
this._game.currentLocation.items.add(item);
|
|
248
|
+
combat.winnings.itemsWon.push(item);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (enemy.currency) {
|
|
254
|
+
this._game.party.currency ??= 0;
|
|
255
|
+
this._game.party.currency += enemy.currency || 0;
|
|
256
|
+
combat.winnings.currency += enemy.currency || 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this._game.statistics.enemiesDefeated ??= 0;
|
|
260
|
+
this._game.statistics.enemiesDefeated += 1;
|
|
261
|
+
combat.winnings.enemiesDefeated.push(enemy);
|
|
262
|
+
this._game.currentLocation.enemies.delete(enemy[StateProperties.Id]);
|
|
263
|
+
this._rules.combat?.enemyDefeated?.(this._game, character, enemy);
|
|
264
|
+
enemy.onDefeat?.(this._game, enemy);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IActiveCombination,
|
|
3
|
+
ICombinable,
|
|
4
|
+
ICombinationAction,
|
|
5
|
+
ICombinationService,
|
|
6
|
+
ICombineResult,
|
|
7
|
+
IEnemy,
|
|
8
|
+
IFeature,
|
|
9
|
+
IGame,
|
|
10
|
+
IInterfaceTexts,
|
|
11
|
+
IItem,
|
|
12
|
+
IPerson,
|
|
13
|
+
IRules,
|
|
14
|
+
removeItemFromParty
|
|
15
|
+
} from 'storyScript';
|
|
16
|
+
import {compareString, getId} from 'src/Engine/utilityFunctions';
|
|
17
|
+
|
|
18
|
+
export class CombinationService implements ICombinationService {
|
|
19
|
+
|
|
20
|
+
private readonly _combinationActions: ICombinationAction[] = [];
|
|
21
|
+
|
|
22
|
+
constructor(private readonly _game: IGame, private readonly _rules: IRules, private readonly _texts: IInterfaceTexts) {
|
|
23
|
+
this._combinationActions = this._rules.combinations?.combinationActions ?? [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get combinationActions(): ICombinationAction[] {
|
|
27
|
+
return this._combinationActions;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getCombineClass = (tool: ICombinable): string => {
|
|
31
|
+
let className: string;
|
|
32
|
+
|
|
33
|
+
if (tool) {
|
|
34
|
+
className = this._game.combinations.activeCombination ?
|
|
35
|
+
this._game.combinations.activeCombination.selectedTool && this._game.combinations.activeCombination.selectedTool.id === tool.id ?
|
|
36
|
+
'combine-active-selected'
|
|
37
|
+
: 'combine-selectable' : '';
|
|
38
|
+
} else {
|
|
39
|
+
className = this._game.combinations.activeCombination ? 'combine-active-hide' : '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return className;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setActiveCombination = (combination: ICombinationAction): void => {
|
|
46
|
+
this._game.combinations.combinationResult.reset();
|
|
47
|
+
|
|
48
|
+
if (!combination) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this._game.combinations.activeCombination && this._game.combinations.activeCombination.selectedCombinationAction === combination) {
|
|
53
|
+
this._game.combinations.activeCombination = null;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
combination.requiresTool = (combination.requiresTool === undefined) || combination.requiresTool === true;
|
|
58
|
+
|
|
59
|
+
this._game.combinations.activeCombination = {
|
|
60
|
+
selectedCombinationAction: combination,
|
|
61
|
+
selectedTool: null
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this._game.combinations.combinationResult.text = combination.requiresTool ? combination.text : combination.text + ' ' + (combination.preposition || '');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
tryCombination = (target: ICombinable): ICombineResult => {
|
|
68
|
+
let combo = this._game.combinations.activeCombination;
|
|
69
|
+
let result = <ICombineResult>{
|
|
70
|
+
success: false,
|
|
71
|
+
text: ''
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (!target || (target as IFeature).interactive === false) {
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!combo) {
|
|
79
|
+
const defaultAction = this.combinationActions.filter(c => c.isDefault)[0];
|
|
80
|
+
|
|
81
|
+
if (defaultAction) {
|
|
82
|
+
combo = {
|
|
83
|
+
selectedCombinationAction: defaultAction,
|
|
84
|
+
selectedTool: null
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!combo?.selectedCombinationAction) {
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
combo.selectedCombinationAction.preposition = combo.selectedCombinationAction.preposition || '';
|
|
94
|
+
|
|
95
|
+
if (combo.selectedCombinationAction.requiresTool && !combo.selectedTool) {
|
|
96
|
+
this._game.combinations.combinationResult.text = combo.selectedCombinationAction.text + ' ' + target.name + ' ' + combo.selectedCombinationAction.preposition;
|
|
97
|
+
combo.selectedTool = target;
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
result = this.performCombination(target, combo);
|
|
102
|
+
|
|
103
|
+
if (result.success) {
|
|
104
|
+
this._rules.combinations?.success?.(this._game, combo, target);
|
|
105
|
+
|
|
106
|
+
if (result.removeTarget) {
|
|
107
|
+
this.removeFeature(target);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (result.removeTool && combo.selectedTool.id != target.id) {
|
|
111
|
+
this.removeFeature(combo.selectedTool);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this._game.combinations.combinationResult.text = result.text;
|
|
116
|
+
this._game.combinations.combinationResult.done = true;
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private readonly performCombination = (target: ICombinable, combo: IActiveCombination): ICombineResult => {
|
|
122
|
+
const tool = combo.selectedTool;
|
|
123
|
+
const type = combo.selectedCombinationAction;
|
|
124
|
+
const prepositionText = combo.selectedCombinationAction.preposition ? ' ' + combo.selectedCombinationAction.preposition + ' ' : ' '
|
|
125
|
+
const text = combo.selectedCombinationAction.requiresTool ? combo.selectedCombinationAction.text + ' ' + tool.name + prepositionText + target.name :
|
|
126
|
+
combo.selectedCombinationAction.text + prepositionText + target.name;
|
|
127
|
+
|
|
128
|
+
this._game.combinations.activeCombination = null;
|
|
129
|
+
|
|
130
|
+
let combination = target.combinations?.combine ? target.combinations.combine.filter(c => {
|
|
131
|
+
const toolMatch = type.requiresTool && c.tool && this.isMatch(c.tool, tool);
|
|
132
|
+
return c.combinationType === type.text && (!type.requiresTool || toolMatch);
|
|
133
|
+
})[0] : null;
|
|
134
|
+
|
|
135
|
+
if (!combination) {
|
|
136
|
+
// For items, the order in which the combination is tried shouldn't matter.
|
|
137
|
+
const anyTool = <any>tool;
|
|
138
|
+
|
|
139
|
+
if (anyTool && anyTool.type === 'item' && target && anyTool.type === 'item') {
|
|
140
|
+
combination = tool.combinations?.combine ? tool.combinations.combine.filter(c => c.combinationType === type.text && this.isMatch(c.tool, target))[0] : null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = <ICombineResult>{
|
|
145
|
+
success: false,
|
|
146
|
+
text: ''
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
if (combination) {
|
|
150
|
+
const matchResult = combination.match ? combination.match(this._game, target, tool)
|
|
151
|
+
: combo.selectedCombinationAction.defaultMatch ? combo.selectedCombinationAction.defaultMatch(this._game, target, tool)
|
|
152
|
+
: undefined;
|
|
153
|
+
|
|
154
|
+
if (matchResult === undefined) {
|
|
155
|
+
const entity = <any>target;
|
|
156
|
+
throw new Error(`No match function specified for ${entity.type} ${entity.id} for action ${combination.combinationType}. Neither was a default action specified. Add one or both.`)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
result.success = true;
|
|
160
|
+
result.text = typeof matchResult === 'string' ? matchResult : matchResult.text;
|
|
161
|
+
result.removeTarget = typeof matchResult !== 'string' && matchResult.removeTarget;
|
|
162
|
+
result.removeTool = typeof matchResult !== 'string' && matchResult.removeTool;
|
|
163
|
+
} else if (target.combinations?.failText) {
|
|
164
|
+
result.text = typeof target.combinations.failText === 'function' ? target.combinations.failText(this._game, target, tool) : target.combinations.failText;
|
|
165
|
+
} else if (type.failText) {
|
|
166
|
+
result.text = typeof type.failText === 'function' ? type.failText(this._game, target, tool) : type.failText;
|
|
167
|
+
} else {
|
|
168
|
+
result.text = tool ? this._texts.format(this._texts.noCombination, [tool.name, target.name, type.text, type.preposition]) : this._texts.format(this._texts.noCombinationNoTool, [target.name, type.text, type.preposition]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
result.text = text + (result.text ? ': ' + result.text : '')
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private readonly isMatch = (combineTool: ICombinable, tool: ICombinable): boolean => {
|
|
176
|
+
const combineId = getId(combineTool.id ?? <any>combineTool);
|
|
177
|
+
return compareString(tool.id, combineId);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private readonly removeFeature = (feature: IFeature): void => {
|
|
181
|
+
// Remove the feature from all possible locations. As we use the object
|
|
182
|
+
// reference, objects of the same type should be left alone.
|
|
183
|
+
this._game.currentLocation.features?.delete(feature);
|
|
184
|
+
this._game.currentLocation.destinations?.forEach(d => {
|
|
185
|
+
d.barriers.forEach(([k, b]) => {
|
|
186
|
+
if (b === feature) {
|
|
187
|
+
d.barriers.delete([k, b]);
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
removeItemFromParty(this._game.party, <IItem>feature);
|
|
193
|
+
this._game.currentLocation.items?.delete(<IItem>feature);
|
|
194
|
+
this._game.currentLocation.enemies?.delete(<IEnemy>feature);
|
|
195
|
+
this._game.currentLocation.persons?.delete(<IPerson>feature);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IAction,
|
|
3
|
+
IBarrier,
|
|
4
|
+
IBarrierAction,
|
|
5
|
+
ICombinationAction,
|
|
6
|
+
ICombinationService,
|
|
7
|
+
ICommandService,
|
|
8
|
+
IConversationService,
|
|
9
|
+
IDataService,
|
|
10
|
+
IDestination,
|
|
11
|
+
IFeature,
|
|
12
|
+
IGame,
|
|
13
|
+
IItem,
|
|
14
|
+
ILocation,
|
|
15
|
+
ILocationService,
|
|
16
|
+
IPerson,
|
|
17
|
+
ITradeService,
|
|
18
|
+
getItemFromParty
|
|
19
|
+
} from 'storyScript';
|
|
20
|
+
|
|
21
|
+
export class CommandService implements ICommandService {
|
|
22
|
+
|
|
23
|
+
private _combinationActions: ICombinationAction[] = [];
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
private _locationService: ILocationService,
|
|
27
|
+
private _conversationService: IConversationService,
|
|
28
|
+
private _tradeService: ITradeService,
|
|
29
|
+
private _combinationService: ICombinationService,
|
|
30
|
+
private _dataService: IDataService,
|
|
31
|
+
private _game: IGame) {
|
|
32
|
+
this._combinationActions = this._combinationService.combinationActions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
go = (location: (() => ILocation) | string, saveProgress?: boolean): void => {
|
|
36
|
+
const travel = saveProgress !== false;
|
|
37
|
+
|
|
38
|
+
this._locationService.changeLocation(location, travel, this._game);
|
|
39
|
+
|
|
40
|
+
if (travel) {
|
|
41
|
+
this._dataService.saveGame(this._game);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
talk = (person: () => IPerson): void => {
|
|
46
|
+
const partner = this._game.currentLocation.persons.get(person);
|
|
47
|
+
|
|
48
|
+
if (!partner) {
|
|
49
|
+
throw new Error(`No person ${person.name} present at location ${this._game.currentLocation.name}!`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this._conversationService.talk(partner);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
answer = (node: string, reply?: string): void => {
|
|
56
|
+
node ??= 'default';
|
|
57
|
+
const selectedNode = this._game.person.conversation.nodes.find(n => n.node?.toLowerCase() === node);
|
|
58
|
+
|
|
59
|
+
if (!selectedNode) {
|
|
60
|
+
throw new Error(`No node ${node} exists on the conversation with person ${this._game.person.name}!`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
reply = reply?.toLowerCase();
|
|
64
|
+
const selectedReply = selectedNode.replies.find(r => r.linkToNode?.toLowerCase() == reply || (r.defaultReply && !reply));
|
|
65
|
+
|
|
66
|
+
if (!selectedReply) {
|
|
67
|
+
throw new Error(`No reply ${reply} exists on conversation node ${node} of person ${this._game.person.name}!`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this._conversationService.answer(selectedNode, selectedReply);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
selectCombination = (combination: string): void => {
|
|
74
|
+
const selectedCombination = this.getCombination(combination);
|
|
75
|
+
this._combinationService.setActiveCombination(selectedCombination);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setTool = (feature: (() => IFeature) | string): void => {
|
|
79
|
+
const selectedTool = this.getFeature(feature);
|
|
80
|
+
|
|
81
|
+
if (!selectedTool) {
|
|
82
|
+
throw new Error(`No feature ${typeof feature === 'function' ? feature.name : feature} was found to set as tool!`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this._combinationService.tryCombination(selectedTool);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
combine = (combination: string, target: (() => IFeature) | string, tool?: (() => IFeature) | string): void => {
|
|
89
|
+
const selectedCombination = this.getCombination(combination);
|
|
90
|
+
const selectedTarget = this.getFeature(target);
|
|
91
|
+
|
|
92
|
+
if (!selectedTarget) {
|
|
93
|
+
throw new Error(`No target feature ${typeof target === 'function' ? target.name : target} was found to try combination ${combination}!`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const selectedTool = tool ? this.getFeature(tool) : null;
|
|
97
|
+
|
|
98
|
+
if (tool && !selectedTool) {
|
|
99
|
+
throw new Error(`No tool feature ${typeof tool === 'function' ? tool.name : tool} was found to try combination ${combination}!`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this._game.combinations.activeCombination = {
|
|
103
|
+
selectedCombinationAction: selectedCombination,
|
|
104
|
+
selectedTool: selectedTool
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this._game.combinations.tryCombine(selectedTarget);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
useAction = (action: string | [string, IAction]): void => {
|
|
111
|
+
const selectedAction = typeof action === 'string' ? this._game.currentLocation.actions.get(action) : action;
|
|
112
|
+
|
|
113
|
+
if (!selectedAction) {
|
|
114
|
+
throw new Error(`Action ${action} is not present at location ${this._game.currentLocation.name}!`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this._locationService.executeAction(selectedAction);
|
|
118
|
+
this._dataService.saveGame(this._game)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
useBarrierAction = (destination: string | IDestination, barrier: string | [string, IBarrier], action: string | [string, IBarrierAction]): void => {
|
|
122
|
+
const selectedDestination = typeof destination === 'string' ? this._game.currentLocation.destinations.get(destination) : destination;
|
|
123
|
+
|
|
124
|
+
if (!selectedDestination) {
|
|
125
|
+
throw new Error(`Destination ${destination} is not present at location ${this._game.currentLocation.name}!`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const selectedBarrier = typeof barrier === 'string' ? selectedDestination.barriers.get(barrier) : barrier;
|
|
129
|
+
|
|
130
|
+
if (!selectedBarrier) {
|
|
131
|
+
throw new Error(`Barrier ${barrier} is not present on destination ${selectedDestination.name}!`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const selectedAction = typeof action === 'string' ? selectedBarrier[1].actions.get(action) : action;
|
|
135
|
+
|
|
136
|
+
if (!selectedAction) {
|
|
137
|
+
throw new Error(`Action ${action} is not present at barrier ${selectedBarrier[0]}!`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
selectedAction[1].execute(this._game, selectedBarrier, selectedDestination);
|
|
141
|
+
selectedBarrier[1].actions.delete(selectedBarrier[1].actions.find(([k, _]) => k === action[0]));
|
|
142
|
+
this._dataService.saveGame(this._game)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
trade = (trade: string | (() => IPerson)): void => {
|
|
146
|
+
const partner = this._game.currentLocation.trade.get(trade);
|
|
147
|
+
|
|
148
|
+
if (!partner) {
|
|
149
|
+
const tradeName = typeof trade === 'string' ? trade : trade.name;
|
|
150
|
+
throw new Error(`No trade ${tradeName} present at location ${this._game.currentLocation.name}!`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this._tradeService.trade(partner);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
buy = (item: (() => IItem)): void => {
|
|
157
|
+
const selectedItem = this._game.trade.buy.items.get(item);
|
|
158
|
+
|
|
159
|
+
if (!selectedItem) {
|
|
160
|
+
throw new Error(`Trader ${this._game.trade.name} does not have item ${item.name} for sale!`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this._tradeService.buy(selectedItem, this._game.trade);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
sell = (item: (() => IItem)): void => {
|
|
167
|
+
const selectedItem = this._game.trade.sell.items.get(item);
|
|
168
|
+
|
|
169
|
+
if (!selectedItem) {
|
|
170
|
+
throw new Error(`Item ${item.name} is not available or cannot be sold to ${this._game.trade.name}!`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this._tradeService.sell(selectedItem, this._game.trade);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private getFeature(feature: (() => IFeature) | string) {
|
|
177
|
+
if (typeof feature === 'string') {
|
|
178
|
+
feature = feature.toLowerCase().replace(/\s/g, '');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let selectedFeature = this._game.currentLocation.features.get(feature);
|
|
182
|
+
selectedFeature ??= this._game.currentLocation.persons.get(<any>feature);
|
|
183
|
+
selectedFeature ??= this._game.currentLocation.enemies.get(<any>feature);
|
|
184
|
+
selectedFeature ??= getItemFromParty(this._game.party, <any>feature);
|
|
185
|
+
return selectedFeature;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private getCombination = (combination: string) => {
|
|
189
|
+
const selectedCombination = this._combinationActions.find(c => c.text.toLowerCase() === combination.toLowerCase());
|
|
190
|
+
|
|
191
|
+
if (!selectedCombination) {
|
|
192
|
+
throw new Error(`Combination ${combination} is not defined!`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return selectedCombination;
|
|
196
|
+
}
|
|
197
|
+
}
|