Progress all over the place with viewer, forms, small engine tweaks
This commit is contained in:
@@ -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;
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,6 +9,7 @@ const linkDependenciesByType = {
|
||||
effect: linkStats,
|
||||
skill: linkSkill,
|
||||
spell: linkResources,
|
||||
toggle: linkVariableName,
|
||||
}
|
||||
|
||||
export default function linkTypeDependencies(dependencyGraph, prop, computation){
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ let SavingThrowSchema = createPropertySchema({
|
||||
// Who this saving throw applies to
|
||||
target: {
|
||||
type: String,
|
||||
defaultValue: 'every',
|
||||
defaultValue: 'target',
|
||||
allowedValues: [
|
||||
'self',
|
||||
'target',
|
||||
|
||||
@@ -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');
|
||||
},
|
||||
|
||||
69
app/imports/ui/properties/components/toggles/ToggleCard.vue
Normal file
69
app/imports/ui/properties/components/toggles/ToggleCard.vue
Normal 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>
|
||||
@@ -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];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user