From bc6c857b6bb97415cf44713047a57cab1dc10a3d Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Sun, 17 Oct 2021 23:28:39 +0200 Subject: [PATCH] UI work to improve look and feel of Viewers --- .../computeComputation/computeByType.js | 2 + .../computeByType/computeSkill.js | 28 ++ .../tests/computeAttribute.testFn.js | 12 + app/imports/api/properties/Skills.js | 1 + app/imports/parser/parseTree/unaryOperator.js | 2 +- .../CreaturePropertiesTree.vue | 4 +- .../CreaturePropertyDialog.vue | 35 ++- .../components/actions/ActionCard.vue | 8 +- .../components/attributes/AttributeCard.vue | 14 +- .../ui/properties/viewers/AttributeViewer.vue | 244 ++++++++++++------ .../ui/properties/viewers/SkillViewer.vue | 187 ++++++++------ .../viewers/shared/PropertyDescription.vue | 17 +- .../viewers/shared/PropertyField.vue | 62 ++++- 13 files changed, 420 insertions(+), 196 deletions(-) create mode 100644 app/imports/api/engine/computation/computeComputation/computeByType/computeSkill.js 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.

- +
+ + mdi-plus + Property + +
@@ -84,14 +84,14 @@ import numberToSignedString from '/imports/ui/utility/numberToSignedString.js'; import doAction from '/imports/api/engine/actions/doAction.js'; import AttributeConsumedView from '/imports/ui/properties/components/actions/AttributeConsumedView.vue'; import ItemConsumedView from '/imports/ui/properties/components/actions/ItemConsumedView.vue'; -import PropertyDescription from '/imports/ui/properties/viewers/shared/PropertyDescription.vue'; import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue'; +import MarkdownText from '/imports/ui/components/MarkdownText.vue'; export default { components: { AttributeConsumedView, ItemConsumedView, - PropertyDescription, + MarkdownText, PropertyIcon, }, inject: { diff --git a/app/imports/ui/properties/components/attributes/AttributeCard.vue b/app/imports/ui/properties/components/attributes/AttributeCard.vue index bb4d871a..597b0521 100644 --- a/app/imports/ui/properties/components/attributes/AttributeCard.vue +++ b/app/imports/ui/properties/components/attributes/AttributeCard.vue @@ -4,10 +4,10 @@ @click="click" >
- + {{ computedValue }} - + {{ model.name }}
@@ -28,14 +28,10 @@ return this.$listeners && !!this.$listeners.click }, computedValue(){ - if (this.model.type === 'attribute'){ - if (this.model.attributeType === 'modifier'){ - return numberToSignedString(this.model.value); - } else { - return this.model.value - } + if (this.model.attributeType === 'modifier' || this.model.type === 'skill'){ + return numberToSignedString(this.model.value); } else { - return this.model.value; + return this.model.value } } }, diff --git a/app/imports/ui/properties/viewers/AttributeViewer.vue b/app/imports/ui/properties/viewers/AttributeViewer.vue index 19f27c71..c90be210 100644 --- a/app/imports/ui/properties/viewers/AttributeViewer.vue +++ b/app/imports/ui/properties/viewers/AttributeViewer.vue @@ -1,10 +1,16 @@ diff --git a/app/imports/ui/properties/viewers/SkillViewer.vue b/app/imports/ui/properties/viewers/SkillViewer.vue index 8f78a69b..91c3d47e 100644 --- a/app/imports/ui/properties/viewers/SkillViewer.vue +++ b/app/imports/ui/properties/viewers/SkillViewer.vue @@ -1,84 +1,114 @@ @@ -100,6 +130,15 @@ export default { inject: { context: { default: {} } }, + data(){return { + proficiencyText: { + 0: 'Not proficient', + 1: 'Proficient', + 0.49: 'Half proficiency bonus rounded down', + 0.5: 'Half proficiency bonus rounded up', + 2: 'Double proficiency bonus', + }, + }}, computed: { displayedModifier(){ let mod = this.model.value; @@ -139,23 +178,23 @@ export default { name: 'Skill base value', operation: 'base', calculation: prop.baseValueCalculation, - result: prop.baseValue, + amount: {value: prop.baseValue?.value}, stats: [prop.variableName], ancestors: prop.ancestors, - }) ).filter(effect => effect.result); + }) ).filter(effect => effect.amount?.value); } else { return []; } }, effects(){ - if (this.context.creatureId){ + if (this.context.creatureId && this.model.variableName){ let creatureId = this.context.creatureId; return CreatureProperties.find({ 'ancestors.id': creatureId, stats: this.model.variableName, type: 'effect', removed: {$ne: true}, - }); + }).fetch(); } else { return []; } @@ -189,7 +228,7 @@ export default { type: 'proficiency', removed: {$ne: true}, inactive: {$ne: true}, - }); + }).fetch(); } else { return []; } @@ -211,7 +250,7 @@ export default { _id: abilityProp._id, name: abilityProp.name, operation: 'base', - result: abilityProp.modifier, + amount: {value: abilityProp.modifier}, stats: [this.model.variableName], ancestors: abilityProp.ancestors, } diff --git a/app/imports/ui/properties/viewers/shared/PropertyDescription.vue b/app/imports/ui/properties/viewers/shared/PropertyDescription.vue index 7ea9f5f2..f1a87521 100644 --- a/app/imports/ui/properties/viewers/shared/PropertyDescription.vue +++ b/app/imports/ui/properties/viewers/shared/PropertyDescription.vue @@ -1,21 +1,32 @@