diff --git a/app/.meteor/packages b/app/.meteor/packages
index 06788bcc..d2c043aa 100644
--- a/app/.meteor/packages
+++ b/app/.meteor/packages
@@ -3,7 +3,6 @@
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
-zegenie:redis-oplog
accounts-password@2.3.4
random@1.2.1
underscore@1.0.13
diff --git a/app/.meteor/versions b/app/.meteor/versions
index 578fce81..e5431969 100644
--- a/app/.meteor/versions
+++ b/app/.meteor/versions
@@ -124,5 +124,4 @@ underscore@1.0.13
url@1.3.2
webapp@1.13.5
webapp-hashing@1.1.1
-zegenie:redis-oplog@2.0.16
zer0th:meteor-vuetify-loader@0.1.41
diff --git a/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js
index 46e7d024..b46205b9 100644
--- a/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js
+++ b/app/imports/api/creature/creatureProperties/methods/copyPropertyToLibrary.js
@@ -132,6 +132,9 @@ function insertNodeFromProperty(propId, ancestors, order, method) {
prop.order = order;
}
+ // Clean the props
+ props = cleanProps(props);
+
// Insert the props as library nodes
LibraryNodes.batchInsert(props);
return prop;
@@ -186,4 +189,11 @@ function assertSourceLibraryCopyPermission(props, method) {
});
}
+function cleanProps(props) {
+ return props.map(prop => {
+ let schema = LibraryNodes.simpleSchema(prop);
+ return schema.clean(prop);
+ });
+}
+
export default copyPropertyToLibrary;
diff --git a/app/imports/api/engine/actions/applyProperty.js b/app/imports/api/engine/actions/applyProperty.js
index 4dc1cb79..18f35d32 100644
--- a/app/imports/api/engine/actions/applyProperty.js
+++ b/app/imports/api/engine/actions/applyProperty.js
@@ -19,6 +19,7 @@ const applyPropertyByType = {
damage,
folder,
note,
+ propertySlot: folder,
roll,
savingThrow,
spell: action,
@@ -26,6 +27,7 @@ const applyPropertyByType = {
};
export default function applyProperty(node, actionContext, ...rest) {
+ if (node.node.deactivatedByToggle) return;
actionContext.scope[`#${node.node.type}`] = node.node;
applyPropertyByType[node.node.type]?.(node, actionContext, ...rest);
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js
index 3aa87df9..115d1998 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js
@@ -3,6 +3,7 @@ import recalculateCalculation from './shared/recalculateCalculation.js';
import rollDice from '/imports/parser/rollDice.js';
import applyProperty from '../applyProperty.js';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { adjustQuantityWork } from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js';
import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
@@ -187,11 +188,6 @@ function applyCrits(value, scope) {
return { criticalHit, criticalMiss };
}
-function applyChildren(node, actionContext) {
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
-}
-
function spendResources(prop, actionContext) {
// Check Uses
if (prop.usesLeft <= 0) {
@@ -276,9 +272,10 @@ function spendResources(prop, actionContext) {
recalculateCalculation(attConsumed.quantity, actionContext);
if (!attConsumed.quantity?.value) return;
+ if (!attConsumed.variableName) return;
let stat = actionContext.scope[attConsumed.variableName];
if (!stat) {
- spendLog.push(stat.name + ': ' + ' not found');
+ spendLog.push(attConsumed.variableName + ': ' + ' not found');
return;
}
damagePropertyWork({
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js b/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js
index ede94665..5ca17972 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyAdjustment.js
@@ -1,9 +1,9 @@
-import applyProperty from '../applyProperty.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import recalculateCalculation from './shared/recalculateCalculation.js';
import { damagePropertyWork } from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
-export default function applyAdjustment(node, actionContext){
+export default function applyAdjustment(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
const prop = node.node;
const damageTargets = prop.target === 'self' ? [actionContext.creature] : actionContext.targets;
@@ -39,7 +39,7 @@ export default function applyAdjustment(node, actionContext){
if (!prop.silent) actionContext.addLog({
name: 'Attribute damage',
value: `${prop.stat}${prop.operation === 'set' ? ' set to' : ''}` +
- ` ${value}`,
+ ` ${value}`,
inline: true,
});
});
@@ -47,15 +47,10 @@ export default function applyAdjustment(node, actionContext){
if (!prop.silent) actionContext.addLog({
name: 'Attribute damage',
value: `${prop.stat}${prop.operation === 'set' ? ' set to' : ''}` +
- ` ${value}`,
+ ` ${value}`,
inline: true,
});
}
return applyChildren(node, actionContext);
}
-
-function applyChildren(node, actionContext){
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
-}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js b/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js
index d48ebc01..8888c461 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyBranch.js
@@ -1,21 +1,18 @@
import applyProperty from '../applyProperty.js';
import recalculateCalculation from './shared/recalculateCalculation.js';
import rollDice from '/imports/parser/rollDice.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
export default function applyBranch(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
- const applyChildren = function () {
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
- };
const scope = actionContext.scope;
const targets = actionContext.targets;
const prop = node.node;
switch (prop.branchType) {
case 'if':
recalculateCalculation(prop.condition, actionContext);
- if (prop.condition?.value) applyChildren();
+ if (prop.condition?.value) applyChildren(node, actionContext);
break;
case 'index':
if (node.children.length) {
@@ -32,30 +29,31 @@ export default function applyBranch(node, actionContext) {
if (index > node.children.length) index = node.children.length;
applyNodeTriggers(node, 'after', actionContext);
applyProperty(node.children[index - 1], actionContext);
+ applyNodeTriggers(node, 'afterChildren', actionContext);
}
break;
case 'hit':
if (scope['~attackHit']?.value) {
if (!targets.length && !prop.silent) actionContext.addLog({ value: '**On hit**' });
- applyChildren();
+ applyChildren(node, actionContext);
}
break;
case 'miss':
if (scope['~attackMiss']?.value) {
if (!targets.length && !prop.silent) actionContext.addLog({ value: '**On miss**' });
- applyChildren();
+ applyChildren(node, actionContext);
}
break;
case 'failedSave':
if (scope['~saveFailed']?.value) {
if (!targets.length && !prop.silent) actionContext.addLog({ value: '**On failed save**' });
- applyChildren();
+ applyChildren(node, actionContext);
}
break;
case 'successfulSave':
if (scope['~saveSucceeded']?.value) {
if (!targets.length && !prop.silent) actionContext.addLog({ value: '**On save**', });
- applyChildren();
+ applyChildren(node, actionContext);
}
break;
case 'random':
@@ -63,6 +61,7 @@ export default function applyBranch(node, actionContext) {
let index = rollDice(1, node.children.length)[0] - 1;
applyNodeTriggers(node, 'after', actionContext);
applyProperty(node.children[index], actionContext);
+ applyNodeTriggers(node, 'afterChildren', actionContext);
}
break;
case 'eachTarget':
@@ -71,9 +70,10 @@ export default function applyBranch(node, actionContext) {
applyNodeTriggers(node, 'after', actionContext);
actionContext.targets = [target]
node.children.forEach(child => applyProperty(child, actionContext));
+ applyNodeTriggers(node, 'afterChildren', actionContext);
});
} else {
- applyChildren();
+ applyChildren(node, actionContext);
}
break;
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js b/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js
index a755a001..49adf4eb 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyBuff.js
@@ -77,6 +77,7 @@ export default function applyBuff(node, actionContext) {
}
});
applyNodeTriggers(node, 'after', actionContext);
+ applyNodeTriggers(node, 'afterChildren', actionContext);
// Don't apply the children of the buff, they get copied to the target instead
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js b/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js
index 86b60949..a9915bdf 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyBuffRemover.js
@@ -5,6 +5,7 @@ import { getProperyAncestors, getPropertiesOfType } from '/imports/api/engine/lo
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import { softRemove } from '/imports/api/parenting/softRemove.js';
import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
export default function applyBuffRemover(node, actionContext) {
// Apply triggers
@@ -13,7 +14,7 @@ export default function applyBuffRemover(node, actionContext) {
const prop = node.node;
// Log Name
- if (prop.name && !prop.silent){
+ if (prop.name && !prop.silent) {
actionContext.addLog({ name: prop.name });
}
@@ -53,11 +54,7 @@ export default function applyBuffRemover(node, actionContext) {
}
}
}
-
- // Apply triggers
- applyNodeTriggers(node, 'after', actionContext);
- // Apply children
- node.children.forEach(child => applyProperty(child, actionContext));
+ applyChildren(node, actionContext);
}
function removeBuff(buff, actionContext, prop) {
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
index a622989e..a6b1902a 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyDamage.js
@@ -1,5 +1,5 @@
import { some, intersection, difference, remove, includes } from 'lodash';
-import applyProperty from '../applyProperty.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { insertCreatureLog } from '/imports/api/creature/log/CreatureLogs.js';
import resolve, { Context, toString } from '/imports/parser/resolve.js';
import logErrors from './shared/logErrors.js';
@@ -13,10 +13,6 @@ import getEffectivePropTags from '/imports/api/engine/computation/utility/getEff
export default function applyDamage(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
- const applyChildren = function () {
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
- };
const prop = node.node;
const scope = actionContext.scope;
@@ -66,7 +62,7 @@ export default function applyDamage(node, actionContext) {
// If we didn't end up with a constant of finite amount, give up
if (reduced?.parseType !== 'constant' || !isFinite(reduced.value)) {
- return applyChildren();
+ return applyChildren(node, actionContext);
}
// Round the damage to a whole number
@@ -133,7 +129,7 @@ export default function applyDamage(node, actionContext) {
value: logValue.join('\n'),
inline: true,
});
- return applyChildren();
+ return applyChildren(node, actionContext);
}
function applyDamageMultipliers({ target, damage, damageProp, logValue }) {
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js b/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js
index 0965f56d..ea216685 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyFolder.js
@@ -1,11 +1,9 @@
-import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js';
-import applyProperty from '../applyProperty.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
export default function applyFolder(node, actionContext) {
// Apply triggers
applyNodeTriggers(node, 'before', actionContext);
- applyNodeTriggers(node, 'after', actionContext);
// Apply children
- node.children.forEach(child => applyProperty(child, actionContext));
+ applyChildren(node, actionContext);
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js
index 0d5f9e84..332d93dc 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js
@@ -1,27 +1,25 @@
import recalculateInlineCalculations from './shared/recalculateInlineCalculations.js';
-import applyProperty from '../applyProperty.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
-export default function applyNote(node, actionContext){
+export default function applyNote(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
const prop = node.node;
// Log Name, summary
let content = { name: prop.name };
- if (prop.summary?.text){
+ if (prop.summary?.text) {
recalculateInlineCalculations(prop.summary, actionContext);
content.value = prop.summary.value;
}
- if (content.name || content.value){
+ if (content.name || content.value) {
actionContext.addLog(content);
}
// Log description
- if (prop.description?.text){
+ if (prop.description?.text) {
recalculateInlineCalculations(prop.description, actionContext);
- actionContext.addLog({value: prop.description.value});
+ actionContext.addLog({ value: prop.description.value });
}
- // Apply triggers
- applyNodeTriggers(node, 'after', actionContext);
// Apply children
- node.children.forEach(child => applyProperty(child, actionContext));
+ applyChildren(node, actionContext);
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js b/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js
index 68892231..d3b7bf12 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyRoll.js
@@ -1,4 +1,4 @@
-import applyProperty from '../applyProperty.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import logErrors from './shared/logErrors.js';
import applyEffectsToCalculationParseNode from '/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js';
import resolve, { toString } from '/imports/parser/resolve.js';
@@ -8,11 +8,6 @@ export default function applyRoll(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
const prop = node.node;
- const applyChildren = function () {
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
- };
-
if (prop.roll?.calculation) {
const logValue = [];
@@ -42,7 +37,7 @@ export default function applyRoll(node, actionContext) {
// If we didn't end up with a constant or a number of finite value, give up
if (reduced?.parseType !== 'constant' || (reduced.valueType === 'number' && !isFinite(reduced.value))) {
- return applyChildren();
+ return applyChildren(node, actionContext);
}
const value = reduced.value;
@@ -57,5 +52,5 @@ export default function applyRoll(node, actionContext) {
});
}
}
- return applyChildren();
+ return applyChildren(node, actionContext);
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js b/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js
index e0803109..ae2f878e 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applySavingThrow.js
@@ -2,6 +2,7 @@ import rollDice from '/imports/parser/rollDice.js';
import recalculateCalculation from './shared/recalculateCalculation.js';
import applyProperty from '../applyProperty.js';
import numberToSignedString from '/imports/api/utility/numberToSignedString.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
import { applyUnresolvedEffects } from '/imports/api/engine/actions/doCheck.js';
@@ -34,8 +35,7 @@ export default function applySavingThrow(node, actionContext) {
if (!saveTargets?.length) {
scope['~saveFailed'] = { value: true };
scope['~saveSucceeded'] = { value: true };
- applyNodeTriggers(node, 'after', actionContext);
- return node.children.forEach(child => applyProperty(child, actionContext));
+ return applyChildren(node, actionContext);
}
// Each target makes the saving throw
@@ -45,10 +45,9 @@ export default function applySavingThrow(node, actionContext) {
delete scope['~saveDiceRoll'];
delete scope['~saveRoll'];
- const applyChildren = function () {
- actionContext.targets = [target]
- applyNodeTriggers(node, 'after', actionContext);
- node.children.forEach(child => applyProperty(child, actionContext));
+ const applyChildrenToTarget = function () {
+ actionContext.targets = [target];
+ return applyChildren(node, actionContext);
};
const save = target.variables[prop.stat];
@@ -58,7 +57,7 @@ export default function applySavingThrow(node, actionContext) {
name: 'Saving throw error',
value: 'No saving throw found: ' + prop.stat,
});
- return applyChildren();
+ return applyChildrenToTarget();
}
let rollModifierText = numberToSignedString(save.value, true);
@@ -105,7 +104,7 @@ export default function applySavingThrow(node, actionContext) {
value: resultPrefix + '\n**' + result + '**',
inline: true,
});
- return applyChildren();
+ return applyChildrenToTarget();
});
// reset the targets after the save to each child
actionContext.targets = originalTargets;
diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js b/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js
index be80b012..47ec3e08 100644
--- a/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js
+++ b/app/imports/api/engine/actions/applyPropertyByType/applyToggle.js
@@ -1,13 +1,12 @@
-import applyProperty from '../applyProperty.js';
import recalculateCalculation from './shared/recalculateCalculation.js';
import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
+import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js';
-export default function applyToggle(node, actionContext){
+export default function applyToggle(node, actionContext) {
applyNodeTriggers(node, 'before', actionContext);
const prop = node.node;
recalculateCalculation(prop.condition, actionContext);
if (prop.condition?.value) {
- applyNodeTriggers(node, 'after', actionContext);
- return node.children.forEach(child => applyProperty(child, actionContext));
+ return applyChildren(node, actionContext);
}
}
diff --git a/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js b/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js
new file mode 100644
index 00000000..9c5c0cbd
--- /dev/null
+++ b/app/imports/api/engine/actions/applyPropertyByType/shared/applyChildren.js
@@ -0,0 +1,8 @@
+import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers.js';
+import applyProperty from '/imports/api/engine/actions/applyProperty.js';
+
+export default function applyChildren(node, actionContext) {
+ applyNodeTriggers(node, 'after', actionContext);
+ node.children.forEach(child => applyProperty(child, actionContext));
+ applyNodeTriggers(node, 'afterChildren', actionContext);
+}
diff --git a/app/imports/api/engine/computation/buildComputation/linkInventory.js b/app/imports/api/engine/computation/buildComputation/linkInventory.js
index ae092bd5..7961e4df 100644
--- a/app/imports/api/engine/computation/buildComputation/linkInventory.js
+++ b/app/imports/api/engine/computation/buildComputation/linkInventory.js
@@ -2,22 +2,22 @@
* Performs a depth first traversal of the character tree, summing the container
* and inventory contents on the way up the tree
*/
-export default function linkInventory(forest, dependencyGraph){
+export default function linkInventory(forest, dependencyGraph) {
// The stack of properties to still navigate
const stack = [...forest];
// The current containers we are inside of
const containerStack = [];
- while(stack.length){
+ while (stack.length) {
const top = stack[stack.length - 1];
const prop = top.node;
- if (prop._computationDetails.inventoryChildrenVisited){
+ if (prop._computationDetails.inventoryChildrenVisited) {
if (prop.type === 'container') containerStack.pop();
stack.pop();
handleProp(prop, containerStack, dependencyGraph);
} else {
// Add all containers to the stack when we first visit them
- if (prop.type === 'container'){
+ if (prop.type === 'container') {
containerStack.push(top.node);
}
// Push children onto the stack and mark this as children are visited
@@ -27,18 +27,18 @@ export default function linkInventory(forest, dependencyGraph){
}
}
-function handleProp(prop, containerStack, dependencyGraph){
+function handleProp(prop, containerStack, dependencyGraph) {
// Skip props that aren't part of the inventory
if (prop.type !== 'item' && prop.type !== 'container') return;
// Determine if this property is carried, items are carried by default
let carried = prop.type === 'container' ? prop.carried : true;
// Item-specific links
- if (prop.type === 'item'){
- if (prop.attuned){
+ if (prop.type === 'item') {
+ if (prop.attuned) {
dependencyGraph.addLink('itemsAttuned', prop._id, 'attunedItem');
}
- if (prop.equipped){
+ if (prop.equipped) {
dependencyGraph.addLink('weightEquipment', prop._id, 'equippedItem');
dependencyGraph.addLink('valueEquipment', prop._id, 'equippedItem');
}
@@ -47,14 +47,14 @@ function handleProp(prop, containerStack, dependencyGraph){
// Get the parent container
const container = containerStack[containerStack.length - 1];
- if (container){
+ if (container) {
// The container depends on this prop for its contents data
dependencyGraph.addLink(container._id, prop._id, 'containerContents');
} else {
// There is no parent container, the character totals depend on this prop
dependencyGraph.addLink('weightTotal', prop._id, 'inventoryStats');
dependencyGraph.addLink('valueTotal', prop._id, 'inventoryStats');
- if (carried){
+ if (carried) {
dependencyGraph.addLink('weightCarried', prop._id, 'inventoryStats');
dependencyGraph.addLink('valueCarried', prop._id, 'inventoryStats');
}
diff --git a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js
index 4a83ab62..85a7b551 100644
--- a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js
+++ b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js
@@ -80,6 +80,15 @@ function linkAction(dependencyGraph, prop, { propsById }) {
key: `resources.attributesConsumed[${index}].quantity`,
});
});
+ // Link conditions
+ prop.resources.conditions?.forEach((con, index) => {
+ // Link the property to its condition calculation
+ dependOnCalc({
+ dependencyGraph,
+ prop,
+ key: `resources.conditions[${index}].condition`,
+ });
+ });
}
function linkAdjustment(dependencyGraph, prop) {
diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeAction.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeAction.js
index 86d23e80..c908aa18 100644
--- a/app/imports/api/engine/computation/computeComputation/computeByType/computeAction.js
+++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeAction.js
@@ -8,14 +8,21 @@ export default function computeAction(computation, node) {
}
computeResources(computation, node);
if (!prop.resources) return;
- prop.resources.itemsConsumed.forEach(itemConsumed => {
+ prop.resources.conditions?.forEach(conObj => {
+ const condition = conObj.condition;
+ if (!condition) return;
+ if (condition.calculation && !condition.value) {
+ prop.insufficientResources = true;
+ }
+ });
+ prop.resources.itemsConsumed?.forEach(itemConsumed => {
if (!itemConsumed.itemId || itemConsumed.available < itemConsumed.quantity?.value) {
prop.insufficientResources = true;
}
});
- prop.resources.attributesConsumed.forEach(attConsumed => {
+ prop.resources.attributesConsumed?.forEach(attConsumed => {
if (!attConsumed.variableName) return;
- if (attConsumed.available < attConsumed.quantity?.value) {
+ if (!(attConsumed.available >= attConsumed.quantity?.value)) {
prop.insufficientResources = true;
}
});
diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeContainer.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeContainer.js
index 61b4b79a..0258692f 100644
--- a/app/imports/api/engine/computation/computeComputation/computeByType/computeContainer.js
+++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeContainer.js
@@ -1,11 +1,17 @@
import aggregate from './computeVariable/aggregate/index.js';
+import { safeStrip } from '/imports/api/engine/computation/utility/stripFloatingPointOddities.js';
-export default function computeContainer(computation, node){
+export default function computeContainer(computation, node) {
if (!node.data) node.data = {};
aggregateLinks(computation, node);
+
+ // Clean up floating points
+ const prop = node.data;
+ prop.contentsWeight = safeStrip(prop.contentsWeight);
+ prop.carriedWeight = safeStrip(prop.carriedWeight);
}
-function aggregateLinks(computation, node){
+function aggregateLinks(computation, node) {
computation.dependencyGraph.forEachLinkedNode(
node.id,
(linkedNode, link) => {
@@ -13,7 +19,7 @@ function aggregateLinks(computation, node){
// Ignore inactive props
if (linkedNode.data.inactive) return;
// Aggregate inventory links
- aggregate.inventory({node, linkedNode, link});
+ aggregate.inventory({ node, linkedNode, link });
},
true // enumerate only outbound links
);
diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/aggregate/aggregateInventory.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/aggregate/aggregateInventory.js
index 6dd01ba2..a7291388 100644
--- a/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/aggregate/aggregateInventory.js
+++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/aggregate/aggregateInventory.js
@@ -1,25 +1,25 @@
-export default function aggregateInventory({node, linkedNode, link}){
+export default function aggregateInventory({ node, linkedNode, link }) {
let linkedProp = linkedNode.data || {};
const prop = node.data;
- switch (link.data){
+ switch (link.data) {
case 'attunedItem':
prop.baseValue = (prop.baseValue || 0) + 1;
return;
case 'equippedItem':
- if (node.id === 'weightEquipment'){
+ if (node.id === 'weightEquipment') {
prop.baseValue = (prop.baseValue || 0) + weight(linkedProp);
- } else if (node.id === 'valueEquipment'){
+ } else if (node.id === 'valueEquipment') {
prop.baseValue = (prop.baseValue || 0) + value(linkedProp);
}
return;
case 'containerContents':
// Add this property's weights and values to the container
- if (!prop.weightless){
+ if (!prop.weightless) {
prop.contentsWeight = (prop.contentsWeight || 0) + weight(linkedProp);
- if (prop.carried){
+ if (prop.carried && !prop.contentsWeightless) {
prop.carriedWeight = (prop.carriedWeight || 0) + carriedWeight(linkedProp);
}
}
@@ -30,39 +30,39 @@ export default function aggregateInventory({node, linkedNode, link}){
return;
case 'inventoryStats':
- if (node.id === 'weightTotal'){
+ if (node.id === 'weightTotal') {
prop.baseValue = (prop.baseValue || 0) + weight(linkedProp);
- } else if (node.id === 'valueTotal'){
+ } else if (node.id === 'valueTotal') {
prop.baseValue = (prop.baseValue || 0) + value(linkedProp);
- } else if (node.id === 'weightCarried'){
+ } else if (node.id === 'weightCarried') {
prop.baseValue = (prop.baseValue || 0) + carriedWeight(linkedProp);
- } else if (node.id === 'valueCarried'){
+ } else if (node.id === 'valueCarried') {
prop.baseValue = (prop.baseValue || 0) + carriedValue(linkedProp);
}
return;
}
}
-function quantity(prop){
- if (typeof prop.quantity === 'number'){
+function quantity(prop) {
+ if (typeof prop.quantity === 'number') {
return prop.quantity;
} else {
return 1;
}
}
-function weight(prop){
+function weight(prop) {
return (prop.weight || 0) * quantity(prop) + (prop.contentsWeight || 0);
}
-function carriedWeight(prop){
+function carriedWeight(prop) {
return (prop.weight || 0) * quantity(prop) + (prop.carriedWeight || 0);
}
-function value (prop){
+function value(prop) {
return (prop.value || 0) * quantity(prop) + (prop.contentsValue || 0);
}
-function carriedValue (prop){
+function carriedValue(prop) {
return (prop.value || 0) * quantity(prop) + (prop.carriedValue || 0);
}
diff --git a/app/imports/api/engine/computation/computeComputation/computeToggles.js b/app/imports/api/engine/computation/computeComputation/computeToggles.js
index 657305d6..a39e8dc4 100644
--- a/app/imports/api/engine/computation/computeComputation/computeToggles.js
+++ b/app/imports/api/engine/computation/computeComputation/computeToggles.js
@@ -5,8 +5,26 @@ export default function evaluateToggles(computation, node) {
if (!toggles) return;
toggles.forEach(toggle => {
if (
- (!toggle.enabled && !toggle.disabled && toggle.condition && !toggle.condition.value)
- || (toggle.disabled)
+ (
+ // Toggle isn't set to constantly enabled or disabled
+ !toggle.enabled &&
+ !toggle.disabled &&
+ // Toggle is not disabled by another toggle targeting it
+ // Ancestor toggles would've handled this child anyway,
+ // and tag targeted toggles break the link
+ !toggle.deactivatedByToggle &&
+ !toggle.deactivatedByAncestor &&
+ // Toggle has a condition with a falsy value
+ toggle.condition &&
+ !toggle.condition.value
+ )
+ || (
+ // Toggle is disabled manually
+ toggle.disabled &&
+ // Toggle isn't deactivated by something else
+ !toggle.deactivatedByToggle &&
+ !toggle.deactivatedByAncestor
+ )
) {
prop.inactive = true;
prop.deactivatedByToggle = true;
diff --git a/app/imports/api/engine/computation/utility/stripFloatingPointOddities.js b/app/imports/api/engine/computation/utility/stripFloatingPointOddities.js
index 8e55685c..3415ff1a 100644
--- a/app/imports/api/engine/computation/utility/stripFloatingPointOddities.js
+++ b/app/imports/api/engine/computation/utility/stripFloatingPointOddities.js
@@ -1,3 +1,8 @@
-export default function stripFloatingPointOddities(num, precision = 12){
+export default function stripFloatingPointOddities(num, precision = 12) {
return +parseFloat(num.toPrecision(precision))
}
+
+export function safeStrip(num, precision = 12) {
+ if (!Number.isFinite(num)) return num;
+ return stripFloatingPointOddities(num, precision);
+}
diff --git a/app/imports/api/properties/Actions.js b/app/imports/api/properties/Actions.js
index 3de84914..163d938d 100644
--- a/app/imports/api/properties/Actions.js
+++ b/app/imports/api/properties/Actions.js
@@ -77,6 +77,7 @@ let ActionSchema = createPropertySchema({
'resources.itemsConsumed': {
type: Array,
defaultValue: [],
+ max: 32,
},
'resources.itemsConsumed.$': {
type: Object,
@@ -104,6 +105,7 @@ let ActionSchema = createPropertySchema({
'resources.attributesConsumed': {
type: Array,
defaultValue: [],
+ max: 32,
},
'resources.attributesConsumed.$': {
type: Object,
@@ -124,6 +126,30 @@ let ActionSchema = createPropertySchema({
type: 'fieldToCompute',
optional: true,
},
+ 'resources.conditions': {
+ type: Array,
+ defaultValue: [],
+ max: 32,
+ },
+ 'resources.conditions.$': {
+ type: Object,
+ },
+ 'resources.conditions.$._id': {
+ type: String,
+ regEx: SimpleSchema.RegEx.Id,
+ autoValue() {
+ if (!this.isSet) return Random.id();
+ }
+ },
+ 'resources.conditions.$.condition': {
+ type: 'fieldToCompute',
+ optional: true,
+ },
+ 'resources.conditions.$.conditionNote': {
+ type: String,
+ optional: true,
+ max: STORAGE_LIMITS.calculation,
+ },
// Prevent the property from showing up in the log
silent: {
type: Boolean,
diff --git a/app/imports/api/properties/Damages.js b/app/imports/api/properties/Damages.js
index 190dd4b5..d01a2e0d 100644
--- a/app/imports/api/properties/Damages.js
+++ b/app/imports/api/properties/Damages.js
@@ -2,6 +2,7 @@ import SimpleSchema from 'simpl-schema';
import createPropertySchema from '/imports/api/properties/subSchemas/createPropertySchema.js';
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js';
+import { SavingThrowSchema, ComputedOnlySavingThrowSchema } from '/imports/api/properties/SavingThrows.js';
const DamageSchema = createPropertySchema({
// The roll that determines how much to damage the attribute
@@ -32,6 +33,15 @@ const DamageSchema = createPropertySchema({
type: Boolean,
optional: true,
},
+ save: {
+ type: SavingThrowSchema,
+ optional: true,
+ },
+ 'save.damageFunction': {
+ type: 'fieldToCompute',
+ optional: true,
+ parseLevel: 'compile',
+ },
});
const ComputedOnlyDamageSchema = createPropertySchema({
@@ -40,6 +50,15 @@ const ComputedOnlyDamageSchema = createPropertySchema({
optional: true,
parseLevel: 'compile',
},
+ save: {
+ type: ComputedOnlySavingThrowSchema,
+ optional: true,
+ },
+ 'save.damageFunction': {
+ type: 'computedOnlyField',
+ optional: true,
+ parseLevel: 'compile',
+ },
});
const ComputedDamageSchema = new SimpleSchema()
diff --git a/app/imports/api/properties/Triggers.js b/app/imports/api/properties/Triggers.js
index 0bfd7d9d..250d6bda 100644
--- a/app/imports/api/properties/Triggers.js
+++ b/app/imports/api/properties/Triggers.js
@@ -18,6 +18,7 @@ const eventOptions = {
const timingOptions = {
before: 'Before',
after: 'After',
+ afterChildren: 'After Children',
}
const actionPropertyTypeOptions = {
@@ -91,7 +92,7 @@ let TriggerSchema = createPropertySchema({
'extraTags.$._id': {
type: String,
regEx: SimpleSchema.RegEx.Id,
- autoValue(){
+ autoValue() {
if (!this.isSet) return Random.id();
}
},
diff --git a/app/imports/client/ui/components/ColorPicker.vue b/app/imports/client/ui/components/ColorPicker.vue
index ef73f90d..b008ccfc 100644
--- a/app/imports/client/ui/components/ColorPicker.vue
+++ b/app/imports/client/ui/components/ColorPicker.vue
@@ -18,7 +18,7 @@
{{ label }}