Added and fixed some tests for tag targeted effects

This commit is contained in:
ThaumRystra
2023-11-11 13:31:15 +02:00
parent 6af9246ad1
commit 3b1f61aa0a
6 changed files with 132 additions and 20 deletions

View File

@@ -55,7 +55,7 @@ function parseAllCalculationFields(prop, schemas) {
// For each computed key in the schema
schemas[prop.type]?.computedFields?.()?.forEach(calcKey => {
// Determine the level the calculation should compute down to
let parseLevel = schemas[prop.type].getDefinition(calcKey).parseLevel || 'reduce';
let parseLevel = schemas[prop.type].getDefinition(calcKey).parseLevel || 'compile';
// Special case of effects, when targeting by tags compile
if (prop.type === 'effect' && prop.targetByTags) parseLevel = 'compile';

View File

@@ -9,16 +9,18 @@ export default function computeCalculation(computation, node) {
if (!calcObj) return;
// resolve the parse node into the initial value
resolveCalculationNode(calcObj, calcObj.parseNode, computation.scope);
// Store the unaffected value
if (calcObj.effectIds || calcObj.proficiencyIds) {
calcObj.unaffected = toPrimitiveOrString(calcObj.valueNode);
}
// link and aggregate the effects and proficiencies
linkCalculationEffects(node, computation);
aggregateCalculationEffects(calcObj, id => computation.propsById[id]);
linkCalculationProficiencies(node, computation)
aggregateCalculationProficiencies(calcObj, id => computation.propsById[id], computation.scope['proficiencyBonus']?.value || 0);
// Store the unaffected value
if (calcObj.effectIds || calcObj.proficiencyIds) {
calcObj.unaffected = toPrimitiveOrString(calcObj.valueNode);
}
// Resolve the valueNode after effects and proficiencies have been applied to it
resolveCalculationNode(calcObj, calcObj.valueNode, computation.scope);
@@ -145,14 +147,14 @@ export function aggregateCalculationEffects(calcObj, getEffectFromId) {
if (aggregator.min) {
calcObj.valueNode = call.create({
functionName: 'max',
args: [calcObj.valueNode, aggregator.min]
args: [calcObj.valueNode, ...aggregator.min]
});
}
// Max
if (aggregator.max) {
calcObj.valueNode = call.create({
functionName: 'min',
args: [calcObj.valueNode, aggregator.max]
args: [calcObj.valueNode, ...aggregator.max]
});
}
}

View File

@@ -1,6 +1,6 @@
import stripFloatingPointOddities from '/imports/api/engine/computation/utility/stripFloatingPointOddities.js';
export default function getAggregatorResult(node){
export default function getAggregatorResult(node) {
// Work out the base value as the greater of the deining stat value
// This baseValue comes from aggregating definitions
let statBase = node.data.baseValue;
@@ -12,9 +12,9 @@ export default function getAggregatorResult(node){
if (!aggregator) return statBase;
let base;
if (!Number.isFinite(aggregator.base)){
if (!Number.isFinite(aggregator.base)) {
base = statBase || 0;
} else if (!Number.isFinite(statBase)){
} else if (!Number.isFinite(statBase)) {
base = aggregator.base || 0;
} else {
base = Math.max(aggregator.base, statBase);
@@ -29,9 +29,9 @@ export default function getAggregatorResult(node){
if (aggregator.set !== undefined) {
result = aggregator.set;
}
if (!node.data.definingProp?.decimal && Number.isFinite(result)){
if (!node.data.definingProp?.decimal && Number.isFinite(result)) {
result = Math.floor(result);
} else if (Number.isFinite(result)){
} else if (Number.isFinite(result)) {
result = stripFloatingPointOddities(result);
}

View File

@@ -0,0 +1,114 @@
import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation.js';
import { assert } from 'chai';
import computeCreatureComputation from '../../computeCreatureComputation.js';
import clean from '../../utility/cleanProp.testFn.js';
export default function () {
const computation = buildComputationFromProps(testProperties);
computeCreatureComputation(computation);
const prop = id => computation.propsById[id];
// Tags target effects on attributes
assert.equal(prop('taggedCon').value, 26, 'Tagged targeted effects affect attribute values');
assert.equal(prop('taggedCon').baseValue.value, 10, 'Tag targeted effects target the attribute itself, not the base value');
// Tag target effects on a calculation
assert.equal(prop('attackAction').attackRoll.value, 20, 'Tag targeted effects change the attack roll correctly');
// Tag target effects can deal with rolls
assert.equal(prop('attackAction').attackRoll.value, 20, 'Tag targeted effects change the attack roll correctly');
assert.equal(prop('attackAction2').attackRoll.value, 'min(3 + d4, d100)', 'Tag targeted effects change the attack roll correctly');
}
var testProperties = [
// Constitution plus some effects that target it by tag
clean({
_id: 'taggedCon',
variableName: 'constitution',
type: 'attribute',
attributeType: 'ability',
baseValue: {
calculation: '10'
},
tags: ['tag']
}),
clean({
_id: 'add3ToCon',
type: 'effect',
operation: 'add',
amount: {
calculation: '3'
},
targetByTags: true,
targetTags: ['tag'],
}),
clean({
_id: 'mulConBy2',
type: 'effect',
operation: 'mul',
amount: {
calculation: '2'
},
targetByTags: true,
targetTags: ['tag'],
}),
// Attack action plus some effects that target it by tag
clean({
_id: 'attackAction',
type: 'action',
ancestors: [{ id: 'charId' }],
attackRoll: {
calculation: '3'
},
tags: ['attackTag']
}),
clean({
_id: 'add1ToAttack',
type: 'effect',
operation: 'add',
amount: {
calculation: '1'
},
targetByTags: true,
targetTags: ['attackTag'],
}),
clean({
_id: 'mulAttackBy5',
type: 'effect',
operation: 'mul',
amount: {
calculation: '5'
},
targetByTags: true,
targetTags: ['attackTag'],
}),
// Attack action plus some effects that target it by tag but have rolled values
clean({
_id: 'attackAction2',
type: 'action',
ancestors: [{ id: 'charId' }],
attackRoll: {
calculation: '3'
},
tags: ['attackTag2']
}),
clean({
_id: 'addD4ToAttackRoll',
type: 'effect',
operation: 'add',
amount: {
calculation: 'd4'
},
targetByTags: true,
targetTags: ['attackTag2'],
}),
clean({
_id: 'MaxAttackByD100',
type: 'effect',
operation: 'max',
amount: {
calculation: 'd100'
},
targetByTags: true,
targetTags: ['attackTag2'],
}),
];

View File

@@ -1,5 +1,6 @@
import computeAction from './computeAction.testFn.js';
import computeAttribute from './computeAttribute.testFn.js';
import computeCalculations from './computeCalculations.testFn.js';
import computeClasses from './computeClasses.testFn.js';
import computeConstants from './computeConstants.testFn.js';
import computeInventory from './computeInventory.testFn.js';
@@ -14,6 +15,9 @@ export default [{
}, {
text: 'Computes attributes',
fn: computeAttribute,
}, {
text: 'Computes calculations',
fn: computeCalculations,
}, {
text: 'Computes classes',
fn: computeClasses,

View File

@@ -8,7 +8,6 @@
<smart-select
label="Operation"
append-icon="mdi-menu-down"
:disabled="model.targetByTags"
:hint="operationHint"
:error-messages="errors.operation"
:menu-props="{transition: 'slide-y-transition', lazy: true}"
@@ -213,15 +212,8 @@ export default {
changeTargetByTags(value, ack) {
if (value === 'stats') {
this.$emit('change', { path: ['targetByTags'], value: undefined, ack });
if (this.oldOperation && this.oldOperation !== this.model.operation) {
this.$emit('change', { path: ['operation'], value: this.oldOperation });
}
} else if (value === 'tags') {
this.$emit('change', { path: ['targetByTags'], value: true, ack });
if (this.model.operation !== 'add') {
this.oldOperation = this.model.operation;
this.$emit('change', { path: ['operation'], value: 'add' });
}
}
},
}