From 7c648f67a38b9d0eb0b48b917dbfb1c2d3999df4 Mon Sep 17 00:00:00 2001 From: ThaumRystra Date: Sat, 9 Nov 2024 15:24:56 +0200 Subject: [PATCH] Fixed tag targeted effects on overridden attributes applying multiple times Closes #358 --- .vscode/settings.json | 1 + .../buildComputation/linkTypeDependencies.js | 5 +- .../computeTagTargetedEffects.test.js | 88 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 app/imports/api/engine/computation/computeTagTargetedEffects.test.js diff --git a/.vscode/settings.json b/.vscode/settings.json index c7852e1f..6de9fd00 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,6 +16,7 @@ "healthbars", "jank", "meteortesting", + "multigraph", "nearley", "ngraph", "ostrio", diff --git a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js index f1cbd104..ad038cb6 100644 --- a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js +++ b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js @@ -156,7 +156,10 @@ function linkEffects(dependencyGraph, prop, computation) { ) { // If the field wasn't specified and we're targeting an attribute or // skill, just treat it like a normal effect on its variable name - dependencyGraph.addLink(targetProp.variableName, prop._id, 'effect'); + // But ensure only a single link is created + if (!dependencyGraph.hasLink(targetProp.variableName, prop._id)) { + dependencyGraph.addLink(targetProp.variableName, prop._id, 'effect'); + } } else { // Otherwise target a field on that property const key = prop.targetField || getDefaultCalculationField(targetProp); diff --git a/app/imports/api/engine/computation/computeTagTargetedEffects.test.js b/app/imports/api/engine/computation/computeTagTargetedEffects.test.js new file mode 100644 index 00000000..c4989b2a --- /dev/null +++ b/app/imports/api/engine/computation/computeTagTargetedEffects.test.js @@ -0,0 +1,88 @@ +import { assert } from 'chai'; +import { + createTestCreature, + getRandomIds, + removeAllCreaturesAndProps, +} from '/imports/api/engine/action/functions/actionEngineTest.testFn'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; + +describe('Apply Action Properties', function () { + // Increase timeout + this.timeout(8000); + + beforeEach(async function () { + await removeAllCreaturesAndProps(); + }); + + it('Should apply a single tag targeted effect', async function () { + const [ + creatureId, singleEffectAttId, tag1Effect + ] = getRandomIds(100); + + const testCreature = { + _id: creatureId, + props: [ + { + _id: singleEffectAttId, + type: 'attribute', + attributeType: 'ability', + variableName: 'strength', + baseValue: { calculation: '10' }, + tags: ['tag1'], + }, + { + _id: tag1Effect, + type: 'effect', + targetByTags: true, + targetTags: ['tag1'], + operation: 'add', + amount: { calculation: '2' }, + }, + ], + }; + await createTestCreature(testCreature); + + const singleEffectAtt = await CreatureProperties.findOneAsync(singleEffectAttId); + assert.equal(singleEffectAtt.value, 12, 'The attribute should have the correct value after the effect is applied'); + }); + + it('Should apply a multiple tag targeted effects, ignoring overridden attributes', async function () { + const [ + creatureId, multipleEffectsAttId, tag1Effect, overriddenAttId + ] = getRandomIds(100); + + const testCreature = { + _id: creatureId, + props: [ + { + _id: overriddenAttId, + type: 'attribute', + attributeType: 'ability', + variableName: 'strength', + baseValue: { calculation: '13' }, + tags: ['tag2'], + }, + { + _id: multipleEffectsAttId, + type: 'attribute', + attributeType: 'ability', + variableName: 'strength', + baseValue: { calculation: '11' }, + tags: ['tag2'], + }, + { + _id: tag1Effect, + type: 'effect', + targetByTags: true, + targetTags: ['tag2'], + operation: 'mul', + amount: { calculation: '2' }, + }, + ], + }; + await createTestCreature(testCreature); + + const singleEffectAtt = await CreatureProperties.findOneAsync(multipleEffectsAttId); + assert.equal(singleEffectAtt.value, 26, 'The attribute should have the correct value after the effect is applied'); + }); +});