narrat 1.3.2 → 2.0.0-rc3
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/CHANGELOG.md +175 -0
- package/README.md +10 -0
- package/lib/app.vue.d.ts +27 -52
- package/lib/components/debug/debug-menu.vue.d.ts +1 -1
- package/lib/config.d.ts +7 -0
- package/lib/exports/plugins.d.ts +4 -4
- package/lib/index.d.ts +1 -4
- package/lib/index.esm.js +1553 -931
- package/lib/index.js +1553 -931
- package/lib/plugins/NarratPlugin.d.ts +1 -1
- package/lib/stores/hud-stats-store.d.ts +2 -0
- package/lib/stores/inventory-store.d.ts +2 -1
- package/lib/stores/main-store.d.ts +92 -110
- package/lib/stores/quest-log.d.ts +4 -1
- package/lib/stores/skills.d.ts +7 -4
- package/lib/stores/vm-store.d.ts +99 -104
- package/lib/types/parser.d.ts +34 -18
- package/lib/utils/audio-loader.d.ts +1 -0
- package/lib/utils/data-helpers.d.ts +5 -0
- package/lib/utils/logger.d.ts +1 -2
- package/lib/utils/skillchecks.d.ts +0 -3
- package/lib/utils/string-helpers.d.ts +2 -0
- package/lib/vm/commands/arithmetic-commands.d.ts +17 -0
- package/lib/vm/commands/audio-commands.d.ts +8 -0
- package/lib/vm/commands/choice.d.ts +36 -4
- package/lib/vm/commands/clear_dialog.d.ts +2 -3
- package/lib/vm/commands/command-helpers.d.ts +2 -0
- package/lib/vm/commands/command-plugin.d.ts +17 -8
- package/lib/vm/commands/flow-commands.d.ts +14 -0
- package/lib/vm/commands/if.d.ts +9 -1
- package/lib/vm/commands/inventory-commands.d.ts +14 -4
- package/lib/vm/commands/logic-command.d.ts +42 -0
- package/lib/vm/commands/notify.d.ts +3 -1
- package/lib/vm/commands/quest-commands.d.ts +29 -4
- package/lib/vm/commands/screen-commands.d.ts +8 -0
- package/lib/vm/commands/set.d.ts +5 -1
- package/lib/vm/commands/skill-commands.d.ts +33 -0
- package/lib/vm/commands/stats-commands.d.ts +12 -0
- package/lib/vm/commands/string-commands.d.ts +9 -0
- package/lib/vm/commands/text.d.ts +13 -2
- package/lib/vm/commands/wait.d.ts +3 -1
- package/lib/vm/vm-helpers.d.ts +6 -6
- package/lib/vm/vm-parser.d.ts +10 -1
- package/lib/vm/vm.d.ts +8 -6
- package/package.json +11 -7
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Version:
|
|
1
|
+
// Version: 2.0.0-rc3 - June 28, 2022 22:38:40
|
|
2
2
|
import 'es6-promise/auto';
|
|
3
3
|
import { ref, reactive, readonly, defineComponent, openBlock, createElementBlock, normalizeStyle, createElementVNode, createCommentVNode, Fragment, renderList, normalizeClass, createBlock, Transition, withCtx, renderSlot, createTextVNode, computed, resolveComponent, withDirectives, vModelText, toDisplayString, TransitionGroup, createVNode, createApp } from 'vue';
|
|
4
4
|
import { defineStore, mapState, createPinia } from 'pinia';
|
|
@@ -30,7 +30,7 @@ function styleInject(css, ref) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
var css_248z = "/*! @import */\n\n/*! modern-normalize v1.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */\n\n/*\nDocument\n========\n*/\n\n/**\nUse a better box model (opinionated).\n*/\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n/**\nUse a more readable tab size (opinionated).\n*/\n\n:root {\n -moz-tab-size: 4;\n -o-tab-size: 4;\n tab-size: 4;\n}\n\n/**\n1. Correct the line height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n*/\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/*\nSections\n========\n*/\n\n/**\nRemove the margin in all browsers.\n*/\n\nbody {\n margin: 0;\n}\n\n/**\nImprove consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)\n*/\n\nbody {\n font-family:\n\t\tsystem-ui,\n\t\t-apple-system, /* Firefox supports this but not yet `system-ui` */\n\t\t'Segoe UI',\n\t\tRoboto,\n\t\tHelvetica,\n\t\tArial,\n\t\tsans-serif,\n\t\t'Apple Color Emoji',\n\t\t'Segoe UI Emoji';\n}\n\n/*\nGrouping content\n================\n*/\n\n/**\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n}\n\n/*\nText-level semantics\n====================\n*/\n\n/**\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr[title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/**\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)\n2. Correct the odd 'em' font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family:\n\t\tui-monospace,\n\t\tSFMono-Regular,\n\t\tConsolas,\n\t\t'Liberation Mono',\n\t\tMenlo,\n\t\tmonospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/**\nPrevent 'sub' and 'sup' elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\nTabular data\n============\n*/\n\n/**\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n}\n\n/*\nForms\n=====\n*/\n\n/**\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\nRemove the inheritance of text transform in Edge and Firefox.\n1. Remove the inheritance of text transform in Firefox.\n*/\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\nCorrect the inability to style clickable types in iOS and Safari.\n*/\n\nbutton,\n[type='button'],\n[type='reset'] {\n -webkit-appearance: button;\n}\n\n/**\nRemove the inner border and padding in Firefox.\n*/\n\n/**\nRestore the focus styles unset by the previous rule.\n*/\n\n/**\nRemove the additional ':invalid' styles in Firefox.\nSee: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737\n*/\n\n/**\nRemove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.\n*/\n\nlegend {\n padding: 0;\n}\n\n/**\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n/**\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n/**\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to 'inherit' in Safari.\n*/\n\n/*\nInteractive\n===========\n*/\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/**\n * Manually forked from SUIT CSS Base: https://github.com/suitcss/base\n * A thin layer on top of normalize.css that provides a starting point more\n * suitable for web applications.\n */\n\n/**\n * Removes the default spacing and border for appropriate elements.\n */\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nbutton {\n background-color: transparent;\n background-image: none;\n}\n\n/**\n * Work around a Firefox/IE bug where the transparent `button` background\n * results in a loss of the default `button` focus styles.\n */\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nol,\nul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/**\n * Tailwind custom reset styles\n */\n\n/**\n * 1. Use the user's configured `sans` font-family (with Tailwind's default\n * sans-serif font stack as a fallback) as a sane default.\n * 2. Use Tailwind's default \"normal\" line-height so the user isn't forced\n * to override it to ensure consistency even when using the default theme.\n */\n\nhtml {\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 1 */\n line-height: 1.5; /* 2 */\n}\n\n/**\n * Inherit font-family and line-height from `html` so users can set them as\n * a class directly on the `html` element.\n */\n\nbody {\n font-family: inherit;\n line-height: inherit;\n}\n\n/**\n * 1. Prevent padding and border from affecting element width.\n *\n * We used to set this in the html element and inherit from\n * the parent element for everything else. This caused issues\n * in shadow-dom-enhanced elements like <details> where the content\n * is wrapped by a div with box-sizing set to `content-box`.\n *\n * https://github.com/mozdevs/cssremedy/issues/4\n *\n *\n * 2. Allow adding a border to an element by just adding a border-width.\n *\n * By default, the way the browser specifies that an element should have no\n * border is by setting it's border-style to `none` in the user-agent\n * stylesheet.\n *\n * In order to easily add borders to elements by just setting the `border-width`\n * property, we change the default border-style for all elements to `solid`, and\n * use border-width to hide them instead. This way our `border` utilities only\n * need to set the `border-width` property instead of the entire `border`\n * shorthand, making our border utilities much more straightforward to compose.\n *\n * https://github.com/tailwindcss/tailwindcss/pull/116\n */\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n/*\n * Ensure horizontal rules are visible by default\n */\n\nhr {\n border-top-width: 1px;\n}\n\n/**\n * Undo the `border-style: none` reset that Normalize applies to images so that\n * our `border-{width}` utilities have the expected effect.\n *\n * The Normalize reset is unnecessary for us since we default the border-width\n * to 0 on all elements.\n *\n * https://github.com/tailwindcss/tailwindcss/issues/362\n */\n\nimg {\n border-style: solid;\n}\n\ntextarea {\n resize: vertical;\n}\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n color: #9ca3af;\n}\n\ninput:-ms-input-placeholder, textarea:-ms-input-placeholder {\n color: #9ca3af;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n color: #9ca3af;\n}\n\nbutton {\n cursor: pointer;\n}\n\ntable {\n border-collapse: collapse;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/**\n * Reset links to optimize for opt-in styling instead of\n * opt-out.\n */\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/**\n * Reset form element properties that are easy to forget to\n * style explicitly so you don't inadvertently introduce\n * styles that deviate from your design system. These styles\n * supplement a partial reset that is already applied by\n * normalize.css.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n padding: 0;\n line-height: inherit;\n color: inherit;\n}\n\n/**\n * Use the configured 'mono' font family for elements that\n * are expected to be rendered with a monospace font, falling\n * back to the system monospace stack if there is no configured\n * 'mono' font family.\n */\n\npre,\ncode,\nkbd,\nsamp {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n/**\n * Make replaced elements `display: block` by default as that's\n * the behavior you want almost all of the time. Inspired by\n * CSS Remedy, with `svg` added as well.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block;\n vertical-align: middle;\n}\n\n/**\n * Constrain images and videos to the parent width and preserve\n * their instrinsic aspect ratio.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n.container {\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .container {\n max-width: 640px;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n}\n\n@media (min-width: 1024px) {\n .container {\n max-width: 1024px;\n }\n}\n\n@media (min-width: 1280px) {\n .container {\n max-width: 1280px;\n }\n}\n\n@media (min-width: 1536px) {\n .container {\n max-width: 1536px;\n }\n}\n\n.bg-gray-800 {\n --tw-bg-opacity: 1;\n background-color: rgba(31, 41, 55, var(--tw-bg-opacity));\n}\n\n.border {\n border-width: 1px;\n}\n\n.flex {\n display: flex;\n}\n\n.table {\n display: table;\n}\n\n.grid {\n display: grid;\n}\n\n.hidden {\n display: none;\n}\n\n.flex-row {\n flex-direction: row;\n}\n\n.flex-col {\n flex-direction: column;\n}\n\n.flex-grow {\n flex-grow: 1;\n}\n\n.flex-shrink {\n flex-shrink: 1;\n}\n\n.list-disc {\n list-style-type: disc;\n}\n\n.absolute {\n position: absolute;\n}\n\n.resize {\n resize: both;\n}\n\n* {\n --tw-shadow: 0 0 #0000;\n}\n\n* {\n --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgba(59, 130, 246, 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n}\n\n.table-auto {\n table-layout: auto;\n}\n\n.line-through {\n text-decoration: line-through;\n}\n\n.w-full {\n width: 100%;\n}\n\n.gap-4 {\n gap: 1rem;\n}\n\n.grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n\n.transform {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n\n.transition {\n transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n\n@-webkit-keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@-webkit-keyframes ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n\n@keyframes ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n\n@-webkit-keyframes pulse {\n 50% {\n opacity: .5;\n }\n}\n\n@keyframes pulse {\n 50% {\n opacity: .5;\n }\n}\n\n@-webkit-keyframes bounce {\n 0%, 100% {\n transform: translateY(-25%);\n -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);\n animation-timing-function: cubic-bezier(0.8,0,1,1);\n }\n\n 50% {\n transform: none;\n -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);\n animation-timing-function: cubic-bezier(0,0,0.2,1);\n }\n}\n\n@keyframes bounce {\n 0%, 100% {\n transform: translateY(-25%);\n -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);\n animation-timing-function: cubic-bezier(0.8,0,1,1);\n }\n\n 50% {\n transform: none;\n -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);\n animation-timing-function: cubic-bezier(0,0,0.2,1);\n }\n}\n\n:root {\n --bg-color: #131720;\n --text-color: #d9e1f2;\n --primary: hsl(255, 30%, 55%);\n --focus: hsl(210, 90%, 50%);\n --secondary: #42b983;\n --border-color: hsla(0, 0%, 100%, 0.2);\n --light-1: hsl(210, 30%, 40%);\n --light-2: hsl(255, 30%, 50%);\n --light-background: linear-gradient(to right, var(--light-1), var(--light-2));\n --shadow-1: hsla(236, 50%, 50%, 0.3);\n --shadow-2: hsla(236, 50%, 50%, 0.4);\n --hud-background: rgba(0, 0, 0, 0.4);\n --hud-text-color: var(--text-color);\n --notifications-bg: darkslateblue;\n --skills-text-background: rgba(0, 0, 0, 0.5);\n --skills-text-color: var(--text-color);\n --skills-level-background: rgba(0, 0, 0, 0.5);\n --skills-level-color: orange;\n --skills-xp-bar-height: 40px;\n --skill-check-name-color: orange;\n --skill-check-difficulty: orange;\n --skill-check-success: green;\n --skill-check-failed: red;\n --skill-check-color: orange;\n --dialog-choice-color: orange;\n --dialog-choice-hover-color: var(--text-color);\n --inventory-text-background: rgba(0, 0, 0, 0.5);\n --inventory-text-color: var(--text-color);\n --inventory-amount-background: rgba(0, 0, 0, 0.5);\n --inventory-amount-color: orange;\n --quest-title-color: yellow;\n --completed-quest-title-color: grey;\n --objective-in-progress-color: white;\n --objective-completed-color: grey;\n}\n\n.list-item {\n display: inline-block;\n margin-right: 10px;\n}\n\n.list-enter-active,\n.list-leave-active {\n transition: all 0.3s ease;\n}\n\n/* .list-move {\n transition: transform 0.3s ease;\n} */\n\n.list-enter-from,\n.list-leave-to {\n opacity: 0;\n transform: translateX(300px);\n}\n\n.notification-item {\n display: inline-block;\n margin-right: 10px;\n}\n\n.notification-enter-active,\n.notification-leave-active {\n transition: all 0.3s ease;\n}\n\n/* .notification-move {\n transition: transform 0.3s ease;\n} */\n\n.notification-enter-from,\n.notification-leave-to {\n opacity: 0;\n transform: translateY(-300px);\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n.fade-in-enter-active {\n transition: opacity 0.1s ease;\n}\n\n.fade-in-enter-from {\n opacity: 0;\n}\n\nbody {\n padding: 0;\n margin: 0;\n font-family: Arial, sans-serif;\n background-color: black;\n}\n\n.select {\n background: var(--light-background);\n padding: 10px;\n}\n\n.option {\n background-color: var(--light-2);\n padding: 5px;\n color: var(--text-color);\n}\n\n.button {\n background: var(--light-background);\n color: var(--text-color);\n box-shadow: 0.4rem 0.4rem 2.4rem 0.2rem var(--shadow-1);\n border-radius: 100px;\n padding: 10px;\n font-weight: 800;\n font-size: 16px;\n margin: 10px;\n transition: 0.2s;\n}\n\n.button:focus,\n.button:hover {\n transform: translateY(-0.2rem);\n box-shadow: 0 0 2.4rem 0.2rem var(--shadow-2);\n}\n\n.disabled {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n pointer-events: none;\n}\n\n.button.disabled {\n box-shadow: unset;\n color: grey;\n background: var(--border-color);\n}\n\n.input {\n background: var(--light-background);\n color: var(--text-color);\n box-shadow: 0.4rem 0.4rem 2.4rem 0.2rem var(--shadow-1);\n border-radius: 100px;\n padding: 10px;\n font-weight: 800;\n font-size: 16px;\n margin: 10px;\n transition: 0.2s;\n}\n\n.input:focus,\n.input:hover {\n transform: translateY(-0.2rem);\n box-shadow: 0 0 2.4rem 0.2rem var(--shadow-2);\n}\n\na {\n color: pink;\n text-decoration: underline;\n}\n\nth,\ntd {\n padding: 4px;\n border: 1px solid var(--text-color);\n text-align: center;\n}\n\n#game-holder {\n width: 100vw;\n height: 100vh;\n padding: 0;\n margin: 0;\n top: 0;\n left: 0;\n background-color: black;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: -webkit-fill-available;\n}\n\n.title {\n font-size: 30px;\n font-weight: 700;\n text-align: center;\n}\n\n.container {\n padding: 20px;\n}\n\nh1,\nh2,\nh3,\nh4 {\n font-weight: 700;\n}\n\nh1 {\n font-size: 30px;\n}\n\nh2 {\n font-size: 26px;\n}\n\nh3 {\n font-size: 24px;\n}\n\nhr.solid {\n border: 1px solid var(--text-color);\n margin-top: 30px;\n margin-bottom: 30px;\n}\n\n.card-1 {\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\n transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n.card-1:hover {\n box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);\n}\n\n.card-2 {\n box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);\n}\n\n.card-3 {\n box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);\n}\n\n.card-4 {\n box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);\n}\n\n.card-5 {\n box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);\n}\n\n.dialog-choice {\n transition: 0.2s;\n}\n\n.dialog-choice:hover {\n transform: scale(1.05, 1.05);\n transform-origin: center;\n}\n\n/* Somewhat arcane CSS to force the hover color to override the child style.\nOtherwise hovering choices doesn't change the color of skill check prompts. */\n\n.dialog-choice:not(:hover) > .skill-check-name,\n.passive-skill-check > .skill-check-name {\n color: var(--skill-check-name-color);\n}\n\n.dialog-choice:not(:hover) > .skill-check-difficulty,\n.passive-skill-check > .skill-check-difficulty {\n color: var(--skill-check-difficulty);\n}\n\n.skill-check-difficulty {\n font-weight: 700;\n}\n\n.dialog-choice:not(:hover) > .skill-check-success,\n.passive-skill-check > .skill-check-success {\n color: var(--skill-check-success);\n}\n\n.dialog-choice:not(:hover) > .skill-check-failed,\n.passive-skill-check > .skill-check-failed {\n color: var(--skill-check-failed);\n}\n\n.dialog-choice:not(:hover) > .skill-check,\n.passive-skill-check.skill-check {\n color: var(--skill-check-color);\n}\n\n.narrat-canvas {\n position: absolute;\n height: 100%;\n top: 0;\n left: 0;\n}\n\n/* Looks ugly */\n\n/* @keyframes strike-anim {\n 0% {\n width: 0;\n }\n 100% {\n width: 100%;\n }\n}\n.strike-anim {\n position: relative;\n}\n.strike-anim::after {\n content: ' ';\n position: absolute;\n top: 50%;\n left: 0;\n width: 100%;\n height: 1px;\n background: var(--text-color);\n animation-name: strike-anim;\n animation-duration: 0.5s;\n animation-timing-function: linear;\n animation-iteration-count: 1;\n animation-fill-mode: forwards;\n} */\n\n#touchTrigger {\n pointer-events: none;\n}\n\n@media (min-width: 640px) {\n}\n\n@media (min-width: 768px) {\n}\n\n@media (min-width: 1024px) {\n}\n\n@media (min-width: 1280px) {\n}\n\n@media (min-width: 1536px) {\n}\n";
|
|
33
|
+
var css_248z = "/*! @import */\n\n/*! modern-normalize v1.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */\n\n/*\nDocument\n========\n*/\n\n/**\nUse a better box model (opinionated).\n*/\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n/**\nUse a more readable tab size (opinionated).\n*/\n\n:root {\n -moz-tab-size: 4;\n -o-tab-size: 4;\n tab-size: 4;\n}\n\n/**\n1. Correct the line height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n*/\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/*\nSections\n========\n*/\n\n/**\nRemove the margin in all browsers.\n*/\n\nbody {\n margin: 0;\n}\n\n/**\nImprove consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)\n*/\n\nbody {\n font-family:\n\t\tsystem-ui,\n\t\t-apple-system, /* Firefox supports this but not yet `system-ui` */\n\t\t'Segoe UI',\n\t\tRoboto,\n\t\tHelvetica,\n\t\tArial,\n\t\tsans-serif,\n\t\t'Apple Color Emoji',\n\t\t'Segoe UI Emoji';\n}\n\n/*\nGrouping content\n================\n*/\n\n/**\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n}\n\n/*\nText-level semantics\n====================\n*/\n\n/**\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr[title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/**\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)\n2. Correct the odd 'em' font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family:\n\t\tui-monospace,\n\t\tSFMono-Regular,\n\t\tConsolas,\n\t\t'Liberation Mono',\n\t\tMenlo,\n\t\tmonospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/**\nPrevent 'sub' and 'sup' elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\nTabular data\n============\n*/\n\n/**\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n}\n\n/*\nForms\n=====\n*/\n\n/**\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\nRemove the inheritance of text transform in Edge and Firefox.\n1. Remove the inheritance of text transform in Firefox.\n*/\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\nCorrect the inability to style clickable types in iOS and Safari.\n*/\n\nbutton,\n[type='button'],\n[type='reset'] {\n -webkit-appearance: button;\n}\n\n/**\nRemove the inner border and padding in Firefox.\n*/\n\n/**\nRestore the focus styles unset by the previous rule.\n*/\n\n/**\nRemove the additional ':invalid' styles in Firefox.\nSee: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737\n*/\n\n/**\nRemove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.\n*/\n\nlegend {\n padding: 0;\n}\n\n/**\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n/**\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n/**\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to 'inherit' in Safari.\n*/\n\n/*\nInteractive\n===========\n*/\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/**\n * Manually forked from SUIT CSS Base: https://github.com/suitcss/base\n * A thin layer on top of normalize.css that provides a starting point more\n * suitable for web applications.\n */\n\n/**\n * Removes the default spacing and border for appropriate elements.\n */\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nbutton {\n background-color: transparent;\n background-image: none;\n}\n\n/**\n * Work around a Firefox/IE bug where the transparent `button` background\n * results in a loss of the default `button` focus styles.\n */\n\nbutton:focus {\n outline: 1px dotted;\n outline: 5px auto -webkit-focus-ring-color;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nol,\nul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/**\n * Tailwind custom reset styles\n */\n\n/**\n * 1. Use the user's configured `sans` font-family (with Tailwind's default\n * sans-serif font stack as a fallback) as a sane default.\n * 2. Use Tailwind's default \"normal\" line-height so the user isn't forced\n * to override it to ensure consistency even when using the default theme.\n */\n\nhtml {\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 1 */\n line-height: 1.5; /* 2 */\n}\n\n/**\n * Inherit font-family and line-height from `html` so users can set them as\n * a class directly on the `html` element.\n */\n\nbody {\n font-family: inherit;\n line-height: inherit;\n}\n\n/**\n * 1. Prevent padding and border from affecting element width.\n *\n * We used to set this in the html element and inherit from\n * the parent element for everything else. This caused issues\n * in shadow-dom-enhanced elements like <details> where the content\n * is wrapped by a div with box-sizing set to `content-box`.\n *\n * https://github.com/mozdevs/cssremedy/issues/4\n *\n *\n * 2. Allow adding a border to an element by just adding a border-width.\n *\n * By default, the way the browser specifies that an element should have no\n * border is by setting it's border-style to `none` in the user-agent\n * stylesheet.\n *\n * In order to easily add borders to elements by just setting the `border-width`\n * property, we change the default border-style for all elements to `solid`, and\n * use border-width to hide them instead. This way our `border` utilities only\n * need to set the `border-width` property instead of the entire `border`\n * shorthand, making our border utilities much more straightforward to compose.\n *\n * https://github.com/tailwindcss/tailwindcss/pull/116\n */\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n/*\n * Ensure horizontal rules are visible by default\n */\n\nhr {\n border-top-width: 1px;\n}\n\n/**\n * Undo the `border-style: none` reset that Normalize applies to images so that\n * our `border-{width}` utilities have the expected effect.\n *\n * The Normalize reset is unnecessary for us since we default the border-width\n * to 0 on all elements.\n *\n * https://github.com/tailwindcss/tailwindcss/issues/362\n */\n\nimg {\n border-style: solid;\n}\n\ntextarea {\n resize: vertical;\n}\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n color: #9ca3af;\n}\n\ninput::placeholder,\ntextarea::placeholder {\n color: #9ca3af;\n}\n\nbutton {\n cursor: pointer;\n}\n\ntable {\n border-collapse: collapse;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/**\n * Reset links to optimize for opt-in styling instead of\n * opt-out.\n */\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/**\n * Reset form element properties that are easy to forget to\n * style explicitly so you don't inadvertently introduce\n * styles that deviate from your design system. These styles\n * supplement a partial reset that is already applied by\n * normalize.css.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n padding: 0;\n line-height: inherit;\n color: inherit;\n}\n\n/**\n * Use the configured 'mono' font family for elements that\n * are expected to be rendered with a monospace font, falling\n * back to the system monospace stack if there is no configured\n * 'mono' font family.\n */\n\npre,\ncode,\nkbd,\nsamp {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n/**\n * Make replaced elements `display: block` by default as that's\n * the behavior you want almost all of the time. Inspired by\n * CSS Remedy, with `svg` added as well.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block;\n vertical-align: middle;\n}\n\n/**\n * Constrain images and videos to the parent width and preserve\n * their instrinsic aspect ratio.\n *\n * https://github.com/mozdevs/cssremedy/issues/14\n */\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n.container {\n width: 100%;\n}\n\n@media (min-width: 640px) {\n .container {\n max-width: 640px;\n }\n}\n\n@media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n}\n\n@media (min-width: 1024px) {\n .container {\n max-width: 1024px;\n }\n}\n\n@media (min-width: 1280px) {\n .container {\n max-width: 1280px;\n }\n}\n\n@media (min-width: 1536px) {\n .container {\n max-width: 1536px;\n }\n}\n\n.bg-gray-800 {\n --tw-bg-opacity: 1;\n background-color: rgba(31, 41, 55, var(--tw-bg-opacity));\n}\n\n.border {\n border-width: 1px;\n}\n\n.flex {\n display: flex;\n}\n\n.table {\n display: table;\n}\n\n.grid {\n display: grid;\n}\n\n.hidden {\n display: none;\n}\n\n.flex-row {\n flex-direction: row;\n}\n\n.flex-col {\n flex-direction: column;\n}\n\n.flex-grow {\n flex-grow: 1;\n}\n\n.flex-shrink {\n flex-shrink: 1;\n}\n\n.list-disc {\n list-style-type: disc;\n}\n\n.absolute {\n position: absolute;\n}\n\n.resize {\n resize: both;\n}\n\n* {\n --tw-shadow: 0 0 #0000;\n}\n\n* {\n --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgba(59, 130, 246, 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n}\n\n.table-auto {\n table-layout: auto;\n}\n\n.line-through {\n text-decoration: line-through;\n}\n\n.w-full {\n width: 100%;\n}\n\n.gap-4 {\n gap: 1rem;\n}\n\n.grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n\n.transform {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n\n.transition {\n transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n\n@-webkit-keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@-webkit-keyframes ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n\n@keyframes ping {\n 75%, 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n\n@-webkit-keyframes pulse {\n 50% {\n opacity: .5;\n }\n}\n\n@keyframes pulse {\n 50% {\n opacity: .5;\n }\n}\n\n@-webkit-keyframes bounce {\n 0%, 100% {\n transform: translateY(-25%);\n -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);\n animation-timing-function: cubic-bezier(0.8,0,1,1);\n }\n\n 50% {\n transform: none;\n -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);\n animation-timing-function: cubic-bezier(0,0,0.2,1);\n }\n}\n\n@keyframes bounce {\n 0%, 100% {\n transform: translateY(-25%);\n -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1);\n animation-timing-function: cubic-bezier(0.8,0,1,1);\n }\n\n 50% {\n transform: none;\n -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1);\n animation-timing-function: cubic-bezier(0,0,0.2,1);\n }\n}\n\n@font-face {\n font-family: 'OpenDyslexic';\n\n src: url('fonts/OpenDyslexic.ttf.woff') format('woff'),\n url('fonts/OpenDyslexic.ttf.svg#OpenDyslexic') format('svg'),\n url('fonts/OpenDyslexic.ttf.eot'),\n url('fonts/OpenDyslexic.ttf.eot?#iefix') format('embedded-opentype');\n\n font-weight: normal;\n\n font-style: normal;\n}\n\n:root {\n --font-family: 'OpenDyslexic';\n --bg-color: #131720;\n --text-color: #d9e1f2;\n --primary: hsl(255, 30%, 55%);\n --focus: hsl(210, 90%, 50%);\n --secondary: #42b983;\n --border-color: hsla(0, 0%, 100%, 0.2);\n --light-1: hsl(210, 30%, 40%);\n --light-2: hsl(255, 30%, 50%);\n --light-background: linear-gradient(to right, var(--light-1), var(--light-2));\n --shadow-1: hsla(236, 50%, 50%, 0.3);\n --shadow-2: hsla(236, 50%, 50%, 0.4);\n --hud-background: rgba(0, 0, 0, 0.4);\n --hud-text-color: var(--text-color);\n --notifications-bg: darkslateblue;\n --skills-text-background: rgba(0, 0, 0, 0.5);\n --skills-text-color: var(--text-color);\n --skills-level-background: rgba(0, 0, 0, 0.5);\n --skills-level-color: orange;\n --skills-xp-bar-height: 40px;\n --skill-check-name-color: orange;\n --skill-check-difficulty: orange;\n --skill-check-success: green;\n --skill-check-failed: red;\n --skill-check-color: orange;\n --dialog-choice-color: orange;\n --dialog-choice-hover-color: var(--text-color);\n --inventory-text-background: rgba(0, 0, 0, 0.5);\n --inventory-text-color: var(--text-color);\n --inventory-amount-background: rgba(0, 0, 0, 0.5);\n --inventory-amount-color: orange;\n --quest-title-color: yellow;\n --completed-quest-title-color: grey;\n --objective-in-progress-color: white;\n --objective-completed-color: grey;\n}\n\nbody {\n font-family: var(--font-family);\n}\n\n* {\n font-family: var(--font-family);\n text-shadow: 1px 1px #000a;\n}\n\n.list-item {\n display: inline-block;\n margin-right: 10px;\n}\n\n.list-enter-active,\n.list-leave-active {\n transition: all 0.3s ease;\n}\n\n#app {\n background-image: url('img/h01.gif');\n background-size: cover;\n}\n\n/* .list-move {\n transition: transform 0.3s ease;\n} */\n\n.list-enter-from,\n.list-leave-to {\n opacity: 0;\n transform: translateX(300px);\n}\n\n.notification-item {\n display: inline-block;\n margin-right: 10px;\n}\n\n.notification-enter-active,\n.notification-leave-active {\n transition: all 0.3s ease;\n}\n\n/* .notification-move {\n transition: transform 0.3s ease;\n} */\n\n.notification-enter-from,\n.notification-leave-to {\n opacity: 0;\n transform: translateY(-300px);\n}\n\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity 0.3s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n\n.fade-in-enter-active {\n transition: opacity 0.1s ease;\n}\n\n.fade-in-enter-from {\n opacity: 0;\n}\n\nbody {\n padding: 0;\n margin: 0;\n font-family: Arial, sans-serif;\n background-color: black;\n}\n\n.select {\n background: var(--light-background);\n padding: 10px;\n}\n\n.option {\n background-color: var(--light-2);\n padding: 5px;\n color: var(--text-color);\n}\n\n.button {\n background: var(--light-background);\n color: var(--text-color);\n box-shadow: 0.4rem 0.5rem 2.4rem 0.2rem var(--shadow-1), inset -2px -4px #0006,\n inset 2px 2px #fff7;\n border-radius: 10px;\n padding: 10px;\n font-weight: 800;\n font-size: 16px;\n margin: 10px;\n transition: 0.2s;\n box-shadow: inset -2px -4px #0006, inset 2px 2px #fff7;\n}\n\n.button.large {\n border-radius: 20px;\n}\n\n.menu-button {\n border-radius: 5px;\n}\n\n.button.main-menu-button {\n border-radius: 20px;\n}\n\n.button:focus,\n.button:hover {\n transform: translateY(-0.2rem);\n box-shadow: 0 0 1rem 0.2rem var(--shadow-2), inset -2px -4px #0006,\n inset 2px 2px #fff7;\n}\n\n.disabled {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n pointer-events: none;\n}\n\n.button.disabled {\n box-shadow: unset;\n color: grey;\n background: var(--border-color);\n}\n\n.input {\n background: var(--light-background);\n color: var(--text-color);\n box-shadow: 0.4rem 0.4rem 2.4rem 0.2rem var(--shadow-1);\n border-radius: 100px;\n padding: 10px;\n font-weight: 800;\n font-size: 16px;\n margin: 10px;\n transition: 0.2s;\n}\n\n.input:focus,\n.input:hover {\n transform: translateY(-0.2rem);\n box-shadow: 0 0 2.4rem 0.2rem var(--shadow-2);\n}\n\na {\n color: pink;\n text-decoration: underline;\n}\n\nth,\ntd {\n padding: 4px;\n border: 1px solid var(--text-color);\n text-align: center;\n}\n\n#game-holder {\n width: 100vw;\n height: 100vh;\n padding: 0;\n margin: 0;\n top: 0;\n left: 0;\n background-color: black;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: -webkit-fill-available;\n}\n\n.title {\n font-size: 30px;\n font-weight: 700;\n text-align: center;\n}\n\n.container {\n padding: 20px;\n}\n\nh1,\nh2,\nh3,\nh4 {\n font-weight: 700;\n}\n\nh1 {\n font-size: 30px;\n}\n\nh2 {\n font-size: 26px;\n}\n\nh3 {\n font-size: 24px;\n}\n\nhr.solid {\n border: 1px solid var(--text-color);\n margin-top: 30px;\n margin-bottom: 30px;\n}\n\n.card-1 {\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);\n transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n.card-1:hover {\n box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);\n}\n\n.card-2 {\n box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);\n}\n\n.card-3 {\n box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);\n}\n\n.card-4 {\n box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);\n}\n\n.card-5 {\n box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);\n}\n\n.dialog-choice {\n transition: 0.2s;\n}\n\n.dialog-choice:hover {\n transform: scale(1.05, 1.05);\n transform-origin: center;\n}\n\n/* Somewhat arcane CSS to force the hover color to override the child style.\nOtherwise hovering choices doesn't change the color of skill check prompts. */\n\n.dialog-choice:not(:hover) > .skill-check-name,\n.passive-skill-check > .skill-check-name {\n color: var(--skill-check-name-color);\n}\n\n.dialog-choice:not(:hover) > .skill-check-difficulty,\n.passive-skill-check > .skill-check-difficulty {\n color: var(--skill-check-difficulty);\n}\n\n.skill-check-difficulty {\n font-weight: 700;\n}\n\n.dialog-choice:not(:hover) > .skill-check-success,\n.passive-skill-check > .skill-check-success {\n color: var(--skill-check-success);\n}\n\n.dialog-choice:not(:hover) > .skill-check-failed,\n.passive-skill-check > .skill-check-failed {\n color: var(--skill-check-failed);\n}\n\n.dialog-choice:not(:hover) > .skill-check,\n.passive-skill-check.skill-check {\n color: var(--skill-check-color);\n}\n\n.narrat-canvas {\n position: absolute;\n height: 100%;\n top: 0;\n left: 0;\n}\n\n/* Looks ugly */\n\n/* @keyframes strike-anim {\n 0% {\n width: 0;\n }\n 100% {\n width: 100%;\n }\n}\n.strike-anim {\n position: relative;\n}\n.strike-anim::after {\n content: ' ';\n position: absolute;\n top: 50%;\n left: 0;\n width: 100%;\n height: 1px;\n background: var(--text-color);\n animation-name: strike-anim;\n animation-duration: 0.5s;\n animation-timing-function: linear;\n animation-iteration-count: 1;\n animation-fill-mode: forwards;\n} */\n\n#touchTrigger {\n pointer-events: none;\n}\n\n@media (min-width: 640px) {\n}\n\n@media (min-width: 768px) {\n}\n\n@media (min-width: 1024px) {\n}\n\n@media (min-width: 1280px) {\n}\n\n@media (min-width: 1536px) {\n}\n";
|
|
34
34
|
styleInject(css_248z);
|
|
35
35
|
|
|
36
36
|
const f=ref([]),v=ref(null),m=ref(null),g=ref(null),h=reactive({current:""}),y=[],b=ref(!1),k=readonly(f),w=readonly(v),M=readonly(m),q=readonly(g),x=readonly(h),$=(e=w.value)=>{h.current=e;const t=k.value.findIndex((t=>t.name===e)),n=k.value.map((e=>e.name));for(let a=0;a<n.length;a++){if(a>0&&a<n.length-1){const e=n[a]+"Minus",r=n[a]+"Plus";h[e]=t<=a,h[r]=t>=a;}h[n[a]]=n[a]===e;}},V=(e=M.value)=>{h.orientation=e,h.isLandscape="landscape"===e,h.isPortrait="portrait"===e;},O=(e=q.value||"light")=>{h.theme=e,h.isDark="dark"===e,h.isLight="light"===e;};function j(e,t){if("undefined"==typeof window||!window.matchMedia)return !1;if("undefined"!=typeof window&&!window.matchMedia)return console.error("Vue3 Mq: No MatchMedia support detected in this browser. Responsive breakpoints not available."),!1;{b.value=!0;const n=window.matchMedia(e),a=({matches:e})=>{e&&t();};y.push({mql:n,cb:a});n.addEventListener&&"function"==typeof n.addEventListener?n.addEventListener("change",a):n.addListener(a),a(n);}}var L=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",bootstrap5:{xs:0,sm:576,md:768,lg:992,xl:1200,xxl:1400},bootstrap4:{xs:0,sm:576,md:768,lg:992,xl:1200},bootstrap3:{xs:0,sm:768,md:992,lg:1200},vuetify:{xs:0,sm:600,md:960,lg:1264,xl:1904},tailwind:{xs:0,sm:640,md:768,lg:1024,xl:1280,xxl:1536},devices:{phone:0,tablet:768,laptop:1370,desktop:1906}});const T=e=>{if(!e||"object"!=typeof e)return !1;const t=[];for(let n in e){const a=parseFloat(e[n]);n&&"string"==typeof n?/^[^a-z]/i.test(n)||/[^a-zA-Z0-9_]/.test(n)?console.warn(`Vue3 Mq: "${n}" is an invalid breakpoint key. Breakpoint keys must start with a letter and contain only alphanumeric characters and underscores. Skipping.`):!a&&0!==a||isNaN(a)||a<0?console.warn(`Vue3 Mq: "${n}: ${e[n]}" is not a valid breakpoint. Breakpoints should be a number of zero or above. Skipping.`):t.push({name:n,min:a}):console.warn(`Vue3 Mq: Invalid or missing breakpoint key (${JSON.stringify(n)}). Skipping.`);}t.some((e=>0===e.min))||console.warn("Vue3 Mq: You have not declared a breakpoint with a minimum value of 0. There may be screen sizes to which Vue3Mq does not respond.");return new Set(t.map((e=>e.min))).size<t.length&&console.warn("Vue3 Mq: Your breakpoint configuration contains duplicate values. Behaviour may be unpredictable."),0!==t.length&&t.sort(((e,t)=>e.min-t.min))};function R({breakpoints:e,preset:t}){const n=(e=>{if("string"==typeof e&&L[e])return L[e];{const t=Object.keys(L);return console.error(`Vue3 Mq: "${e}" is not a valid preset. Available options are: ${t.join(", ")}`),!1}})(t),a=T(e);if(!1===n&&!a)throw new TypeError("Vue3 Mq: You must provide a valid preset, or valid breakpoint settings.");var r;r=a||T(n),f.value=r,function(){for(;y.length>0;){const e=y.shift();if(e&&"object"==typeof e){const{mql:t,cb:n}=e;t.addEventListener&&"function"==typeof t.addEventListener?t.removeEventListener("change",n):t.removeListener(n);}}}(),(()=>{const e=Object.keys(h);for(let t of e)delete h[t];$(),V(),O();})();const o=k.value.reduce(((e,t,n,a)=>{const r=`(min-width: ${t.min}px)`,o=n<a.length-1?`(max-width: ${a[n+1].min-1}px)`:null,i=r+(o?" and "+o:"");return Object.assign(e,{[t.name]:i})}),{});for(const i in o){j(o[i],(()=>{$(i);}));}["portrait","landscape"].forEach((e=>{j(`(orientation: ${e})`,(()=>{V(e);}));})),["light","dark"].forEach((e=>{j(`(prefers-color-scheme: ${e})`,(()=>{O(e);}));}));}var N={install:(e,{preset:t="bootstrap5",breakpoints:n,defaultBreakpoint:a,defaultOrientation:r="landscape",defaultTheme:o}={})=>{try{const l=!1===["landscape","portrait"].includes(s=r)?(console.error(`Vue3 Mq: "${s}" is not a valid default orientation. Reverting to unset value.`),null):s,u=((e=null)=>!1===["dark","light"].includes(e)&&null!==e?(console.error(`Vue3 Mq: "${e}" is not a valid default theme. Reverting to unset value.`),null):e)(o);i=a,v.value=i,(e=>{m.value=e;})(l),(e=>{g.value=e;})(u),e.provide("mq",x),e.provide("updateBreakpoints",R),R({breakpoints:n,preset:t});}catch(l){console.error(l);}var i,s;}};
|
|
@@ -104,9 +104,11 @@ const defaultConfig = {
|
|
|
104
104
|
},
|
|
105
105
|
},
|
|
106
106
|
quests: {},
|
|
107
|
+
audioTriggers: {},
|
|
107
108
|
};
|
|
108
109
|
|
|
109
110
|
function parserError(ctx, line, text) {
|
|
111
|
+
console.error(`Parser error: ${ctx.fileName}:${ctx.currentLine}`, text);
|
|
110
112
|
const errorText = `[Parser Error] in <span class="error-filename">${ctx.fileName}:${line + 1}</span> - <b>${text}</b>`;
|
|
111
113
|
error(errorText);
|
|
112
114
|
}
|
|
@@ -3445,6 +3447,7 @@ const useAudio = defineStore('audio', {
|
|
|
3445
3447
|
|
|
3446
3448
|
const audio = {};
|
|
3447
3449
|
howler.Howler.volume(0.5);
|
|
3450
|
+
let audioTriggers = {};
|
|
3448
3451
|
async function loadAudioAssets(config) {
|
|
3449
3452
|
logger.log(`Loading audio`);
|
|
3450
3453
|
const loadingPromises = [];
|
|
@@ -3473,8 +3476,16 @@ async function loadAudioAssets(config) {
|
|
|
3473
3476
|
}
|
|
3474
3477
|
loadingPromises.push(loadAudio(key, config.audio[key]));
|
|
3475
3478
|
}
|
|
3479
|
+
if (config.audioTriggers) {
|
|
3480
|
+
audioTriggers = config.audioTriggers;
|
|
3481
|
+
}
|
|
3476
3482
|
return Promise.all(loadingPromises);
|
|
3477
3483
|
}
|
|
3484
|
+
function audioEvent(event) {
|
|
3485
|
+
if (audioTriggers[event]) {
|
|
3486
|
+
playAudio(audioTriggers[event]);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3478
3489
|
async function loadAudio(key, config) {
|
|
3479
3490
|
return new Promise((resolve, reject) => {
|
|
3480
3491
|
logger.log(`Loading audio ${config.src}`);
|
|
@@ -3565,228 +3576,6 @@ function randomId() {
|
|
|
3565
3576
|
return `${Date.now() - Math.floor(Math.random() * 99999999)}`;
|
|
3566
3577
|
}
|
|
3567
3578
|
|
|
3568
|
-
// Generate a pinia store named notifications with a state using the type NotificationsState, and save type NotificationsSave, with actions:
|
|
3569
|
-
// addNotification(text: string): Adds a new notification to the state, and deletes it after a timeout
|
|
3570
|
-
// deleteNotification(id: string): Deletes a notification from the state
|
|
3571
|
-
const useNotifications = defineStore('notifications', {
|
|
3572
|
-
state: () => ({ notifications: {} }),
|
|
3573
|
-
actions: {
|
|
3574
|
-
async addNotification(text) {
|
|
3575
|
-
const id = `${Date.now()}-${Math.random() * 10000}`;
|
|
3576
|
-
this.notifications[id] = {
|
|
3577
|
-
text,
|
|
3578
|
-
};
|
|
3579
|
-
if (getConfig().notifications.alsoPrintInDialogue) {
|
|
3580
|
-
writeText(`[NOTIFICATION] ${text}`);
|
|
3581
|
-
}
|
|
3582
|
-
await timeout(getConfig().notifications.timeOnScreen * 1000);
|
|
3583
|
-
this.deleteNotification(id);
|
|
3584
|
-
},
|
|
3585
|
-
deleteNotification(id) {
|
|
3586
|
-
delete this.notifications[id];
|
|
3587
|
-
},
|
|
3588
|
-
},
|
|
3589
|
-
});
|
|
3590
|
-
|
|
3591
|
-
// create a pinia store named inventory with a state containing items and actions to add and delete items
|
|
3592
|
-
// create a pinia store named inventory with a state of type ItemState and actions to add and delete items. Adding items should increase the amount of any existing item that matches the id.
|
|
3593
|
-
const useInventory = defineStore('inventory', {
|
|
3594
|
-
state: () => ({
|
|
3595
|
-
items: {},
|
|
3596
|
-
interactionTags: {},
|
|
3597
|
-
}),
|
|
3598
|
-
actions: {
|
|
3599
|
-
generateSaveData() {
|
|
3600
|
-
return {
|
|
3601
|
-
items: this.items,
|
|
3602
|
-
interactionTags: this.interactionTags,
|
|
3603
|
-
};
|
|
3604
|
-
},
|
|
3605
|
-
loadSaveData(save) {
|
|
3606
|
-
this.items = { ...this.items, ...save.items };
|
|
3607
|
-
this.interactionTags = { ...save.interactionTags };
|
|
3608
|
-
},
|
|
3609
|
-
setupItems(items) {
|
|
3610
|
-
Object.keys(items).forEach((key) => {
|
|
3611
|
-
this.items[key] = {
|
|
3612
|
-
amount: 0,
|
|
3613
|
-
id: key,
|
|
3614
|
-
};
|
|
3615
|
-
});
|
|
3616
|
-
},
|
|
3617
|
-
getExistingItem(id) {
|
|
3618
|
-
return this.items[id];
|
|
3619
|
-
},
|
|
3620
|
-
getItemAmount(id) {
|
|
3621
|
-
return this.getExistingItem(id)?.amount || 0;
|
|
3622
|
-
},
|
|
3623
|
-
add(item) {
|
|
3624
|
-
const existingItem = this.getExistingItem(item.id);
|
|
3625
|
-
if (existingItem) {
|
|
3626
|
-
existingItem.amount += item.amount;
|
|
3627
|
-
}
|
|
3628
|
-
else {
|
|
3629
|
-
this.items[item.id] = { ...item };
|
|
3630
|
-
}
|
|
3631
|
-
useNotifications().addNotification(`Received item: ${getItemConfig(item.id).name} x ${item.amount}`);
|
|
3632
|
-
},
|
|
3633
|
-
enableInteraction(tag) {
|
|
3634
|
-
if (!tag) {
|
|
3635
|
-
tag = 'default';
|
|
3636
|
-
}
|
|
3637
|
-
this.interactionTags[tag] = {
|
|
3638
|
-
blockedInteraction: false,
|
|
3639
|
-
};
|
|
3640
|
-
},
|
|
3641
|
-
disableInteraction(tag) {
|
|
3642
|
-
if (!tag) {
|
|
3643
|
-
tag = 'default';
|
|
3644
|
-
}
|
|
3645
|
-
this.interactionTags[tag] = {
|
|
3646
|
-
blockedInteraction: true,
|
|
3647
|
-
};
|
|
3648
|
-
},
|
|
3649
|
-
onScriptStart() {
|
|
3650
|
-
const tags = getConfig().interactionTags;
|
|
3651
|
-
Object.keys(tags).forEach((tag) => {
|
|
3652
|
-
const conf = tags[tag];
|
|
3653
|
-
if (conf.onlyInteractOutsideOfScripts) {
|
|
3654
|
-
this.disableInteraction(tag);
|
|
3655
|
-
}
|
|
3656
|
-
});
|
|
3657
|
-
},
|
|
3658
|
-
onScriptEnd() {
|
|
3659
|
-
const tags = getConfig().interactionTags;
|
|
3660
|
-
Object.keys(tags).forEach((tag) => {
|
|
3661
|
-
const conf = tags[tag];
|
|
3662
|
-
if (conf.onlyInteractOutsideOfScripts) {
|
|
3663
|
-
this.enableInteraction(tag);
|
|
3664
|
-
}
|
|
3665
|
-
});
|
|
3666
|
-
},
|
|
3667
|
-
isInteractionTagBlocked(tag) {
|
|
3668
|
-
if (!tag) {
|
|
3669
|
-
tag = 'default';
|
|
3670
|
-
}
|
|
3671
|
-
if (this.interactionTags[tag]) {
|
|
3672
|
-
return this.interactionTags[tag].blockedInteraction;
|
|
3673
|
-
}
|
|
3674
|
-
return false;
|
|
3675
|
-
},
|
|
3676
|
-
remove(item) {
|
|
3677
|
-
const existingItem = this.getExistingItem(item.id);
|
|
3678
|
-
if (existingItem) {
|
|
3679
|
-
existingItem.amount -= item.amount;
|
|
3680
|
-
useNotifications().addNotification(`Lost item: ${getItemConfig(item.id).name} x ${item.amount}`);
|
|
3681
|
-
if (existingItem.amount <= 0) {
|
|
3682
|
-
this.deleteItem(item.id);
|
|
3683
|
-
}
|
|
3684
|
-
}
|
|
3685
|
-
},
|
|
3686
|
-
deleteItem(id) {
|
|
3687
|
-
const existingItem = this.getExistingItem(id);
|
|
3688
|
-
if (existingItem) {
|
|
3689
|
-
this.items[id].amount = 0;
|
|
3690
|
-
}
|
|
3691
|
-
},
|
|
3692
|
-
},
|
|
3693
|
-
});
|
|
3694
|
-
|
|
3695
|
-
const everyObject = (object, predicate) => {
|
|
3696
|
-
for (const key in object) {
|
|
3697
|
-
if (!predicate(object[key])) {
|
|
3698
|
-
return false;
|
|
3699
|
-
}
|
|
3700
|
-
}
|
|
3701
|
-
return true;
|
|
3702
|
-
};
|
|
3703
|
-
const filterObject = (object, predicate) => {
|
|
3704
|
-
const result = {};
|
|
3705
|
-
for (const key in object) {
|
|
3706
|
-
if (predicate(object[key])) {
|
|
3707
|
-
result[key] = object[key];
|
|
3708
|
-
}
|
|
3709
|
-
}
|
|
3710
|
-
return result;
|
|
3711
|
-
};
|
|
3712
|
-
|
|
3713
|
-
const useQuests = defineStore('quests', {
|
|
3714
|
-
state: () => ({
|
|
3715
|
-
quests: {},
|
|
3716
|
-
}),
|
|
3717
|
-
actions: {
|
|
3718
|
-
getQuest(questId) {
|
|
3719
|
-
const quest = this.quests[questId];
|
|
3720
|
-
if (quest) {
|
|
3721
|
-
return quest;
|
|
3722
|
-
}
|
|
3723
|
-
error(`Quest ${questId} doesn't exist!`);
|
|
3724
|
-
},
|
|
3725
|
-
getObjective(quest, objectiveId) {
|
|
3726
|
-
const questObjective = this.getQuest(quest).objectives[objectiveId];
|
|
3727
|
-
if (questObjective) {
|
|
3728
|
-
return questObjective;
|
|
3729
|
-
}
|
|
3730
|
-
error(`Objective ${objectiveId} doesn't exist in quest ${quest}!`);
|
|
3731
|
-
},
|
|
3732
|
-
setupQuests(quests) {
|
|
3733
|
-
// iterate through quests to generate quest states to add to this.quests object
|
|
3734
|
-
for (const key of Object.keys(quests)) {
|
|
3735
|
-
const data = quests[key];
|
|
3736
|
-
this.quests[key] = {
|
|
3737
|
-
id: key,
|
|
3738
|
-
state: 'hidden',
|
|
3739
|
-
objectives: {},
|
|
3740
|
-
};
|
|
3741
|
-
// iterate through data.objectives to populate the objectives array of this.quests[key]
|
|
3742
|
-
for (const objectiveKey of Object.keys(data.objectives)) {
|
|
3743
|
-
const objective = data.objectives[objectiveKey];
|
|
3744
|
-
this.quests[key].objectives[objectiveKey] = {
|
|
3745
|
-
id: objectiveKey,
|
|
3746
|
-
state: objective.hidden ? 'hidden' : 'unlocked',
|
|
3747
|
-
};
|
|
3748
|
-
}
|
|
3749
|
-
}
|
|
3750
|
-
},
|
|
3751
|
-
startQuest(questId) {
|
|
3752
|
-
this.getQuest(questId).state = 'unlocked';
|
|
3753
|
-
useNotifications().addNotification(`Started quest: ${getQuestConfig(questId).title}`);
|
|
3754
|
-
},
|
|
3755
|
-
startObjective(questId, objectiveId) {
|
|
3756
|
-
this.getObjective(questId, objectiveId).state = 'unlocked';
|
|
3757
|
-
useNotifications().addNotification(`New quest objective: ${getObjectiveConfig(questId, objectiveId).description}`);
|
|
3758
|
-
},
|
|
3759
|
-
completeObjective(questId, objectiveId) {
|
|
3760
|
-
this.getObjective(questId, objectiveId).state = 'completed';
|
|
3761
|
-
useNotifications().addNotification(`Objective completed!`);
|
|
3762
|
-
},
|
|
3763
|
-
completeQuest(questId, ending) {
|
|
3764
|
-
this.getQuest(questId).state = 'completed';
|
|
3765
|
-
if (ending) {
|
|
3766
|
-
this.getQuest(questId).ending = ending;
|
|
3767
|
-
}
|
|
3768
|
-
useNotifications().addNotification(`Quest completed: ${getQuestConfig(questId).title}`);
|
|
3769
|
-
},
|
|
3770
|
-
isQuestCompleted(questId) {
|
|
3771
|
-
const quest = this.getQuest(questId);
|
|
3772
|
-
return everyObject(quest.objectives, (objective) => objective.state === 'completed');
|
|
3773
|
-
},
|
|
3774
|
-
removeQuest(id) {
|
|
3775
|
-
delete this.quests[id];
|
|
3776
|
-
},
|
|
3777
|
-
generateSaveData() {
|
|
3778
|
-
return {
|
|
3779
|
-
quests: {
|
|
3780
|
-
...this.quests,
|
|
3781
|
-
},
|
|
3782
|
-
};
|
|
3783
|
-
},
|
|
3784
|
-
loadSaveData(data) {
|
|
3785
|
-
this.quests = data.quests;
|
|
3786
|
-
},
|
|
3787
|
-
},
|
|
3788
|
-
});
|
|
3789
|
-
|
|
3790
3579
|
var isMergeableObject = function isMergeableObject(value) {
|
|
3791
3580
|
return isNonNullObject(value)
|
|
3792
3581
|
&& !isSpecial(value)
|
|
@@ -3919,6 +3708,29 @@ var deepmerge_1 = deepmerge;
|
|
|
3919
3708
|
|
|
3920
3709
|
var cjs = deepmerge_1;
|
|
3921
3710
|
|
|
3711
|
+
// Generate a pinia store named notifications with a state using the type NotificationsState, and save type NotificationsSave, with actions:
|
|
3712
|
+
// addNotification(text: string): Adds a new notification to the state, and deletes it after a timeout
|
|
3713
|
+
// deleteNotification(id: string): Deletes a notification from the state
|
|
3714
|
+
const useNotifications = defineStore('notifications', {
|
|
3715
|
+
state: () => ({ notifications: {} }),
|
|
3716
|
+
actions: {
|
|
3717
|
+
async addNotification(text) {
|
|
3718
|
+
const id = `${Date.now()}-${Math.random() * 10000}`;
|
|
3719
|
+
this.notifications[id] = {
|
|
3720
|
+
text,
|
|
3721
|
+
};
|
|
3722
|
+
if (getConfig().notifications.alsoPrintInDialogue) {
|
|
3723
|
+
writeText(`[NOTIFICATION] ${text}`);
|
|
3724
|
+
}
|
|
3725
|
+
await timeout(getConfig().notifications.timeOnScreen * 1000);
|
|
3726
|
+
this.deleteNotification(id);
|
|
3727
|
+
},
|
|
3728
|
+
deleteNotification(id) {
|
|
3729
|
+
delete this.notifications[id];
|
|
3730
|
+
},
|
|
3731
|
+
},
|
|
3732
|
+
});
|
|
3733
|
+
|
|
3922
3734
|
// Create a pinia store named skills with a state using the type Skills, with actions:
|
|
3923
3735
|
// setupSkillCheck(skillCheck: SkillCheckState, id: string)
|
|
3924
3736
|
// passSkillCheck(skillCheckId: string)
|
|
@@ -3937,13 +3749,19 @@ const useSkills = defineStore('skills', {
|
|
|
3937
3749
|
setupSkillCheck(skillCheck, id) {
|
|
3938
3750
|
this.skillChecks[id] = skillCheck;
|
|
3939
3751
|
},
|
|
3940
|
-
passSkillCheck(skillCheckId) {
|
|
3941
|
-
this.skillChecks[skillCheckId].
|
|
3942
|
-
this.skillChecks[skillCheckId].
|
|
3752
|
+
passSkillCheck(skillCheckId, hide) {
|
|
3753
|
+
this.skillChecks[skillCheckId].happened = true;
|
|
3754
|
+
this.skillChecks[skillCheckId].succeeded = true;
|
|
3755
|
+
if (hide) {
|
|
3756
|
+
this.skillChecks[skillCheckId].hidden = true;
|
|
3757
|
+
}
|
|
3943
3758
|
},
|
|
3944
|
-
failSkillCheck(skillCheckId) {
|
|
3945
|
-
this.skillChecks[skillCheckId].
|
|
3946
|
-
this.skillChecks[skillCheckId].
|
|
3759
|
+
failSkillCheck(skillCheckId, hide) {
|
|
3760
|
+
this.skillChecks[skillCheckId].happened = true;
|
|
3761
|
+
this.skillChecks[skillCheckId].succeeded = false;
|
|
3762
|
+
if (hide) {
|
|
3763
|
+
this.skillChecks[skillCheckId].hidden = true;
|
|
3764
|
+
}
|
|
3947
3765
|
},
|
|
3948
3766
|
generateSaveData() {
|
|
3949
3767
|
return {
|
|
@@ -3951,6 +3769,20 @@ const useSkills = defineStore('skills', {
|
|
|
3951
3769
|
skills: this.skills,
|
|
3952
3770
|
};
|
|
3953
3771
|
},
|
|
3772
|
+
getSkillCheck(id) {
|
|
3773
|
+
if (!this.skillChecks[id]) {
|
|
3774
|
+
this.setupSkillCheck(this.createSkillCheckState(), id);
|
|
3775
|
+
}
|
|
3776
|
+
return this.skillChecks[id];
|
|
3777
|
+
},
|
|
3778
|
+
createSkillCheckState() {
|
|
3779
|
+
const skillCheck = {
|
|
3780
|
+
happened: false,
|
|
3781
|
+
succeeded: false,
|
|
3782
|
+
hidden: false,
|
|
3783
|
+
};
|
|
3784
|
+
return skillCheck;
|
|
3785
|
+
},
|
|
3954
3786
|
loadSaveData(data) {
|
|
3955
3787
|
this.skillChecks = cjs(this.skillChecks, data.skillChecks);
|
|
3956
3788
|
this.skills = cjs(this.skills, data.skills);
|
|
@@ -4009,8 +3841,266 @@ function getFile(url) {
|
|
|
4009
3841
|
});
|
|
4010
3842
|
}
|
|
4011
3843
|
|
|
4012
|
-
// Create a pinia store named
|
|
4013
|
-
//
|
|
3844
|
+
// Create a pinia store named hud with a state using the type HudState, and save type HudSave, with actions:
|
|
3845
|
+
// setupHudStats(stats: { [key: string]: HudStatConfig }): Iterates the stats argument to add new stats to the state
|
|
3846
|
+
// setStat(stat: string, value: number): Sets the value of a stat
|
|
3847
|
+
// addStat(stat: string, value: number): Adds a value to a stat
|
|
3848
|
+
// generateSaveData(): Function that generates a HudSave object from the data in the state
|
|
3849
|
+
// loadSaveData(data: HudSave): Function that loads the data into the state
|
|
3850
|
+
const useHud = defineStore('hud', {
|
|
3851
|
+
state: () => ({
|
|
3852
|
+
hudStats: {},
|
|
3853
|
+
}),
|
|
3854
|
+
actions: {
|
|
3855
|
+
setupHudStats(stats) {
|
|
3856
|
+
for (const stat in stats) {
|
|
3857
|
+
this.hudStats[stat] = {
|
|
3858
|
+
value: stats[stat].startingValue,
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
},
|
|
3862
|
+
setStat(stat, value) {
|
|
3863
|
+
this.hudStats[stat].value = value;
|
|
3864
|
+
},
|
|
3865
|
+
addStat(stat, value) {
|
|
3866
|
+
this.hudStats[stat].value += value;
|
|
3867
|
+
},
|
|
3868
|
+
getStat(stat) {
|
|
3869
|
+
return this.hudStats[stat];
|
|
3870
|
+
},
|
|
3871
|
+
getStatValue(stat) {
|
|
3872
|
+
return this.hudStats[stat].value;
|
|
3873
|
+
},
|
|
3874
|
+
generateSaveData() {
|
|
3875
|
+
return {
|
|
3876
|
+
hudStats: this.hudStats,
|
|
3877
|
+
};
|
|
3878
|
+
},
|
|
3879
|
+
loadSaveData(data) {
|
|
3880
|
+
this.hudStats = cjs(this.hudStats, data.hudStats);
|
|
3881
|
+
},
|
|
3882
|
+
},
|
|
3883
|
+
});
|
|
3884
|
+
|
|
3885
|
+
// create a pinia store named inventory with a state containing items and actions to add and delete items
|
|
3886
|
+
// create a pinia store named inventory with a state of type ItemState and actions to add and delete items. Adding items should increase the amount of any existing item that matches the id.
|
|
3887
|
+
const useInventory = defineStore('inventory', {
|
|
3888
|
+
state: () => ({
|
|
3889
|
+
items: {},
|
|
3890
|
+
interactionTags: {},
|
|
3891
|
+
}),
|
|
3892
|
+
actions: {
|
|
3893
|
+
generateSaveData() {
|
|
3894
|
+
return {
|
|
3895
|
+
items: this.items,
|
|
3896
|
+
interactionTags: this.interactionTags,
|
|
3897
|
+
};
|
|
3898
|
+
},
|
|
3899
|
+
loadSaveData(save) {
|
|
3900
|
+
this.items = { ...this.items, ...save.items };
|
|
3901
|
+
this.interactionTags = { ...save.interactionTags };
|
|
3902
|
+
},
|
|
3903
|
+
setupItems(items) {
|
|
3904
|
+
Object.keys(items).forEach((key) => {
|
|
3905
|
+
this.items[key] = {
|
|
3906
|
+
amount: 0,
|
|
3907
|
+
id: key,
|
|
3908
|
+
};
|
|
3909
|
+
});
|
|
3910
|
+
},
|
|
3911
|
+
hasItem(itemId, amount) {
|
|
3912
|
+
if (!amount) {
|
|
3913
|
+
amount = 1;
|
|
3914
|
+
}
|
|
3915
|
+
return this.items[itemId]?.amount >= amount;
|
|
3916
|
+
},
|
|
3917
|
+
getExistingItem(id) {
|
|
3918
|
+
return this.items[id];
|
|
3919
|
+
},
|
|
3920
|
+
getItemAmount(id) {
|
|
3921
|
+
return this.getExistingItem(id)?.amount || 0;
|
|
3922
|
+
},
|
|
3923
|
+
add(item) {
|
|
3924
|
+
const existingItem = this.getExistingItem(item.id);
|
|
3925
|
+
if (existingItem) {
|
|
3926
|
+
existingItem.amount += item.amount;
|
|
3927
|
+
}
|
|
3928
|
+
else {
|
|
3929
|
+
this.items[item.id] = { ...item };
|
|
3930
|
+
}
|
|
3931
|
+
useNotifications().addNotification(`Received item: ${getItemConfig(item.id).name} x ${item.amount}`);
|
|
3932
|
+
},
|
|
3933
|
+
enableInteraction(tag) {
|
|
3934
|
+
if (!tag) {
|
|
3935
|
+
tag = 'default';
|
|
3936
|
+
}
|
|
3937
|
+
this.interactionTags[tag] = {
|
|
3938
|
+
blockedInteraction: false,
|
|
3939
|
+
};
|
|
3940
|
+
},
|
|
3941
|
+
disableInteraction(tag) {
|
|
3942
|
+
if (!tag) {
|
|
3943
|
+
tag = 'default';
|
|
3944
|
+
}
|
|
3945
|
+
this.interactionTags[tag] = {
|
|
3946
|
+
blockedInteraction: true,
|
|
3947
|
+
};
|
|
3948
|
+
},
|
|
3949
|
+
onScriptStart() {
|
|
3950
|
+
const tags = getConfig().interactionTags;
|
|
3951
|
+
Object.keys(tags).forEach((tag) => {
|
|
3952
|
+
const conf = tags[tag];
|
|
3953
|
+
if (conf.onlyInteractOutsideOfScripts) {
|
|
3954
|
+
this.disableInteraction(tag);
|
|
3955
|
+
}
|
|
3956
|
+
});
|
|
3957
|
+
},
|
|
3958
|
+
onScriptEnd() {
|
|
3959
|
+
const tags = getConfig().interactionTags;
|
|
3960
|
+
Object.keys(tags).forEach((tag) => {
|
|
3961
|
+
const conf = tags[tag];
|
|
3962
|
+
if (conf.onlyInteractOutsideOfScripts) {
|
|
3963
|
+
this.enableInteraction(tag);
|
|
3964
|
+
}
|
|
3965
|
+
});
|
|
3966
|
+
},
|
|
3967
|
+
isInteractionTagBlocked(tag) {
|
|
3968
|
+
if (!tag) {
|
|
3969
|
+
tag = 'default';
|
|
3970
|
+
}
|
|
3971
|
+
if (this.interactionTags[tag]) {
|
|
3972
|
+
return this.interactionTags[tag].blockedInteraction;
|
|
3973
|
+
}
|
|
3974
|
+
return false;
|
|
3975
|
+
},
|
|
3976
|
+
remove(item) {
|
|
3977
|
+
const existingItem = this.getExistingItem(item.id);
|
|
3978
|
+
if (existingItem) {
|
|
3979
|
+
existingItem.amount -= item.amount;
|
|
3980
|
+
useNotifications().addNotification(`Lost item: ${getItemConfig(item.id).name} x ${item.amount}`);
|
|
3981
|
+
if (existingItem.amount <= 0) {
|
|
3982
|
+
this.deleteItem(item.id);
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
},
|
|
3986
|
+
deleteItem(id) {
|
|
3987
|
+
const existingItem = this.getExistingItem(id);
|
|
3988
|
+
if (existingItem) {
|
|
3989
|
+
this.items[id].amount = 0;
|
|
3990
|
+
}
|
|
3991
|
+
},
|
|
3992
|
+
},
|
|
3993
|
+
});
|
|
3994
|
+
|
|
3995
|
+
const everyObject = (object, predicate) => {
|
|
3996
|
+
for (const key in object) {
|
|
3997
|
+
if (!predicate(object[key])) {
|
|
3998
|
+
return false;
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
return true;
|
|
4002
|
+
};
|
|
4003
|
+
const filterObject = (object, predicate) => {
|
|
4004
|
+
const result = {};
|
|
4005
|
+
for (const key in object) {
|
|
4006
|
+
if (predicate(object[key])) {
|
|
4007
|
+
result[key] = object[key];
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
return result;
|
|
4011
|
+
};
|
|
4012
|
+
|
|
4013
|
+
const useQuests = defineStore('quests', {
|
|
4014
|
+
state: () => ({
|
|
4015
|
+
quests: {},
|
|
4016
|
+
}),
|
|
4017
|
+
actions: {
|
|
4018
|
+
getQuest(questId) {
|
|
4019
|
+
const quest = this.quests[questId];
|
|
4020
|
+
if (quest) {
|
|
4021
|
+
return quest;
|
|
4022
|
+
}
|
|
4023
|
+
error(`Quest ${questId} doesn't exist!`);
|
|
4024
|
+
},
|
|
4025
|
+
getObjective(quest, objectiveId) {
|
|
4026
|
+
const questObjective = this.getQuest(quest).objectives[objectiveId];
|
|
4027
|
+
if (questObjective) {
|
|
4028
|
+
return questObjective;
|
|
4029
|
+
}
|
|
4030
|
+
error(`Objective ${objectiveId} doesn't exist in quest ${quest}!`);
|
|
4031
|
+
},
|
|
4032
|
+
setupQuests(quests) {
|
|
4033
|
+
// iterate through quests to generate quest states to add to this.quests object
|
|
4034
|
+
for (const key of Object.keys(quests)) {
|
|
4035
|
+
const data = quests[key];
|
|
4036
|
+
this.quests[key] = {
|
|
4037
|
+
id: key,
|
|
4038
|
+
state: 'hidden',
|
|
4039
|
+
objectives: {},
|
|
4040
|
+
};
|
|
4041
|
+
// iterate through data.objectives to populate the objectives array of this.quests[key]
|
|
4042
|
+
for (const objectiveKey of Object.keys(data.objectives)) {
|
|
4043
|
+
const objective = data.objectives[objectiveKey];
|
|
4044
|
+
this.quests[key].objectives[objectiveKey] = {
|
|
4045
|
+
id: objectiveKey,
|
|
4046
|
+
state: objective.hidden ? 'hidden' : 'unlocked',
|
|
4047
|
+
};
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
},
|
|
4051
|
+
startQuest(questId) {
|
|
4052
|
+
this.getQuest(questId).state = 'unlocked';
|
|
4053
|
+
useNotifications().addNotification(`Started quest: ${getQuestConfig(questId).title}`);
|
|
4054
|
+
},
|
|
4055
|
+
startObjective(questId, objectiveId) {
|
|
4056
|
+
this.getObjective(questId, objectiveId).state = 'unlocked';
|
|
4057
|
+
useNotifications().addNotification(`New quest objective: ${getObjectiveConfig(questId, objectiveId).description}`);
|
|
4058
|
+
},
|
|
4059
|
+
completeObjective(questId, objectiveId) {
|
|
4060
|
+
this.getObjective(questId, objectiveId).state = 'completed';
|
|
4061
|
+
useNotifications().addNotification(`Objective completed!`);
|
|
4062
|
+
},
|
|
4063
|
+
completeQuest(questId, ending) {
|
|
4064
|
+
this.getQuest(questId).state = 'completed';
|
|
4065
|
+
if (ending) {
|
|
4066
|
+
this.getQuest(questId).ending = ending;
|
|
4067
|
+
}
|
|
4068
|
+
useNotifications().addNotification(`Quest completed: ${getQuestConfig(questId).title}`);
|
|
4069
|
+
},
|
|
4070
|
+
isQuestCompleted(questId) {
|
|
4071
|
+
const quest = this.getQuest(questId);
|
|
4072
|
+
return everyObject(quest.objectives, (objective) => objective.state === 'completed');
|
|
4073
|
+
},
|
|
4074
|
+
isObjectiveCompleted(questId, objectiveId) {
|
|
4075
|
+
const objective = this.getObjective(questId, objectiveId);
|
|
4076
|
+
return objective.state === 'completed';
|
|
4077
|
+
},
|
|
4078
|
+
isQuestStarted(questId) {
|
|
4079
|
+
const quest = this.getQuest(questId);
|
|
4080
|
+
return quest.state === 'unlocked';
|
|
4081
|
+
},
|
|
4082
|
+
isObjectiveStarted(questId, objectiveId) {
|
|
4083
|
+
const objective = this.getObjective(questId, objectiveId);
|
|
4084
|
+
return objective.state === 'unlocked';
|
|
4085
|
+
},
|
|
4086
|
+
removeQuest(id) {
|
|
4087
|
+
delete this.quests[id];
|
|
4088
|
+
},
|
|
4089
|
+
generateSaveData() {
|
|
4090
|
+
return {
|
|
4091
|
+
quests: {
|
|
4092
|
+
...this.quests,
|
|
4093
|
+
},
|
|
4094
|
+
};
|
|
4095
|
+
},
|
|
4096
|
+
loadSaveData(data) {
|
|
4097
|
+
this.quests = data.quests;
|
|
4098
|
+
},
|
|
4099
|
+
},
|
|
4100
|
+
});
|
|
4101
|
+
|
|
4102
|
+
// Create a pinia store named screens with a state using the type ScreenState, with actions:
|
|
4103
|
+
// setScreen(screen: string): Sets the current screen to the given screen
|
|
4014
4104
|
// setButtons(buttons: { [key: string]: ButtonConfig }): Adds buttons to the buttons state by using the values in the buttons config object
|
|
4015
4105
|
// changeButton(button: string, newValue: boolean): Changes the value of a button in the buttons state
|
|
4016
4106
|
// generateSaveData(): Function that generates a ScreenState object from the data in the state
|
|
@@ -4063,6 +4153,25 @@ function findDataHelper(sourceObj, path) {
|
|
|
4063
4153
|
key = keys[i];
|
|
4064
4154
|
return [obj, key];
|
|
4065
4155
|
}
|
|
4156
|
+
function findDataHelperWithoutAutoCreate(sourceObj, path) {
|
|
4157
|
+
const keys = path.split('.');
|
|
4158
|
+
let obj = sourceObj;
|
|
4159
|
+
const end = keys.length - 1;
|
|
4160
|
+
let key = keys[0];
|
|
4161
|
+
let i = 0;
|
|
4162
|
+
for (i = 0; i < end; i++) {
|
|
4163
|
+
key = keys[i];
|
|
4164
|
+
if (!obj[key]) {
|
|
4165
|
+
obj[key] = {};
|
|
4166
|
+
}
|
|
4167
|
+
obj = obj[key];
|
|
4168
|
+
}
|
|
4169
|
+
key = keys[i];
|
|
4170
|
+
if (typeof obj[key] === 'undefined') {
|
|
4171
|
+
obj[key] = null;
|
|
4172
|
+
}
|
|
4173
|
+
return [obj, key];
|
|
4174
|
+
}
|
|
4066
4175
|
function setDataHelper(sourceObj, path, value) {
|
|
4067
4176
|
const [obj, key] = findDataHelper(sourceObj, path);
|
|
4068
4177
|
obj[key] = value;
|
|
@@ -4077,44 +4186,78 @@ function getModifiableDataPinia() {
|
|
|
4077
4186
|
const skills = useSkills();
|
|
4078
4187
|
const screens = useScreens();
|
|
4079
4188
|
const inventory = useInventory();
|
|
4080
|
-
|
|
4189
|
+
const scope = useVM().currentScope;
|
|
4190
|
+
const state = {
|
|
4081
4191
|
data: vm.data,
|
|
4082
4192
|
skills: skills.skills,
|
|
4083
4193
|
buttons: screens.buttons,
|
|
4084
4194
|
items: inventory.items,
|
|
4085
4195
|
quests: useQuests().quests,
|
|
4196
|
+
stats: useHud().hudStats,
|
|
4197
|
+
scope,
|
|
4086
4198
|
};
|
|
4199
|
+
const proxy = new Proxy(state, {
|
|
4200
|
+
get: (target, prop, receiver) => {
|
|
4201
|
+
const scope = useVM().currentScope;
|
|
4202
|
+
if (typeof scope[prop] !== 'undefined') {
|
|
4203
|
+
return scope[prop];
|
|
4204
|
+
}
|
|
4205
|
+
return Reflect.get(target, prop, receiver);
|
|
4206
|
+
},
|
|
4207
|
+
set: (target, prop, value, receiver) => {
|
|
4208
|
+
const scope = useVM().currentScope;
|
|
4209
|
+
if (typeof scope[prop] !== 'undefined') {
|
|
4210
|
+
scope[prop] = value;
|
|
4211
|
+
return scope[prop];
|
|
4212
|
+
}
|
|
4213
|
+
return Reflect.set(target, prop, value, receiver);
|
|
4214
|
+
},
|
|
4215
|
+
});
|
|
4216
|
+
return proxy;
|
|
4087
4217
|
}
|
|
4088
4218
|
|
|
4219
|
+
const loggerManager = new LogManager();
|
|
4220
|
+
loggerManager.setupDebugger(false);
|
|
4221
|
+
const logger$1 = loggerManager.logger;
|
|
4089
4222
|
function parseScript(errorHandler, code, fileName) {
|
|
4090
4223
|
const ctx = {
|
|
4091
4224
|
fileName,
|
|
4225
|
+
currentLine: 0,
|
|
4092
4226
|
error: (line, text) => errorHandler(ctx, line, text),
|
|
4093
4227
|
processCommandsFunction: processCommands,
|
|
4094
4228
|
indentSize: 0, // Will be overriden soon
|
|
4095
4229
|
};
|
|
4096
4230
|
ctx.indentSize = detectIndentation(ctx, code);
|
|
4097
4231
|
const lines = findLines(ctx, code);
|
|
4098
|
-
|
|
4232
|
+
ctx.currentLine = 0;
|
|
4233
|
+
logger$1.log(lines);
|
|
4099
4234
|
const script = {};
|
|
4100
4235
|
for (const line of lines) {
|
|
4101
4236
|
if (line.code.search(':') === -1) {
|
|
4102
4237
|
ctx.error(line.line, `First indentation level should only be used to specify labels`);
|
|
4103
4238
|
}
|
|
4104
|
-
const
|
|
4239
|
+
const labelString = line.code.replace(':', '');
|
|
4240
|
+
const labelWords = labelString.split(/ +/g);
|
|
4241
|
+
const labelName = labelWords[0];
|
|
4242
|
+
const labelArgs = labelWords.slice(1);
|
|
4105
4243
|
if (!line.branch) {
|
|
4106
4244
|
ctx.error(line.line, `This line should have a branch but doesn't`);
|
|
4107
4245
|
}
|
|
4108
|
-
script[labelName] =
|
|
4246
|
+
script[labelName] = {
|
|
4247
|
+
branch: processCommands(ctx, line.branch, undefined),
|
|
4248
|
+
args: labelArgs,
|
|
4249
|
+
};
|
|
4109
4250
|
}
|
|
4110
4251
|
return script;
|
|
4111
4252
|
}
|
|
4112
4253
|
function processCommands(ctx, lines, parentLine) {
|
|
4254
|
+
const startLine = ctx.currentLine;
|
|
4113
4255
|
const branchContext = {
|
|
4114
4256
|
processCommandsFunction: processCommands,
|
|
4115
4257
|
parserContext: ctx,
|
|
4116
4258
|
lines,
|
|
4117
4259
|
currentLine: 0,
|
|
4260
|
+
line: lines[0],
|
|
4118
4261
|
};
|
|
4119
4262
|
const branch = [];
|
|
4120
4263
|
if (!lines) {
|
|
@@ -4127,29 +4270,58 @@ function processCommands(ctx, lines, parentLine) {
|
|
|
4127
4270
|
}
|
|
4128
4271
|
while (branchContext.currentLine < lines.length) {
|
|
4129
4272
|
const line = lines[branchContext.currentLine];
|
|
4130
|
-
const operator = line.operator;
|
|
4131
|
-
const args = line.args;
|
|
4132
|
-
const command = {
|
|
4133
|
-
code: line.code,
|
|
4134
|
-
operator,
|
|
4135
|
-
args,
|
|
4136
|
-
line: line.line,
|
|
4137
|
-
fileName: ctx.fileName,
|
|
4138
|
-
};
|
|
4139
4273
|
branchContext.line = line;
|
|
4140
|
-
|
|
4141
|
-
const commandPlugin = vm.commands[operator];
|
|
4274
|
+
const parsed = parseExpression(ctx, line, line.expression);
|
|
4275
|
+
const commandPlugin = vm.commands[parsed.command.operator];
|
|
4142
4276
|
let parseFunction = commandPlugin?.parser;
|
|
4143
4277
|
if (!parseFunction) {
|
|
4144
4278
|
// default to text function
|
|
4145
4279
|
parseFunction = vm.commands.text.parser;
|
|
4146
4280
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4281
|
+
logger$1.log(vm.commands.text);
|
|
4282
|
+
const { newLine } = parseFunction(branchContext, parsed);
|
|
4283
|
+
branchContext.currentLine = newLine;
|
|
4284
|
+
ctx.currentLine = startLine + newLine;
|
|
4285
|
+
branch.push(parsed);
|
|
4149
4286
|
}
|
|
4150
4287
|
return branch;
|
|
4151
4288
|
}
|
|
4152
|
-
function
|
|
4289
|
+
function parseExpression(ctx, line, expression) {
|
|
4290
|
+
logger$1.log(expression);
|
|
4291
|
+
if (typeof expression[0] !== 'string') {
|
|
4292
|
+
ctx.error(line.line, `Expression operator should be a string`);
|
|
4293
|
+
}
|
|
4294
|
+
const parsed = {
|
|
4295
|
+
code: line.code,
|
|
4296
|
+
fileName: ctx.fileName,
|
|
4297
|
+
line: line.line,
|
|
4298
|
+
command: {
|
|
4299
|
+
commandType: expression[0],
|
|
4300
|
+
operator: expression[0],
|
|
4301
|
+
args: expression.slice(1).map((arg) => parseArgument(ctx, line, arg)),
|
|
4302
|
+
options: {},
|
|
4303
|
+
},
|
|
4304
|
+
};
|
|
4305
|
+
const firstElement = expression[0];
|
|
4306
|
+
const command = vm.commands[firstElement];
|
|
4307
|
+
if (!command) {
|
|
4308
|
+
const otherKeywords = ['else', 'success', 'failure'];
|
|
4309
|
+
if (!isParsedTokenString(firstElement) &&
|
|
4310
|
+
!otherKeywords.includes(firstElement)) {
|
|
4311
|
+
ctx.error(line.line, `Unknown command ${firstElement}`);
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
return parsed;
|
|
4315
|
+
}
|
|
4316
|
+
function parseArgument(ctx, line, argument) {
|
|
4317
|
+
if (Array.isArray(argument)) {
|
|
4318
|
+
return parseExpression(ctx, line, argument);
|
|
4319
|
+
}
|
|
4320
|
+
else {
|
|
4321
|
+
return argument;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
function parseTokenToPrimitive(value) {
|
|
4153
4325
|
if (value === 'true') {
|
|
4154
4326
|
return true;
|
|
4155
4327
|
}
|
|
@@ -4159,26 +4331,18 @@ function parseValue(value) {
|
|
|
4159
4331
|
else if (!isNaN(Number(value))) {
|
|
4160
4332
|
return Number(value);
|
|
4161
4333
|
}
|
|
4162
|
-
|
|
4163
|
-
return value.substr(1, value.length - 2);
|
|
4164
|
-
}
|
|
4165
|
-
else {
|
|
4166
|
-
return value;
|
|
4167
|
-
}
|
|
4334
|
+
return value;
|
|
4168
4335
|
}
|
|
4169
|
-
function parseCodeLine(codeToProcess) {
|
|
4336
|
+
function parseCodeLine(ctx, codeToProcess) {
|
|
4170
4337
|
if (codeToProcess.charAt(codeToProcess.length - 1) === ':') {
|
|
4171
4338
|
codeToProcess = codeToProcess.substr(0, codeToProcess.length - 1);
|
|
4172
4339
|
}
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
code = codeToProcess.substr(0, ifIndex);
|
|
4180
|
-
ifWords = ['if', codeToProcess.substr(ifIndex + 3)];
|
|
4181
|
-
}
|
|
4340
|
+
const tokens = parseCodeLineIntoTokens(codeToProcess);
|
|
4341
|
+
const [expression] = tokensToExpression(ctx, tokens);
|
|
4342
|
+
return expression;
|
|
4343
|
+
}
|
|
4344
|
+
function parseCodeLineIntoTokens(code) {
|
|
4345
|
+
// Finds strings and processes the code around them to get all tokens
|
|
4182
4346
|
const regex = /(["'])(?:\\\1|.)*?\1/g;
|
|
4183
4347
|
const matches = [];
|
|
4184
4348
|
let match;
|
|
@@ -4186,26 +4350,92 @@ function parseCodeLine(codeToProcess) {
|
|
|
4186
4350
|
matches.push(match);
|
|
4187
4351
|
}
|
|
4188
4352
|
let currentIndex = 0;
|
|
4189
|
-
let
|
|
4353
|
+
let tokens = [];
|
|
4190
4354
|
for (const match of matches) {
|
|
4355
|
+
// For each string match, process the code before it to add all tokens
|
|
4191
4356
|
const index = match.index;
|
|
4192
4357
|
if (index > currentIndex) {
|
|
4193
4358
|
const inBetween = code.substr(currentIndex, index - currentIndex);
|
|
4194
|
-
const
|
|
4195
|
-
|
|
4359
|
+
const newTokens = splitIntoTokens(inBetween);
|
|
4360
|
+
tokens = [...tokens, ...newTokens];
|
|
4196
4361
|
}
|
|
4197
4362
|
// Remove backticks for escaped quotes
|
|
4198
4363
|
const finalMatch = match[0].replace(/\\/g, '');
|
|
4199
|
-
|
|
4364
|
+
tokens.push(`$$"${finalMatch.substring(1, finalMatch.length - 1)}`);
|
|
4200
4365
|
currentIndex = index + match[0].length;
|
|
4201
4366
|
}
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4367
|
+
// Process the last tokens from after the last string
|
|
4368
|
+
tokens = [...tokens, ...splitIntoTokens(code.substr(currentIndex))];
|
|
4369
|
+
// Adding a closing parenthesis at the end of the line so users don't have to
|
|
4370
|
+
tokens.push(')');
|
|
4371
|
+
return tokens;
|
|
4372
|
+
}
|
|
4373
|
+
// Splits a chunk of code (without strings) into tokens
|
|
4374
|
+
function splitIntoTokens(code) {
|
|
4375
|
+
code = code.replace(/: *$/g, '');
|
|
4376
|
+
let result = code.split(' ').filter((el) => el);
|
|
4377
|
+
result = result.reduce((total, curr) => [...total, ...curr.split(/(\(|\))/g)].filter((el) => el && el), []);
|
|
4378
|
+
return result.map((token) => parseTokenToPrimitive(token));
|
|
4379
|
+
}
|
|
4380
|
+
function tokensToExpression(ctx, tokens) {
|
|
4381
|
+
logger$1.log('===============');
|
|
4382
|
+
let expression = [];
|
|
4383
|
+
let cursor = 0;
|
|
4384
|
+
// Find sub expressions inside this expression
|
|
4385
|
+
let parenthesisIndex = findExpressionStart(tokens) + cursor;
|
|
4386
|
+
let parenthesisEndIndex = findExpressionEnd(tokens) + cursor;
|
|
4387
|
+
logger$1.log(`Parsing expression: ${tokens}`);
|
|
4388
|
+
logger$1.log(`Parenthesis start index: ${parenthesisIndex} - end: ${parenthesisEndIndex}`);
|
|
4389
|
+
while (parenthesisIndex !== -1 && parenthesisEndIndex > parenthesisIndex) {
|
|
4390
|
+
// Add everything before the sub expression
|
|
4391
|
+
expression = [...expression, ...tokens.slice(cursor, parenthesisIndex)];
|
|
4392
|
+
const subExpressionString = tokens.slice(parenthesisIndex + 1);
|
|
4393
|
+
logger$1.log(`Found a sub expression. Before: ${expression} - After: ${subExpressionString}`);
|
|
4394
|
+
cursor = parenthesisIndex;
|
|
4395
|
+
// Process the sub expression
|
|
4396
|
+
const [subExpression, subExpressionLength] = tokensToExpression(ctx, subExpressionString);
|
|
4397
|
+
const subExpressionEndIndex = cursor + subExpressionLength;
|
|
4398
|
+
expression.push(subExpression);
|
|
4399
|
+
cursor = subExpressionEndIndex + 1;
|
|
4400
|
+
const restOfString = tokens.slice(cursor);
|
|
4401
|
+
logger$1.log(`Sub expression came back: ${subExpression} - rest of string: ${restOfString}`);
|
|
4402
|
+
// Find the next sub expression, if any
|
|
4403
|
+
parenthesisIndex = findExpressionStart(restOfString);
|
|
4404
|
+
if (parenthesisIndex !== -1) {
|
|
4405
|
+
parenthesisIndex += cursor;
|
|
4406
|
+
}
|
|
4407
|
+
parenthesisEndIndex = findExpressionEnd(restOfString);
|
|
4408
|
+
if (parenthesisEndIndex !== -1) {
|
|
4409
|
+
parenthesisEndIndex += cursor;
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
if (parenthesisEndIndex !== -1) {
|
|
4413
|
+
logger$1.log(`Found parenthesis end before new opening parenthesis, close this expression`);
|
|
4414
|
+
}
|
|
4415
|
+
// Find the end of the current expression
|
|
4416
|
+
const endIndex = findExpressionEnd(tokens.slice(cursor)) + cursor;
|
|
4417
|
+
if (endIndex === -1) {
|
|
4418
|
+
ctx.error(ctx.currentLine, `Expression is not closed (missing ")" closing parenthesis)`);
|
|
4419
|
+
return [expression, endIndex];
|
|
4420
|
+
}
|
|
4421
|
+
const restOfString = tokens.slice(cursor, endIndex);
|
|
4422
|
+
logger$1.log(`End of expression: ${endIndex} - ${restOfString}`);
|
|
4423
|
+
logger$1.log('===================');
|
|
4424
|
+
// Add the remaining tokens to the expression
|
|
4425
|
+
expression = [...expression, ...restOfString];
|
|
4426
|
+
validateExpression(ctx, expression);
|
|
4427
|
+
return [expression, endIndex + 1];
|
|
4428
|
+
}
|
|
4429
|
+
function validateExpression(ctx, expression) {
|
|
4430
|
+
if (expression.length < 1) {
|
|
4431
|
+
ctx.error(ctx.currentLine, `Expression is empty`);
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
function findExpressionStart(tokens) {
|
|
4435
|
+
return tokens.findIndex((token) => token === '(');
|
|
4436
|
+
}
|
|
4437
|
+
function findExpressionEnd(tokens) {
|
|
4438
|
+
return tokens.findIndex((token) => token === ')');
|
|
4209
4439
|
}
|
|
4210
4440
|
function findLines(ctx, data) {
|
|
4211
4441
|
const code = data.split(/\r?\n|$/).map((line) => {
|
|
@@ -4228,11 +4458,12 @@ function findBranches(ctx, code, startLine, indentLevel) {
|
|
|
4228
4458
|
}
|
|
4229
4459
|
let lineText = code[currentLine];
|
|
4230
4460
|
if (lineText.search(/^\s*$/) !== -1) {
|
|
4461
|
+
// Ignore empty lines
|
|
4231
4462
|
currentLine++;
|
|
4232
4463
|
}
|
|
4233
4464
|
else {
|
|
4234
4465
|
const lineIndent = getIndentLevel(ctx, lineText);
|
|
4235
|
-
lineText = lineText.
|
|
4466
|
+
lineText = lineText.substring(lineIndent * ctx.indentSize);
|
|
4236
4467
|
validateIndent(ctx, lineIndent, currentLine);
|
|
4237
4468
|
if (lineIndent < indentLevel) {
|
|
4238
4469
|
stillInBranch = false;
|
|
@@ -4246,16 +4477,16 @@ function findBranches(ctx, code, startLine, indentLevel) {
|
|
|
4246
4477
|
currentLine = branchLines.endLine;
|
|
4247
4478
|
}
|
|
4248
4479
|
else {
|
|
4249
|
-
const
|
|
4480
|
+
const expression = parseCodeLine(ctx, lineText);
|
|
4250
4481
|
const line = {
|
|
4251
4482
|
code: lineText,
|
|
4252
4483
|
indentation: lineIndent,
|
|
4253
4484
|
line: currentLine,
|
|
4254
|
-
|
|
4255
|
-
args: words.slice(1),
|
|
4485
|
+
expression,
|
|
4256
4486
|
};
|
|
4257
4487
|
lines.push(line);
|
|
4258
4488
|
currentLine++;
|
|
4489
|
+
ctx.currentLine = currentLine;
|
|
4259
4490
|
}
|
|
4260
4491
|
}
|
|
4261
4492
|
}
|
|
@@ -4278,7 +4509,7 @@ function detectIndentation(ctx, script) {
|
|
|
4278
4509
|
if (result.length < 2) {
|
|
4279
4510
|
ctx.error(0, `Can't detect indentation level. Make sure you indent with at least 2 spaces and consistently`);
|
|
4280
4511
|
}
|
|
4281
|
-
logger.log(result);
|
|
4512
|
+
logger$1.log(result);
|
|
4282
4513
|
return result[1].length;
|
|
4283
4514
|
}
|
|
4284
4515
|
|
|
@@ -4301,6 +4532,7 @@ const useVM = defineStore('vm', {
|
|
|
4301
4532
|
lastLabel: 'main',
|
|
4302
4533
|
script: {},
|
|
4303
4534
|
labelStack: ['main'],
|
|
4535
|
+
currentScope: {},
|
|
4304
4536
|
}),
|
|
4305
4537
|
actions: {
|
|
4306
4538
|
generateSaveData() {
|
|
@@ -4313,6 +4545,26 @@ const useVM = defineStore('vm', {
|
|
|
4313
4545
|
this.lastLabel = data.lastLabel;
|
|
4314
4546
|
this.data = data.data;
|
|
4315
4547
|
},
|
|
4548
|
+
resetScope() {
|
|
4549
|
+
this.currentScope = {};
|
|
4550
|
+
},
|
|
4551
|
+
setReturnValue(value) {
|
|
4552
|
+
this.currentStack.returnValue = value;
|
|
4553
|
+
},
|
|
4554
|
+
removeFromScope(vars) {
|
|
4555
|
+
for (const varName of vars) {
|
|
4556
|
+
delete this.currentScope[varName];
|
|
4557
|
+
}
|
|
4558
|
+
},
|
|
4559
|
+
addScopedVariable(key, value) {
|
|
4560
|
+
this.currentScope[key] = value;
|
|
4561
|
+
if (this.currentStack) {
|
|
4562
|
+
this.currentStack.scope[key] = value;
|
|
4563
|
+
}
|
|
4564
|
+
},
|
|
4565
|
+
extendScope(scope) {
|
|
4566
|
+
Object.assign(this.currentScope, scope);
|
|
4567
|
+
},
|
|
4316
4568
|
async loadScripts(scriptPaths) {
|
|
4317
4569
|
const filePromises = [];
|
|
4318
4570
|
for (const path of scriptPaths) {
|
|
@@ -4333,13 +4585,20 @@ const useVM = defineStore('vm', {
|
|
|
4333
4585
|
this.setScript(scripts);
|
|
4334
4586
|
},
|
|
4335
4587
|
start() {
|
|
4336
|
-
this.
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
branch: this.script.main,
|
|
4340
|
-
|
|
4588
|
+
this.setStack({
|
|
4589
|
+
currentIndex: 0,
|
|
4590
|
+
branchData: {
|
|
4591
|
+
branch: this.script.main.branch,
|
|
4592
|
+
},
|
|
4593
|
+
label: 'main',
|
|
4594
|
+
});
|
|
4595
|
+
this.setStack({
|
|
4596
|
+
currentIndex: 0,
|
|
4597
|
+
branchData: {
|
|
4598
|
+
branch: this.script.main.branch,
|
|
4341
4599
|
},
|
|
4342
|
-
|
|
4600
|
+
label: 'main',
|
|
4601
|
+
});
|
|
4343
4602
|
},
|
|
4344
4603
|
setLastLabel(label) {
|
|
4345
4604
|
this.lastLabel = label;
|
|
@@ -4347,9 +4606,11 @@ const useVM = defineStore('vm', {
|
|
|
4347
4606
|
reset() {
|
|
4348
4607
|
this.stack = [];
|
|
4349
4608
|
this.data = {};
|
|
4350
|
-
this.
|
|
4609
|
+
this.setStack({
|
|
4351
4610
|
currentIndex: 0,
|
|
4352
|
-
|
|
4611
|
+
branchData: {
|
|
4612
|
+
branch: this.script.main.branch,
|
|
4613
|
+
},
|
|
4353
4614
|
label: 'main',
|
|
4354
4615
|
});
|
|
4355
4616
|
},
|
|
@@ -4360,9 +4621,30 @@ const useVM = defineStore('vm', {
|
|
|
4360
4621
|
this.data = data;
|
|
4361
4622
|
},
|
|
4362
4623
|
setStack(stack) {
|
|
4624
|
+
this.resetScope();
|
|
4363
4625
|
this.stack = [];
|
|
4626
|
+
const newStack = this.stackOptionsToStack(stack);
|
|
4364
4627
|
this.lastLabel = stack.label;
|
|
4365
|
-
this.stack.push(
|
|
4628
|
+
this.stack.push(newStack);
|
|
4629
|
+
},
|
|
4630
|
+
stackOptionsToStack(stack) {
|
|
4631
|
+
const newStack = {
|
|
4632
|
+
...stack,
|
|
4633
|
+
scope: {},
|
|
4634
|
+
returnValue: null,
|
|
4635
|
+
};
|
|
4636
|
+
if (stack.scope) {
|
|
4637
|
+
newStack.scope = stack.scope;
|
|
4638
|
+
}
|
|
4639
|
+
if (stack.args && stack.branchData.args) {
|
|
4640
|
+
for (const [index, argName] of stack.branchData.args.entries()) {
|
|
4641
|
+
if (stack.args.length > index) {
|
|
4642
|
+
newStack.scope[argName] = stack.args[index];
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
this.extendScope(newStack.scope || {});
|
|
4647
|
+
return newStack;
|
|
4366
4648
|
},
|
|
4367
4649
|
setData(path, value) {
|
|
4368
4650
|
const dataToModify = getModifiableDataPinia();
|
|
@@ -4372,10 +4654,11 @@ const useVM = defineStore('vm', {
|
|
|
4372
4654
|
const dataToModify = getModifiableDataPinia();
|
|
4373
4655
|
addDataHelper(dataToModify, path, value);
|
|
4374
4656
|
},
|
|
4375
|
-
addStack(
|
|
4376
|
-
if (!
|
|
4377
|
-
|
|
4657
|
+
addStack(newStackOptions) {
|
|
4658
|
+
if (!newStackOptions.label) {
|
|
4659
|
+
newStackOptions.label = this.currentStack.label;
|
|
4378
4660
|
}
|
|
4661
|
+
const newStack = this.stackOptionsToStack(newStackOptions);
|
|
4379
4662
|
this.stack.push(newStack);
|
|
4380
4663
|
return this.runLine();
|
|
4381
4664
|
},
|
|
@@ -4385,13 +4668,12 @@ const useVM = defineStore('vm', {
|
|
|
4385
4668
|
return;
|
|
4386
4669
|
}
|
|
4387
4670
|
if (this.currentStack.currentIndex <
|
|
4388
|
-
this.currentStack.branch.length - 1) {
|
|
4671
|
+
this.currentStack.branchData.branch.length - 1) {
|
|
4389
4672
|
this.currentStack.currentIndex++;
|
|
4390
4673
|
}
|
|
4391
4674
|
else {
|
|
4392
|
-
this.previousStack();
|
|
4675
|
+
return this.previousStack();
|
|
4393
4676
|
// This branch is finished, go back to previous stack
|
|
4394
|
-
return this.nextLine();
|
|
4395
4677
|
}
|
|
4396
4678
|
if (this.stack.length === 0) {
|
|
4397
4679
|
this.finishGame();
|
|
@@ -4401,8 +4683,17 @@ const useVM = defineStore('vm', {
|
|
|
4401
4683
|
}
|
|
4402
4684
|
this.currentStack.currentIndex++;
|
|
4403
4685
|
},
|
|
4404
|
-
previousStack() {
|
|
4686
|
+
async previousStack() {
|
|
4687
|
+
const previousScope = this.currentStack.scope;
|
|
4688
|
+
this.removeFromScope(Object.keys(previousScope));
|
|
4689
|
+
const { returnValue, onComplete } = this.currentStack;
|
|
4405
4690
|
this.stack.splice(this.stack.length - 1, 1);
|
|
4691
|
+
if (onComplete) {
|
|
4692
|
+
onComplete(returnValue);
|
|
4693
|
+
}
|
|
4694
|
+
else {
|
|
4695
|
+
return this.nextLine();
|
|
4696
|
+
}
|
|
4406
4697
|
},
|
|
4407
4698
|
finishGame() {
|
|
4408
4699
|
useInventory().onScriptEnd();
|
|
@@ -4416,38 +4707,41 @@ const useVM = defineStore('vm', {
|
|
|
4416
4707
|
}
|
|
4417
4708
|
},
|
|
4418
4709
|
async runLine() {
|
|
4419
|
-
const
|
|
4710
|
+
const expression = this.currentLine;
|
|
4420
4711
|
useInventory().onScriptStart();
|
|
4421
|
-
await runCommand(
|
|
4712
|
+
await runCommand(expression);
|
|
4422
4713
|
},
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
this.
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4714
|
+
runLabelFunction(label, ...args) {
|
|
4715
|
+
return new Promise((resolve, reject) => {
|
|
4716
|
+
const branchData = this.script[label];
|
|
4717
|
+
if (!branchData) {
|
|
4718
|
+
console.error(`Label ${label} doesn't exist`);
|
|
4719
|
+
}
|
|
4720
|
+
// TODO: Inject args
|
|
4721
|
+
const stack = {
|
|
4722
|
+
currentIndex: 0,
|
|
4723
|
+
branchData: branchData,
|
|
4724
|
+
label,
|
|
4725
|
+
args,
|
|
4726
|
+
onComplete: (returnValue) => {
|
|
4727
|
+
resolve(returnValue);
|
|
4728
|
+
},
|
|
4729
|
+
};
|
|
4730
|
+
this.addStack(stack);
|
|
4731
|
+
});
|
|
4437
4732
|
},
|
|
4438
|
-
runLabel(label) {
|
|
4439
|
-
const
|
|
4440
|
-
if (!
|
|
4441
|
-
console.error(`Label ${
|
|
4733
|
+
runLabel(label, ...args) {
|
|
4734
|
+
const branchData = this.script[label];
|
|
4735
|
+
if (!branchData) {
|
|
4736
|
+
console.error(`Label ${branchData} doesn't exist`);
|
|
4442
4737
|
}
|
|
4443
4738
|
this.setLastLabel(label);
|
|
4444
|
-
this.
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
];
|
|
4739
|
+
this.setStack({
|
|
4740
|
+
currentIndex: 0,
|
|
4741
|
+
branchData,
|
|
4742
|
+
args,
|
|
4743
|
+
label,
|
|
4744
|
+
});
|
|
4451
4745
|
this.runLine();
|
|
4452
4746
|
},
|
|
4453
4747
|
},
|
|
@@ -4458,7 +4752,7 @@ const useVM = defineStore('vm', {
|
|
|
4458
4752
|
},
|
|
4459
4753
|
currentLine() {
|
|
4460
4754
|
const currentStack = this.currentStack;
|
|
4461
|
-
return currentStack.branch[currentStack.currentIndex];
|
|
4755
|
+
return currentStack.branchData.branch[currentStack.currentIndex];
|
|
4462
4756
|
},
|
|
4463
4757
|
},
|
|
4464
4758
|
});
|
|
@@ -4468,16 +4762,20 @@ function processText(text) {
|
|
|
4468
4762
|
const skillStore = useSkills();
|
|
4469
4763
|
return text.replace(/%{[^}]*}/g, (match) => {
|
|
4470
4764
|
const key = match.substr(2, match.length - 3);
|
|
4471
|
-
const searchableState =
|
|
4472
|
-
data: vmStore.data,
|
|
4473
|
-
skills: skillStore.skills,
|
|
4474
|
-
items: useInventory().items,
|
|
4475
|
-
quests: useQuests().quests,
|
|
4476
|
-
};
|
|
4765
|
+
const searchableState = getModifiableDataPinia();
|
|
4477
4766
|
const [obj, newKey] = findDataHelper(searchableState, key);
|
|
4478
4767
|
return obj[newKey];
|
|
4479
4768
|
});
|
|
4480
|
-
}
|
|
4769
|
+
}
|
|
4770
|
+
const stringRegex = /\$\$"/;
|
|
4771
|
+
const isParsedTokenString = (arg) => {
|
|
4772
|
+
if (typeof arg === 'string') {
|
|
4773
|
+
if (arg.search(stringRegex) === 0) {
|
|
4774
|
+
return true;
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
return false;
|
|
4778
|
+
};
|
|
4481
4779
|
|
|
4482
4780
|
// Create a pinia store named dialog with a state using the type DialogState, with actions addDialog and clearDialog
|
|
4483
4781
|
const useDialogStore = defineStore('dialog', {
|
|
@@ -4515,57 +4813,6 @@ const useDialogStore = defineStore('dialog', {
|
|
|
4515
4813
|
},
|
|
4516
4814
|
});
|
|
4517
4815
|
|
|
4518
|
-
// Create a pinia store named hud with a state using the type HudState, and save type HudSave, with actions:
|
|
4519
|
-
// setupHudStats(stats: { [key: string]: HudStatConfig }): Iterates the stats argument to add new stats to the state
|
|
4520
|
-
// setStat(stat: string, value: number): Sets the value of a stat
|
|
4521
|
-
// addStat(stat: string, value: number): Adds a value to a stat
|
|
4522
|
-
// generateSaveData(): Function that generates a HudSave object from the data in the state
|
|
4523
|
-
// loadSaveData(data: HudSave): Function that loads the data into the state
|
|
4524
|
-
const useHud = defineStore('hud', {
|
|
4525
|
-
state: () => ({
|
|
4526
|
-
hudStats: {},
|
|
4527
|
-
}),
|
|
4528
|
-
actions: {
|
|
4529
|
-
setupHudStats(stats) {
|
|
4530
|
-
for (const stat in stats) {
|
|
4531
|
-
this.hudStats[stat] = {
|
|
4532
|
-
value: stats[stat].startingValue,
|
|
4533
|
-
};
|
|
4534
|
-
}
|
|
4535
|
-
},
|
|
4536
|
-
setStat(stat, value) {
|
|
4537
|
-
this.hudStats[stat].value = value;
|
|
4538
|
-
},
|
|
4539
|
-
addStat(stat, value) {
|
|
4540
|
-
this.hudStats[stat].value += value;
|
|
4541
|
-
},
|
|
4542
|
-
generateSaveData() {
|
|
4543
|
-
return {
|
|
4544
|
-
hudStats: this.hudStats,
|
|
4545
|
-
};
|
|
4546
|
-
},
|
|
4547
|
-
loadSaveData(data) {
|
|
4548
|
-
this.hudStats = cjs(this.hudStats, data.hudStats);
|
|
4549
|
-
},
|
|
4550
|
-
},
|
|
4551
|
-
});
|
|
4552
|
-
|
|
4553
|
-
function createSkillCheckState() {
|
|
4554
|
-
const skillCheck = {
|
|
4555
|
-
passed: false,
|
|
4556
|
-
available: true,
|
|
4557
|
-
};
|
|
4558
|
-
return skillCheck;
|
|
4559
|
-
}
|
|
4560
|
-
function getSkillCheckState(skillCheckId) {
|
|
4561
|
-
const skillStore = useSkills();
|
|
4562
|
-
let skillCheck = skillStore.skillChecks[skillCheckId];
|
|
4563
|
-
if (!skillCheck) {
|
|
4564
|
-
skillCheck = createSkillCheckState();
|
|
4565
|
-
skillStore.setupSkillCheck(skillCheck, skillCheckId);
|
|
4566
|
-
}
|
|
4567
|
-
return skillCheck;
|
|
4568
|
-
}
|
|
4569
4816
|
function getSkillCheckDifficultyScore(value, level) {
|
|
4570
4817
|
return value - level * getConfig().skillChecks.skillMultiplier;
|
|
4571
4818
|
}
|
|
@@ -4593,16 +4840,16 @@ function getSkillCheckDifficultyText(value, level) {
|
|
|
4593
4840
|
}
|
|
4594
4841
|
function getSkillCheckText({ skill, skillCheckId, value, }) {
|
|
4595
4842
|
const skillStore = useSkills();
|
|
4596
|
-
const skillCheckState =
|
|
4843
|
+
const skillCheckState = skillStore.getSkillCheck(skillCheckId);
|
|
4597
4844
|
const skillConfig = getSkillConfig(skill);
|
|
4598
4845
|
const level = skillStore.skills[skill].level;
|
|
4599
4846
|
const difficultyText = getSkillCheckDifficultyText(value, level);
|
|
4600
4847
|
let allowed = true;
|
|
4601
4848
|
let text = `<span class='skill-check'>[<span class='skill-check-name'>${skillConfig.name}</span> - `;
|
|
4602
|
-
if (skillCheckState.
|
|
4849
|
+
if (!skillCheckState.happened) {
|
|
4603
4850
|
text += ` <span class='skill-check-difficulty'>${difficultyText}</span>]</span>`;
|
|
4604
4851
|
}
|
|
4605
|
-
else if (skillCheckState.
|
|
4852
|
+
else if (skillCheckState.succeeded) {
|
|
4606
4853
|
text = '';
|
|
4607
4854
|
}
|
|
4608
4855
|
else {
|
|
@@ -4646,41 +4893,44 @@ function resolveSkillCheck(params) {
|
|
|
4646
4893
|
success = false;
|
|
4647
4894
|
}
|
|
4648
4895
|
logger.log(`[SKILL CHECK ${skill.name}]: ${success ? '✅' : '❌'}`, `(${params.id}) - ${roll}/${params.value}`);
|
|
4896
|
+
success
|
|
4897
|
+
? audioEvent('onSkillCheckSuccess')
|
|
4898
|
+
: audioEvent('onSkillCheckFailure');
|
|
4649
4899
|
return success;
|
|
4650
4900
|
}
|
|
4651
4901
|
|
|
4652
|
-
function processSkillCheck(skillcheck) {
|
|
4653
|
-
return runSkillCheck({
|
|
4654
|
-
skill: skillcheck.skill,
|
|
4655
|
-
value: skillcheck.value,
|
|
4656
|
-
id: skillcheck.id,
|
|
4657
|
-
success: skillcheck.success.text,
|
|
4658
|
-
failure: skillcheck.failure.text,
|
|
4659
|
-
});
|
|
4660
|
-
}
|
|
4661
4902
|
function runSkillCheck(params) {
|
|
4662
|
-
const success = resolveSkillCheck(params);
|
|
4663
4903
|
const skillStore = useSkills();
|
|
4904
|
+
const result = skillStore.getSkillCheck(params.id);
|
|
4905
|
+
if (result && result.happened) {
|
|
4906
|
+
return result;
|
|
4907
|
+
}
|
|
4908
|
+
const success = resolveSkillCheck(params);
|
|
4664
4909
|
writeText(getPassiveSkillCheckText(success, params));
|
|
4665
4910
|
if (success) {
|
|
4666
|
-
skillStore.passSkillCheck(params.id);
|
|
4667
|
-
return true;
|
|
4911
|
+
skillStore.passSkillCheck(params.id, params.hideAfterRoll);
|
|
4668
4912
|
}
|
|
4669
|
-
|
|
4670
|
-
|
|
4913
|
+
else {
|
|
4914
|
+
skillStore.failSkillCheck(params.id, params.hideAfterRoll);
|
|
4915
|
+
}
|
|
4916
|
+
return skillStore.getSkillCheck(params.id);
|
|
4671
4917
|
}
|
|
4672
4918
|
function runConditionCommand(command) {
|
|
4673
4919
|
const options = command.options;
|
|
4674
|
-
const
|
|
4920
|
+
const staticOptions = command.staticOptions;
|
|
4921
|
+
const result = !!options.condition;
|
|
4675
4922
|
logger.log(result);
|
|
4676
4923
|
if (result) {
|
|
4677
|
-
return
|
|
4924
|
+
return staticOptions.success;
|
|
4678
4925
|
}
|
|
4679
|
-
if (!result &&
|
|
4680
|
-
return
|
|
4926
|
+
if (!result && staticOptions.failure) {
|
|
4927
|
+
return staticOptions.failure;
|
|
4681
4928
|
}
|
|
4682
4929
|
return undefined;
|
|
4683
4930
|
}
|
|
4931
|
+
function isExpression(arg) {
|
|
4932
|
+
return typeof arg === 'object';
|
|
4933
|
+
}
|
|
4684
4934
|
function writeText(text) {
|
|
4685
4935
|
const dialog = {
|
|
4686
4936
|
speaker: 'game',
|
|
@@ -4690,48 +4940,6 @@ function writeText(text) {
|
|
|
4690
4940
|
const dialogStore = useDialogStore();
|
|
4691
4941
|
dialogStore.addDialog(dialog);
|
|
4692
4942
|
}
|
|
4693
|
-
function runCondition(condition) {
|
|
4694
|
-
return conditionFunction(condition);
|
|
4695
|
-
}
|
|
4696
|
-
function conditionFunction(condition) {
|
|
4697
|
-
const skillStore = useSkills();
|
|
4698
|
-
const vm = useVM();
|
|
4699
|
-
const inventory = useInventory();
|
|
4700
|
-
const context = {
|
|
4701
|
-
data: vm.data,
|
|
4702
|
-
skills: skillStore.skills,
|
|
4703
|
-
skillChecks: skillStore.skillChecks,
|
|
4704
|
-
stats: useHud().hudStats,
|
|
4705
|
-
items: inventory.items,
|
|
4706
|
-
quests: useQuests().quests,
|
|
4707
|
-
itemAmount: (id) => {
|
|
4708
|
-
return useInventory().getItemAmount(id);
|
|
4709
|
-
},
|
|
4710
|
-
roll: (checkId, skill, value) => {
|
|
4711
|
-
const skillCheckState = getSkillCheckState(checkId);
|
|
4712
|
-
if (skillCheckState) {
|
|
4713
|
-
if (skillCheckState.passed) {
|
|
4714
|
-
return true;
|
|
4715
|
-
}
|
|
4716
|
-
if (!skillCheckState.available) {
|
|
4717
|
-
return false;
|
|
4718
|
-
}
|
|
4719
|
-
}
|
|
4720
|
-
return runSkillCheck({
|
|
4721
|
-
skill,
|
|
4722
|
-
value,
|
|
4723
|
-
id: checkId,
|
|
4724
|
-
});
|
|
4725
|
-
},
|
|
4726
|
-
};
|
|
4727
|
-
return evalInContext(`(${condition})`, context);
|
|
4728
|
-
}
|
|
4729
|
-
function evalInContext(script, context) {
|
|
4730
|
-
// # Return the results of the in-line anonymous function we .call with the passed context
|
|
4731
|
-
return function () {
|
|
4732
|
-
return eval(script);
|
|
4733
|
-
}.call(context);
|
|
4734
|
-
}
|
|
4735
4943
|
async function textCommand(dialog) {
|
|
4736
4944
|
const dialogStore = useDialogStore();
|
|
4737
4945
|
dialogStore.addDialog(dialog);
|
|
@@ -4765,73 +4973,112 @@ class VM {
|
|
|
4765
4973
|
}
|
|
4766
4974
|
}
|
|
4767
4975
|
const vm = new VM();
|
|
4768
|
-
async function runCommand(
|
|
4976
|
+
async function runCommand(expression, choices) {
|
|
4769
4977
|
const vmStore = useVM();
|
|
4770
4978
|
try {
|
|
4771
|
-
const
|
|
4772
|
-
|
|
4773
|
-
commandPlugin.runner(cmd, choices);
|
|
4774
|
-
}
|
|
4979
|
+
const result = await runExpression(expression, choices);
|
|
4980
|
+
return result;
|
|
4775
4981
|
}
|
|
4776
4982
|
catch (err) {
|
|
4777
|
-
logger.log(`Error at: `, vmStore.currentStack.label);
|
|
4778
4983
|
console.error(err);
|
|
4779
|
-
error(
|
|
4984
|
+
console.error(expression);
|
|
4985
|
+
error(`Narrat script runtime error at <span class="error-filename">${expression.fileName}:${expression.line + 1}</span>
|
|
4780
4986
|
<b>${err}</b>
|
|
4781
|
-
Script: ${
|
|
4987
|
+
Script: ${expression.code}
|
|
4782
4988
|
Label: ${vmStore.currentStack.label}`);
|
|
4783
4989
|
}
|
|
4784
4990
|
}
|
|
4785
|
-
async function
|
|
4786
|
-
const
|
|
4787
|
-
const
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4991
|
+
async function generateCommand(expr, choices) {
|
|
4992
|
+
const command = expr.command;
|
|
4993
|
+
const commandPlugin = vm.commands[command.commandType];
|
|
4994
|
+
if (commandPlugin) {
|
|
4995
|
+
const generatedCommand = {
|
|
4996
|
+
args: [],
|
|
4997
|
+
options: {},
|
|
4998
|
+
operator: command.operator,
|
|
4999
|
+
staticOptions: command.staticOptions,
|
|
5000
|
+
code: expr.code,
|
|
5001
|
+
commandType: command.commandType,
|
|
5002
|
+
fileName: expr.fileName,
|
|
5003
|
+
line: expr.line,
|
|
5004
|
+
};
|
|
5005
|
+
// Evaluate arguments
|
|
5006
|
+
const argTypes = commandPlugin.argTypes;
|
|
5007
|
+
generatedCommand.options = {};
|
|
5008
|
+
for (const [i, arg] of command.args.entries()) {
|
|
5009
|
+
let finalArg;
|
|
5010
|
+
if (isExpression(arg)) {
|
|
5011
|
+
// Arg is an expression, run it
|
|
5012
|
+
finalArg = await runExpression(arg, choices);
|
|
5013
|
+
}
|
|
5014
|
+
else if (typeof arg === 'string') {
|
|
5015
|
+
if (arg.search(stringRegex) === 0) {
|
|
5016
|
+
// This is an actual string
|
|
5017
|
+
finalArg = arg.substring(3);
|
|
5018
|
+
}
|
|
5019
|
+
else if (arg.search(/\$/) === 0) {
|
|
5020
|
+
// This is potentially a variable token
|
|
5021
|
+
const modifiable = getModifiableDataPinia();
|
|
5022
|
+
const result = findDataHelperWithoutAutoCreate(modifiable, arg.substring(1));
|
|
5023
|
+
if (result) {
|
|
5024
|
+
const [target, key] = result;
|
|
5025
|
+
finalArg = target[key];
|
|
5026
|
+
}
|
|
5027
|
+
else {
|
|
5028
|
+
finalArg = arg;
|
|
5029
|
+
}
|
|
4801
5030
|
}
|
|
4802
5031
|
else {
|
|
4803
|
-
|
|
4804
|
-
const winner = result ? skillcheck.success : skillcheck.failure;
|
|
4805
|
-
newBranch = winner.branch;
|
|
4806
|
-
playerText = undefined;
|
|
5032
|
+
finalArg = arg;
|
|
4807
5033
|
}
|
|
4808
5034
|
}
|
|
4809
5035
|
else {
|
|
4810
|
-
|
|
4811
|
-
}
|
|
4812
|
-
if (playerText) {
|
|
4813
|
-
// If the choice involves printing a player dialog, show it
|
|
4814
|
-
const dialog = {
|
|
4815
|
-
speaker: 'player',
|
|
4816
|
-
text: playerText,
|
|
4817
|
-
interactive: false,
|
|
4818
|
-
};
|
|
4819
|
-
dialogStore.addDialog(dialog);
|
|
5036
|
+
finalArg = arg;
|
|
4820
5037
|
}
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
return vmStore.addStack(newStack);
|
|
5038
|
+
generatedCommand.args.push(finalArg);
|
|
5039
|
+
if (Array.isArray(argTypes) && argTypes.length > i) {
|
|
5040
|
+
const argType = argTypes[i];
|
|
5041
|
+
if (finalArg !== null) {
|
|
5042
|
+
generatedCommand.options[argType.name] = finalArg;
|
|
5043
|
+
}
|
|
4828
5044
|
}
|
|
4829
|
-
|
|
4830
|
-
|
|
5045
|
+
}
|
|
5046
|
+
return generatedCommand;
|
|
5047
|
+
}
|
|
5048
|
+
else {
|
|
5049
|
+
throw new Error(`${command.commandType} is not a valid command`);
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
async function runExpression(expr, choices) {
|
|
5053
|
+
const command = await generateCommand(expr, choices);
|
|
5054
|
+
const commandPlugin = vm.commands[command.commandType];
|
|
5055
|
+
if (commandPlugin) {
|
|
5056
|
+
const result = await commandPlugin.runner(command, choices);
|
|
5057
|
+
return result;
|
|
5058
|
+
}
|
|
5059
|
+
else {
|
|
5060
|
+
throw new Error(`${command.commandType} is not a valid command`);
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
async function playerAnswered(choiceIndex) {
|
|
5064
|
+
audioEvent('onPlayerAnswered');
|
|
5065
|
+
const vmStore = useVM();
|
|
5066
|
+
// For some super weird reason, vmStore.currentCommand has a broken type?
|
|
5067
|
+
const command = vmStore.lastChoiceCommand;
|
|
5068
|
+
vmStore.lastChoiceCommand = undefined;
|
|
5069
|
+
const currentLine = vmStore.currentLine;
|
|
5070
|
+
try {
|
|
5071
|
+
if (command) {
|
|
5072
|
+
const commandPlugin = vm.commands[command.commandType];
|
|
5073
|
+
if (commandPlugin && commandPlugin.onPlayerAnswered) {
|
|
5074
|
+
return await commandPlugin.onPlayerAnswered(command, choiceIndex);
|
|
4831
5075
|
}
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
5076
|
+
}
|
|
5077
|
+
return await vmStore.nextLine();
|
|
5078
|
+
}
|
|
5079
|
+
catch (err) {
|
|
5080
|
+
console.error(err);
|
|
5081
|
+
error(`Error after player answer at ${currentLine.fileName}:${currentLine.line + 1} (${currentLine.code}<br /> - Error: ${err}`);
|
|
4835
5082
|
}
|
|
4836
5083
|
}
|
|
4837
5084
|
|
|
@@ -5287,7 +5534,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
5287
5534
|
], 4))
|
|
5288
5535
|
}
|
|
5289
5536
|
|
|
5290
|
-
var css_248z$1 = ".dialog-title {\n font-size: 20px;\n font-weight: bold;\n}\n\n.dialog-text {\n font-size: 16px;\n}\n\n.dialog-box {\n /* border-radius: 10px; */\n /* border: 1px solid #a8a8a8; */\n color: var(--text-color);\n /* background-color: #2e2e2e; */\n padding: 10px;\n padding-left: 2em;\n margin-bottom: 10px;\n}\n\n.dialog-choice {\n color: var(--dialog-choice-color);\n}\n\n.dialog-choice:hover {\n color: var(--dialog-choice-hover-color);\n cursor: pointer;\n}\n\n.buttons-container {\n width: 100%;\n padding: 10px;\n display: flex;\n justify-content: space-evenly;\n align-items: stretch;\n box-sizing: border-box;\n}\n\n.interact-button {\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n
|
|
5537
|
+
var css_248z$1 = ".dialog-title {\n font-size: 20px;\n font-weight: bold;\n}\n\n.dialog-text {\n font-size: 16px;\n}\n\n.dialog-box {\n /* border-radius: 10px; */\n /* border: 1px solid #a8a8a8; */\n color: var(--text-color);\n /* background-color: #2e2e2e; */\n padding: 10px;\n padding-left: 2em;\n margin-bottom: 10px;\n}\n\n.dialog-choice {\n color: var(--dialog-choice-color);\n}\n\n.dialog-choice:hover {\n color: var(--dialog-choice-hover-color);\n cursor: pointer;\n}\n\n.buttons-container {\n width: 100%;\n padding: 10px;\n display: flex;\n justify-content: space-evenly;\n align-items: stretch;\n box-sizing: border-box;\n}\n\n.interact-button {\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n height: 50px;\n color: var(--text-color);\n border: 1px solid black;\n font-weight: bold;\n font-size: 24px;\n text-align: center;\n flex-grow: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n\n.interact-button:not(:last-child) {\n margin-right: 10px;\n}\n";
|
|
5291
5538
|
styleInject(css_248z$1);
|
|
5292
5539
|
|
|
5293
5540
|
script.render = render;
|
|
@@ -6738,13 +6985,13 @@ const KeyType = {
|
|
|
6738
6985
|
PATTERN: '$val'
|
|
6739
6986
|
};
|
|
6740
6987
|
|
|
6741
|
-
const isExpression = (query) =>
|
|
6988
|
+
const isExpression$1 = (query) =>
|
|
6742
6989
|
!!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
|
|
6743
6990
|
|
|
6744
6991
|
const isPath = (query) => !!query[KeyType.PATH];
|
|
6745
6992
|
|
|
6746
6993
|
const isLeaf = (query) =>
|
|
6747
|
-
!isArray(query) && isObject(query) && !isExpression(query);
|
|
6994
|
+
!isArray(query) && isObject(query) && !isExpression$1(query);
|
|
6748
6995
|
|
|
6749
6996
|
const convertToExplicit = (query) => ({
|
|
6750
6997
|
[LogicalOperator.AND]: Object.keys(query).map((key) => ({
|
|
@@ -6760,7 +7007,7 @@ function parse(query, options, { auto = true } = {}) {
|
|
|
6760
7007
|
|
|
6761
7008
|
const isQueryPath = isPath(query);
|
|
6762
7009
|
|
|
6763
|
-
if (!isQueryPath && keys.length > 1 && !isExpression(query)) {
|
|
7010
|
+
if (!isQueryPath && keys.length > 1 && !isExpression$1(query)) {
|
|
6764
7011
|
return next(convertToExplicit(query))
|
|
6765
7012
|
}
|
|
6766
7013
|
|
|
@@ -6803,7 +7050,7 @@ function parse(query, options, { auto = true } = {}) {
|
|
|
6803
7050
|
return node
|
|
6804
7051
|
};
|
|
6805
7052
|
|
|
6806
|
-
if (!isExpression(query)) {
|
|
7053
|
+
if (!isExpression$1(query)) {
|
|
6807
7054
|
query = convertToExplicit(query);
|
|
6808
7055
|
}
|
|
6809
7056
|
|
|
@@ -7312,7 +7559,7 @@ var script$3 = defineComponent({
|
|
|
7312
7559
|
items: inventoryStore.items,
|
|
7313
7560
|
skills: skillsStore.skills,
|
|
7314
7561
|
skillChecks: skillsStore.skillChecks,
|
|
7315
|
-
}
|
|
7562
|
+
},
|
|
7316
7563
|
},
|
|
7317
7564
|
onChange: (updatedContent) => {
|
|
7318
7565
|
vmStore.overrideData(updatedContent.json.data);
|
|
@@ -7390,28 +7637,30 @@ var script$3 = defineComponent({
|
|
|
7390
7637
|
const scripts = Object.values(this.script);
|
|
7391
7638
|
const count = scripts.reduce((count, script) => {
|
|
7392
7639
|
logger.log(count);
|
|
7393
|
-
return count + this.countWordsInScriptBranch(script);
|
|
7640
|
+
return count + this.countWordsInScriptBranch(script.branch);
|
|
7394
7641
|
}, 0);
|
|
7395
7642
|
alert(`You have ${count} words`);
|
|
7396
7643
|
},
|
|
7397
7644
|
countWordsInScriptLine(scriptLine) {
|
|
7398
|
-
if (scriptLine.commandType === 'talk') {
|
|
7399
|
-
|
|
7645
|
+
if (scriptLine.command.commandType === 'talk') {
|
|
7646
|
+
if (typeof scriptLine.command.args[2] === 'string') {
|
|
7647
|
+
return this.countWordsInString(scriptLine.command.args[2]);
|
|
7648
|
+
}
|
|
7400
7649
|
}
|
|
7401
|
-
if (scriptLine.commandType === 'text') {
|
|
7402
|
-
return this.countWordsInString(scriptLine.
|
|
7650
|
+
if (scriptLine.command.commandType === 'text') {
|
|
7651
|
+
return this.countWordsInString(scriptLine.code);
|
|
7403
7652
|
}
|
|
7404
|
-
if (scriptLine.commandType === 'choice') {
|
|
7405
|
-
const opt = scriptLine.
|
|
7653
|
+
if (scriptLine.command.commandType === 'choice') {
|
|
7654
|
+
const opt = scriptLine.command.staticOptions;
|
|
7406
7655
|
let count = this.countWordsInScriptLine(opt.prompt);
|
|
7407
|
-
count += opt.choices.reduce((count, choice) => count + this.countWordsInString(choice.
|
|
7656
|
+
count += opt.choices.reduce((count, choice) => count + this.countWordsInString(choice.prompt.code), 0);
|
|
7408
7657
|
const choices = opt.choices;
|
|
7409
7658
|
return choices.reduce((count, choice) => {
|
|
7410
7659
|
return count + this.countWordsInScriptBranch(choice.branch);
|
|
7411
7660
|
}, count);
|
|
7412
7661
|
}
|
|
7413
|
-
if (scriptLine.commandType === 'if') {
|
|
7414
|
-
const opt = scriptLine.
|
|
7662
|
+
if (scriptLine.command.commandType === 'if') {
|
|
7663
|
+
const opt = scriptLine.command.staticOptions;
|
|
7415
7664
|
const branches = [opt.success, opt.failure];
|
|
7416
7665
|
return branches.reduce((count, choice) => {
|
|
7417
7666
|
if (choice) {
|
|
@@ -7628,8 +7877,8 @@ function render$3(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
7628
7877
|
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.skillChecks, (check, key) => {
|
|
7629
7878
|
return (openBlock(), createElementBlock("tr", { key: key }, [
|
|
7630
7879
|
createElementVNode("td", null, toDisplayString(key), 1),
|
|
7631
|
-
createElementVNode("td", null, toDisplayString(
|
|
7632
|
-
createElementVNode("td", null, toDisplayString(check.
|
|
7880
|
+
createElementVNode("td", null, toDisplayString(check.happened ? '✅' : '❌'), 1),
|
|
7881
|
+
createElementVNode("td", null, toDisplayString(!check.happened ? 'NA' : check.succeeded ? '✅' : '❌'), 1)
|
|
7633
7882
|
]))
|
|
7634
7883
|
}), 128))
|
|
7635
7884
|
])
|
|
@@ -8666,9 +8915,6 @@ var script$d = defineComponent({
|
|
|
8666
8915
|
}
|
|
8667
8916
|
return undefined;
|
|
8668
8917
|
},
|
|
8669
|
-
command() {
|
|
8670
|
-
return this.currentLine;
|
|
8671
|
-
},
|
|
8672
8918
|
picture() {
|
|
8673
8919
|
if (this.lastDialog) {
|
|
8674
8920
|
return getCharacterPictureUrl(this.lastDialog.speaker, this.lastDialog.pose);
|
|
@@ -8809,10 +9055,12 @@ var script$d = defineComponent({
|
|
|
8809
9055
|
return localStorage.getItem(SAVE_FILE);
|
|
8810
9056
|
},
|
|
8811
9057
|
async startGame() {
|
|
9058
|
+
audioEvent('onPressStart');
|
|
8812
9059
|
const main = useMain();
|
|
8813
9060
|
await main.startGame();
|
|
8814
9061
|
},
|
|
8815
9062
|
async loadGame() {
|
|
9063
|
+
audioEvent('onPressStart');
|
|
8816
9064
|
useMain().loadGame(this.getSaveFile());
|
|
8817
9065
|
},
|
|
8818
9066
|
isDialogActive(i) {
|
|
@@ -8860,13 +9108,14 @@ const _hoisted_1$c = ["width", "height"];
|
|
|
8860
9108
|
const _hoisted_2$a = /*#__PURE__*/createElementVNode("div", { class: "anchor" }, null, -1);
|
|
8861
9109
|
const _hoisted_3$7 = {
|
|
8862
9110
|
key: 2,
|
|
8863
|
-
|
|
9111
|
+
id: "game-menu",
|
|
8864
9112
|
style: {"height":"100%","padding":"20px"}
|
|
8865
9113
|
};
|
|
8866
|
-
const _hoisted_4$6 = { id: "game-
|
|
8867
|
-
const _hoisted_5$6 = { id: "game-title-
|
|
8868
|
-
const _hoisted_6$6 = {
|
|
8869
|
-
const _hoisted_7$5 = {
|
|
9114
|
+
const _hoisted_4$6 = { id: "game-header" };
|
|
9115
|
+
const _hoisted_5$6 = { id: "game-title-container" };
|
|
9116
|
+
const _hoisted_6$6 = { id: "game-title-text" };
|
|
9117
|
+
const _hoisted_7$5 = { class: "flex flex-col" };
|
|
9118
|
+
const _hoisted_8$4 = { key: 3 };
|
|
8870
9119
|
|
|
8871
9120
|
function render$d(_ctx, _cache, $props, $setup, $data, $options) {
|
|
8872
9121
|
const _component_Hud = resolveComponent("Hud");
|
|
@@ -8975,23 +9224,25 @@ function render$d(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
8975
9224
|
: (_ctx.gameLoaded)
|
|
8976
9225
|
? (openBlock(), createElementBlock("div", _hoisted_3$7, [
|
|
8977
9226
|
createElementVNode("div", _hoisted_4$6, [
|
|
8978
|
-
createElementVNode("
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
createElementVNode("
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
9227
|
+
createElementVNode("div", _hoisted_5$6, [
|
|
9228
|
+
createElementVNode("h1", _hoisted_6$6, toDisplayString(_ctx.gameTitle), 1)
|
|
9229
|
+
]),
|
|
9230
|
+
createElementVNode("div", _hoisted_7$5, [
|
|
9231
|
+
createElementVNode("button", {
|
|
9232
|
+
class: "button menu-button main-menu-button larg start-button override",
|
|
9233
|
+
onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.startGame && _ctx.startGame(...args)))
|
|
9234
|
+
}, " Start Game "),
|
|
9235
|
+
(_ctx.hasSave)
|
|
9236
|
+
? (openBlock(), createElementBlock("button", {
|
|
9237
|
+
key: 0,
|
|
9238
|
+
class: "button menu-button main-menu-button large continue-button override",
|
|
9239
|
+
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.loadGame && _ctx.loadGame(...args)))
|
|
9240
|
+
}, " Continue Game "))
|
|
9241
|
+
: createCommentVNode("", true)
|
|
9242
|
+
])
|
|
8992
9243
|
])
|
|
8993
9244
|
]))
|
|
8994
|
-
: (openBlock(), createElementBlock("div",
|
|
9245
|
+
: (openBlock(), createElementBlock("div", _hoisted_8$4, [
|
|
8995
9246
|
createVNode(_component_LoadingBar, {
|
|
8996
9247
|
percentage: _ctx.loadingPercentage,
|
|
8997
9248
|
step: _ctx.loadingStep
|
|
@@ -9004,7 +9255,7 @@ function render$d(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
9004
9255
|
], 4))
|
|
9005
9256
|
}
|
|
9006
9257
|
|
|
9007
|
-
var css_248z$e = "#app {\n background-color: var(--bg-color);\n width: 100%;\n height: 100%;\n position: absolute;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n color: var(--text-color);\n box-sizing: border-box;\n overflow: hidden;\n transform-origin: center center;\n}\n\n.game {\n background-color: var(--bg-color);\n position: relative;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.interact-button {\n height: 50px;\n border: 1px solid black;\n font-weight: bold;\n font-size: 20px;\n text-align: center;\n flex-grow: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n\n.interact-button:not(:last-child) {\n margin-right: 10px;\n}\n\n.dialog-container {\n flex-shrink: 2;\n /* padding: 20px; */\n min-height: 100%;\n width: 100%;\n background-color: (var(--bg-color));\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: center;\n overflow-x: hidden;\n}\n\n.dialog {\n overflow-y: auto;\n overflow-x: hidden;\n position: relative;\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n}\n\n.dialog::-webkit-scrollbar {\n display: none; /* webkit */\n}\n\n.dialog * {\n overflow-anchor: none;\n}\n\n.background {\n margin: 0;\n}\n\n#background-canvas {\n height: 100%;\n}\n\n.anchor {\n overflow-anchor: auto;\n height: 1px;\n}\n\n.menu-toggle {\n position: fixed;\n bottom: 0px;\n right: 15%;\n z-index: 2;\n}\n\n#game-title-container {\n margin-bottom: 50px;\n}\n\n#game-title-text {\n text-align: center;\n font-size: 50px;\n}\n\n.menu-button {\n font-size: 25px;\n}\n";
|
|
9258
|
+
var css_248z$e = "#app {\n background-color: var(--bg-color);\n width: 100%;\n height: 100%;\n position: absolute;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n color: var(--text-color);\n box-sizing: border-box;\n overflow: hidden;\n transform-origin: center center;\n}\n\n.game {\n background-color: var(--bg-color);\n position: relative;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.interact-button {\n height: 50px;\n border: 1px solid black;\n font-weight: bold;\n font-size: 20px;\n text-align: center;\n flex-grow: 2;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n\n.interact-button:not(:last-child) {\n margin-right: 10px;\n}\n\n.dialog-container {\n flex-shrink: 2;\n /* padding: 20px; */\n min-height: 100%;\n width: 100%;\n background-color: (var(--bg-color));\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: center;\n overflow-x: hidden;\n}\n\n.dialog {\n overflow-y: auto;\n overflow-x: hidden;\n position: relative;\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n}\n\n.dialog::-webkit-scrollbar {\n display: none; /* webkit */\n}\n\n.dialog * {\n overflow-anchor: none;\n}\n\n.background {\n margin: 0;\n}\n\n#background-canvas {\n height: 100%;\n}\n\n.anchor {\n overflow-anchor: auto;\n height: 1px;\n}\n\n.menu-toggle {\n position: fixed;\n bottom: 0px;\n right: 15%;\n z-index: 2;\n}\n\n#game-title-container {\n margin-bottom: 50px;\n}\n\n#game-title-text {\n text-align: center;\n font-size: 50px;\n}\n\n.menu-button {\n font-size: 25px;\n}\n\n#game-header {\n position: relative;\n top: 100px;\n}\n";
|
|
9008
9259
|
styleInject(css_248z$e);
|
|
9009
9260
|
|
|
9010
9261
|
script$d.render = render$d;
|
|
@@ -9090,7 +9341,7 @@ function mouseclick(e) {
|
|
|
9090
9341
|
// clicked button
|
|
9091
9342
|
const scriptToRun = button.action;
|
|
9092
9343
|
const newStack = {
|
|
9093
|
-
|
|
9344
|
+
branchData: vmStore.script[scriptToRun],
|
|
9094
9345
|
currentIndex: 0,
|
|
9095
9346
|
label: scriptToRun,
|
|
9096
9347
|
};
|
|
@@ -9102,264 +9353,203 @@ function mouseclick(e) {
|
|
|
9102
9353
|
}
|
|
9103
9354
|
}
|
|
9104
9355
|
|
|
9356
|
+
function commandRuntimeError(cmd, errorText) {
|
|
9357
|
+
console.error(`Runtime error =========================`);
|
|
9358
|
+
console.error('Args: ', cmd.args);
|
|
9359
|
+
console.error('Options: ', cmd.options);
|
|
9360
|
+
error(`Runtime error at ${cmd.fileName}:${cmd.line} (${cmd.commandType}) ${cmd.code}. -
|
|
9361
|
+
<br />
|
|
9362
|
+
Error: ${errorText}`);
|
|
9363
|
+
console.error('============================');
|
|
9364
|
+
}
|
|
9365
|
+
|
|
9105
9366
|
class CommandPlugin {
|
|
9106
9367
|
keyword;
|
|
9107
9368
|
runner;
|
|
9369
|
+
argTypes;
|
|
9108
9370
|
parser;
|
|
9109
|
-
|
|
9371
|
+
onPlayerAnswered;
|
|
9372
|
+
constructor(keyword, argTypes, runner, parser) {
|
|
9110
9373
|
this.keyword = keyword;
|
|
9111
9374
|
this.runner = runner;
|
|
9112
|
-
this.
|
|
9375
|
+
this.argTypes = argTypes;
|
|
9376
|
+
if (!parser) {
|
|
9377
|
+
this.parser = generateParser(this.keyword, this.argTypes);
|
|
9378
|
+
}
|
|
9379
|
+
else {
|
|
9380
|
+
this.parser = parser;
|
|
9381
|
+
}
|
|
9113
9382
|
}
|
|
9114
9383
|
}
|
|
9115
|
-
function generateParser(keyword) {
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
const vm = useVM();
|
|
9126
|
-
vm.addInstruction(addKey, addValue);
|
|
9127
|
-
return vm.nextLine();
|
|
9128
|
-
};
|
|
9129
|
-
const addPlugin = new CommandPlugin('add', add, generateParser('add'));
|
|
9130
|
-
|
|
9131
|
-
const addLevelRunner = async (cmd) => {
|
|
9132
|
-
const [skillKey, levelToAdd] = cmd.args;
|
|
9133
|
-
if (!skillKey || !levelToAdd) {
|
|
9134
|
-
error(`add_level command needs a skill id and a value as parameters`);
|
|
9135
|
-
}
|
|
9136
|
-
useSkills().incrementSkill(skillKey, levelToAdd);
|
|
9137
|
-
return useVM().nextLine();
|
|
9138
|
-
};
|
|
9139
|
-
const addLevelParser = (ctx) => {
|
|
9140
|
-
ctx.command.commandType = 'add_level';
|
|
9141
|
-
ctx.currentLine++;
|
|
9142
|
-
};
|
|
9143
|
-
const addLevelPlugin = new CommandPlugin('add_level', addLevelRunner, addLevelParser);
|
|
9144
|
-
|
|
9145
|
-
const addStatRunner = async (cmd) => {
|
|
9146
|
-
const statKey = cmd.args[0];
|
|
9147
|
-
const amountToAdd = cmd.args[1];
|
|
9148
|
-
if (!statKey || !amountToAdd) {
|
|
9149
|
-
error(`add_stat command needs a stat id and a value as parameters`);
|
|
9150
|
-
}
|
|
9151
|
-
const hud = useHud();
|
|
9152
|
-
hud.addStat(statKey, amountToAdd);
|
|
9153
|
-
return useVM().nextLine();
|
|
9154
|
-
};
|
|
9155
|
-
const addStatParser = (ctx) => {
|
|
9156
|
-
ctx.command.commandType = 'add_stat';
|
|
9157
|
-
ctx.currentLine++;
|
|
9158
|
-
};
|
|
9159
|
-
const addStatPlugin = new CommandPlugin('add_stat', addStatRunner, addStatParser);
|
|
9160
|
-
|
|
9161
|
-
const addXp = async (cmd) => {
|
|
9162
|
-
const xpKey = cmd.args[0];
|
|
9163
|
-
const xpToAdd = cmd.args[1];
|
|
9164
|
-
if (!xpKey || !xpToAdd) {
|
|
9165
|
-
error(`add_xp command needs a skill id and a value as parameters`);
|
|
9166
|
-
}
|
|
9167
|
-
useSkills().addXp(xpKey, xpToAdd);
|
|
9168
|
-
return useVM().nextLine();
|
|
9169
|
-
};
|
|
9170
|
-
const addXpPlugin = new CommandPlugin('add_xp', addXp, generateParser('add_xp'));
|
|
9171
|
-
|
|
9172
|
-
const choice = async (cmd) => {
|
|
9173
|
-
await runChoice(cmd);
|
|
9174
|
-
};
|
|
9175
|
-
async function runChoice(cmd) {
|
|
9176
|
-
const options = cmd.options;
|
|
9177
|
-
const prompt = options.prompt;
|
|
9178
|
-
const choices = options.choices
|
|
9179
|
-
.filter((choice) => {
|
|
9180
|
-
// Delete the choice if it fails a condition
|
|
9181
|
-
if (choice.condition) {
|
|
9182
|
-
return runCondition(choice.condition);
|
|
9384
|
+
function generateParser(keyword, argTypes) {
|
|
9385
|
+
let expectedArgCount = [];
|
|
9386
|
+
if (argTypes !== 'any') {
|
|
9387
|
+
expectedArgCount = [argTypes.length];
|
|
9388
|
+
const optionalArgs = argTypes.reduce((total, argType) => (argType.optional ? total + 1 : total), 0);
|
|
9389
|
+
if (optionalArgs > 1) {
|
|
9390
|
+
throw new Error(`Only one optional argument is allowed for commands but ${keyword} has multiple ones`);
|
|
9391
|
+
}
|
|
9392
|
+
if (optionalArgs === 1) {
|
|
9393
|
+
expectedArgCount.push(argTypes.length - 1);
|
|
9183
9394
|
}
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9395
|
+
}
|
|
9396
|
+
return (ctx, parsed) => {
|
|
9397
|
+
const returnValue = {
|
|
9398
|
+
newLine: ctx.currentLine + 1
|
|
9399
|
+
};
|
|
9400
|
+
const args = parsed.command.args;
|
|
9401
|
+
if (argTypes !== 'any') {
|
|
9402
|
+
if (!expectedArgCount.includes(args.length)) {
|
|
9403
|
+
console.log("Error details");
|
|
9404
|
+
console.log(parsed.command);
|
|
9405
|
+
console.log(args);
|
|
9406
|
+
ctx.parserContext.error(ctx.line.line, `Command ${keyword}: Expected ${expectedArgCount.join(' or ')} arguments but got ${args.length}`);
|
|
9407
|
+
return returnValue;
|
|
9188
9408
|
}
|
|
9189
9409
|
}
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9410
|
+
parsed.command.commandType = keyword;
|
|
9411
|
+
// todo: check types of args
|
|
9412
|
+
if (argTypes !== 'any') {
|
|
9413
|
+
parsed.command.args.forEach((arg, index) => {
|
|
9414
|
+
const argType = argTypes[index];
|
|
9415
|
+
if (!isExpression(arg)) {
|
|
9416
|
+
// Only run this if the arg isn't an expression, as expressions aren't currently typed
|
|
9417
|
+
// eslint-disable-next-line valid-typeof
|
|
9418
|
+
const isValid = argType.type === 'any' || typeof arg === argType.type;
|
|
9419
|
+
if (!isValid) {
|
|
9420
|
+
ctx.parserContext.error(ctx.line.line, `Command ${keyword}: Argument #${index + 1} (${argType.name}) should be a ${argType.type}, but got type ${typeof arg}: ${JSON.stringify(arg)}`);
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9201
9423
|
});
|
|
9202
|
-
text = `${difficultyText} ${text}`;
|
|
9203
|
-
choiceAllowed = allowed;
|
|
9204
9424
|
}
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
originalIndex: choice.index,
|
|
9208
|
-
allowed: choiceAllowed,
|
|
9425
|
+
return {
|
|
9426
|
+
newLine: ctx.currentLine + 1,
|
|
9209
9427
|
};
|
|
9210
|
-
return result;
|
|
9211
|
-
});
|
|
9212
|
-
runCommand(prompt, choices);
|
|
9213
|
-
}
|
|
9214
|
-
const choiceParser = (ctx) => {
|
|
9215
|
-
const { line, command } = ctx;
|
|
9216
|
-
if (!line.branch || line.branch.length < 2) {
|
|
9217
|
-
ctx.parserContext.error(line.line, `Choice menu needs to have at least one option`);
|
|
9218
|
-
}
|
|
9219
|
-
const prompt = line.branch[0];
|
|
9220
|
-
const choices = line.branch.slice(1);
|
|
9221
|
-
const prompts = choices.map((choice, index) => {
|
|
9222
|
-
if (!choice.branch) {
|
|
9223
|
-
ctx.parserContext.error(choice.line, `Choice option doesn't have any branch to go to (${choice.code})`);
|
|
9224
|
-
}
|
|
9225
|
-
return parseChoiceOption(ctx, choice, index);
|
|
9226
|
-
});
|
|
9227
|
-
command.options = {
|
|
9228
|
-
prompt: ctx.processCommandsFunction(ctx.parserContext, [prompt], line)[0],
|
|
9229
|
-
choices: prompts,
|
|
9230
9428
|
};
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
const success = {
|
|
9247
|
-
text: successBranch.args[0],
|
|
9248
|
-
branch: ctx.processCommandsFunction(ctx.parserContext, successBranch.branch, choice),
|
|
9249
|
-
};
|
|
9250
|
-
let failedBranch;
|
|
9251
|
-
if (failureBranch.branch) {
|
|
9252
|
-
failedBranch = ctx.processCommandsFunction(ctx.parserContext, failureBranch.branch, choice);
|
|
9253
|
-
}
|
|
9254
|
-
const failure = {
|
|
9255
|
-
text: failureBranch.args[0],
|
|
9256
|
-
branch: failedBranch,
|
|
9257
|
-
};
|
|
9258
|
-
skillCheck = {
|
|
9259
|
-
id: choice.args[0],
|
|
9260
|
-
skill: choice.args[1],
|
|
9261
|
-
value: choice.args[2],
|
|
9262
|
-
hideAfterRoll,
|
|
9263
|
-
success,
|
|
9264
|
-
failure,
|
|
9265
|
-
};
|
|
9429
|
+
}
|
|
9430
|
+
|
|
9431
|
+
const addLevelPlugin = new CommandPlugin('add_level', [
|
|
9432
|
+
{
|
|
9433
|
+
name: 'skillKey',
|
|
9434
|
+
type: 'string',
|
|
9435
|
+
},
|
|
9436
|
+
{
|
|
9437
|
+
name: 'amount',
|
|
9438
|
+
type: 'number',
|
|
9439
|
+
},
|
|
9440
|
+
], async (cmd) => {
|
|
9441
|
+
const { skillKey, amount } = cmd.options;
|
|
9442
|
+
if (!skillKey || !amount) {
|
|
9443
|
+
commandRuntimeError(cmd, `add_level command needs a skill id and a value as parameters`);
|
|
9266
9444
|
}
|
|
9267
|
-
|
|
9268
|
-
|
|
9445
|
+
useSkills().incrementSkill(skillKey, amount);
|
|
9446
|
+
return useVM().nextLine();
|
|
9447
|
+
});
|
|
9448
|
+
const addXpPlugin = new CommandPlugin('add_xp', [
|
|
9449
|
+
{ name: 'xpKey', type: 'string' },
|
|
9450
|
+
{ name: 'xpToAdd', type: 'number' },
|
|
9451
|
+
], async (cmd) => {
|
|
9452
|
+
const { xpKey, xpToAdd } = cmd.options;
|
|
9453
|
+
if (!xpKey || !xpToAdd) {
|
|
9454
|
+
commandRuntimeError(cmd, `add_xp command needs a skill id and a value as parameters`);
|
|
9269
9455
|
}
|
|
9270
|
-
|
|
9271
|
-
choice: choiceText,
|
|
9272
|
-
condition,
|
|
9273
|
-
skillCheck,
|
|
9274
|
-
branch: ctx.processCommandsFunction(ctx.parserContext, choice.branch, choice),
|
|
9275
|
-
index,
|
|
9276
|
-
};
|
|
9277
|
-
}
|
|
9278
|
-
const choicePlugin = new CommandPlugin('choice', choice, choiceParser);
|
|
9279
|
-
|
|
9280
|
-
const clearDialog = async (cmd) => {
|
|
9281
|
-
useDialogStore().clearDialog();
|
|
9456
|
+
useSkills().addXp(xpKey, xpToAdd);
|
|
9282
9457
|
return useVM().nextLine();
|
|
9283
|
-
};
|
|
9284
|
-
const
|
|
9458
|
+
});
|
|
9459
|
+
const rollPlugin = new CommandPlugin('roll', [
|
|
9460
|
+
{ name: 'id', type: 'string' },
|
|
9461
|
+
{ name: 'skill', type: 'string' },
|
|
9462
|
+
{ name: 'value', type: 'number' },
|
|
9463
|
+
{ name: 'hideAfterRoll', type: 'boolean', optional: true },
|
|
9464
|
+
], async (cmd) => {
|
|
9465
|
+
const { id, skill, value, hideAfterRoll } = cmd.options;
|
|
9466
|
+
const skillCheck = {
|
|
9467
|
+
id,
|
|
9468
|
+
skill,
|
|
9469
|
+
value,
|
|
9470
|
+
hideAfterRoll,
|
|
9471
|
+
};
|
|
9472
|
+
const result = runSkillCheck(skillCheck);
|
|
9473
|
+
return result;
|
|
9474
|
+
});
|
|
9285
9475
|
|
|
9286
|
-
const
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9476
|
+
const addStatPlugin = new CommandPlugin('add_stat', [
|
|
9477
|
+
{ name: 'statKey', type: 'string' },
|
|
9478
|
+
{ name: 'amountToAdd', type: 'number' },
|
|
9479
|
+
], async (cmd) => {
|
|
9480
|
+
const { statKey, amountToAdd } = cmd.options;
|
|
9481
|
+
if (!statKey || !amountToAdd) {
|
|
9482
|
+
commandRuntimeError(cmd, `add_stat command needs a stat id and a value as parameters`);
|
|
9483
|
+
}
|
|
9484
|
+
const hud = useHud();
|
|
9485
|
+
hud.addStat(statKey, amountToAdd);
|
|
9486
|
+
return useVM().nextLine();
|
|
9487
|
+
});
|
|
9488
|
+
const setStatPlugin = new CommandPlugin('set_stat', [
|
|
9489
|
+
{ name: 'statKey', type: 'string' },
|
|
9490
|
+
{ name: 'value', type: 'number' },
|
|
9491
|
+
], async (cmd) => {
|
|
9492
|
+
const { statKey, value } = cmd.options;
|
|
9493
|
+
if (!statKey || !value) {
|
|
9494
|
+
commandRuntimeError(cmd, `set_stat command needs a stat id and a value as parameters`);
|
|
9295
9495
|
}
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
failure = ctx.processCommandsFunction(ctx.parserContext, nextLine.branch, line);
|
|
9305
|
-
ctx.currentLine++;
|
|
9496
|
+
const hud = useHud();
|
|
9497
|
+
hud.setStat(statKey, value);
|
|
9498
|
+
return useVM().nextLine();
|
|
9499
|
+
});
|
|
9500
|
+
const getStatPlugin = new CommandPlugin('get_stat_value', [{ name: 'statKey', type: 'string' }], async (cmd) => {
|
|
9501
|
+
const { statKey } = cmd.options;
|
|
9502
|
+
if (!statKey) {
|
|
9503
|
+
commandRuntimeError(cmd, `get_stat_value command needs a stat id as parameter`);
|
|
9306
9504
|
}
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
failure,
|
|
9311
|
-
};
|
|
9312
|
-
ctx.currentLine++;
|
|
9313
|
-
};
|
|
9314
|
-
const ifCommand = new CommandPlugin('if', ifFunction, ifParser);
|
|
9505
|
+
const hud = useHud();
|
|
9506
|
+
return hud.getStatValue(statKey);
|
|
9507
|
+
});
|
|
9315
9508
|
|
|
9316
|
-
const
|
|
9317
|
-
|
|
9509
|
+
const jumpCommand = new CommandPlugin('jump', 'any', async (cmd) => {
|
|
9510
|
+
if (cmd.args.length < 1 || typeof cmd.args[0] !== 'string') {
|
|
9511
|
+
commandRuntimeError(cmd, `requires a label argument`);
|
|
9512
|
+
}
|
|
9513
|
+
const label = cmd.args[0];
|
|
9318
9514
|
const vm = useVM();
|
|
9319
9515
|
const newStack = {
|
|
9320
|
-
|
|
9321
|
-
label:
|
|
9516
|
+
branchData: vm.script[label],
|
|
9517
|
+
label: label,
|
|
9518
|
+
args: cmd.args.splice(1),
|
|
9322
9519
|
currentIndex: 0,
|
|
9323
9520
|
};
|
|
9324
9521
|
vm.setStack(newStack);
|
|
9325
9522
|
await useMain().saveGame();
|
|
9326
9523
|
await vm.runLine();
|
|
9327
|
-
};
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
useNotifications().addNotification(text);
|
|
9333
|
-
return useVM().nextLine();
|
|
9334
|
-
};
|
|
9335
|
-
const notifyPlugin = new CommandPlugin('notify', notify, generateParser('notify'));
|
|
9336
|
-
|
|
9337
|
-
const pause = async (cmd) => {
|
|
9338
|
-
const pauseOptions = cmd.options;
|
|
9339
|
-
if (pauseOptions.mode === 'music') {
|
|
9340
|
-
const audioStore = useAudio();
|
|
9341
|
-
pauseAudio(audioStore.currentMusic);
|
|
9342
|
-
}
|
|
9343
|
-
else if (pauseOptions.mode === 'sound' && pauseOptions.audio) {
|
|
9344
|
-
pauseAudio(pauseOptions.audio);
|
|
9345
|
-
}
|
|
9346
|
-
else {
|
|
9347
|
-
error(`pause first option needs to either be in music mode, or if stopping a sound needs to have the sound name supplied as second argument.`);
|
|
9524
|
+
});
|
|
9525
|
+
// Write a CommandPlugin for running a label using the runLabelFunction of the useVM store
|
|
9526
|
+
const runLabelPlugin = new CommandPlugin('run_label', 'any', async (cmd) => {
|
|
9527
|
+
if (cmd.args.length < 1 || typeof cmd.args[0] !== 'string') {
|
|
9528
|
+
commandRuntimeError(cmd, `run_label command needs a label to argument run`);
|
|
9348
9529
|
}
|
|
9530
|
+
const label = cmd.args[0];
|
|
9531
|
+
const res = await useVM().runLabelFunction(label, ...cmd.args.slice(1));
|
|
9532
|
+
return res;
|
|
9533
|
+
});
|
|
9534
|
+
const defineVariablePlugin = new CommandPlugin('var', [
|
|
9535
|
+
{ name: 'name', type: 'string' },
|
|
9536
|
+
{ name: 'value', type: 'any' },
|
|
9537
|
+
], async (cmd) => {
|
|
9538
|
+
const { name, value } = cmd.options;
|
|
9539
|
+
useVM().addScopedVariable(name, value);
|
|
9349
9540
|
return useVM().nextLine();
|
|
9350
|
-
};
|
|
9351
|
-
const
|
|
9352
|
-
const {
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
audio: command.args[1],
|
|
9357
|
-
};
|
|
9358
|
-
ctx.currentLine++;
|
|
9359
|
-
};
|
|
9360
|
-
const pauseCommand = new CommandPlugin('pause', pause, pauseParser);
|
|
9541
|
+
});
|
|
9542
|
+
const returnPlugin = new CommandPlugin('return', [{ name: 'value', type: 'any' }], async (cmd) => {
|
|
9543
|
+
const { value } = cmd.options;
|
|
9544
|
+
useVM().setReturnValue(value);
|
|
9545
|
+
return useVM().nextLine();
|
|
9546
|
+
});
|
|
9361
9547
|
|
|
9362
|
-
const
|
|
9548
|
+
const playCommandArgs = [
|
|
9549
|
+
{ name: 'mode', type: 'string' },
|
|
9550
|
+
{ name: 'audio', type: 'string', optional: true },
|
|
9551
|
+
];
|
|
9552
|
+
const playCommand = new CommandPlugin('play', playCommandArgs, async (cmd) => {
|
|
9363
9553
|
const playOptions = cmd.options;
|
|
9364
9554
|
if (playOptions.mode === 'music') {
|
|
9365
9555
|
changeMusic(playOptions.audio);
|
|
@@ -9368,69 +9558,22 @@ const play = async (cmd) => {
|
|
|
9368
9558
|
playAudio(playOptions.audio);
|
|
9369
9559
|
}
|
|
9370
9560
|
useVM().nextLine();
|
|
9371
|
-
};
|
|
9372
|
-
const
|
|
9373
|
-
const
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
audio: command.args[1],
|
|
9378
|
-
};
|
|
9379
|
-
ctx.currentLine++;
|
|
9380
|
-
};
|
|
9381
|
-
const playCommand = new CommandPlugin('play', play, playParser);
|
|
9382
|
-
|
|
9383
|
-
const set = async (cmd, choices) => {
|
|
9384
|
-
const key = cmd.args[0];
|
|
9385
|
-
const value = cmd.args[1];
|
|
9386
|
-
const vm = useVM();
|
|
9387
|
-
vm.setData(key, value);
|
|
9388
|
-
return vm.nextLine();
|
|
9389
|
-
};
|
|
9390
|
-
const setCommand = new CommandPlugin('set', set, generateParser('set'));
|
|
9391
|
-
|
|
9392
|
-
const setButton = async (cmd) => {
|
|
9393
|
-
const screens = useScreens();
|
|
9394
|
-
screens.changeButton(cmd.args[0], cmd.args[1]);
|
|
9395
|
-
return useVM().nextLine();
|
|
9396
|
-
};
|
|
9397
|
-
const setButtonParser = (ctx) => {
|
|
9398
|
-
const { command, line } = ctx;
|
|
9399
|
-
command.commandType = 'set_button';
|
|
9400
|
-
if (command.args.length !== 2) {
|
|
9401
|
-
ctx.parserContext.error(line.line, `set_button command should have 2 arguments`);
|
|
9561
|
+
});
|
|
9562
|
+
const pauseCommand = new CommandPlugin('pause', playCommandArgs, async (cmd) => {
|
|
9563
|
+
const pauseOptions = cmd.options;
|
|
9564
|
+
if (pauseOptions.mode === 'music') {
|
|
9565
|
+
const audioStore = useAudio();
|
|
9566
|
+
pauseAudio(audioStore.currentMusic);
|
|
9402
9567
|
}
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
const screens = useScreens();
|
|
9409
|
-
screens.setScreen(cmd.options.screen);
|
|
9410
|
-
return useVM().nextLine();
|
|
9411
|
-
};
|
|
9412
|
-
const setScreenParser = (ctx) => {
|
|
9413
|
-
const { command } = ctx;
|
|
9414
|
-
command.commandType = 'set_screen';
|
|
9415
|
-
command.options = {
|
|
9416
|
-
screen: command.args[0],
|
|
9417
|
-
};
|
|
9418
|
-
ctx.currentLine++;
|
|
9419
|
-
};
|
|
9420
|
-
const setScreenCommand = new CommandPlugin('set_screen', setScreen, setScreenParser);
|
|
9421
|
-
|
|
9422
|
-
const setStat = async (cmd) => {
|
|
9423
|
-
const setStatKey = cmd.args[0];
|
|
9424
|
-
const setAmount = cmd.args[1];
|
|
9425
|
-
if (!setStatKey || !setAmount) {
|
|
9426
|
-
error(`set_stat command needs a stat id and a value as parameters`);
|
|
9568
|
+
else if (pauseOptions.mode === 'sound' && pauseOptions.audio) {
|
|
9569
|
+
pauseAudio(pauseOptions.audio);
|
|
9570
|
+
}
|
|
9571
|
+
else {
|
|
9572
|
+
commandRuntimeError(cmd, `pause first option needs to either be in music mode, or if stopping a sound needs to have the sound name supplied as second argument.`);
|
|
9427
9573
|
}
|
|
9428
|
-
useHud().setStat(setStatKey, setAmount);
|
|
9429
9574
|
return useVM().nextLine();
|
|
9430
|
-
};
|
|
9431
|
-
const
|
|
9432
|
-
|
|
9433
|
-
const stop = async (cmd) => {
|
|
9575
|
+
});
|
|
9576
|
+
const stopCommand = new CommandPlugin('stop', playCommandArgs, async (cmd) => {
|
|
9434
9577
|
const stopOptions = cmd.options;
|
|
9435
9578
|
if (stopOptions.mode === 'music') {
|
|
9436
9579
|
const audioStore = useAudio();
|
|
@@ -9440,186 +9583,665 @@ const stop = async (cmd) => {
|
|
|
9440
9583
|
stopAudio(stopOptions.audio);
|
|
9441
9584
|
}
|
|
9442
9585
|
else {
|
|
9443
|
-
|
|
9586
|
+
commandRuntimeError(cmd, `stop option needs to either be in music mode, or if stopping a sound needs to have the sound name supplied as second argument.`);
|
|
9444
9587
|
}
|
|
9445
9588
|
return useVM().nextLine();
|
|
9446
|
-
};
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
};
|
|
9456
|
-
const
|
|
9589
|
+
});
|
|
9590
|
+
|
|
9591
|
+
const setCommand = new CommandPlugin('set', [
|
|
9592
|
+
{ name: 'key', type: 'string' },
|
|
9593
|
+
{ name: 'value', type: 'any' },
|
|
9594
|
+
], async (cmd) => {
|
|
9595
|
+
const state = getModifiableDataPinia();
|
|
9596
|
+
setDataHelper(state, cmd.options.key, cmd.options.value);
|
|
9597
|
+
return useVM().nextLine();
|
|
9598
|
+
});
|
|
9599
|
+
const addPlugin = new CommandPlugin('add', [
|
|
9600
|
+
{ name: 'key', type: 'string' },
|
|
9601
|
+
{ name: 'value', type: 'any' },
|
|
9602
|
+
], async (cmd) => {
|
|
9603
|
+
const state = getModifiableDataPinia();
|
|
9604
|
+
addDataHelper(state, cmd.options.key, cmd.options.value);
|
|
9605
|
+
return useVM().nextLine();
|
|
9606
|
+
});
|
|
9607
|
+
|
|
9608
|
+
const setScreenCommand = new CommandPlugin('set_screen', [{ name: 'screen', type: 'string' }], (cmd) => {
|
|
9609
|
+
const screens = useScreens();
|
|
9610
|
+
screens.setScreen(cmd.options.screen);
|
|
9611
|
+
return useVM().nextLine();
|
|
9612
|
+
});
|
|
9613
|
+
const setButtonCommand = new CommandPlugin('set_button', [
|
|
9614
|
+
{ name: 'buttonId', type: 'string' },
|
|
9615
|
+
{ name: 'enabled', type: 'boolean' },
|
|
9616
|
+
], async (cmd) => {
|
|
9617
|
+
const { buttonId, enabled } = cmd.options;
|
|
9618
|
+
const screens = useScreens();
|
|
9619
|
+
screens.changeButton(buttonId, enabled);
|
|
9620
|
+
return useVM().nextLine();
|
|
9621
|
+
});
|
|
9457
9622
|
|
|
9458
|
-
const
|
|
9623
|
+
const talkCommand = new CommandPlugin('talk', [
|
|
9624
|
+
{
|
|
9625
|
+
name: 'speaker',
|
|
9626
|
+
type: 'string',
|
|
9627
|
+
},
|
|
9628
|
+
{
|
|
9629
|
+
name: 'pose',
|
|
9630
|
+
type: 'string',
|
|
9631
|
+
},
|
|
9632
|
+
{
|
|
9633
|
+
name: 'text',
|
|
9634
|
+
type: 'string',
|
|
9635
|
+
},
|
|
9636
|
+
], async (cmd, choices) => {
|
|
9459
9637
|
await textCommand({
|
|
9460
|
-
speaker: cmd.
|
|
9461
|
-
pose: cmd.
|
|
9462
|
-
text: `"${cmd.
|
|
9638
|
+
speaker: cmd.options.speaker,
|
|
9639
|
+
pose: cmd.options.pose,
|
|
9640
|
+
text: `"${cmd.options.text}"`,
|
|
9463
9641
|
choices,
|
|
9464
9642
|
interactive: true,
|
|
9465
9643
|
});
|
|
9644
|
+
});
|
|
9645
|
+
const textParser = () => {
|
|
9646
|
+
const parser = generateParser('text', []);
|
|
9647
|
+
return (ctx, parsed) => {
|
|
9648
|
+
const result = parser(ctx, parsed);
|
|
9649
|
+
parsed.command.staticOptions = {
|
|
9650
|
+
text: parsed.code,
|
|
9651
|
+
};
|
|
9652
|
+
return result;
|
|
9653
|
+
};
|
|
9466
9654
|
};
|
|
9467
|
-
const
|
|
9468
|
-
const { command, line } = ctx;
|
|
9469
|
-
command.commandType = 'talk';
|
|
9470
|
-
if (command.args.length < 3) {
|
|
9471
|
-
ctx.parserContext.error(line.line, `Talk command needs 3 arguments!`);
|
|
9472
|
-
}
|
|
9473
|
-
ctx.currentLine++;
|
|
9474
|
-
};
|
|
9475
|
-
const talkCommand = new CommandPlugin('talk', talk, talkParser);
|
|
9476
|
-
|
|
9477
|
-
const text = async (cmd, choices) => {
|
|
9655
|
+
const textCommandPlugin = new CommandPlugin('text', [], async (cmd, choices) => {
|
|
9478
9656
|
await textCommand({
|
|
9479
9657
|
speaker: 'game',
|
|
9480
|
-
text: cmd.
|
|
9658
|
+
text: cmd.staticOptions.text,
|
|
9481
9659
|
choices,
|
|
9482
9660
|
interactive: true,
|
|
9483
9661
|
});
|
|
9484
|
-
};
|
|
9485
|
-
|
|
9486
|
-
const { command, line } = ctx;
|
|
9487
|
-
command.commandType = 'text';
|
|
9488
|
-
command.options = {
|
|
9489
|
-
text: line.operator,
|
|
9490
|
-
};
|
|
9491
|
-
ctx.currentLine++;
|
|
9492
|
-
};
|
|
9493
|
-
const textCommandPlugin = new CommandPlugin('text', text, textParser);
|
|
9494
|
-
|
|
9495
|
-
const wait = async (cmd) => {
|
|
9496
|
-
await timeout(cmd.options.duration);
|
|
9497
|
-
return useVM().nextLine();
|
|
9498
|
-
};
|
|
9499
|
-
const waitParser = (ctx) => {
|
|
9500
|
-
const { command } = ctx;
|
|
9501
|
-
command.commandType = 'wait';
|
|
9502
|
-
command.options = {
|
|
9503
|
-
duration: parseInt(command.args[0], 10),
|
|
9504
|
-
};
|
|
9505
|
-
ctx.currentLine++;
|
|
9506
|
-
};
|
|
9507
|
-
const waitCommand = new CommandPlugin('wait', wait, waitParser);
|
|
9662
|
+
}, textParser());
|
|
9663
|
+
console.log(textCommandPlugin);
|
|
9508
9664
|
|
|
9509
9665
|
// Write a CommandPlugin for adding items to the inventory store
|
|
9510
|
-
const addItemPlugin = new CommandPlugin('add_item',
|
|
9511
|
-
|
|
9512
|
-
|
|
9666
|
+
const addItemPlugin = new CommandPlugin('add_item', [
|
|
9667
|
+
{ name: 'id', type: 'string' },
|
|
9668
|
+
{ name: 'amount', type: 'number' },
|
|
9669
|
+
], async (cmd) => {
|
|
9670
|
+
const { id, amount } = cmd.options;
|
|
9513
9671
|
const inventory = useInventory();
|
|
9514
9672
|
inventory.add({
|
|
9515
9673
|
id,
|
|
9516
9674
|
amount,
|
|
9517
9675
|
});
|
|
9518
9676
|
return useVM().nextLine();
|
|
9519
|
-
}
|
|
9677
|
+
});
|
|
9520
9678
|
// Write a CommandPlugin for removeing items to the inventory store
|
|
9521
|
-
const removeItemPlugin = new CommandPlugin('remove_item',
|
|
9522
|
-
|
|
9523
|
-
|
|
9679
|
+
const removeItemPlugin = new CommandPlugin('remove_item', [
|
|
9680
|
+
{ name: 'id', type: 'string' },
|
|
9681
|
+
{ name: 'amount', type: 'number' },
|
|
9682
|
+
], async (cmd) => {
|
|
9683
|
+
const { id, amount } = cmd.options;
|
|
9524
9684
|
const inventory = useInventory();
|
|
9525
9685
|
inventory.remove({
|
|
9526
9686
|
id,
|
|
9527
9687
|
amount,
|
|
9528
9688
|
});
|
|
9529
9689
|
return useVM().nextLine();
|
|
9530
|
-
}
|
|
9690
|
+
});
|
|
9691
|
+
// Write a CommandPlugin for command named 'has_item?' taking options itemId and optional parameter 'amount', which returns true if the inventory has the item, using the inventory store hasItem function and passing itemId and amount
|
|
9692
|
+
const hasItemPlugin = new CommandPlugin('has_item?', [
|
|
9693
|
+
{ name: 'id', type: 'string' },
|
|
9694
|
+
{ name: 'amount', type: 'number', optional: true },
|
|
9695
|
+
], async (cmd) => {
|
|
9696
|
+
const { id, amount } = cmd.options;
|
|
9697
|
+
const inventory = useInventory();
|
|
9698
|
+
return inventory.hasItem(id, amount);
|
|
9699
|
+
});
|
|
9700
|
+
// Write a CommandPlugin named 'item_amount?' taking option itemId and returning how many of itemId the player has using the inventory store getItemAmount function and passing itemId
|
|
9701
|
+
const itemAmountPlugin = new CommandPlugin('item_amount?', [{ name: 'id', type: 'string' }], async (cmd) => {
|
|
9702
|
+
const { id } = cmd.options;
|
|
9703
|
+
const inventory = useInventory();
|
|
9704
|
+
return inventory.getItemAmount(id);
|
|
9705
|
+
});
|
|
9531
9706
|
// Write a CommandPlugin for enabling an interactiongTag in the inventory store
|
|
9532
|
-
const enableInteractionPlugin = new CommandPlugin('enable_interaction', async (cmd) => {
|
|
9533
|
-
const tag = cmd.
|
|
9707
|
+
const enableInteractionPlugin = new CommandPlugin('enable_interaction', [{ name: 'tag', type: 'string' }], async (cmd) => {
|
|
9708
|
+
const tag = cmd.options.tag;
|
|
9534
9709
|
const inventory = useInventory();
|
|
9535
9710
|
inventory.enableInteraction(tag);
|
|
9536
9711
|
return useVM().nextLine();
|
|
9537
|
-
}
|
|
9712
|
+
});
|
|
9538
9713
|
// Write a CommandPlugin for disabling an interactiongTag in the inventory store
|
|
9539
|
-
const disableInteractionPlugin = new CommandPlugin('disable_interaction', async (cmd) => {
|
|
9540
|
-
const tag = cmd.
|
|
9714
|
+
const disableInteractionPlugin = new CommandPlugin('disable_interaction', [{ name: 'tag', type: 'string' }], async (cmd) => {
|
|
9715
|
+
const tag = cmd.options.tag;
|
|
9541
9716
|
const inventory = useInventory();
|
|
9542
9717
|
inventory.disableInteraction(tag);
|
|
9543
9718
|
return useVM().nextLine();
|
|
9544
|
-
}
|
|
9719
|
+
});
|
|
9545
9720
|
|
|
9546
9721
|
// Write a CommandPlugin for starting a quest with the useQuests quests store
|
|
9547
|
-
const startQuestPlugin = new CommandPlugin('start_quest', async (cmd) => {
|
|
9548
|
-
const questId = cmd.
|
|
9722
|
+
const startQuestPlugin = new CommandPlugin('start_quest', [{ name: 'questId', type: 'string' }], async (cmd) => {
|
|
9723
|
+
const questId = cmd.options.questId;
|
|
9549
9724
|
const quests = useQuests();
|
|
9550
9725
|
quests.startQuest(questId);
|
|
9551
9726
|
return useVM().nextLine();
|
|
9552
|
-
}
|
|
9727
|
+
});
|
|
9553
9728
|
// Write a CommandPlugin for starting a quest objective with the cmd having arguments questId and objectiveId, using the useQuests store's startObjective method
|
|
9554
|
-
const startObjectivePlugin = new CommandPlugin('start_objective',
|
|
9555
|
-
|
|
9556
|
-
|
|
9729
|
+
const startObjectivePlugin = new CommandPlugin('start_objective', [
|
|
9730
|
+
{ name: 'questId', type: 'string' },
|
|
9731
|
+
{ name: 'objectiveId', type: 'string' },
|
|
9732
|
+
], async (cmd) => {
|
|
9733
|
+
const { questId, objectiveId } = cmd.options;
|
|
9557
9734
|
const quests = useQuests();
|
|
9558
9735
|
quests.startObjective(questId, objectiveId);
|
|
9559
9736
|
return useVM().nextLine();
|
|
9560
|
-
}
|
|
9737
|
+
});
|
|
9561
9738
|
// Write a CommandPlugin for completing a quest objective with the cmd having arguments questId and objectiveId, using the useQuests store's completeObjective method
|
|
9562
|
-
const completeObjectivePlugin = new CommandPlugin('complete_objective',
|
|
9563
|
-
|
|
9564
|
-
|
|
9739
|
+
const completeObjectivePlugin = new CommandPlugin('complete_objective', [
|
|
9740
|
+
{ name: 'questId', type: 'string' },
|
|
9741
|
+
{ name: 'objectiveId', type: 'string' },
|
|
9742
|
+
], async (cmd) => {
|
|
9743
|
+
const { questId, objectiveId } = cmd.options;
|
|
9565
9744
|
const quests = useQuests();
|
|
9566
9745
|
quests.completeObjective(questId, objectiveId);
|
|
9567
9746
|
return useVM().nextLine();
|
|
9568
|
-
}
|
|
9747
|
+
});
|
|
9569
9748
|
// Write a CommandPlugin for completing a quest with the cmd having arguments questId, using the useQuests store's completeQuest method
|
|
9570
|
-
const completeQuestPlugin = new CommandPlugin('complete_quest',
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
}
|
|
9749
|
+
const completeQuestPlugin = new CommandPlugin('complete_quest', [
|
|
9750
|
+
{ name: 'questId', type: 'string' },
|
|
9751
|
+
{ name: 'ending', type: 'string', optional: true },
|
|
9752
|
+
], async (cmd) => {
|
|
9753
|
+
const { questId, ending } = cmd.options;
|
|
9576
9754
|
const quests = useQuests();
|
|
9577
9755
|
quests.completeQuest(questId, ending);
|
|
9578
9756
|
return useVM().nextLine();
|
|
9579
|
-
}
|
|
9757
|
+
});
|
|
9758
|
+
// Write a CommandPlugin for a command named 'quest_completed?' that returns true if the quest with the given questId has status value completed, false otherwise, using the useQuests store's isQuestCompleted method
|
|
9759
|
+
const questCompletedPlugin = new CommandPlugin('quest_completed?', [{ name: 'questId', type: 'string' }], async (cmd) => {
|
|
9760
|
+
const { questId } = cmd.options;
|
|
9761
|
+
const quests = useQuests();
|
|
9762
|
+
return quests.isQuestCompleted(questId);
|
|
9763
|
+
});
|
|
9764
|
+
// Write a CommandPlugin for a command named 'objective_completed?' that returns true if the quest with the given questId has the given objectiveId completed, false otherwise, using the useQuests store's isObjectiveCompleted method
|
|
9765
|
+
const objectiveCompletedPlugin = new CommandPlugin('objective_completed?', [
|
|
9766
|
+
{ name: 'questId', type: 'string' },
|
|
9767
|
+
{ name: 'objectiveId', type: 'string' },
|
|
9768
|
+
], async (cmd) => {
|
|
9769
|
+
const { questId, objectiveId } = cmd.options;
|
|
9770
|
+
const quests = useQuests();
|
|
9771
|
+
return quests.isObjectiveCompleted(questId, objectiveId);
|
|
9772
|
+
});
|
|
9773
|
+
// Write a CommandPlugin for a command named 'quest_started?' that returns true if the quest with the given questId has status value started, false otherwise, using the useQuests store's isQuestStarted method
|
|
9774
|
+
const questStartedPlugin = new CommandPlugin('quest_started?', [{ name: 'questId', type: 'string' }], async (cmd) => {
|
|
9775
|
+
const { questId } = cmd.options;
|
|
9776
|
+
const quests = useQuests();
|
|
9777
|
+
return quests.isQuestStarted(questId);
|
|
9778
|
+
});
|
|
9779
|
+
// Write a CommandPlugin for a command named 'objective_started?' that returns true if the quest with the given questId has the given objectiveId started, false otherwise, using the useQuests store's isObjectiveStarted method
|
|
9780
|
+
const objectiveStartedPlugin = new CommandPlugin('objective_started?', [
|
|
9781
|
+
{ name: 'questId', type: 'string' },
|
|
9782
|
+
{ name: 'objectiveId', type: 'string' },
|
|
9783
|
+
], async (cmd) => {
|
|
9784
|
+
const { questId, objectiveId } = cmd.options;
|
|
9785
|
+
const quests = useQuests();
|
|
9786
|
+
return quests.isObjectiveStarted(questId, objectiveId);
|
|
9787
|
+
});
|
|
9580
9788
|
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9789
|
+
const waitCommand = new CommandPlugin('wait', [{ name: 'duration', type: 'number' }], async (cmd) => {
|
|
9790
|
+
await timeout(cmd.options.duration);
|
|
9791
|
+
return useVM().nextLine();
|
|
9792
|
+
});
|
|
9793
|
+
|
|
9794
|
+
const notifyPlugin = new CommandPlugin('notify', [{ name: 'text', type: 'string' }], async (cmd) => {
|
|
9795
|
+
const { text } = cmd.options;
|
|
9796
|
+
useNotifications().addNotification(text);
|
|
9797
|
+
return useVM().nextLine();
|
|
9798
|
+
});
|
|
9799
|
+
|
|
9800
|
+
const clearDialogPlugin = new CommandPlugin('clear_dialog', [], async (cmd) => {
|
|
9801
|
+
useDialogStore().clearDialog();
|
|
9802
|
+
return useVM().nextLine();
|
|
9803
|
+
});
|
|
9804
|
+
|
|
9805
|
+
const ifCommand = new CommandPlugin('if', [{ name: 'condition', type: 'boolean' }], async (cmd) => {
|
|
9806
|
+
const newBranch = runConditionCommand(cmd);
|
|
9807
|
+
const vmStore = useVM();
|
|
9808
|
+
if (newBranch) {
|
|
9809
|
+
const newStack = {
|
|
9810
|
+
branchData: {
|
|
9811
|
+
branch: newBranch,
|
|
9812
|
+
},
|
|
9813
|
+
currentIndex: 0,
|
|
9814
|
+
};
|
|
9815
|
+
return vmStore.addStack(newStack);
|
|
9816
|
+
}
|
|
9817
|
+
return vmStore.nextLine();
|
|
9818
|
+
}, (ctx, parsed) => {
|
|
9819
|
+
let newLine = ctx.currentLine;
|
|
9820
|
+
const parser = generateParser('if', [
|
|
9821
|
+
{ name: 'condition', type: 'string' },
|
|
9822
|
+
]);
|
|
9823
|
+
parser(ctx, parsed);
|
|
9824
|
+
const { lines, currentLine, line } = ctx;
|
|
9825
|
+
const command = parsed.command;
|
|
9826
|
+
let failure;
|
|
9827
|
+
const nextLine = getLine(lines, currentLine + 1);
|
|
9828
|
+
if (nextLine && nextLine.code === 'else:') {
|
|
9829
|
+
failure = ctx.processCommandsFunction(ctx.parserContext, nextLine.branch, line);
|
|
9830
|
+
newLine++;
|
|
9831
|
+
}
|
|
9832
|
+
command.staticOptions = {
|
|
9833
|
+
success: ctx.processCommandsFunction(ctx.parserContext, line.branch, line),
|
|
9834
|
+
failure,
|
|
9835
|
+
};
|
|
9836
|
+
newLine++;
|
|
9837
|
+
return {
|
|
9838
|
+
newLine,
|
|
9839
|
+
};
|
|
9840
|
+
});
|
|
9841
|
+
|
|
9842
|
+
/* eslint-disable eqeqeq */
|
|
9843
|
+
// export const add: CommandRunner = async (cmd) => {
|
|
9844
|
+
// const addKey = cmd.args[0];
|
|
9845
|
+
// const addValue = cmd.args[1];
|
|
9846
|
+
// const vm = useVM();
|
|
9847
|
+
// vm.addInstruction(addKey, addValue as any);
|
|
9848
|
+
// return vm.nextLine();
|
|
9849
|
+
// };
|
|
9850
|
+
const equalPlugin = new CommandPlugin('==', 'any', async (cmd) => {
|
|
9851
|
+
if (cmd.args.length < 2) {
|
|
9852
|
+
commandRuntimeError(cmd, `requires at least two arguments`);
|
|
9853
|
+
}
|
|
9854
|
+
let previousValue = cmd.args[0];
|
|
9855
|
+
let allEqual = true;
|
|
9856
|
+
for (const arg of cmd.args) {
|
|
9857
|
+
if (arg != previousValue) {
|
|
9858
|
+
allEqual = false;
|
|
9859
|
+
break;
|
|
9860
|
+
}
|
|
9861
|
+
else {
|
|
9862
|
+
previousValue = arg;
|
|
9863
|
+
}
|
|
9864
|
+
}
|
|
9865
|
+
return allEqual;
|
|
9866
|
+
});
|
|
9867
|
+
const greaterThanPlugin = new CommandPlugin('>', [
|
|
9868
|
+
{ name: 'a', type: 'any' },
|
|
9869
|
+
{ name: 'b', type: 'any' },
|
|
9870
|
+
], async (cmd) => {
|
|
9871
|
+
const { a, b } = cmd.options;
|
|
9872
|
+
return a > b;
|
|
9873
|
+
});
|
|
9874
|
+
// Write a lesserThanPlugin, greaterOrEqualPlugin, lesserOrEqualPlugin, notEqualPlugin
|
|
9875
|
+
const lesserThanPlugin = new CommandPlugin('<', [
|
|
9876
|
+
{ name: 'a', type: 'any' },
|
|
9877
|
+
{ name: 'b', type: 'any' },
|
|
9878
|
+
], async (cmd) => {
|
|
9879
|
+
const { a, b } = cmd.options;
|
|
9880
|
+
return a < b;
|
|
9881
|
+
});
|
|
9882
|
+
const greaterOrEqualPlugin = new CommandPlugin('>=', [
|
|
9883
|
+
{ name: 'a', type: 'any' },
|
|
9884
|
+
{ name: 'b', type: 'any' },
|
|
9885
|
+
], async (cmd) => {
|
|
9886
|
+
const { a, b } = cmd.options;
|
|
9887
|
+
return a >= b;
|
|
9888
|
+
});
|
|
9889
|
+
const lesserOrEqualPlugin = new CommandPlugin('<=', [
|
|
9890
|
+
{ name: 'a', type: 'any' },
|
|
9891
|
+
{ name: 'b', type: 'any' },
|
|
9892
|
+
], async (cmd) => {
|
|
9893
|
+
const { a, b } = cmd.options;
|
|
9894
|
+
return a <= b;
|
|
9895
|
+
});
|
|
9896
|
+
const notEqualPlugin = new CommandPlugin('!=', [
|
|
9897
|
+
{ name: 'a', type: 'any' },
|
|
9898
|
+
{ name: 'b', type: 'any' },
|
|
9899
|
+
], async (cmd) => {
|
|
9900
|
+
const { a, b } = cmd.options;
|
|
9901
|
+
return a != b;
|
|
9902
|
+
});
|
|
9903
|
+
const notPlugin = new CommandPlugin('!', [{ name: 'a', type: 'any' }], async (cmd) => {
|
|
9904
|
+
const { a } = cmd.options;
|
|
9905
|
+
return !a;
|
|
9906
|
+
});
|
|
9907
|
+
// Create an andPlugin and an orPlugin
|
|
9908
|
+
const andPlugin = new CommandPlugin('&&', 'any', async (cmd) => {
|
|
9909
|
+
const args = cmd.args;
|
|
9910
|
+
if (cmd.args.length < 2) {
|
|
9911
|
+
commandRuntimeError(cmd, 'requires at least two arguments');
|
|
9912
|
+
}
|
|
9913
|
+
return args.reduce((acc, curr) => acc && curr, true);
|
|
9914
|
+
});
|
|
9915
|
+
const orPlugin = new CommandPlugin('||', 'any', async (cmd) => {
|
|
9916
|
+
if (cmd.args.length < 2) {
|
|
9917
|
+
commandRuntimeError(cmd, 'requires at least two arguments');
|
|
9918
|
+
}
|
|
9919
|
+
return cmd.args.reduce((acc, curr) => acc || curr, false);
|
|
9920
|
+
});
|
|
9921
|
+
// Write a ternaryPlugin
|
|
9922
|
+
const ternaryPlugin = new CommandPlugin('?', [
|
|
9923
|
+
{ name: 'a', type: 'any' },
|
|
9924
|
+
{ name: 'b', type: 'any' },
|
|
9925
|
+
{ name: 'c', type: 'any' },
|
|
9926
|
+
], async (cmd) => {
|
|
9927
|
+
const { a, b, c } = cmd.options;
|
|
9928
|
+
return a ? b : c;
|
|
9929
|
+
});
|
|
9930
|
+
|
|
9931
|
+
// export const add: CommandRunner = async (cmd) => {
|
|
9932
|
+
// const addKey = cmd.args[0];
|
|
9933
|
+
// const addValue = cmd.args[1];
|
|
9934
|
+
// const vm = useVM();
|
|
9935
|
+
// vm.addInstruction(addKey, addValue as any);
|
|
9936
|
+
// return vm.nextLine();
|
|
9937
|
+
// };
|
|
9938
|
+
const additionPlugin = new CommandPlugin('+', 'any', async (cmd) => {
|
|
9939
|
+
if (cmd.args.length < 2) {
|
|
9940
|
+
commandRuntimeError(cmd, `requires at least two arguments`);
|
|
9941
|
+
}
|
|
9942
|
+
return cmd.args.reduce((acc, curr) => {
|
|
9943
|
+
if (typeof curr === 'number') {
|
|
9944
|
+
return acc + curr;
|
|
9945
|
+
}
|
|
9946
|
+
commandRuntimeError(cmd, `requires all arguments to be numbers`);
|
|
9947
|
+
return acc;
|
|
9948
|
+
}, 0);
|
|
9949
|
+
});
|
|
9950
|
+
const substractionPlugin = new CommandPlugin('-', 'any', async (cmd) => {
|
|
9951
|
+
if (cmd.args.length < 2) {
|
|
9952
|
+
commandRuntimeError(cmd, `requires at least two arguments`);
|
|
9953
|
+
}
|
|
9954
|
+
return cmd.args.reduce((acc, curr) => {
|
|
9955
|
+
if (typeof curr === 'number') {
|
|
9956
|
+
return acc - curr;
|
|
9957
|
+
}
|
|
9958
|
+
commandRuntimeError(cmd, `requires all arguments to be numbers`);
|
|
9959
|
+
return acc;
|
|
9960
|
+
}, 0);
|
|
9961
|
+
});
|
|
9962
|
+
// Write multiplicationPlugin and divisionPlugin
|
|
9963
|
+
const multiplicationPlugin = new CommandPlugin('*', 'any', async (cmd) => {
|
|
9964
|
+
if (cmd.args.length < 2) {
|
|
9965
|
+
commandRuntimeError(cmd, `requires at least two arguments`);
|
|
9966
|
+
}
|
|
9967
|
+
return cmd.args.reduce((acc, curr) => {
|
|
9968
|
+
if (typeof curr === 'number') {
|
|
9969
|
+
return acc * curr;
|
|
9970
|
+
}
|
|
9971
|
+
commandRuntimeError(cmd, `requires all arguments to be numbers`);
|
|
9972
|
+
return acc;
|
|
9973
|
+
}, 0);
|
|
9974
|
+
});
|
|
9975
|
+
const divisionPlugin = new CommandPlugin('/', 'any', async (cmd) => {
|
|
9976
|
+
if (cmd.args.length < 2) {
|
|
9977
|
+
commandRuntimeError(cmd, `requires at least two arguments`);
|
|
9978
|
+
}
|
|
9979
|
+
return cmd.args.reduce((acc, curr) => {
|
|
9980
|
+
if (typeof curr === 'number') {
|
|
9981
|
+
return acc / curr;
|
|
9982
|
+
}
|
|
9983
|
+
commandRuntimeError(cmd, `requires all arguments to be numbers`);
|
|
9984
|
+
return acc;
|
|
9985
|
+
}, 0);
|
|
9986
|
+
});
|
|
9987
|
+
|
|
9988
|
+
const runChoice = async (cmd) => {
|
|
9989
|
+
// Hack for us to be able to find that command again on playerAnswered
|
|
9990
|
+
useVM().lastChoiceCommand = cmd;
|
|
9991
|
+
const { prompt, choices } = cmd.staticOptions;
|
|
9992
|
+
// For each possible choice, we run the choice prompt expression which will return us the info we need to generate the choice options
|
|
9993
|
+
const choiceResults = [];
|
|
9994
|
+
for (const [index, choice] of choices.entries()) {
|
|
9995
|
+
const choiceResult = await runExpression(choice.prompt);
|
|
9996
|
+
choiceResults.push(choiceResult);
|
|
9997
|
+
}
|
|
9998
|
+
// Lazy hack to store those results for after the player answers.
|
|
9999
|
+
cmd.options.choiceResults = choiceResults;
|
|
10000
|
+
// Convert the results into dialog options
|
|
10001
|
+
const dialogChoices = choiceResults
|
|
10002
|
+
.map((res, index) => {
|
|
10003
|
+
let allowed = true;
|
|
10004
|
+
if (res.skillCheck) {
|
|
10005
|
+
allowed = res.skillCheck?.allowed ?? false;
|
|
10006
|
+
}
|
|
10007
|
+
const result = {
|
|
10008
|
+
choice: res.text,
|
|
10009
|
+
originalIndex: index,
|
|
10010
|
+
allowed,
|
|
10011
|
+
};
|
|
10012
|
+
return result;
|
|
10013
|
+
})
|
|
10014
|
+
// Choices that have a null text are options that didn't pass conditions, or hidden skill checks
|
|
10015
|
+
.filter((el) => el.choice);
|
|
10016
|
+
runCommand(prompt, dialogChoices);
|
|
10017
|
+
};
|
|
10018
|
+
function parseChoiceOption(ctx, choice, index) {
|
|
10019
|
+
const command = choice.expression;
|
|
10020
|
+
if (!choice.branch) {
|
|
10021
|
+
ctx.parserContext.error(choice.line, `Choice option doesn't have any branch to go to (${choice.code} - ${choice.line})`);
|
|
10022
|
+
}
|
|
10023
|
+
let skillBranches;
|
|
10024
|
+
let mainBranch;
|
|
10025
|
+
if (choice.expression[1] === 'roll') {
|
|
10026
|
+
skillBranches = {
|
|
10027
|
+
success: ctx.processCommandsFunction(ctx.parserContext, choice.branch[0].branch, choice),
|
|
10028
|
+
failure: ctx.processCommandsFunction(ctx.parserContext, choice.branch[1].branch, choice),
|
|
10029
|
+
};
|
|
10030
|
+
}
|
|
10031
|
+
else {
|
|
10032
|
+
mainBranch = ctx.processCommandsFunction(ctx.parserContext, choice.branch, choice);
|
|
10033
|
+
}
|
|
10034
|
+
const choiceInfo = {
|
|
10035
|
+
prompt: ctx.processCommandsFunction(ctx.parserContext, [choice], choice)[0],
|
|
10036
|
+
branch: mainBranch,
|
|
10037
|
+
skillBranches,
|
|
10038
|
+
};
|
|
10039
|
+
return choiceInfo;
|
|
10040
|
+
}
|
|
10041
|
+
const choiceParser = (ctx, parsed) => {
|
|
10042
|
+
let newLine = ctx.currentLine;
|
|
10043
|
+
const parser = generateParser('choice', []);
|
|
10044
|
+
const { line } = ctx;
|
|
10045
|
+
const command = parsed.command;
|
|
10046
|
+
if (!line.branch || line.branch.length < 2) {
|
|
10047
|
+
ctx.parserContext.error(line.line, `Choice menu needs to have at least one option`);
|
|
10048
|
+
}
|
|
10049
|
+
const prompt = line.branch[0];
|
|
10050
|
+
if (!prompt) {
|
|
10051
|
+
ctx.parserContext.error(ctx.line.line, `Choice prompt is missing `);
|
|
10052
|
+
}
|
|
10053
|
+
const choices = line.branch.slice(1);
|
|
10054
|
+
const prompts = choices.map((choice, index) => {
|
|
10055
|
+
if (!choice.branch) {
|
|
10056
|
+
ctx.parserContext.error(choice.line, `Choice option doesn't have any branch to go to (${choice.code})`);
|
|
10057
|
+
}
|
|
10058
|
+
choice = getChoiceOptionLineFromChoicePrompt(ctx.parserContext, choice);
|
|
10059
|
+
return parseChoiceOption(ctx, choice);
|
|
10060
|
+
});
|
|
10061
|
+
command.staticOptions = {
|
|
10062
|
+
prompt: ctx.processCommandsFunction(ctx.parserContext, [prompt], line)[0],
|
|
10063
|
+
choices: prompts,
|
|
10064
|
+
};
|
|
10065
|
+
newLine++;
|
|
10066
|
+
return {
|
|
10067
|
+
newLine,
|
|
10068
|
+
};
|
|
10069
|
+
};
|
|
10070
|
+
const choicePlugin = new CommandPlugin('choice', [], runChoice, choiceParser);
|
|
10071
|
+
choicePlugin.onPlayerAnswered = async (command, choiceIndex) => {
|
|
10072
|
+
// The player has answered, we now need to go to the right branch and perform any needed skill checks
|
|
10073
|
+
const vmStore = useVM();
|
|
10074
|
+
const { choices } = command.staticOptions;
|
|
10075
|
+
const choice = choices[choiceIndex];
|
|
10076
|
+
const choicePromptResult = command.options.choiceResults[choiceIndex];
|
|
10077
|
+
let newBranch;
|
|
10078
|
+
if (choicePromptResult.skillCheck) {
|
|
10079
|
+
const result = runSkillCheck({
|
|
10080
|
+
skill: choicePromptResult.skillCheck.skillId,
|
|
10081
|
+
value: choicePromptResult.skillCheck.difficulty,
|
|
10082
|
+
id: choicePromptResult.skillCheck.skillCheckId,
|
|
10083
|
+
hideAfterRoll: choicePromptResult.skillCheck.hideAfterRoll,
|
|
10084
|
+
});
|
|
10085
|
+
if (result.succeeded) {
|
|
10086
|
+
newBranch = choice.skillBranches.success;
|
|
10087
|
+
}
|
|
10088
|
+
else {
|
|
10089
|
+
newBranch = choice.skillBranches.failure;
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
else {
|
|
10093
|
+
newBranch = choice.branch;
|
|
10094
|
+
}
|
|
10095
|
+
if (newBranch) {
|
|
10096
|
+
const newStack = {
|
|
10097
|
+
currentIndex: 0,
|
|
10098
|
+
branchData: {
|
|
10099
|
+
branch: newBranch,
|
|
10100
|
+
},
|
|
10101
|
+
};
|
|
10102
|
+
return vmStore.addStack(newStack);
|
|
10103
|
+
}
|
|
10104
|
+
else {
|
|
10105
|
+
vmStore.nextLine();
|
|
10106
|
+
}
|
|
10107
|
+
};
|
|
10108
|
+
// Turns a choice prompt (Which is normally just text + an optional condition) into a proper choice prompt command so it can be parsed properly
|
|
10109
|
+
function getChoiceOptionLineFromChoicePrompt(ctx, choice) {
|
|
10110
|
+
const generatedCode = `choicePrompt ${choice.code}`;
|
|
10111
|
+
const newLine = {
|
|
10112
|
+
code: generatedCode,
|
|
10113
|
+
indentation: choice.indentation,
|
|
10114
|
+
line: choice.line,
|
|
10115
|
+
branch: choice.branch,
|
|
10116
|
+
expression: ['choicePrompt', ...choice.expression],
|
|
10117
|
+
};
|
|
10118
|
+
return newLine;
|
|
10119
|
+
}
|
|
10120
|
+
/** Custom "fake" instruction generated on choice prompts to process their optional conditions */
|
|
10121
|
+
const choicePromptCommandPlugin = new CommandPlugin('choicePrompt', 'any',
|
|
10122
|
+
// Will return null if the choice prompt should not be used (failed condition or hidden skillcheck). Otherwise, returns the info needed to display the prompt + later run the skillcheck
|
|
10123
|
+
async (cmd) => {
|
|
10124
|
+
const args = cmd.args;
|
|
10125
|
+
if (args[0] === 'roll') {
|
|
10126
|
+
const skillCheckId = args[1];
|
|
10127
|
+
const skillId = args[2];
|
|
10128
|
+
const difficulty = args[3];
|
|
10129
|
+
const skillText = args[4];
|
|
10130
|
+
const hideAfterRoll = args.length > 5 ? args[5] : false;
|
|
10131
|
+
const state = useSkills().getSkillCheck(skillCheckId);
|
|
10132
|
+
if (state.hidden) {
|
|
10133
|
+
return {
|
|
10134
|
+
text: null,
|
|
10135
|
+
};
|
|
10136
|
+
}
|
|
10137
|
+
const skillCheckFailed = state.happened && !state.succeeded;
|
|
10138
|
+
const { difficultyText, allowed } = getSkillCheckText({
|
|
10139
|
+
skill: skillId,
|
|
10140
|
+
skillCheckId: skillCheckId,
|
|
10141
|
+
value: difficulty,
|
|
10142
|
+
});
|
|
10143
|
+
const text = `${difficultyText} ${skillText}`;
|
|
10144
|
+
return {
|
|
10145
|
+
text,
|
|
10146
|
+
skillCheck: {
|
|
10147
|
+
allowed: !skillCheckFailed,
|
|
10148
|
+
skillId,
|
|
10149
|
+
skillCheckId,
|
|
10150
|
+
difficulty,
|
|
10151
|
+
hideAfterRoll,
|
|
10152
|
+
},
|
|
10153
|
+
};
|
|
9586
10154
|
}
|
|
9587
|
-
|
|
9588
|
-
|
|
10155
|
+
else if (args.length > 1 && args[1] === 'if') {
|
|
10156
|
+
const text = args[0];
|
|
10157
|
+
let condition = true;
|
|
10158
|
+
if (args.length > 2) {
|
|
10159
|
+
condition = args[2];
|
|
10160
|
+
}
|
|
10161
|
+
if (condition) {
|
|
10162
|
+
return {
|
|
10163
|
+
text,
|
|
10164
|
+
};
|
|
10165
|
+
}
|
|
10166
|
+
else {
|
|
10167
|
+
return {
|
|
10168
|
+
text: null,
|
|
10169
|
+
};
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
else {
|
|
10173
|
+
return {
|
|
10174
|
+
text: args[0],
|
|
10175
|
+
};
|
|
10176
|
+
}
|
|
10177
|
+
});
|
|
9589
10178
|
|
|
9590
10179
|
function registerBaseCommands(vm) {
|
|
9591
|
-
|
|
9592
|
-
vm.addCommand(addStatPlugin);
|
|
9593
|
-
vm.addCommand(addXpPlugin);
|
|
9594
|
-
vm.addCommand(addPlugin);
|
|
10180
|
+
// Choices
|
|
9595
10181
|
vm.addCommand(choicePlugin);
|
|
9596
|
-
vm.addCommand(
|
|
10182
|
+
vm.addCommand(choicePromptCommandPlugin);
|
|
9597
10183
|
vm.addCommand(ifCommand);
|
|
9598
|
-
|
|
10184
|
+
// Stats
|
|
10185
|
+
vm.addCommand(addStatPlugin);
|
|
10186
|
+
vm.addCommand(setStatPlugin);
|
|
10187
|
+
vm.addCommand(getStatPlugin);
|
|
10188
|
+
vm.addCommand(clearDialogPlugin);
|
|
9599
10189
|
vm.addCommand(notifyPlugin);
|
|
10190
|
+
// Audio
|
|
9600
10191
|
vm.addCommand(pauseCommand);
|
|
9601
10192
|
vm.addCommand(playCommand);
|
|
10193
|
+
vm.addCommand(stopCommand);
|
|
10194
|
+
// Screens
|
|
9602
10195
|
vm.addCommand(setButtonCommand);
|
|
9603
10196
|
vm.addCommand(setScreenCommand);
|
|
9604
|
-
vm.addCommand(
|
|
10197
|
+
vm.addCommand(waitCommand);
|
|
10198
|
+
// Logic operations
|
|
10199
|
+
vm.addCommand(equalPlugin);
|
|
10200
|
+
vm.addCommand(greaterThanPlugin);
|
|
10201
|
+
vm.addCommand(lesserThanPlugin);
|
|
10202
|
+
vm.addCommand(greaterOrEqualPlugin);
|
|
10203
|
+
vm.addCommand(lesserOrEqualPlugin);
|
|
10204
|
+
vm.addCommand(notEqualPlugin);
|
|
10205
|
+
vm.addCommand(notPlugin);
|
|
10206
|
+
vm.addCommand(andPlugin);
|
|
10207
|
+
vm.addCommand(orPlugin);
|
|
10208
|
+
vm.addCommand(ternaryPlugin);
|
|
10209
|
+
// Arithmetic operations
|
|
10210
|
+
vm.addCommand(additionPlugin);
|
|
10211
|
+
vm.addCommand(substractionPlugin);
|
|
10212
|
+
vm.addCommand(multiplicationPlugin);
|
|
10213
|
+
vm.addCommand(divisionPlugin);
|
|
10214
|
+
// Setting variables
|
|
10215
|
+
vm.addCommand(addPlugin);
|
|
9605
10216
|
vm.addCommand(setCommand);
|
|
9606
|
-
|
|
9607
|
-
vm.addCommand(talkCommand);
|
|
10217
|
+
// Text display
|
|
9608
10218
|
vm.addCommand(textCommandPlugin);
|
|
9609
|
-
vm.addCommand(
|
|
9610
|
-
// functions and labels
|
|
10219
|
+
vm.addCommand(talkCommand);
|
|
10220
|
+
// // functions and labels
|
|
9611
10221
|
vm.addCommand(jumpCommand);
|
|
9612
10222
|
vm.addCommand(runLabelPlugin);
|
|
9613
|
-
|
|
10223
|
+
vm.addCommand(defineVariablePlugin);
|
|
10224
|
+
vm.addCommand(returnPlugin);
|
|
10225
|
+
// // Quests
|
|
9614
10226
|
vm.addCommand(startQuestPlugin);
|
|
9615
10227
|
vm.addCommand(startObjectivePlugin);
|
|
9616
10228
|
vm.addCommand(completeObjectivePlugin);
|
|
9617
10229
|
vm.addCommand(completeQuestPlugin);
|
|
9618
|
-
|
|
10230
|
+
vm.addCommand(questStartedPlugin);
|
|
10231
|
+
vm.addCommand(objectiveStartedPlugin);
|
|
10232
|
+
vm.addCommand(questCompletedPlugin);
|
|
10233
|
+
vm.addCommand(objectiveCompletedPlugin);
|
|
10234
|
+
// // Inventory
|
|
9619
10235
|
vm.addCommand(addItemPlugin);
|
|
9620
10236
|
vm.addCommand(removeItemPlugin);
|
|
9621
10237
|
vm.addCommand(enableInteractionPlugin);
|
|
9622
10238
|
vm.addCommand(disableInteractionPlugin);
|
|
10239
|
+
vm.addCommand(hasItemPlugin);
|
|
10240
|
+
vm.addCommand(itemAmountPlugin);
|
|
10241
|
+
// Skills
|
|
10242
|
+
vm.addCommand(addLevelPlugin);
|
|
10243
|
+
vm.addCommand(addXpPlugin);
|
|
10244
|
+
vm.addCommand(rollPlugin);
|
|
9623
10245
|
}
|
|
9624
10246
|
|
|
9625
10247
|
class NarratPlugin {
|
|
@@ -9662,7 +10284,7 @@ async function startApp(config, options) {
|
|
|
9662
10284
|
});
|
|
9663
10285
|
registerBaseCommands(vm);
|
|
9664
10286
|
logManager.setupDebugger(options.debug);
|
|
9665
|
-
console.log('%c Narrat game engine –
|
|
10287
|
+
console.log('%c Narrat game engine – 2.0.0-rc3 - June 28, 2022 22:38:40', 'background: #222; color: #bada55');
|
|
9666
10288
|
vm.callHook('onNarratSetup');
|
|
9667
10289
|
app.mount('#game-holder');
|
|
9668
10290
|
if (options.debug) {
|