Added proficiency target by tag to backend

This commit is contained in:
Stefan Zermatten
2023-03-17 17:45:05 +02:00
parent 2b7851ab32
commit 50cb6185ce
3 changed files with 127 additions and 9 deletions

View File

@@ -268,14 +268,36 @@ 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) {
dependOnCalc({ dependencyGraph, prop, key: 'dc' });

View File

@@ -4,9 +4,10 @@ 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(
@@ -46,3 +47,48 @@ export function aggregateCalculationEffects(node, computation){
});
}
}
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;
}
}

View File

@@ -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({});