diff --git a/app/imports/api/engine/computation/computeComputation/computeByType.js b/app/imports/api/engine/computation/computeComputation/computeByType.js index 45ce9316..e9b7aa23 100644 --- a/app/imports/api/engine/computation/computeComputation/computeByType.js +++ b/app/imports/api/engine/computation/computeComputation/computeByType.js @@ -1,6 +1,7 @@ import _variable from './computeByType/computeVariable.js'; import action from './computeByType/computeAction.js'; import attribute from './computeByType/computeAttribute.js'; +import skill from './computeByType/computeSkill.js'; import slot from './computeByType/computeSlot.js'; import container from './computeByType/computeContainer.js'; @@ -9,6 +10,7 @@ export default Object.freeze({ action, attribute, container, + skill, slot, spell: action, }); diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeSkill.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeSkill.js new file mode 100644 index 00000000..2e79d18a --- /dev/null +++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeSkill.js @@ -0,0 +1,28 @@ +// If we compute this skill without a variable name, it just +// uses its base value, proficiency, and damage since no effects can target it +// If this skill does have a variable name, it is recomputed later +// by computeVariableAsSkill +export default function computeSkill(computation, node){ + const prop = node.data; + prop.proficiency = prop.baseProficiency; + let profBonus = computation.scope['proficiencyBonus']?.value || 0; + // Multiply the proficiency bonus by the actual proficiency + if(prop.proficiency === 0.49){ + // Round down proficiency bonus in the special case + profBonus = Math.floor(profBonus * 0.5); + } else { + profBonus = Math.ceil(profBonus * prop.proficiency); + } + + const ability = computation.scope[prop.ability]; + prop.abilityMod = ability?.modifier || 0; + + const base = prop.baseValue?.value || 0; + + let result = base + prop.abilityMod + profBonus; + if (Number.isFinite(result)){ + result = Math.floor(result); + } + + prop.value = result; +} diff --git a/app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js b/app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js index 25f298bb..49794a02 100644 --- a/app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js +++ b/app/imports/api/engine/computation/computeComputation/tests/computeAttribute.testFn.js @@ -15,6 +15,7 @@ export default function(){ assert.equal(scope('strength').modifier, 1); assert.equal(prop('referencesDexId').value, 4); assert.equal(prop('hitDiceId').constitutionMod, 5); + assert.equal(prop('overriddenDexId').overridden, true, 'override properties with the same variable name'); assert.equal( prop('parseErrorId').baseValue.value, null, 'Parse errors should null the value' @@ -44,11 +45,22 @@ var testProperties = [ calculation: '12' }, }), + clean({ + _id: 'overriddenDexId', + variableName: 'dexterity', + type: 'attribute', + attributeType: 'ability', + order: 1, + baseValue: { + calculation: '15' + }, + }), clean({ _id: 'dexterityId', variableName: 'dexterity', type: 'attribute', attributeType: 'ability', + order: 2, baseValue: { calculation: '15' }, diff --git a/app/imports/api/properties/Skills.js b/app/imports/api/properties/Skills.js index 82a4b165..281fe985 100644 --- a/app/imports/api/properties/Skills.js +++ b/app/imports/api/properties/Skills.js @@ -20,6 +20,7 @@ let SkillSchema = createPropertySchema({ regEx: VARIABLE_NAME_REGEX, min: 2, max: STORAGE_LIMITS.variableName, + optional: true, }, // The variable name of the ability this skill relies on ability: { diff --git a/app/imports/parser/parseTree/unaryOperator.js b/app/imports/parser/parseTree/unaryOperator.js index c8aaebe1..20065794 100644 --- a/app/imports/parser/parseTree/unaryOperator.js +++ b/app/imports/parser/parseTree/unaryOperator.js @@ -11,7 +11,7 @@ const unaryOperator = { }, resolve(fn, node, scope, context){ const {result: rightNode} = resolve(fn, node.right, scope, context); - if (rightNode.parseType !== 'number'){ + if (rightNode.valueType !== 'number'){ return { result: unaryOperator.create({ operator: node.operator, diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue index 79bce174..083e8ca1 100644 --- a/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue +++ b/app/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue @@ -39,13 +39,15 @@ }, meteor: { children(){ - return nodesToTree({ + const children = nodesToTree({ collection: CreatureProperties, ancestorId: this.root.id, filter: this.filter, includeFilteredDocAncestors: true, includeFilteredDocDescendants: true, }); + this.$emit('length', children.length); + return children; }, }, methods: { diff --git a/app/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue b/app/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue index 2bf244e3..93692c6b 100644 --- a/app/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue +++ b/app/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue @@ -41,28 +41,34 @@ This property can't be viewed yet.
- -