Added proficiency target by tag to backend
This commit is contained in:
@@ -268,13 +268,35 @@ function linkPointBuy(dependencyGraph, prop) {
|
||||
if (prop.inactive) return;
|
||||
}
|
||||
|
||||
function linkProficiencies(dependencyGraph, prop) {
|
||||
function linkProficiencies(dependencyGraph, prop, computation) {
|
||||
// The stats depend on the proficiency
|
||||
if (prop.inactive) return;
|
||||
if (prop.targetByTags) {
|
||||
getEffectTagTargets(prop, computation).forEach(targetId => {
|
||||
const targetProp = computation.propsById[targetId];
|
||||
if (
|
||||
(targetProp.type === 'attribute' || targetProp.type === 'skill')
|
||||
&& targetProp.variableName
|
||||
&& !prop.targetField
|
||||
) {
|
||||
// If the field wasn't specified and we're targeting an attribute or
|
||||
// skill, just treat it like a normal proficiency on its variable name
|
||||
dependencyGraph.addLink(targetProp.variableName, prop._id, 'proficiency');
|
||||
} else {
|
||||
// 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, 'proficiency');
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
prop.stats.forEach(statName => {
|
||||
if (!statName) return;
|
||||
dependencyGraph.addLink(statName, prop._id, prop.type);
|
||||
dependencyGraph.addLink(statName, prop._id, 'proficiency');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function linkSavingThrow(dependencyGraph, prop) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import evaluateCalculation from '../../utility/evaluateCalculation.js';
|
||||
|
||||
export default function computeCalculation(computation, node){
|
||||
export default function computeCalculation(computation, node) {
|
||||
const calcObj = node.data;
|
||||
evaluateCalculation(calcObj, computation.scope);
|
||||
aggregateCalculationEffects(node, computation);
|
||||
aggregateCalculationProficiencies(node, computation);
|
||||
}
|
||||
|
||||
export function aggregateCalculationEffects(node, computation){
|
||||
function aggregateCalculationEffects(node, computation) {
|
||||
const calcObj = node.data;
|
||||
delete calcObj.effects;
|
||||
computation.dependencyGraph.forEachLinkedNode(
|
||||
@@ -34,15 +35,60 @@ export function aggregateCalculationEffects(node, computation){
|
||||
},
|
||||
true // enumerate only outbound links
|
||||
);
|
||||
if (calcObj.effects && typeof calcObj.value === 'number'){
|
||||
if (calcObj.effects && typeof calcObj.value === 'number') {
|
||||
calcObj.baseValue = calcObj.value;
|
||||
calcObj.effects.forEach(effect => {
|
||||
if (
|
||||
effect.operation === 'add' &&
|
||||
effect.amount && typeof effect.amount.value === 'number'
|
||||
){
|
||||
) {
|
||||
calcObj.value += effect.amount.value
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function aggregateCalculationProficiencies(node, computation) {
|
||||
const calcObj = node.data;
|
||||
delete calcObj.proficiencies;
|
||||
delete calcObj.proficiency;
|
||||
computation.dependencyGraph.forEachLinkedNode(
|
||||
node.id,
|
||||
(linkedNode, link) => {
|
||||
// Only proficiency links
|
||||
if (link.data !== 'proficiency') return;
|
||||
// That have data
|
||||
if (!linkedNode.data) return;
|
||||
// Ignore inactive props
|
||||
if (linkedNode.data.inactive) return;
|
||||
|
||||
// Collate effects
|
||||
calcObj.proficiencies = calcObj.proficiencies || [];
|
||||
calcObj.proficiencies.push({
|
||||
_id: linkedNode.data._id,
|
||||
name: linkedNode.data.name,
|
||||
value: linkedNode.data.value,
|
||||
});
|
||||
},
|
||||
true // enumerate only outbound links
|
||||
);
|
||||
if (calcObj.proficiencies) {
|
||||
calcObj.proficiency = 0;
|
||||
calcObj.proficiencies.forEach(prof => {
|
||||
if (prof.value > calcObj.proficiency) {
|
||||
calcObj.proficiency = prof.value;
|
||||
}
|
||||
});
|
||||
// Get the character's proficiency bonus to apply
|
||||
let profBonus = computation.scope['proficiencyBonus']?.value || 0;
|
||||
|
||||
// Multiply the proficiency bonus by the actual proficiency
|
||||
if (calcObj.proficiency === 0.49) {
|
||||
// Round down proficiency bonus in the special case
|
||||
calcObj.proficiencyBonus = Math.floor(profBonus * 0.5);
|
||||
} else {
|
||||
calcObj.proficiencyBonus = Math.ceil(profBonus * calcObj.proficiency);
|
||||
}
|
||||
calcObj.value += calcObj.proficiencyBonus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,56 @@ let ProficiencySchema = new SimpleSchema({
|
||||
allowedValues: [0.49, 0.5, 1, 2],
|
||||
defaultValue: 1,
|
||||
},
|
||||
// True when targeting by tags instead of stats
|
||||
targetByTags: {
|
||||
type: Boolean,
|
||||
optional: true,
|
||||
},
|
||||
// If targeting by tags, the field which will be targeted
|
||||
targetField: {
|
||||
type: String,
|
||||
optional: true,
|
||||
max: STORAGE_LIMITS.variableName,
|
||||
},
|
||||
// Which tags the effect is applied to
|
||||
targetTags: {
|
||||
type: Array,
|
||||
optional: true,
|
||||
maxCount: STORAGE_LIMITS.tagCount,
|
||||
},
|
||||
'targetTags.$': {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.tagLength,
|
||||
},
|
||||
extraTags: {
|
||||
type: Array,
|
||||
optional: true,
|
||||
maxCount: STORAGE_LIMITS.extraTagsCount,
|
||||
},
|
||||
'extraTags.$': {
|
||||
type: Object,
|
||||
},
|
||||
'extraTags.$._id': {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
autoValue() {
|
||||
if (!this.isSet) return Random.id();
|
||||
}
|
||||
},
|
||||
'extraTags.$.operation': {
|
||||
type: String,
|
||||
allowedValues: ['OR', 'NOT'],
|
||||
defaultValue: 'OR',
|
||||
},
|
||||
'extraTags.$.tags': {
|
||||
type: Array,
|
||||
defaultValue: [],
|
||||
maxCount: STORAGE_LIMITS.tagCount,
|
||||
},
|
||||
'extraTags.$.tags.$': {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.tagLength,
|
||||
},
|
||||
});
|
||||
|
||||
const ComputedOnlyProficiencySchema = new SimpleSchema({});
|
||||
|
||||
Reference in New Issue
Block a user