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
-
-
+
+
+ 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 @@
-
-
+
+
@@ -17,93 +23,171 @@
{{ model.value }}
-
+
- $vuetify.icons.abacus
+
+ $vuetify.icons.abacus
+
-
-
+
- {{ numberToSignedString(model.modifier) }}
-
-
-
-
-
-
-
-
+ {{ numberToSignedString(model.modifier) }}
+
+
+
-
-
+
+
+
+
+
+ {{ proficiencyIcon }}
+
+
+ {{ proficiencyText[model.proficiency] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
-
-
+
-
+
{{ icon }}
-
- {{ numberToSignedString(model.value) }}
+
+ {{ proficiencyText[model.proficiency] }}
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -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 @@
-
+ :name="label"
+ :cols="{col: 12}"
+ >
+
+