Progress all over the place with viewer, forms, small engine tweaks

This commit is contained in:
Stefan Zermatten
2021-10-21 22:18:01 +02:00
parent 1b5bb981e9
commit e3a1eff751
28 changed files with 554 additions and 258 deletions

View File

@@ -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;

View File

@@ -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';

View File

@@ -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;

View File

@@ -9,6 +9,7 @@ const linkDependenciesByType = {
effect: linkStats,
skill: linkSkill,
spell: linkResources,
toggle: linkVariableName,
}
export default function linkTypeDependencies(dependencyGraph, prop, computation){

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -18,7 +18,7 @@ let SavingThrowSchema = createPropertySchema({
// Who this saving throw applies to
target: {
type: String,
defaultValue: 'every',
defaultValue: 'target',
allowedValues: [
'self',
'target',

View File

@@ -75,6 +75,18 @@
</v-card>
</div>
<div
v-for="toggle in toggles"
:key="toggle._id"
class="toggle"
>
<toggle-card
:model="toggle"
:data-id="toggle._id"
@click="clickProperty({_id: toggle._id})"
/>
</div>
<div
v-for="stat in stats"
:key="stat._id"
@@ -335,9 +347,10 @@
import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue';
import RestButton from '/imports/ui/creature/RestButton.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import ToggleCard from '/imports/ui/properties/components/toggles/ToggleCard.vue';
//import castSpellWithSlot from '/imports/api/creature/actions/castSpellWithSlot.js';
const getProperties = function(creature, filter,){
const getProperties = function(creature, filter){
if (!creature) return;
if (creature.settings.hideUnusedStats){
filter.hide = {$ne: true};
@@ -378,6 +391,7 @@
ResourceCard,
SpellSlotListTile,
ActionCard,
ToggleCard,
},
props: {
creatureId: {
@@ -395,6 +409,17 @@
stats(){
return getAttributeOfType(this.creature, 'stat');
},
toggles(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'toggle',
removed: {$ne: true},
deactivatedByAncestor: {$ne: true},
showUI: true,
}, {
sort: {order: 1}
});
},
modifiers(){
return getAttributeOfType(this.creature, 'modifier');
},

View File

@@ -0,0 +1,69 @@
<template lang="html">
<v-card
:hover="hasClickListener"
@click="click"
>
<div class="layout align-center">
<div
class="value layout justify-center flex-grow-0"
>
<smart-checkbox
:value="toggleValue"
:disabled="toggleDisabled"
@change="(val, ack) => toggleToggle(val, ack)"
@click.native.stop=""
/>
</div>
<v-card-title class="name text-subtitle-1 text-truncate d-block pl-0">
{{ model.name }}
</v-card-title>
</div>
</v-card>
</template>
<script lang="js">
import flipToggle from '/imports/api/creature/creatureProperties/methods/flipToggle.js';
export default {
props: {
model: {
type: Object,
required: true,
},
},
computed: {
hasClickListener(){
return this.$listeners && !!this.$listeners.click
},
toggleValue(){
if (this.model.enabled) return true;
if (this.model.disabled) return false;
if (!this.model.condition) return undefined;
return !!this.model.condition.value
},
toggleDisabled(){
return !this.model.enabled && !this.model.disabled;
},
},
methods: {
click(e){
this.$emit('click', e);
},
toggleToggle(value, ack){
flipToggle.call({
_id: this.model._id
}, (error) =>{
if (error) console.warn(error);
ack && ack(error && error.reason || error);
});
},
},
}
</script>
<style lang="css" scoped>
.value {
min-width: 64px;
justify-content: center;
}
</style>

View File

@@ -19,7 +19,7 @@
cols="12"
md="6"
>
<smart-select
<smart-combobox
label="Damage Type"
style="flex-basis: 200px;"
hint="Use the Healing type to restore hit points"
@@ -57,12 +57,8 @@
<script lang="js">
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];
}
},

View File

@@ -1,9 +1,14 @@
<template lang="html">
<div class="folder-form layout justify-start wrap">
<div data-id="change-ref">
<property-field
name="Linked Property"
data-id="change-ref"
style="cursor: pointer;"
@click="changeReference"
>
<v-input
:label="model.cache && model.cache.node ? '' : 'Linked Property'"
style="flex-basis: 300px; cursor: pointer;"
style="overflow: hidden;"
readonly
outlined
persistent-hint
@@ -16,16 +21,14 @@
:error-messages="model.cache.error || errors.ref"
prepend-icon="mdi-vector-link"
append-icon="mdi-refresh"
@click="changeReference"
@click:prepend="changeReference"
@click:append="updateReferenceNode"
@click:append.stop="updateReferenceNode"
>
<tree-node-view
v-if="model && model.cache && model.cache.node"
:model="model.cache.node"
/>
</v-input>
</div>
</property-field>
</div>
</template>
@@ -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 {

View File

@@ -1,23 +1,33 @@
<template lang="html">
<div class="roll-form">
<div class="layout wrap">
<text-field
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<text-field
label="Variable name"
:value="model.variableName"
style="flex-basis: 300px;"
hint="Use this name in action formulae to refer to the result of this roll"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</div>
<v-row dense>
<v-col
cols="12"
md="6"
>
<text-field
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<text-field
label="Variable name"
:value="model.variableName"
style="flex-basis: 300px;"
hint="Use this name in action formulae to refer to the result of this roll"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</v-col>
</v-row>
<computed-field
label="Roll bonus"
label="Roll"
hint="The calculation that will be evaluated when the roll is triggered by an action. The result will be saved as the variable name in the context of the roll."
:model="model.roll"
:error-messages="errors.roll"

View File

@@ -1,39 +1,59 @@
<template lang="html">
<div class="saving-throw-form">
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<computed-field
label="DC"
hint="A calculation of the DC that the target of an action needs to save against in order to succeed. If the saving throw is lower than the DC, the children of this property will be activated."
:model="model.dc"
:error-messages="errors.dc"
@change="({path, value, ack}) =>
$emit('change', {path: ['dc', ...path], value, ack})"
/>
<smart-combobox
label="Save"
hint="Which stat the saving throw targets"
:value="model.stat"
:items="saveList"
:error-messages="errors.stat"
@change="change('stat', ...arguments)"
/>
<smart-select
label="Target"
:hint="targetOptionHint"
:items="targetOptions"
:value="model.target"
:error-messages="errors.target"
:menu-props="{auto: true, lazy: true}"
@change="change('target', ...arguments)"
/>
<v-row dense>
<v-col
cols="12"
md="6"
>
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<computed-field
label="DC"
hint="A calculation of the DC that the target of an action needs to save against in order to succeed. If the saving throw is lower than the DC, the children of this property will be activated."
:model="model.dc"
:error-messages="errors.dc"
@change="({path, value, ack}) =>
$emit('change', {path: ['dc', ...path], value, ack})"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-combobox
label="Save"
hint="Which stat the saving throw targets"
:value="model.stat"
:items="saveList"
:error-messages="errors.stat"
@change="change('stat', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Target"
:hint="targetOptionHint"
:items="targetOptions"
:value="model.target"
:error-messages="errors.target"
:menu-props="{auto: true, lazy: true}"
@change="change('target', ...arguments)"
/>
</v-col>
</v-row>
<smart-combobox
label="Tags"
class="mr-2"
@@ -61,25 +81,16 @@ export default {
text: 'Self',
value: 'self',
}, {
text: 'Roll once for each target',
value: 'each',
}, {
text: 'Roll once and apply to every target',
value: 'every',
text: 'Target',
value: 'target',
},
];
},
targetOptionHint(){
let hints = {
self: 'The damage will be applied to the character\'s own attribute when taking the action',
target: 'The damage will be applied to the target of the action',
each: 'The damage will be rolled separately for each of the targets of the action',
every: 'The damage will be rolled once and applied to each of the targets of the action',
self: 'The save will be applied to the character taking the action',
target: 'The save will be applied to the targets of the action',
};
if (this.parentTarget === 'singleTarget'){
hints.each = hints.target;
hints.every = hints.target;
}
return hints[this.model.target];
}
},

View File

@@ -22,7 +22,6 @@
:error-messages="errors.description"
@change="change('description', ...arguments)"
/>
<calculation-error-list :calculations="model.descriptionCalculations" />
<text-field
label="Picture URL"
@@ -51,6 +50,7 @@
@change="change('slotQuantityFilled', ...arguments)"
/>
<text-field
v-if="context.isLibraryForm"
label="Condition"
hint="A caclulation to determine if this can be added to the character"
placeholder="Always active"
@@ -81,6 +81,9 @@
CalculationErrorList,
},
mixins: [propertyFormMixin],
inject: {
context: { default: {} }
},
data(){
let slotTypes = [];
for (let key in PROPERTIES){

View File

@@ -1,34 +1,69 @@
<template lang="html">
<div class="feature-form">
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<v-layout
column
align-center
>
<v-radio-group
:value="radioSelection"
@change="radioChange"
<v-row dense>
<v-col
cols="12"
md="6"
>
<v-radio
value="enabled"
label="Enabled"
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<v-radio
value="disabled"
label="Disabled"
</v-col>
<v-col
cols="12"
md="6"
>
<text-field
label="Variable name"
:value="model.variableName"
hint="Use this name in calculations to reference this attribute"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
<v-radio
value="calculated"
label="Calculated"
</v-col>
<v-col
cols="12"
md="6"
>
<smart-checkbox
label="Show on character sheet"
:value="model.showUI"
:error-messages="errors.showUI"
@change="change('showUI', ...arguments)"
/>
</v-radio-group>
</v-layout>
</v-col>
<v-col
cols="12"
md="6"
>
<v-layout
column
>
<v-radio-group
:value="radioSelection"
@change="radioChange"
>
<v-radio
value="enabled"
label="Enabled"
/>
<v-radio
value="disabled"
label="Disabled"
/>
<v-radio
value="calculated"
label="Calculated"
/>
</v-radio-group>
</v-layout>
</v-col>
</v-row>
<v-fade-transition>
<computed-field
v-show="radioSelection === 'calculated'"

View File

@@ -28,6 +28,7 @@
name="To hit"
large
center
signed
:value="rollBonus"
/>
<property-field
@@ -93,6 +94,7 @@
/>
</div>
</property-field>
<slot />
<property-description
name="Summary"
:model="model.summary"

View File

@@ -1,17 +1,15 @@
<template lang="html">
<div class="note-viewer">
<property-name :value="model.name" />
<property-description
:string="model.summary"
:calculations="model.summaryCalculations"
:inactive="model.inactive"
/>
<v-divider class="mt-3 mb-3" />
<property-description
:string="model.description"
:calculations="model.descriptionCalculations"
:inactive="model.inactive"
/>
<v-row dense>
<property-description
name="Summary"
:model="model.summary"
/>
<property-description
name="Description"
:model="model.description"
/>
</v-row>
</div>
</template>

View File

@@ -1,17 +1,25 @@
<template lang="html">
<div class="proficiency-viewer">
<div class="text-h5">
{{ model.stats && model.stats.join(' ') }}
</div>
<div class="text-h5 layout">
<proficiency-icon
:value="model.value"
class="mr-1"
<v-row dense>
<property-field
v-if="model.value !== undefined"
name="Proficiency"
>
<proficiency-icon
:value="model.value"
style="height: 12px"
class="ml-1 mr-2"
/>
<div>
{{ proficiencyText }}
</div>
</property-field>
<property-field
name="Stats"
:value="model.stats && model.stats.join(', ')"
mono
/>
<div>
{{ proficiencyText }}
</div>
</div>
</v-row>
</div>
</template>
@@ -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';

View File

@@ -1,21 +1,25 @@
<template lang="html">
<div class="reference-viewer">
<property-field
v-if="model.cache.error"
name="Error"
:value="model.cache.error"
/>
<template v-else-if="model.ref && model.ref.id">
<div class="text-caption">
Linked Property
</div>
<tree-node-view :model="model.cache.node" />
</template>
<property-field
v-if="model.cache.library && model.cache.library.name"
name="Library"
:value="model.cache.library.name"
/>
<v-row>
<property-field
v-if="model.cache.error"
name="Error"
:value="model.cache.error"
/>
<property-field
v-else-if="model.ref && model.ref.id"
name="Linked Property"
>
<div style="overflow: hidden;">
<tree-node-view :model="model.cache.node" />
</div>
</property-field>
<property-field
v-if="model.cache.library && model.cache.library.name"
name="Library"
:value="model.cache.library.name"
/>
</v-row>
</div>
</template>

View File

@@ -1,23 +1,25 @@
<template lang="html">
<div class="buff-viewer">
<property-name :value="model.name" />
<property-variable-name :value="model.variableName" />
<property-field
name="Roll"
:value="'rollResult' in model ? model.rollResult : model.roll"
/>
<calculation-error-list :errors="model.rollErrors" />
<div class="roll-viewer">
<v-row dense>
<property-field
name="Variable Name"
mono
:value="model.variableName"
/>
<property-field
name="Roll"
large
center
:calculation="model.roll"
/>
</v-row>
</div>
</template>
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue';
export default {
components: {
CalculationErrorList,
},
mixins: [propertyViewerMixin],
}
</script>

View File

@@ -1,14 +1,23 @@
<template lang="html">
<div class="buff-viewer">
<property-name :value="model.name" />
<property-field
name="Save"
:value="model.stat"
/>
<property-field
name="DC"
:value="'dcResult' in model ? model.dcResult : model.dc"
/>
<div class="saving-throw-viewer">
<v-row dense>
<property-field
name="DC"
large
center
:calculation="model.dc"
/>
<property-field
name="Save"
mono
:value="model.stat"
/>
<property-field
v-if="model.target === 'self'"
name="Target"
value="Self"
/>
</v-row>
</div>
</template>

View File

@@ -1,37 +1,55 @@
<template lang="html">
<div class="slot-filler-viewer">
<property-name :value="model.name" />
<v-img
v-if="model.picture"
:src="model.picture"
:height="200"
contain
class="slot-card-image"
/>
<property-field
name="Type"
:value="model.slotFillerType"
/>
<property-field
name="Quantity"
:value="model.slotQuantityFilled"
/>
<property-field
name="Condition"
:value="model.slotFillerCondition"
/>
<property-description
:string="model.description"
:calculations="model.descriptionCalculations"
:inactive="model.inactive"
/>
<v-row dense>
<property-field
name="Type"
:value="slotTypeName"
/>
<property-field
name="Quantity filled"
:value="model.slotQuantityFilled"
/>
<property-field
v-if="context.creatureId"
name="Condition"
mono
:value="model.slotFillerCondition"
/>
<property-field
v-if="model.picture"
name="Image"
:cols="{cols: 12}"
>
<v-img
:src="model.picture"
:height="200"
contain
class="slot-card-image"
/>
</property-field>
<property-field
name="Description"
:cols="{cols: 12}"
:value="model.description"
/>
</v-row>
</div>
</template>
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js';
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default {
mixins: [propertyViewerMixin],
inject: {
context: { default: {} }
},
computed: {
slotTypeName(){
if (!this.model.slotFillerType) return;
return getPropertyName(this.model.slotFillerType);
},
}
}
</script>

View File

@@ -50,7 +50,7 @@
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
import {getPropertyName} from '/imports/constants/PROPERTIES.js';
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
const uniqueText = {
uniqueInSlot: 'Each property inside this slot should be unique',

View File

@@ -1,24 +1,36 @@
<template lang="html">
<div class="spell-list-viewer">
<property-name :value="model.name" />
<property-variable-name :value="model.variableName" />
<property-field
name="Maximum prepared spells"
:value="'maxPreparedResult' in model ? model.maxPreparedResult : model.maxPrepared"
/>
<property-field
name="Spell Save DC"
:value="'dcResult' in model ? model.dcResult : model.dc"
/>
<property-field
name="Attack roll bonus"
:value="'attackRollBonusResult' in model ? model.attackRollBonusResult : model.attackRollBonus"
/>
<property-description
:string="model.description"
:calculations="model.descriptionCalculations"
:inactive="model.inactive"
/>
<v-row dense>
<property-field
name="Variable Name"
mono
:value="model.variableName"
/>
<property-field
name="Maximum prepared spells"
large
center
:calculation="model.maxPrepared"
/>
<property-field
name="Spell Save DC"
large
center
:calculation="model.dc"
/>
<property-field
name="Attack roll bonus"
large
center
signed
:calculation="model.attackRollBonus"
/>
<property-description
name="Description"
:model="model.description"
/>
</v-row>
</div>
</template>

View File

@@ -1,9 +1,16 @@
<template lang="html">
<div class="spell-viewer">
<property-name :value="model.name" />
<p class="text-caption">
{{ levelAndSchool }}
</p>
<action-viewer
:model="model"
class="spell-viewer"
>
<property-field
name="School"
:value="model.school"
/>
<property-field
name="Level"
:value="levelText"
/>
<property-field
name="Casting time"
:value="model.castingTime"
@@ -20,16 +27,12 @@
name="Duration"
:value="model.duration"
/>
<property-description
:string="model.description"
:calculations="model.descriptionCalculations"
:inactive="model.inactive"
/>
</div>
</action-viewer>
</template>
<script lang="js">
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js';
import ActionViewer from './ActionViewer.vue';
const levelText = [
'cantrip', '1st-level', '2nd-level', '3rd-level', '4th-level', '5th-level',
@@ -37,14 +40,13 @@ const levelText = [
];
export default {
components: {
ActionViewer,
},
mixins: [propertyViewerMixin],
computed:{
levelAndSchool(){
if (this.model.level == 0){
return `${this.model.school} ${levelText[0]}`
} else {
return `${levelText[this.model.level]} ${this.model.school}`
}
levelText(){
return levelText[this.model.level]
},
spellComponents(){
let components = [];

View File

@@ -1,24 +1,25 @@
<template lang="html">
<div class="toggle-viewer">
<property-name :value="model.name" />
<property-field
v-if="model.disabled || model.enabled"
name="Status"
:value="model.enabled ? 'Enabled' : 'Disabled'"
/>
<template
v-else-if="model.condition"
>
<v-row dense>
<property-field
name="Condition"
:value="model.condition"
name="Variable Name"
mono
:value="model.variableName"
/>
<property-field
v-if="'toggleResult' in model"
name="Result"
:value="model.toggleResult"
v-if="model.disabled || model.enabled"
name="Status"
:value="model.enabled ? 'Enabled' : 'Disabled'"
/>
</template>
<template
v-else-if="model.condition"
>
<property-field
name="Condition"
:calculation="model.condition"
/>
</template>
</v-row>
</div>
</template>

View File

@@ -9,6 +9,7 @@
<v-sheet
outlined
class="pa-2 layout column align-start fill-height"
@click="$emit('click', $event)"
>
<v-sheet
v-if="name"
@@ -38,11 +39,7 @@
{{ value }}
</template>
<template v-else-if="calculation !== undefined">
{{
calculation.value !== undefined ?
calculation.value :
calculation.calculation
}}
{{ calculationText }}
</template>
</slot>
</div>
@@ -52,6 +49,8 @@
</template>
<script lang="js">
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default {
props: {
name: {
@@ -70,6 +69,7 @@ export default {
end: Boolean,
large: Boolean,
mono: Boolean,
signed: Boolean,
cols: {
type: Object,
default: () => ({cols: 12, sm: 6, md: 4}),
@@ -80,22 +80,45 @@ export default {
if (!this.calculation) return;
return this.calculation && this.calculation.value === undefined;
},
valueNotReduced(){
if (!this.calculation) return;
return typeof this.calculation.value === 'string'
},
calculationText(){
const calculation = this.calculation;
if (!calculation) {
return undefined;
}
if (calculation.value === undefined){
return calculation.calculation;
}
if (this.signed) {
return numberToSignedString(calculation.value);
}
return calculation.value;
},
// large and center are only applied to calculations if we are showing their
// value, if we are showing the calculation itself, large and center are
// turned off
isLarge(){
if (this.showCalculationInsteadOfValue) return false;
if (this.valueNotReduced) return false;
return this.large;
},
isCenter(){
if (this.showCalculationInsteadOfValue) return false;
if (this.valueNotReduced) return false;
return this.center;
},
isMono(){
if (this.showCalculationInsteadOfValue) return true;
if (this.valueNotReduced) return true;
return this.mono;
}
},
},
methods: {
numberToSignedString,
}
}
</script>