@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.
Files changed (370) hide show
  1. package/.env +1 -0
  2. package/CodeSnippets/StoryScriptSnippets.code-snippets +573 -0
  3. package/LICENSE.txt +21 -0
  4. package/LiveTemplates/StoryScript.xml +271 -0
  5. package/README.md +9 -2
  6. package/baseViteConfig.js +112 -0
  7. package/clientFiles/currentGameName.js +1 -0
  8. package/clientFiles/gitignore +12 -0
  9. package/clientFiles/tsconfig.json +34 -0
  10. package/clientFiles/vite.config.ts +14 -0
  11. package/clientFiles/vitest.config.ts +29 -0
  12. package/dist/src/Engine/Actions/index.d.ts +2 -0
  13. package/dist/src/Engine/Actions/open.d.ts +6 -0
  14. package/dist/src/Engine/Actions/openWithKey.d.ts +7 -0
  15. package/dist/src/Engine/EntityCreatorFunctions.d.ts +18 -0
  16. package/dist/src/Engine/Interfaces/action.d.ts +37 -0
  17. package/dist/src/Engine/Interfaces/autoplayStep.d.ts +11 -0
  18. package/dist/src/Engine/Interfaces/barrier.d.ts +16 -0
  19. package/dist/src/Engine/Interfaces/barrierAction.d.ts +19 -0
  20. package/dist/src/Engine/Interfaces/character.d.ts +48 -0
  21. package/dist/src/Engine/Interfaces/combatSetup.d.ts +9 -0
  22. package/dist/src/Engine/Interfaces/combatTurn.d.ts +37 -0
  23. package/dist/src/Engine/Interfaces/combatWinnings.d.ts +6 -0
  24. package/dist/src/Engine/Interfaces/combinations/activeCombination.d.ts +14 -0
  25. package/dist/src/Engine/Interfaces/combinations/combinable.d.ts +18 -0
  26. package/dist/src/Engine/Interfaces/combinations/combinationAction.d.ts +41 -0
  27. package/dist/src/Engine/Interfaces/combinations/combinationMatchResult.d.ts +14 -0
  28. package/dist/src/Engine/Interfaces/combinations/combinations.d.ts +17 -0
  29. package/dist/src/Engine/Interfaces/combinations/combine.d.ts +22 -0
  30. package/dist/src/Engine/Interfaces/combinations/combineResult.d.ts +18 -0
  31. package/dist/src/Engine/Interfaces/combinations/gameCombinations.d.ts +40 -0
  32. package/dist/src/Engine/Interfaces/compiledLocation.d.ts +33 -0
  33. package/dist/src/Engine/Interfaces/conversations/conversation.d.ts +44 -0
  34. package/dist/src/Engine/Interfaces/conversations/conversationLogEntry.d.ts +13 -0
  35. package/dist/src/Engine/Interfaces/conversations/conversationNode.d.ts +22 -0
  36. package/dist/src/Engine/Interfaces/conversations/conversationReply.d.ts +49 -0
  37. package/dist/src/Engine/Interfaces/createCharacter/createCharacter.d.ts +20 -0
  38. package/dist/src/Engine/Interfaces/createCharacter/createCharacterAttribute.d.ts +18 -0
  39. package/dist/src/Engine/Interfaces/createCharacter/createCharacterAttributeEntry.d.ts +18 -0
  40. package/dist/src/Engine/Interfaces/createCharacter/createCharacterQuestion.d.ts +18 -0
  41. package/dist/src/Engine/Interfaces/createCharacter/createCharacterQuestionEntry.d.ts +22 -0
  42. package/dist/src/Engine/Interfaces/createCharacter/createCharacterStep.d.ts +40 -0
  43. package/dist/src/Engine/Interfaces/customCursor.d.ts +8 -0
  44. package/dist/src/Engine/Interfaces/defaultEquipment.d.ts +19 -0
  45. package/dist/src/Engine/Interfaces/definitions.d.ts +40 -0
  46. package/dist/src/Engine/Interfaces/destination.d.ts +31 -0
  47. package/dist/src/Engine/Interfaces/dynamicStyle.d.ts +10 -0
  48. package/dist/src/Engine/Interfaces/enemy.d.ts +46 -0
  49. package/dist/src/Engine/Interfaces/enumerations/actionStatus.d.ts +18 -0
  50. package/dist/src/Engine/Interfaces/enumerations/actionType.d.ts +9 -0
  51. package/dist/src/Engine/Interfaces/enumerations/equipmentType.d.ts +51 -0
  52. package/dist/src/Engine/Interfaces/enumerations/gameState.d.ts +11 -0
  53. package/dist/src/Engine/Interfaces/enumerations/playState.d.ts +10 -0
  54. package/dist/src/Engine/Interfaces/enumerations/targetType.d.ts +9 -0
  55. package/dist/src/Engine/Interfaces/equipment.d.ts +43 -0
  56. package/dist/src/Engine/Interfaces/feature.d.ts +37 -0
  57. package/dist/src/Engine/Interfaces/featureCollection.d.ts +7 -0
  58. package/dist/src/Engine/Interfaces/game.d.ts +148 -0
  59. package/dist/src/Engine/Interfaces/gameEvents.d.ts +7 -0
  60. package/dist/src/Engine/Interfaces/groupableItem.d.ts +32 -0
  61. package/dist/src/Engine/Interfaces/helpers.d.ts +50 -0
  62. package/dist/src/Engine/Interfaces/index.d.ts +78 -0
  63. package/dist/src/Engine/Interfaces/interfaceTexts.d.ts +140 -0
  64. package/dist/src/Engine/Interfaces/item.d.ts +96 -0
  65. package/dist/src/Engine/Interfaces/key.d.ts +16 -0
  66. package/dist/src/Engine/Interfaces/location.d.ts +78 -0
  67. package/dist/src/Engine/Interfaces/maps/map.d.ts +45 -0
  68. package/dist/src/Engine/Interfaces/maps/mapLocation.d.ts +23 -0
  69. package/dist/src/Engine/Interfaces/party.d.ts +33 -0
  70. package/dist/src/Engine/Interfaces/person.d.ts +25 -0
  71. package/dist/src/Engine/Interfaces/quest.d.ts +51 -0
  72. package/dist/src/Engine/Interfaces/rules/characterRules.d.ts +84 -0
  73. package/dist/src/Engine/Interfaces/rules/combatRules.d.ts +46 -0
  74. package/dist/src/Engine/Interfaces/rules/combinationRules.d.ts +15 -0
  75. package/dist/src/Engine/Interfaces/rules/demoMode.d.ts +15 -0
  76. package/dist/src/Engine/Interfaces/rules/encounterRules.d.ts +4 -0
  77. package/dist/src/Engine/Interfaces/rules/explorationRules.d.ts +42 -0
  78. package/dist/src/Engine/Interfaces/rules/generalRules.d.ts +62 -0
  79. package/dist/src/Engine/Interfaces/rules/rules.d.ts +31 -0
  80. package/dist/src/Engine/Interfaces/rules/setupRules.d.ts +56 -0
  81. package/dist/src/Engine/Interfaces/rules/titleScreen.d.ts +16 -0
  82. package/dist/src/Engine/Interfaces/saveGame.d.ts +33 -0
  83. package/dist/src/Engine/Interfaces/scoreEntry.d.ts +13 -0
  84. package/dist/src/Engine/Interfaces/services/autoplayService.d.ts +19 -0
  85. package/dist/src/Engine/Interfaces/services/characterService.d.ts +17 -0
  86. package/dist/src/Engine/Interfaces/services/combatService.d.ts +26 -0
  87. package/dist/src/Engine/Interfaces/services/combinationService.d.ts +9 -0
  88. package/dist/src/Engine/Interfaces/services/commandService.d.ts +64 -0
  89. package/dist/src/Engine/Interfaces/services/conversationService.d.ts +5 -0
  90. package/dist/src/Engine/Interfaces/services/dataSerializer.d.ts +4 -0
  91. package/dist/src/Engine/Interfaces/services/dataService.d.ts +33 -0
  92. package/dist/src/Engine/Interfaces/services/dataSynchronizer.d.ts +3 -0
  93. package/dist/src/Engine/Interfaces/services/gameService.d.ts +10 -0
  94. package/dist/src/Engine/Interfaces/services/index.d.ts +16 -0
  95. package/dist/src/Engine/Interfaces/services/itemService.d.ts +14 -0
  96. package/dist/src/Engine/Interfaces/services/localStorageService.d.ts +6 -0
  97. package/dist/src/Engine/Interfaces/services/locationService.d.ts +8 -0
  98. package/dist/src/Engine/Interfaces/services/soundService.d.ts +5 -0
  99. package/dist/src/Engine/Interfaces/services/tradeService.d.ts +9 -0
  100. package/dist/src/Engine/Interfaces/soundPlayer.d.ts +30 -0
  101. package/dist/src/Engine/Interfaces/sprite.d.ts +23 -0
  102. package/dist/src/Engine/Interfaces/stateList.d.ts +9 -0
  103. package/dist/src/Engine/Interfaces/statistics.d.ts +13 -0
  104. package/dist/src/Engine/Interfaces/stock.d.ts +39 -0
  105. package/dist/src/Engine/Interfaces/trade.d.ts +62 -0
  106. package/dist/src/Engine/ServiceFactory.d.ts +52 -0
  107. package/dist/src/Engine/Services/AutoplayService.d.ts +11 -0
  108. package/dist/src/Engine/Services/CharacterService.d.ts +21 -0
  109. package/dist/src/Engine/Services/CombatService.d.ts +16 -0
  110. package/dist/src/Engine/Services/CombinationService.d.ts +15 -0
  111. package/dist/src/Engine/Services/CommandService.d.ts +24 -0
  112. package/dist/src/Engine/Services/ConversationService.d.ts +26 -0
  113. package/dist/src/Engine/Services/DataSerializer.d.ts +17 -0
  114. package/dist/src/Engine/Services/DataService.d.ts +16 -0
  115. package/dist/src/Engine/Services/DataSynchronizer.d.ts +12 -0
  116. package/dist/src/Engine/Services/GameService.d.ts +28 -0
  117. package/dist/src/Engine/Services/HelperService.d.ts +18 -0
  118. package/dist/src/Engine/Services/ItemService.d.ts +21 -0
  119. package/dist/src/Engine/Services/LocalStorageService.d.ts +7 -0
  120. package/dist/src/Engine/Services/LocationService.d.ts +25 -0
  121. package/dist/src/Engine/Services/SoundService.d.ts +13 -0
  122. package/dist/src/Engine/Services/TradeService.d.ts +17 -0
  123. package/dist/src/Engine/Services/index.d.ts +17 -0
  124. package/dist/src/Engine/Services/serializationData.d.ts +8 -0
  125. package/dist/src/Engine/Services/sharedFunctions.d.ts +21 -0
  126. package/dist/src/Engine/arrayAndFunctionExtensions.d.ts +3 -0
  127. package/dist/src/Engine/defaultTexts.d.ts +7 -0
  128. package/dist/src/Engine/gameEvents.d.ts +10 -0
  129. package/dist/src/Engine/index.d.ts +8 -0
  130. package/dist/src/Engine/stateProperties.d.ts +6 -0
  131. package/dist/src/Engine/utilityFunctions.d.ts +25 -0
  132. package/dist/src/UI/Composables/CustomCursor.d.ts +2 -0
  133. package/dist/src/UI/Composables/LocationMap.d.ts +26 -0
  134. package/dist/src/UI/Composables/Sound.d.ts +7 -0
  135. package/dist/src/UI/Composables/TextFeatures.d.ts +8 -0
  136. package/dist/src/UI/Composables/VisualFeatures.d.ts +7 -0
  137. package/dist/src/UI/Composables/index.d.ts +7 -0
  138. package/dist/src/UI/Composables/playStateWatch.d.ts +2 -0
  139. package/dist/src/UI/StateStore.d.ts +14256 -0
  140. package/dist/src/UI/error.d.ts +6 -0
  141. package/dist/src/UI/helpers.d.ts +3 -0
  142. package/dist/src/UI/index.d.ts +6 -0
  143. package/dist/src/UI/main.d.ts +1 -0
  144. package/dist/src/UI/startup.d.ts +2 -0
  145. package/dist/src/constants.d.ts +17 -0
  146. package/dist/src/index.d.ts +3 -0
  147. package/dist/storyscript.css +9566 -0
  148. package/dist/storyscript.js +9659 -0
  149. package/dist/storyscript.js.map +1 -0
  150. package/dist/storyscript.mjs +9569 -0
  151. package/dist/storyscript.mjs.map +1 -0
  152. package/electron.cjs +44 -0
  153. package/index.html +14 -0
  154. package/package.json +118 -4
  155. package/scripts/cli.js +268 -0
  156. package/scripts/createAsset.js +117 -0
  157. package/scripts/createGame.js +40 -0
  158. package/scripts/helpers.js +21 -0
  159. package/scripts/postbuild.js +179 -0
  160. package/scripts/setupTesting.js +17 -0
  161. package/shims-vue.d.ts +1 -0
  162. package/src/Engine/Actions/index.ts +2 -0
  163. package/src/Engine/Actions/open.ts +12 -0
  164. package/src/Engine/Actions/openWithKey.ts +23 -0
  165. package/src/Engine/EntityCreatorFunctions.ts +602 -0
  166. package/src/Engine/Interfaces/action.ts +43 -0
  167. package/src/Engine/Interfaces/autoplayStep.ts +13 -0
  168. package/src/Engine/Interfaces/barrier.ts +18 -0
  169. package/src/Engine/Interfaces/barrierAction.ts +21 -0
  170. package/src/Engine/Interfaces/character.ts +58 -0
  171. package/src/Engine/Interfaces/combatSetup.ts +10 -0
  172. package/src/Engine/Interfaces/combatTurn.ts +45 -0
  173. package/src/Engine/Interfaces/combatWinnings.ts +7 -0
  174. package/src/Engine/Interfaces/combinations/activeCombination.ts +16 -0
  175. package/src/Engine/Interfaces/combinations/combinable.ts +21 -0
  176. package/src/Engine/Interfaces/combinations/combinationAction.ts +45 -0
  177. package/src/Engine/Interfaces/combinations/combinationMatchResult.ts +16 -0
  178. package/src/Engine/Interfaces/combinations/combinations.ts +19 -0
  179. package/src/Engine/Interfaces/combinations/combine.ts +25 -0
  180. package/src/Engine/Interfaces/combinations/combineResult.ts +21 -0
  181. package/src/Engine/Interfaces/combinations/gameCombinations.ts +48 -0
  182. package/src/Engine/Interfaces/compiledLocation.ts +37 -0
  183. package/src/Engine/Interfaces/conversations/conversation.ts +47 -0
  184. package/src/Engine/Interfaces/conversations/conversationLogEntry.ts +14 -0
  185. package/src/Engine/Interfaces/conversations/conversationNode.ts +26 -0
  186. package/src/Engine/Interfaces/conversations/conversationReply.ts +59 -0
  187. package/src/Engine/Interfaces/createCharacter/createCharacter.ts +23 -0
  188. package/src/Engine/Interfaces/createCharacter/createCharacterAttribute.ts +21 -0
  189. package/src/Engine/Interfaces/createCharacter/createCharacterAttributeEntry.ts +21 -0
  190. package/src/Engine/Interfaces/createCharacter/createCharacterQuestion.ts +21 -0
  191. package/src/Engine/Interfaces/createCharacter/createCharacterQuestionEntry.ts +25 -0
  192. package/src/Engine/Interfaces/createCharacter/createCharacterStep.ts +47 -0
  193. package/src/Engine/Interfaces/customCursor.ts +5 -0
  194. package/src/Engine/Interfaces/defaultEquipment.ts +32 -0
  195. package/src/Engine/Interfaces/definitions.ts +48 -0
  196. package/src/Engine/Interfaces/destination.ts +37 -0
  197. package/src/Engine/Interfaces/dynamicStyle.ts +11 -0
  198. package/src/Engine/Interfaces/enemy.ts +54 -0
  199. package/src/Engine/Interfaces/enumerations/actionStatus.ts +20 -0
  200. package/src/Engine/Interfaces/enumerations/actionType.ts +9 -0
  201. package/src/Engine/Interfaces/enumerations/equipmentType.ts +61 -0
  202. package/src/Engine/Interfaces/enumerations/gameState.ts +11 -0
  203. package/src/Engine/Interfaces/enumerations/playState.ts +10 -0
  204. package/src/Engine/Interfaces/enumerations/targetType.ts +9 -0
  205. package/src/Engine/Interfaces/equipment.ts +44 -0
  206. package/src/Engine/Interfaces/feature.ts +43 -0
  207. package/src/Engine/Interfaces/featureCollection.ts +8 -0
  208. package/src/Engine/Interfaces/game.ts +201 -0
  209. package/src/Engine/Interfaces/gameEvents.ts +11 -0
  210. package/src/Engine/Interfaces/groupableItem.ts +37 -0
  211. package/src/Engine/Interfaces/helpers.ts +55 -0
  212. package/src/Engine/Interfaces/index.ts +158 -0
  213. package/src/Engine/Interfaces/interfaceTexts.ts +142 -0
  214. package/src/Engine/Interfaces/item.ts +111 -0
  215. package/src/Engine/Interfaces/key.ts +18 -0
  216. package/src/Engine/Interfaces/location.ts +92 -0
  217. package/src/Engine/Interfaces/maps/map.ts +55 -0
  218. package/src/Engine/Interfaces/maps/mapLocation.ts +28 -0
  219. package/src/Engine/Interfaces/party.ts +40 -0
  220. package/src/Engine/Interfaces/person.ts +29 -0
  221. package/src/Engine/Interfaces/quest.ts +60 -0
  222. package/src/Engine/Interfaces/rules/characterRules.ts +96 -0
  223. package/src/Engine/Interfaces/rules/combatRules.ts +52 -0
  224. package/src/Engine/Interfaces/rules/combinationRules.ts +17 -0
  225. package/src/Engine/Interfaces/rules/demoMode.ts +18 -0
  226. package/src/Engine/Interfaces/rules/encounterRules.ts +5 -0
  227. package/src/Engine/Interfaces/rules/explorationRules.ts +47 -0
  228. package/src/Engine/Interfaces/rules/generalRules.ts +80 -0
  229. package/src/Engine/Interfaces/rules/rules.ts +46 -0
  230. package/src/Engine/Interfaces/rules/setupRules.ts +65 -0
  231. package/src/Engine/Interfaces/rules/titleScreen.ts +19 -0
  232. package/src/Engine/Interfaces/saveGame.ts +39 -0
  233. package/src/Engine/Interfaces/scoreEntry.ts +14 -0
  234. package/src/Engine/Interfaces/services/autoplayService.ts +23 -0
  235. package/src/Engine/Interfaces/services/characterService.ts +35 -0
  236. package/src/Engine/Interfaces/services/combatService.ts +30 -0
  237. package/src/Engine/Interfaces/services/combinationService.ts +10 -0
  238. package/src/Engine/Interfaces/services/commandService.ts +75 -0
  239. package/src/Engine/Interfaces/services/conversationService.ts +7 -0
  240. package/src/Engine/Interfaces/services/dataSerializer.ts +4 -0
  241. package/src/Engine/Interfaces/services/dataService.ts +39 -0
  242. package/src/Engine/Interfaces/services/dataSynchronizer.ts +9 -0
  243. package/src/Engine/Interfaces/services/gameService.ts +17 -0
  244. package/src/Engine/Interfaces/services/index.ts +33 -0
  245. package/src/Engine/Interfaces/services/itemService.ts +25 -0
  246. package/src/Engine/Interfaces/services/localStorageService.ts +6 -0
  247. package/src/Engine/Interfaces/services/locationService.ts +13 -0
  248. package/src/Engine/Interfaces/services/soundService.ts +7 -0
  249. package/src/Engine/Interfaces/services/tradeService.ts +15 -0
  250. package/src/Engine/Interfaces/soundPlayer.ts +30 -0
  251. package/src/Engine/Interfaces/sprite.ts +27 -0
  252. package/src/Engine/Interfaces/stateList.ts +13 -0
  253. package/src/Engine/Interfaces/statistics.ts +14 -0
  254. package/src/Engine/Interfaces/stock.ts +46 -0
  255. package/src/Engine/Interfaces/trade.ts +72 -0
  256. package/src/Engine/ServiceFactory.ts +167 -0
  257. package/src/Engine/Services/AutoplayService.ts +59 -0
  258. package/src/Engine/Services/CharacterService.ts +291 -0
  259. package/src/Engine/Services/CombatService.ts +266 -0
  260. package/src/Engine/Services/CombinationService.ts +197 -0
  261. package/src/Engine/Services/CommandService.ts +197 -0
  262. package/src/Engine/Services/ConversationService.ts +406 -0
  263. package/src/Engine/Services/DataSerializer.ts +326 -0
  264. package/src/Engine/Services/DataService.ts +93 -0
  265. package/src/Engine/Services/DataSynchronizer.ts +216 -0
  266. package/src/Engine/Services/GameService.ts +554 -0
  267. package/src/Engine/Services/HelperService.ts +94 -0
  268. package/src/Engine/Services/ItemService.ts +294 -0
  269. package/src/Engine/Services/LocalStorageService.ts +24 -0
  270. package/src/Engine/Services/LocationService.ts +380 -0
  271. package/src/Engine/Services/SoundService.ts +54 -0
  272. package/src/Engine/Services/TradeService.ts +176 -0
  273. package/src/Engine/Services/index.ts +17 -0
  274. package/src/Engine/Services/serializationData.ts +8 -0
  275. package/src/Engine/Services/sharedFunctions.ts +296 -0
  276. package/src/Engine/arrayAndFunctionExtensions.ts +269 -0
  277. package/src/Engine/defaultTexts.ts +162 -0
  278. package/src/Engine/gameEvents.ts +51 -0
  279. package/src/Engine/index.ts +9 -0
  280. package/src/Engine/stateProperties.ts +9 -0
  281. package/src/Engine/utilityFunctions.ts +238 -0
  282. package/src/Games/_GameTemplate/character.ts +31 -0
  283. package/src/Games/_GameTemplate/customTexts.ts +8 -0
  284. package/src/Games/_GameTemplate/interfaces/action.ts +5 -0
  285. package/src/Games/_GameTemplate/interfaces/combatSetup.ts +7 -0
  286. package/src/Games/_GameTemplate/interfaces/combatTurn.ts +8 -0
  287. package/src/Games/_GameTemplate/interfaces/destination.ts +5 -0
  288. package/src/Games/_GameTemplate/interfaces/enemy.ts +11 -0
  289. package/src/Games/_GameTemplate/interfaces/equipment.ts +5 -0
  290. package/src/Games/_GameTemplate/interfaces/feature.ts +9 -0
  291. package/src/Games/_GameTemplate/interfaces/game.ts +22 -0
  292. package/src/Games/_GameTemplate/interfaces/interfaceTexts.ts +5 -0
  293. package/src/Games/_GameTemplate/interfaces/item.ts +18 -0
  294. package/src/Games/_GameTemplate/interfaces/key.ts +10 -0
  295. package/src/Games/_GameTemplate/interfaces/location.ts +22 -0
  296. package/src/Games/_GameTemplate/interfaces/map.ts +16 -0
  297. package/src/Games/_GameTemplate/interfaces/party.ts +8 -0
  298. package/src/Games/_GameTemplate/interfaces/person.ts +11 -0
  299. package/src/Games/_GameTemplate/interfaces/quest.ts +9 -0
  300. package/src/Games/_GameTemplate/locations/Start.html +5 -0
  301. package/src/Games/_GameTemplate/locations/start.ts +12 -0
  302. package/src/Games/_GameTemplate/rules.ts +60 -0
  303. package/src/Games/_GameTemplate/types.ts +55 -0
  304. package/src/Games/_GameTemplate/ui/styles/game.css +3 -0
  305. package/src/Games/_GameTemplate/webroot/favicon.ico +0 -0
  306. package/src/Games/_GameTemplate/webroot/gameinfo.json +10 -0
  307. package/src/Games/_GameTemplate/webroot/logo192.png +0 -0
  308. package/src/Games/_GameTemplate/webroot/logo512.png +0 -0
  309. package/src/Tests/Games/_GameTemplate/specs/rules.test.ts +9 -0
  310. package/src/UI/Components/AppShell.vue +43 -0
  311. package/src/UI/Components/Autoplay.vue +32 -0
  312. package/src/UI/Components/Combinations.vue +37 -0
  313. package/src/UI/Components/Common/Collapsible.vue +50 -0
  314. package/src/UI/Components/Common/ModalDialog.vue +54 -0
  315. package/src/UI/Components/Common/Sprite.vue +53 -0
  316. package/src/UI/Components/Description.vue +23 -0
  317. package/src/UI/Components/Encounter/Combat/Combat.vue +89 -0
  318. package/src/UI/Components/Encounter/Combat/CombatActions.vue +26 -0
  319. package/src/UI/Components/Encounter/Combat/CombatParticipant.vue +22 -0
  320. package/src/UI/Components/Encounter/Combat/CombatTargetSelect.vue +55 -0
  321. package/src/UI/Components/Encounter/Combat/CombatWin.vue +33 -0
  322. package/src/UI/Components/Encounter/Conversation.vue +66 -0
  323. package/src/UI/Components/Encounter/Encounter.vue +39 -0
  324. package/src/UI/Components/Encounter/Enemy.vue +30 -0
  325. package/src/UI/Components/Encounter/Trade/Stock.vue +58 -0
  326. package/src/UI/Components/Encounter/Trade/Trade.vue +24 -0
  327. package/src/UI/Components/Exploration/ActionLog.vue +17 -0
  328. package/src/UI/Components/Exploration/Destination.vue +66 -0
  329. package/src/UI/Components/Exploration/Exploration.vue +67 -0
  330. package/src/UI/Components/Exploration/Ground.vue +22 -0
  331. package/src/UI/Components/Exploration/LocationMap.vue +42 -0
  332. package/src/UI/Components/Exploration/LocationText.vue +39 -0
  333. package/src/UI/Components/Exploration/LocationVisual.vue +38 -0
  334. package/src/UI/Components/GameContainer.vue +49 -0
  335. package/src/UI/Components/GameMenu.vue +111 -0
  336. package/src/UI/Components/GameState/GameOver.vue +20 -0
  337. package/src/UI/Components/GameState/HighScores.vue +22 -0
  338. package/src/UI/Components/GameState/Intro.vue +17 -0
  339. package/src/UI/Components/GameState/TitleScreen.vue +42 -0
  340. package/src/UI/Components/GameState/Victory.vue +28 -0
  341. package/src/UI/Components/Navigation.vue +94 -0
  342. package/src/UI/Components/Party/Backpack.vue +68 -0
  343. package/src/UI/Components/Party/BuildCharacter.vue +64 -0
  344. package/src/UI/Components/Party/CharacterSheet.vue +57 -0
  345. package/src/UI/Components/Party/CreateCharacter.vue +46 -0
  346. package/src/UI/Components/Party/Equipment.vue +48 -0
  347. package/src/UI/Components/Party/EquipmentSlot.vue +31 -0
  348. package/src/UI/Components/Party/LevelUp.vue +27 -0
  349. package/src/UI/Components/Party/Party.vue +29 -0
  350. package/src/UI/Components/Party/Quests.vue +48 -0
  351. package/src/UI/Components/Sound.vue +42 -0
  352. package/src/UI/Composables/CustomCursor.ts +60 -0
  353. package/src/UI/Composables/LocationMap.ts +315 -0
  354. package/src/UI/Composables/Sound.ts +111 -0
  355. package/src/UI/Composables/TextFeatures.ts +148 -0
  356. package/src/UI/Composables/VisualFeatures.ts +220 -0
  357. package/src/UI/Composables/index.ts +15 -0
  358. package/src/UI/Composables/playStateWatch.ts +31 -0
  359. package/src/UI/StateStore.ts +237 -0
  360. package/src/UI/error.ts +6 -0
  361. package/src/UI/helpers.ts +62 -0
  362. package/src/UI/index.ts +13 -0
  363. package/src/UI/main.ts +62 -0
  364. package/src/UI/startup.ts +58 -0
  365. package/src/UI/styles/bootstrap-storyscript.scss +31 -0
  366. package/src/UI/styles/empty.css +3 -0
  367. package/src/UI/styles/lookinglass.png +0 -0
  368. package/src/UI/styles/storyscript.css +735 -0
  369. package/typeExtensions.d.ts +25 -0
  370. 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
+ }