Triggers can fire on character sheet checks
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user