diff --git a/README.md b/README.md index 65837e3..75c94d1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Are you annoyed with assigning a single tag for a huge bunch of tiles? Or with m Just select all your tiles (or tokens) and drag&drop the tag to assign it. Choose a color for it (useless but fancy) and create an action: toggle your tiles' visibility or fire the Active Tiles' trigger. Your actions are stored in the scene's data so that you can have many of them. The global tags are global; let's be consistent across the scenes! +Director sometimes looks too complex, so read [Documentation](https://github.com/averrin/director/wiki/How-to-use.-With-examples.). It contains a couple of easy to go examples. + ## Hints - you can drag and drop tags - right click on tag opens a color picker @@ -29,155 +31,18 @@ It's not going to be MATT's alternative, so actions are pretty basic * Sequencer [BETA, required] * Token Magic FX [Virtual Sequencer's section] -## Sequencer support progress -
- Effects - -### Generic Methods -- [x] Wait Until Finished -- [x] Async -- [x] Repeats -- [x] Play if -- [x] Delay -- [x] Fade In -- [x] Fade Out -- [x] Duration -- [x] Opacity -- [x] Start Time -- [x] Start Time Percentage -- [x] End Time -- [x] End Time Percentage -- [x] Time Range -- [x] Locally -- [ ] For Users -### Effect Methods -- [ ] Base folder -- [x] File -- [x] From -- [x] At location -- [x] Attach To -- [x] Rotate Towards -- [x] Stretch To -- [x] Move Towards -- [x] Move Speed -- [x] Snap to Grid -- [x] Offset -- [x] Sprite Offset -- [x] Zero Sprite Rotation -- [x] Persist -- [x] No Loop -- [x] Extra End Duration -- [x] Origin -- [x] Name -- [x] Private -- [x] Missed -- [ ] Add override -- [ ] Set mustache -- [x] Size (partially) -- [x] Scale -- [x] Scale In -- [x] Scale Out -- [x] Scale To Object -- [x] Anchor (partially) -- [x] Sprite Anchor (partially) -- [x] Center -- [x] Mirror -- [x] Randomize mirror -- [x] Rotate -- [x] Rotate In -- [x] Rotate Out -- [x] Random rotation -- [x] Playback rate -- [x] Below tokens -- [x] Below tiles -- [x] Above lighting -- [x] Z-Index -- [ ] Animate Property -- [ ] Loop Property -- [ ] Filter -- [x] Tint (without picker) -- [x] Screen Space -- [x] Screen Space Above UI -- [x] Screen Space Position -- [x] Screen Space Anchor -- [ ] Screen Space Scale -- [x] Text (fill + fontSize) -- [x] XRay -- [x] Mask -
- -
- Animation - -### Generic Methods -- [x] Wait Until Finished -- [x] Async -- [x] Repeats -- [x] Play if -- [x] Delay -- [x] Opacity -- [x] Fade In -- [x] Fade Out -- [x] Duration -- [x] Volume -- [x] Fade In Audio -- [x] Audio Out Audio -### Animation Methods -- [x] On -- [x] Move Towards -- [x] Move Speed -- [x] Rotate Towards -- [x] Teleport To -- [x] Offset -- [x] Closest Square -- [x] Snap to Grid -- [x] Rotate -- [x] Rotate In -- [x] Rotate Out -- [x] Tint -- [x] Hide -- [x] Show -
- -
- Sound - -### Generic Methods -- [x] Wait Until Finished -- [x] Async -- [x] Repeats -- [x] Play if -- [x] Delay -- [x] Duration -- [x] Volume -- [x] Fade In Audio -- [x] Audio Out Audio -- [x] Start Time -- [x] Start Time Percentage -- [x] End Time -- [x] End Time Percentage -- [x] Time Range -- [x] Locally -- [ ] For Users -### Sound methods -- [ ] Base folder -- [x] File -- [ ] Add override -- [ ] Set mustache -
- ## Plans - [ ] Documentation - [ ] v10 support - [ ] Beginner / Expert UI mode - [ ] Better import / export -- [X] Better support of Sequencer's functions and types +- [ ] Better support of Sequencer's functions and types - [ ] Better support for Token Magic FX - [ ] Support for Dynamic Active Effects - [ ] Hooks for ending effects of a sequence. E.g. to destroy DAE's effects. - [ ] [Alpha HUD](https://github.com/averrin/alpha-hud) integrations. A scene widget with something like the hotbar. -## Images +## Images (quite outdated, see docs) ![toolbar](/assets/toolbar.png) ![selection](/assets/selection.png) ![actions](/assets/actions.png) diff --git a/src/constants.js b/src/constants.js index eef0c9c..d926b28 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,5 +1,11 @@ export const moduleId = "director"; +export function evalExpression(expr, ...args) { + let code = `try {return ${expr}} catch(e) {return false}`; + const f = new Function("...args", code); + return f(...args) +} + // import { foundry } from '../modules/foundry.js'; // import { moduleId, SETTINGS } from '../constants.js'; @@ -15,6 +21,7 @@ export const SETTINGS = { MANUAL_MODE: "warpgate-mode", SELECTED_SEQ: "selected-seq", SELECTED_TAB: "selected-tab", + HIDE_IMPORT: "hide-import", }; export const HOOKS = [ @@ -244,6 +251,18 @@ export const hookSpecs = [ return f(...args) }, args: [{ type: "expression", label: "test" }] }, + { + id: "#onUpdateToken", parents: ["updateToken"], test: (prop, ...args) => { + let code = `try {return ${prop}} catch(e) {return false}`; + const f = new Function("...args", code); + return f(...args) + }, args: [{ type: "expression", label: "test" }] + }, + { + id: "#setInterval", parents: [], test: (prop, ...args) => { + return evalExpression(prop, ...args); + }, args: [{ type: "expression", label: "test" }, { type: "expression", label: "interval" }] + }, ]; export const argSpecs = [ @@ -325,7 +344,8 @@ export const argSpecs = [ { value: "#onTokenProperty", label: "On Token's property" }, { value: "#onActorProperty", label: "On Actor's property" }, { value: "#onUpdateToken", label: "Generic updateToken" }, - { value: "#onUpdateActor", label: "Generic updateActor" },] + { value: "#onUpdateActor", label: "Generic updateActor" }, + { value: "#setInterval", label: "Set Interval" },] }, { id: "effectSource", var_types: ["effect"], options: [ diff --git a/src/modules/HookManager.js b/src/modules/HookManager.js index a332d2c..5e19bc7 100644 --- a/src/modules/HookManager.js +++ b/src/modules/HookManager.js @@ -1,4 +1,4 @@ -import { logger, calculateValueSync } from './helpers.js'; +import { logger, calculateValueSync, evalExpression } from './helpers.js'; import { hookSpecs, moduleId, SETTINGS } from '../constants.js'; class HookManager { @@ -22,7 +22,6 @@ class HookManager { getHandler(parent) { return (...args) => { - logger.info(this.#hooks); for (const hook of this.#hooks) { if (!hook.enabled || !hook.event || !hook.target) continue; let targets = calculateValueSync(hook.target); @@ -88,7 +87,17 @@ class HookManager { updateHandlers() { for (const [hook, handler] of Object.entries(this.#handlers)) { - if (this.#hooks.some(h => h.enabled && hookSpecs.find(s => s.id == h.event)?.parents.includes(hook))) { + if (hook.startsWith("#setInterval")) { + if (this.#hooks.some(h => h.enabled && `${h.event}-${h.args[1]}` == hook)) { + continue; + } else { + globalThis.Hooks.off(hook, handler); + delete this.#handlers[hook] + logger.info(`Hook: ${hook}#${handler} was uninstalled.`) + logger.info(this.#handlers); + } + } else if (this.#hooks.some(h => h.enabled && + hookSpecs.find(s => s.id == h.event)?.parents.includes(hook))) { continue; } else if (this.#actions.some(a => this.isActionListen(a, hook))) { continue; @@ -101,6 +110,24 @@ class HookManager { } } + getIntervalHandler(hook) { + return (...args) => { + logger.info("interval handler called"); + const interval = evalExpression(hook.args[1]) + setTimeout(() => { + const spec = hookSpecs.find(s => s.id == hook.event); + const id = `${spec.id}-${hook.args[1]}`; + if (id in this.#handlers) { + if (hook.enabled, spec.test(...hook.args, ...args)) { + logger.info(`Interval hook ${hook.getHookName()} was called`, hook); + globalThis.Hooks.call(hook.getHookName(), ...hook.args); + } + this.#handlers[id](); + } + }, interval); + } + } + async onHooksChange(hooks) { this.#hooks = hooks; this.updateHandlers(); @@ -113,6 +140,13 @@ class HookManager { logger.info(`Hook: ${parent}#${this.#handlers[parent]} was installed.`); logger.info(this.#handlers); } + if (spec.id == "#setInterval") { + const id = `${spec.id}-${hook.args[1]}`; + if (id in this.#handlers) continue; + this.#handlers[id] = this.getIntervalHandler(hook); + this.#handlers[id](); + logger.info(`Hook: ${id}#${this.#handlers[id]} was installed.`); + } } } diff --git a/src/modules/helpers.js b/src/modules/helpers.js index 9038896..ab18ce7 100644 --- a/src/modules/helpers.js +++ b/src/modules/helpers.js @@ -122,7 +122,7 @@ export function calculateValueSync(val, type, seq) { } else if (Array.isArray(val)) { val = globalThis.Tagger.getByTag(val); if (type != "selection") { - if (val.length > 0) val = val[0]; + if (val.length > 0) val = globalThis.Sequencer.Helpers.random_array_element(val); } } return val; @@ -146,3 +146,9 @@ export async function calculateValue(val, type, seq) { } return calculateValueSync(val, type, seq) } + +export function evalExpression(expr, ...args) { + let code = `try {return ${expr}} catch(e) {return false}`; + const f = new Function("...args", code); + return f(...args) +} diff --git a/src/modules/settings.js b/src/modules/settings.js index ca33aa8..ded97a7 100644 --- a/src/modules/settings.js +++ b/src/modules/settings.js @@ -94,4 +94,13 @@ export function initSettings(app) { default: 2, type: Number, }); + + game.settings.register(moduleId, SETTINGS.HIDE_IMPORT, { + name: "Disable import/export feature", + hint: "Just hide buttons if you don't need it", + scope: "world", + config: true, + default: false, + type: Boolean, + }); } diff --git a/src/styles/main.scss b/src/styles/main.scss index 73fd56e..181e557 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -20,9 +20,11 @@ max-width: 600px; border-radius: var(--rounded-btn, 0.5rem); background: #fff !important; + height: 3rem !important; input, .selection { - font-size: 1rem !important; + font-size: 1rem !important; + height: 3rem !important; } } diff --git a/src/view/MainUI.svelte b/src/view/MainUI.svelte index 48d2622..2d6661f 100644 --- a/src/view/MainUI.svelte +++ b/src/view/MainUI.svelte @@ -17,9 +17,10 @@ import { HsvPicker } from "svelte-color-picker"; - import { tagColors, currentScene } from "../modules/stores.js"; + import { tagColors, currentScene, actions } from "../modules/stores.js"; import { getContext } from "svelte"; + import Action from "../modules/Actions"; const { application } = getContext("external"); const position = application.position; position.scale = game.settings.get(moduleId, SETTINGS.UI_SCALE); @@ -38,13 +39,9 @@ } function createAction(_, tags) { - currentScene.update((scene) => { - let actions = - "director-actions" in scene.data.flags ? scene.data.flags["director-actions"].filter((a) => a) : []; - actions = [{ id: uuidv4(), tags: tags, type: "" }, ...actions]; - scene.data.flags["director-actions"] = actions; - scene.update({ "flags.director-actions": actions }); - return scene; + actions.update((actions) => { + actions = [Action.fromPlain({ id: uuidv4(), value: tags, type: "" }), ...actions]; + return actions; }); mode = "actions"; } @@ -64,6 +61,10 @@ mode = t.mode; globalThis.game.settings.set(moduleId, SETTINGS.SELECTED_TAB, mode); } + let availableTabs = tabs; + if (setting(SETTINGS.HIDE_IMPORT)) { + availableTabs = availableTabs.filter((t) => t.mode != "import"); + } @@ -79,7 +80,7 @@
diff --git a/src/view/components/ArgInput.svelte b/src/view/components/ArgInput.svelte index 7469d17..50e5296 100644 --- a/src/view/components/ArgInput.svelte +++ b/src/view/components/ArgInput.svelte @@ -19,8 +19,9 @@ export let hideSign = false; export let widthAuto = false; export let onTagClick; + export let justify = "start"; let spec = argSpecs.find((s) => s.id == type); - if (value === undefined || value == null || (value == "" && "default" in spec && value !== spec.default)) { + if (value === undefined || value === null || (value === "" && "default" in spec && value !== spec.default)) { resetValue(); } @@ -68,7 +69,7 @@ if (spec && "options" in spec) { options = [...spec.options, ...additionalItems].flat(); } - if (value === undefined || value == null || (value == "" && "default" in spec && value !== spec.default)) { + if (value === undefined || value === null || (value === "" && "default" in spec && value !== spec.default)) { resetValue(); } debounce(dispatch("change", value), 200); @@ -120,7 +121,12 @@ {/if} -
{#each currentHooks as hook (hook.id)}
- +
-
-
-
{/if} diff --git a/src/view/components/SequencerTab.svelte b/src/view/components/SequencerTab.svelte index 2e9be86..dfaddbf 100644 --- a/src/view/components/SequencerTab.svelte +++ b/src/view/components/SequencerTab.svelte @@ -104,7 +104,9 @@
- + {#if !setting(SETTINGS.HIDE_IMPORT)} + + {/if}