From e3a1eff751816267858bbff97347afabcb024be0 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Thu, 21 Oct 2021 22:18:01 +0200 Subject: [PATCH] Progress all over the place with viewer, forms, small engine tweaks --- .../creatureProperties/methods/flipToggle.js | 48 ++++++++ .../creatureProperties/methods/index.js | 1 + .../buildComputation/computeInactiveStatus.js | 11 +- .../buildComputation/linkTypeDependencies.js | 1 + .../computeByType/computeVariable.js | 11 +- .../computeVariableAsToggle.js | 7 ++ .../computation/computeCreatureComputation.js | 1 + app/imports/api/properties/SavingThrows.js | 2 +- .../character/characterSheetTabs/StatsTab.vue | 27 ++++- .../components/toggles/ToggleCard.vue | 69 ++++++++++++ .../ui/properties/forms/DamageForm.vue | 10 +- .../ui/properties/forms/ReferenceForm.vue | 17 ++- app/imports/ui/properties/forms/RollForm.vue | 44 +++++--- .../ui/properties/forms/SavingThrowForm.vue | 105 ++++++++++-------- .../ui/properties/forms/SlotFillerForm.vue | 5 +- .../ui/properties/forms/ToggleForm.vue | 85 +++++++++----- .../ui/properties/viewers/ActionViewer.vue | 2 + .../ui/properties/viewers/NoteViewer.vue | 22 ++-- .../properties/viewers/ProficiencyViewer.vue | 31 ++++-- .../ui/properties/viewers/ReferenceViewer.vue | 36 +++--- .../ui/properties/viewers/RollViewer.vue | 26 +++-- .../properties/viewers/SavingThrowViewer.vue | 29 +++-- .../properties/viewers/SlotFillerViewer.vue | 68 +++++++----- .../ui/properties/viewers/SlotViewer.vue | 2 +- .../ui/properties/viewers/SpellListViewer.vue | 50 +++++---- .../ui/properties/viewers/SpellViewer.vue | 36 +++--- .../ui/properties/viewers/ToggleViewer.vue | 31 +++--- .../viewers/shared/PropertyField.vue | 35 +++++- 28 files changed, 554 insertions(+), 258 deletions(-) create mode 100644 app/imports/api/creature/creatureProperties/methods/flipToggle.js create mode 100644 app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/computeVariableAsToggle.js create mode 100644 app/imports/ui/properties/components/toggles/ToggleCard.vue diff --git a/app/imports/api/creature/creatureProperties/methods/flipToggle.js b/app/imports/api/creature/creatureProperties/methods/flipToggle.js new file mode 100644 index 00000000..e39d0c75 --- /dev/null +++ b/app/imports/api/creature/creatureProperties/methods/flipToggle.js @@ -0,0 +1,48 @@ +import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; +import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor.js'; +import computeCreature from '/imports/api/engine/computeCreature.js'; + +const flipToggle = new ValidatedMethod({ + name: 'creatureProperties.flipToggle', + validate({_id}){ + if (!_id) throw new Meteor.Error('No _id', '_id is required'); + }, + mixins: [RateLimiterMixin], + rateLimit: { + numRequests: 5, + timeInterval: 5000, + }, + run({_id}) { + // Permission + let property = CreatureProperties.findOne(_id, { + fields: {type: 1, ancestors: 1, enabled: 1, disabled: 1} + }); + if (property.type !== 'toggle'){ + throw new Meteor.Error('wrong property', + 'This method can only be applied to toggles'); + } + if (!property.enabled && !property.disabled){ + throw new Meteor.Error('Computed toggle', + 'Can\'t flip a toggle that is computed') + } + let rootCreature = getRootCreatureAncestor(property); + assertEditPermission(rootCreature, this.userId); + + // Invert the current value, disabled is the canonical store of value + const currentValue = !property.disabled; + CreatureProperties.update(_id, {$set: { + enabled: !currentValue, + disabled: currentValue, + }}, { + selector: {type: 'toggle'}, + }); + + // Updating a toggle is likely to change the whole tree, do a full recompute + computeCreature(rootCreature._id); + }, +}); + +export default flipToggle; diff --git a/app/imports/api/creature/creatureProperties/methods/index.js b/app/imports/api/creature/creatureProperties/methods/index.js index 72fe3da3..45a0e323 100644 --- a/app/imports/api/creature/creatureProperties/methods/index.js +++ b/app/imports/api/creature/creatureProperties/methods/index.js @@ -12,3 +12,4 @@ import '/imports/api/creature/creatureProperties/methods/restoreProperty.js'; import '/imports/api/creature/creatureProperties/methods/selectAmmoItem.js'; import '/imports/api/creature/creatureProperties/methods/softRemoveProperty.js'; import '/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js'; +import '/imports/api/creature/creatureProperties/methods/flipToggle.js'; diff --git a/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js b/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js index 2eb41428..b289e1c6 100644 --- a/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js +++ b/app/imports/api/engine/computation/buildComputation/computeInactiveStatus.js @@ -3,9 +3,14 @@ import walkDown from '/imports/api/engine/computation/utility/walkdown.js'; export default function computeInactiveStatus(node){ const prop = node.node; if (isActive(prop)) return; - // Unequipped items, notes, and actions disable their children, + // Unequipped items, notes, spells, and actions disable their children, // but are not disabled themselves - if (prop.type !== 'item' && prop.type !== 'note' && prop.type !== 'action' ){ + if ( + prop.type !== 'item' && + prop.type !== 'note' && + prop.type !== 'action' && + prop.type !== 'spell' + ){ prop.inactive = true; prop.deactivatedBySelf = true; } @@ -20,7 +25,7 @@ function isActive(prop){ if (prop.disabled) return false; switch (prop.type){ case 'item': return !!prop.equipped; - case 'spell': return !!prop.prepared || !!prop.alwaysPrepared; + case 'spell': return false; case 'note': return false; case 'action': return false; default: return true; diff --git a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js index d6e30222..af007302 100644 --- a/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js +++ b/app/imports/api/engine/computation/buildComputation/linkTypeDependencies.js @@ -9,6 +9,7 @@ const linkDependenciesByType = { effect: linkStats, skill: linkSkill, spell: linkResources, + toggle: linkVariableName, } export default function linkTypeDependencies(dependencyGraph, prop, computation){ diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable.js index ee9685db..0f9bdab1 100644 --- a/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable.js +++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable.js @@ -3,6 +3,7 @@ import computeVariableAsAttribute from './computeVariable/computeVariableAsAttri import computeVariableAsSkill from './computeVariable/computeVariableAsSkill.js'; import computeVariableAsConstant from './computeVariable/computeVariableAsConstant.js'; import computeVariableAsClass from './computeVariable/computeVariableAsClass.js'; +import computeVariableAsToggle from './computeVariable/computeVariableAsToggle.js'; import computeImplicitVariable from './computeVariable/computeImplicitVariable.js'; export default function computeVariable(computation, node){ @@ -50,13 +51,15 @@ function combineAggregations(computation, node){ function computeVariableProp(computation, node, prop){ if (!prop) return; if (prop.type === 'attribute'){ - computeVariableAsAttribute(computation, node, prop) + computeVariableAsAttribute(computation, node, prop); } else if (prop.type === 'skill'){ - computeVariableAsSkill(computation, node, prop) + computeVariableAsSkill(computation, node, prop); } else if (prop.type === 'constant'){ - computeVariableAsConstant(computation, node, prop) + computeVariableAsConstant(computation, node, prop); } else if (prop.type === 'class'){ - computeVariableAsClass(computation, node, prop) + computeVariableAsClass(computation, node, prop); + } else if (prop.type === 'toggle'){ + computeVariableAsToggle(computation, node, prop); } } diff --git a/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/computeVariableAsToggle.js b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/computeVariableAsToggle.js new file mode 100644 index 00000000..0c3c41a9 --- /dev/null +++ b/app/imports/api/engine/computation/computeComputation/computeByType/computeVariable/computeVariableAsToggle.js @@ -0,0 +1,7 @@ +import getAggregatorResult from './getAggregatorResult.js'; + +export default function computeVariableAsToggle(computation, node, prop){ + let result = getAggregatorResult(node, prop) || 0; + + prop.value = !!result || !!prop.enabled || !!prop.condition?.value; +} diff --git a/app/imports/api/engine/computation/computeCreatureComputation.js b/app/imports/api/engine/computation/computeCreatureComputation.js index 2c542c92..d91c8dfc 100644 --- a/app/imports/api/engine/computation/computeCreatureComputation.js +++ b/app/imports/api/engine/computation/computeCreatureComputation.js @@ -36,6 +36,7 @@ function compute(computation, node){ // Determine the prop's active status by its toggles computeToggles(computation, node); computeCalculations(computation, node); + if (node.data) delete node.data._computationDetails; // Compute the property by type computeByType[node.data?.type || '_variable']?.(computation, node); } diff --git a/app/imports/api/properties/SavingThrows.js b/app/imports/api/properties/SavingThrows.js index 70fc8485..f5cfbf70 100644 --- a/app/imports/api/properties/SavingThrows.js +++ b/app/imports/api/properties/SavingThrows.js @@ -18,7 +18,7 @@ let SavingThrowSchema = createPropertySchema({ // Who this saving throw applies to target: { type: String, - defaultValue: 'every', + defaultValue: 'target', allowedValues: [ 'self', 'target', diff --git a/app/imports/ui/creature/character/characterSheetTabs/StatsTab.vue b/app/imports/ui/creature/character/characterSheetTabs/StatsTab.vue index e36938e8..e9fa76f6 100644 --- a/app/imports/ui/creature/character/characterSheetTabs/StatsTab.vue +++ b/app/imports/ui/creature/character/characterSheetTabs/StatsTab.vue @@ -75,6 +75,18 @@ +
+ +
+
+ +
+
+ +
+ + {{ model.name }} + +
+
+ + + + + diff --git a/app/imports/ui/properties/forms/DamageForm.vue b/app/imports/ui/properties/forms/DamageForm.vue index 3b3e7c96..b56a913d 100644 --- a/app/imports/ui/properties/forms/DamageForm.vue +++ b/app/imports/ui/properties/forms/DamageForm.vue @@ -19,7 +19,7 @@ cols="12" md="6" > - import DAMAGE_TYPES from '/imports/constants/DAMAGE_TYPES.js'; import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js'; -import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue'; export default { - components: { - CalculationErrorList, - }, mixins: [propertyFormMixin], props: { parentTarget: { @@ -90,10 +86,6 @@ export default { self: 'The damage will be applied to the character taking the action', target: 'The damage will be applied to the target of the action', }; - if (this.parentTarget === 'singleTarget'){ - hints.each = hints.target; - hints.every = hints.target; - } return hints[this.model.target]; } }, diff --git a/app/imports/ui/properties/forms/ReferenceForm.vue b/app/imports/ui/properties/forms/ReferenceForm.vue index 95608437..8c580322 100644 --- a/app/imports/ui/properties/forms/ReferenceForm.vue +++ b/app/imports/ui/properties/forms/ReferenceForm.vue @@ -1,9 +1,14 @@ @@ -33,10 +36,12 @@ import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue'; import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js'; import updateReferenceNode from '/imports/api/library/methods/updateReferenceNode.js'; + import PropertyField from '/imports/ui/properties/viewers/shared/PropertyField.vue'; export default { components: { TreeNodeView, + PropertyField, }, mixins: [propertyFormMixin], data(){return { diff --git a/app/imports/ui/properties/forms/RollForm.vue b/app/imports/ui/properties/forms/RollForm.vue index 27530a93..c0ef80df 100644 --- a/app/imports/ui/properties/forms/RollForm.vue +++ b/app/imports/ui/properties/forms/RollForm.vue @@ -1,23 +1,33 @@ diff --git a/app/imports/ui/properties/viewers/ProficiencyViewer.vue b/app/imports/ui/properties/viewers/ProficiencyViewer.vue index a7c44e1b..0ee43e14 100644 --- a/app/imports/ui/properties/viewers/ProficiencyViewer.vue +++ b/app/imports/ui/properties/viewers/ProficiencyViewer.vue @@ -1,17 +1,25 @@ @@ -27,6 +35,7 @@ export default { computed: { proficiencyText(){ switch (this.model.value){ + case 0.49: return 'Half proficiency bonus rounded down'; case 0.5: return 'Half proficiency bonus'; case 1: return 'Proficient'; case 2: return 'Double proficiency bonus'; diff --git a/app/imports/ui/properties/viewers/ReferenceViewer.vue b/app/imports/ui/properties/viewers/ReferenceViewer.vue index eb70e7a9..9b2c6419 100644 --- a/app/imports/ui/properties/viewers/ReferenceViewer.vue +++ b/app/imports/ui/properties/viewers/ReferenceViewer.vue @@ -1,21 +1,25 @@ diff --git a/app/imports/ui/properties/viewers/RollViewer.vue b/app/imports/ui/properties/viewers/RollViewer.vue index 0cd8e184..d00aeed1 100644 --- a/app/imports/ui/properties/viewers/RollViewer.vue +++ b/app/imports/ui/properties/viewers/RollViewer.vue @@ -1,23 +1,25 @@ diff --git a/app/imports/ui/properties/viewers/SavingThrowViewer.vue b/app/imports/ui/properties/viewers/SavingThrowViewer.vue index 8bd22491..02b4fbcb 100644 --- a/app/imports/ui/properties/viewers/SavingThrowViewer.vue +++ b/app/imports/ui/properties/viewers/SavingThrowViewer.vue @@ -1,14 +1,23 @@ diff --git a/app/imports/ui/properties/viewers/SlotFillerViewer.vue b/app/imports/ui/properties/viewers/SlotFillerViewer.vue index 1da985d0..0834ff2b 100644 --- a/app/imports/ui/properties/viewers/SlotFillerViewer.vue +++ b/app/imports/ui/properties/viewers/SlotFillerViewer.vue @@ -1,37 +1,55 @@ diff --git a/app/imports/ui/properties/viewers/SlotViewer.vue b/app/imports/ui/properties/viewers/SlotViewer.vue index 4e28f038..bdd07cd5 100644 --- a/app/imports/ui/properties/viewers/SlotViewer.vue +++ b/app/imports/ui/properties/viewers/SlotViewer.vue @@ -50,7 +50,7 @@