From 13fc0c0b120218de9d64a7ebf36e5648e9c7dcb5 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Fri, 12 Aug 2022 19:52:58 +0200 Subject: [PATCH] Triggers can fire on character sheet checks --- .../api/engine/actions/applyTriggers.js | 72 ++++++++++--------- app/imports/api/engine/actions/doCheck.js | 33 +++++++++ app/imports/api/properties/Triggers.js | 2 + 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/app/imports/api/engine/actions/applyTriggers.js b/app/imports/api/engine/actions/applyTriggers.js index ee2af708..d0863ed4 100644 --- a/app/imports/api/engine/actions/applyTriggers.js +++ b/app/imports/api/engine/actions/applyTriggers.js @@ -11,46 +11,18 @@ export default function applyTriggers(node, { creature, targets, scope, log }, t const type = prop.type; if (creature.triggers?.[type]?.[timing]) { creature.triggers[type][timing].forEach(trigger => { - if (triggerMatchTags(trigger, prop)) { - applyTrigger(trigger, { creature, targets, scope, log }); - } + applyTrigger(trigger, { creature, prop, targets, scope, log }); }); } } -function triggerMatchTags(trigger, prop) { - let matched = false; - const propTags = getEffectivePropTags(prop); - // Check the target tags - if ( - !trigger.targetTags?.length || - difference(trigger.targetTags, propTags).length === 0 - ) { - matched = true; +export function applyTrigger(trigger, { creature, prop, targets, scope, log }) { + // If there is a prop we are applying the trigger from, + // don't fire if the tags don't match + if (!triggerMatchTags(trigger, prop)) { + return; } - // Check the extra tags - trigger.extraTags?.forEach(extra => { - if (extra.operation === 'OR') { - if (matched) return; - if ( - !extra.tags.length || - difference(extra.tags, propTags).length === 0 - ) { - matched = true; - } - } else if (extra.operation === 'NOT') { - if ( - extra.tags.length && - intersection(extra.tags, propTags) - ) { - return false; - } - } - }); - return matched; -} -export function applyTrigger(trigger, { creature, targets, scope, log }) { // Prevent trigger from firing if it's inactive if (trigger.inactive) { return; @@ -102,3 +74,35 @@ export function applyTrigger(trigger, { creature, targets, scope, log }) { trigger.firing = false; } + +function triggerMatchTags(trigger, prop) { + let matched = false; + const propTags = getEffectivePropTags(prop); + // Check the target tags + if ( + !trigger.targetTags?.length || + difference(trigger.targetTags, propTags).length === 0 + ) { + matched = true; + } + // Check the extra tags + trigger.extraTags?.forEach(extra => { + if (extra.operation === 'OR') { + if (matched) return; + if ( + !extra.tags.length || + difference(extra.tags, propTags).length === 0 + ) { + matched = true; + } + } else if (extra.operation === 'NOT') { + if ( + extra.tags.length && + intersection(extra.tags, propTags) + ) { + return false; + } + } + }); + return matched; +} diff --git a/app/imports/api/engine/actions/doCheck.js b/app/imports/api/engine/actions/doCheck.js index 9f139f2c..0a5fef41 100644 --- a/app/imports/api/engine/actions/doCheck.js +++ b/app/imports/api/engine/actions/doCheck.js @@ -3,10 +3,15 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import { + getPropertiesOfType, getVariables +} from '/imports/api/engine/loadCreatures.js'; +import { groupBy, remove } from 'lodash'; import { CreatureLogSchema, insertCreatureLogWork } from '/imports/api/creature/log/CreatureLogs.js'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; import rollDice from '/imports/parser/rollDice.js'; import numberToSignedString from '/imports/ui/utility/numberToSignedString.js'; +import { applyTrigger } from '/imports/api/engine/actions/applyTriggers.js'; const doCheck = new ValidatedMethod({ name: 'creatureProperties.doCheck', @@ -45,12 +50,40 @@ export function doCheckWork({ creatureName: creature.name, }); + // Add the variables to the creature document + const variables = getVariables(creature._id); + delete variables._id; + delete variables._creatureId; + creature.variables = variables; + const scope = creature.variables; + + // Get the triggers + let triggers = getPropertiesOfType(creature._id, 'trigger'); + remove(triggers, trigger => trigger.event !== 'check'); + triggers = groupBy(triggers, 'timing'); + + // Set the creature as the target + const targets = [creature]; + + applyTriggers(triggers, 'before', { creature, prop, targets, scope, log }); rollCheck({prop, log, methodScope}); + applyTriggers(triggers, 'after', { creature, prop, targets, scope, log }); // Insert the log insertCreatureLogWork({log, creature, method}); } +function applyTriggers(triggers, timing, opts) { + // Get matching triggers + let selectedTriggers = triggers[timing] || []; + // Sort the triggers + selectedTriggers.sort((a, b) => a.order - b.order); + // Apply the triggers + selectedTriggers.forEach(trigger => { + applyTrigger(trigger, opts) + }); +} + function rollCheck({prop, log, methodScope}){ // get the modifier for the roll let rollModifier; diff --git a/app/imports/api/properties/Triggers.js b/app/imports/api/properties/Triggers.js index 3b9b0d13..da99fddc 100644 --- a/app/imports/api/properties/Triggers.js +++ b/app/imports/api/properties/Triggers.js @@ -5,6 +5,7 @@ import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js'; const eventOptions = { doActionProperty: 'Do action', // receiveActionProperty: 'Receiving action property', + check: 'Roll check', // flipToggle: 'Toggle changed', // adjustProperty: 'Attribute adjusted', anyRest: 'Short or long rest', @@ -26,6 +27,7 @@ const actionPropertyTypeOptions = { note: 'Note', roll: 'Roll', savingThrow: 'Saving throw', + spell: 'Spell', toggle: 'Toggle', }