fixed: Show only the last event with a var name

This commit is contained in:
Stefan Zermatten
2022-11-22 21:59:44 +02:00
parent d947b62ba4
commit fd9d525ba9
7 changed files with 108 additions and 74 deletions

View File

@@ -23,23 +23,26 @@ const linkDependenciesByType = {
toggle: linkToggle,
}
export default function linkTypeDependencies(dependencyGraph, prop, computation){
export default function linkTypeDependencies(dependencyGraph, prop, computation) {
linkDependenciesByType[prop.type]?.(dependencyGraph, prop, computation);
}
function dependOnCalc({dependencyGraph, prop, key}){
function dependOnCalc({ dependencyGraph, prop, key }) {
let calc = get(prop, key);
if (!calc) return;
if (calc.type !== '_calculation'){
if (calc.type !== '_calculation') {
throw `Expected calculation got ${calc.type}`
}
dependencyGraph.addLink(prop._id, `${prop._id}.${key}`, 'calculation');
}
function linkAction(dependencyGraph, prop, {propsById}){
function linkAction(dependencyGraph, prop, { propsById }) {
if (prop.variableName) {
dependencyGraph.addLink(prop.variableName, prop._id, 'eventDefinition');
}
// The action depends on its attack roll and uses calculations
dependOnCalc({dependencyGraph, prop, key: 'attackRoll'});
dependOnCalc({dependencyGraph, prop, key: 'uses'});
dependOnCalc({ dependencyGraph, prop, key: 'attackRoll' });
dependOnCalc({ dependencyGraph, prop, key: 'uses' });
// Link the resources the action uses
if (!prop.resources) return;
@@ -47,7 +50,7 @@ function linkAction(dependencyGraph, prop, {propsById}){
prop.resources.itemsConsumed.forEach((itemConsumed, index) => {
if (!itemConsumed.itemId) return;
const item = propsById[itemConsumed.itemId];
if (!item || item.inactive){
if (!item || item.inactive) {
// Unlink if the item doesn't exist or is inactive
itemConsumed.itemId = undefined;
return;
@@ -79,48 +82,48 @@ function linkAction(dependencyGraph, prop, {propsById}){
});
}
function linkAdjustment(dependencyGraph, prop){
function linkAdjustment(dependencyGraph, prop) {
// Adjustment depends on its amount
dependOnCalc({dependencyGraph, prop, key: 'amount'});
dependOnCalc({ dependencyGraph, prop, key: 'amount' });
}
function linkAttribute(dependencyGraph, prop){
function linkAttribute(dependencyGraph, prop) {
linkVariableName(dependencyGraph, prop);
// Depends on spellSlotLevel
dependOnCalc({dependencyGraph, prop, key: 'spellSlotLevel'});
dependOnCalc({ dependencyGraph, prop, key: 'spellSlotLevel' });
// Depends on base value
dependOnCalc({dependencyGraph, prop, key: 'baseValue'});
dependOnCalc({ dependencyGraph, prop, key: 'baseValue' });
// hit dice depend on constitution
if (prop.attributeType === 'hitDice'){
if (prop.attributeType === 'hitDice') {
dependencyGraph.addLink(prop._id, 'constitution', 'hitDiceConMod');
}
}
function linkBranch(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'condition'});
function linkBranch(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'condition' });
}
function linkBuff(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'duration'});
function linkBuff(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'duration' });
}
function linkClassLevel(dependencyGraph, prop) {
if (prop.inactive) return;
// The variableName of the prop depends on the prop
if (prop.variableName && prop.level){
if (prop.variableName && prop.level) {
dependencyGraph.addLink(prop.variableName, prop._id, 'classLevel');
// The level variable depends on the class variableName variable
let existingLevelLink = dependencyGraph.getLink('level', prop.variableName);
if (!existingLevelLink){
if (!existingLevelLink) {
dependencyGraph.addLink('level', prop.variableName, 'level');
}
}
}
function linkDamage(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'amount'});
function linkDamage(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'amount' });
}
function linkEffects(dependencyGraph, prop, computation) {
@@ -132,7 +135,7 @@ function linkEffects(dependencyGraph, prop, computation) {
if (prop.inactive) {
// Inactive effects apply to no stats
return;
} else if (prop.targetByTags){
} else if (prop.targetByTags) {
getEffectTagTargets(prop, computation).forEach(targetId => {
const targetProp = computation.propsById[targetId];
if (
@@ -147,8 +150,8 @@ function linkEffects(dependencyGraph, prop, computation) {
// Otherwise target a field on that property
const key = prop.targetField || getDefaultCalculationField(targetProp);
const calcObj = get(targetProp, key);
if (calcObj && calcObj.calculation){
dependencyGraph.addLink(`${targetProp._id}.${key}`, prop._id , 'effect');
if (calcObj && calcObj.calculation) {
dependencyGraph.addLink(`${targetProp._id}.${key}`, prop._id, 'effect');
}
}
});
@@ -161,14 +164,14 @@ function linkEffects(dependencyGraph, prop, computation) {
}
// Returns an array of IDs of the properties the effect targets
function getEffectTagTargets(effect, computation){
function getEffectTagTargets(effect, computation) {
let targets = getTargetListFromTags(effect.targetTags, computation);
let notIds = [];
if (effect.extraTags){
if (effect.extraTags) {
effect.extraTags.forEach(ex => {
if (ex.operation === 'OR') {
targets = union(targets, getTargetListFromTags(ex.tags, computation));
} else if (ex.operation === 'NOT'){
} else if (ex.operation === 'NOT') {
ex.tags.forEach(tag => {
const idList = computation.propsWithTag[tag];
if (idList) {
@@ -181,7 +184,7 @@ function getEffectTagTargets(effect, computation){
return difference(targets, notIds);
}
function getTargetListFromTags(tags, computation){
function getTargetListFromTags(tags, computation) {
const targetTagIdLists = [];
if (!tags) return [];
tags.forEach(tag => {
@@ -192,8 +195,8 @@ function getTargetListFromTags(tags, computation){
return targets;
}
function getDefaultCalculationField(prop){
switch (prop.type){
function getDefaultCalculationField(prop) {
switch (prop.type) {
case 'action': return 'attackRoll';
case 'adjustment': return 'amount';
case 'attribute': return 'baseValue';
@@ -223,13 +226,13 @@ function getDefaultCalculationField(prop){
}
}
function linkRoll(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'roll'});
function linkRoll(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'roll' });
}
function linkVariableName(dependencyGraph, prop){
function linkVariableName(dependencyGraph, prop) {
// The variableName of the prop depends on the prop if the prop is active
if (prop.variableName && !prop.inactive){
if (prop.variableName && !prop.inactive) {
dependencyGraph.addLink(prop.variableName, prop._id, 'definition');
}
}
@@ -243,7 +246,7 @@ function linkDamageMultiplier(dependencyGraph, prop) {
});
}
function linkPointBuy(dependencyGraph, prop){
function linkPointBuy(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'min' });
dependOnCalc({ dependencyGraph, prop, key: 'max' });
dependOnCalc({ dependencyGraph, prop, key: 'cost' });
@@ -265,7 +268,7 @@ function linkPointBuy(dependencyGraph, prop){
if (prop.inactive) return;
}
function linkProficiencies(dependencyGraph, prop){
function linkProficiencies(dependencyGraph, prop) {
// The stats depend on the proficiency
if (prop.inactive) return;
prop.stats.forEach(statName => {
@@ -274,36 +277,36 @@ function linkProficiencies(dependencyGraph, prop){
});
}
function linkSavingThrow(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'dc'});
function linkSavingThrow(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'dc' });
}
function linkSkill(dependencyGraph, prop){
function linkSkill(dependencyGraph, prop) {
// Depends on base value
dependOnCalc({ dependencyGraph, prop, key: 'baseValue' });
// Link dependents
if (prop.inactive) return;
linkVariableName(dependencyGraph, prop);
// The prop depends on the variable references as the ability
if (prop.ability){
if (prop.ability) {
dependencyGraph.addLink(prop._id, prop.ability, 'skillAbilityScore');
}
// Skills depend on the creature's proficiencyBonus
dependencyGraph.addLink(prop._id, 'proficiencyBonus', 'skillProficiencyBonus');
}
function linkSlot(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'quantityExpected'});
dependOnCalc({dependencyGraph, prop, key: 'slotCondition'});
function linkSlot(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'quantityExpected' });
dependOnCalc({ dependencyGraph, prop, key: 'slotCondition' });
}
function linkSpellList(dependencyGraph, prop){
dependOnCalc({dependencyGraph, prop, key: 'maxPrepared'});
dependOnCalc({dependencyGraph, prop, key: 'attackRollBonus'});
dependOnCalc({dependencyGraph, prop, key: 'dc'});
function linkSpellList(dependencyGraph, prop) {
dependOnCalc({ dependencyGraph, prop, key: 'maxPrepared' });
dependOnCalc({ dependencyGraph, prop, key: 'attackRollBonus' });
dependOnCalc({ dependencyGraph, prop, key: 'dc' });
}
function linkToggle(dependencyGraph, prop){
function linkToggle(dependencyGraph, prop) {
linkVariableName(dependencyGraph, prop);
dependOnCalc({dependencyGraph, prop, key: 'condition'});
dependOnCalc({ dependencyGraph, prop, key: 'condition' });
}

View File

@@ -1,8 +1,8 @@
export default function computeAction(computation, node){
export default function computeAction(computation, node) {
const prop = node.data;
if (prop.uses){
if (prop.uses) {
prop.usesLeft = prop.uses.value - (prop.usesUsed || 0);
if (!prop.usesLeft){
if (!prop.usesLeft) {
prop.insufficientResources = true;
}
}
@@ -10,19 +10,19 @@ export default function computeAction(computation, node){
if (!prop.resources) return;
prop.resources.itemsConsumed.forEach(itemConsumed => {
if (!itemConsumed.itemId) return;
if (itemConsumed.available < itemConsumed.quantity?.value){
if (itemConsumed.available < itemConsumed.quantity?.value) {
prop.insufficientResources = true;
}
});
prop.resources.attributesConsumed.forEach(attConsumed => {
if (!attConsumed.variableName) return;
if (attConsumed.available < attConsumed.quantity?.value){
if (attConsumed.available < attConsumed.quantity?.value) {
prop.insufficientResources = true;
}
});
}
function computeResources(computation, node){
function computeResources(computation, node) {
const resources = node.data?.resources;
if (!resources) return;
resources.attributesConsumed.forEach(attConsumed => {

View File

@@ -7,7 +7,7 @@ import computeVariableAsToggle from './computeVariable/computeVariableAsToggle.j
import computeImplicitVariable from './computeVariable/computeImplicitVariable.js';
import VARIABLE_NAME_REGEX from '/imports/constants/VARIABLE_NAME_REGEX.js';
export default function computeVariable(computation, node){
export default function computeVariable(computation, node) {
const scope = computation.scope;
if (!node.data) node.data = {};
aggregateLinks(computation, node);
@@ -15,7 +15,7 @@ export default function computeVariable(computation, node){
// Don't add to the scope if the node id is not a legitimate variable name
// Without this `some.thing` could break the entire sheet as a database key
if (!VARIABLE_NAME_REGEX.test(node.id)) return;
if (node.data.definingProp){
if (node.data.definingProp) {
// Add the defining variable to the scope
scope[node.id] = node.data.definingProp
} else {
@@ -24,7 +24,7 @@ export default function computeVariable(computation, node){
}
}
function aggregateLinks(computation, node){
function aggregateLinks(computation, node) {
computation.dependencyGraph.forEachLinkedNode(
node.id,
(linkedNode, link) => {
@@ -32,11 +32,12 @@ function aggregateLinks(computation, node){
// Ignore inactive props
if (linkedNode.data.inactive) return;
// Apply all the aggregations
let arg = {node, linkedNode, link, computation};
let arg = { node, linkedNode, link, computation };
aggregate.classLevel(arg);
aggregate.damageMultiplier(arg);
aggregate.definition(arg);
aggregate.effect(arg);
aggregate.eventDefinition(arg);
aggregate.inventory(arg);
aggregate.proficiency(arg);
},
@@ -44,7 +45,7 @@ function aggregateLinks(computation, node){
);
}
function combineAggregations(computation, node){
function combineAggregations(computation, node) {
combineMultiplierAggregator(node);
node.data.overridenProps?.forEach(prop => {
computeVariableProp(computation, node, prop);
@@ -52,51 +53,51 @@ function combineAggregations(computation, node){
computeVariableProp(computation, node, node.data.definingProp);
}
function computeVariableProp(computation, node, prop){
function computeVariableProp(computation, node, prop) {
if (!prop) return;
// Combine damage multipliers in all props so that they can't be overridden
if (node.data.immunity){
if (node.data.immunity) {
prop.immunity = node.data.immunity;
prop.immunities = node.data.immunities;
}
if (node.data.resistance){
if (node.data.resistance) {
prop.resistance = node.data.resistance;
prop.resistances = node.data.resistances;
}
if (node.data.vulnerability){
if (node.data.vulnerability) {
prop.vulnerability = node.data.vulnerability;
prop.vulnerabilities = node.data.vulnerabilities;
}
if (prop.type === 'attribute'){
if (prop.type === 'attribute') {
computeVariableAsAttribute(computation, node, prop);
} else if (prop.type === 'skill'){
} else if (prop.type === 'skill') {
computeVariableAsSkill(computation, node, prop);
} else if (prop.type === 'constant'){
} else if (prop.type === 'constant') {
computeVariableAsConstant(computation, node, prop);
} else if (prop.type === 'class'){
} else if (prop.type === 'class') {
computeVariableAsClass(computation, node, prop);
} else if (prop.type === 'toggle'){
} else if (prop.type === 'toggle') {
computeVariableAsToggle(computation, node, prop);
}
}
function combineMultiplierAggregator(node){
function combineMultiplierAggregator(node) {
// get a reference to the aggregator
const aggregator = node.data.multiplierAggregator;
if (!aggregator) return;
// Combine
if (aggregator.immunities?.length){
if (aggregator.immunities?.length) {
node.data.immunity = true;
node.data.immunities = aggregator.immunities;
}
if (aggregator.resistances?.length){
if (aggregator.resistances?.length) {
node.data.resistance = true;
node.data.resistances = aggregator.resistances;
}
if (aggregator.vulnerabilities?.length){
if (aggregator.vulnerabilities?.length) {
node.data.vulnerability = true;
node.data.vulnerabilities = aggregator.vulnerabilities;
}

View File

@@ -0,0 +1,22 @@
export default function aggregateEventDefinition({ node, linkedNode, link }) {
// Look at all event definition links
if (link.data !== 'eventDefinition') return;
// Store which property is THE defining event and which are overridden
const prop = linkedNode.data;
// get current defining event
const definingEvent = node.data.definingEvent;
// Find the last defining event
if (
!definingEvent ||
prop.order > definingEvent.order
) {
// override the current defining prop
if (definingEvent) definingEvent.overridden = true;
// set this prop as the new defining prop
node.data.definingEvent = prop;
} else {
prop.overridden = true;
}
}

View File

@@ -1,6 +1,7 @@
import definition from './aggregateDefinition.js';
import damageMultiplier from './aggregateDamageMultiplier.js';
import effect from './aggregateEffect.js';
import eventDefinition from './aggregateEventDefinition.js';
import proficiency from './aggregateProficiency.js';
import classLevel from './aggregateClassLevel.js';
import inventory from './aggregateInventory.js';
@@ -10,6 +11,7 @@ export default Object.freeze({
damageMultiplier,
definition,
effect,
eventDefinition,
inventory,
proficiency,
});

View File

@@ -162,6 +162,12 @@ const ComputedOnlyActionSchema = createPropertySchema({
optional: true,
removeBeforeCompute: true,
},
// Denormalised tag if event is overridden by one with the same variable name
overridden: {
type: Boolean,
optional: true,
removeBeforeCompute: true,
},
// Resources
resources: {
type: Object,

View File

@@ -461,7 +461,7 @@ const propertyHandlers = {
return { propPath: 'toggle' };
},
action(prop) {
if (prop.actionType === 'event') {
if (prop.actionType === 'event' && !prop.overridden) {
return { propPath: 'event' };
}
return { propPath: null };