Form overhaul: roll -> trigger

roll, savingThrow, skill, slot, slotfiller, spell, spellList,
toggle, trigger
This commit is contained in:
Stefan Zermatten
2023-05-17 11:32:39 +02:00
parent 4c34986fb7
commit 0a3ea7672f
12 changed files with 443 additions and 814 deletions

View File

@@ -203,7 +203,7 @@ const updateLibraryNode = new ValidatedMethod({
},
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
numRequests: 15,
timeInterval: 5000,
},
run({ _id, path, value }) {

View File

@@ -22,6 +22,12 @@
height="42"
v-on="(value == option.value) ? {} : { click() { click(option.value) } }"
>
<v-icon
v-if="option.icon"
left
>
{{ option.icon }}
</v-icon>
{{ option.name }}
</v-btn>
</v-btn-toggle>

View File

@@ -83,19 +83,6 @@ import propertyFormMixin from '/imports/client/ui/properties/forms/shared/proper
export default {
mixins: [propertyFormMixin],
data() {
return {
targetOptions: [
{
text: 'Self',
value: 'self',
}, {
text: 'Target',
value: 'target',
},
],
}
},
}
</script>

View File

@@ -1,17 +1,6 @@
<template lang="html">
<div class="roll-form">
<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"
@@ -25,48 +14,30 @@
@change="change('variableName', ...arguments)"
/>
</v-col>
</v-row>
<computed-field
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"
@change="({path, value, ack}) =>
$emit('change', {path: ['roll', ...path], value, ack})"
/>
<form-sections>
<form-section
v-if="$slots.children"
name="Children"
<v-col
cols="12"
md="6"
>
<slot name="children" />
</form-section>
<form-section name="Advanced">
<v-row dense>
<v-col
cols="12"
sm="6"
md="4"
>
<smart-switch
label="Don't show in log"
:value="model.silent"
:error-messages="errors.silent"
@change="change('silent', ...arguments)"
/>
</v-col>
</v-row>
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
@change="change('tags', ...arguments)"
<computed-field
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"
@change="({path, value, ack}) =>
$emit('change', {path: ['roll', ...path], value, ack})"
/>
</v-col>
</v-row>
<form-sections>
<form-section name="Log">
<smart-switch
label="Don't show in log"
:value="model.silent"
:error-messages="errors.silent"
@change="change('silent', ...arguments)"
/>
</form-section>
<slot />
</form-sections>
</div>
</template>

View File

@@ -1,25 +1,13 @@
<template lang="html">
<div class="saving-throw-form">
<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."
hint="Saving throw DC"
:model="model.dc"
:error-messages="errors.dc"
@change="({path, value, ack}) =>
@@ -43,41 +31,29 @@
cols="12"
md="6"
>
<smart-select
label="Target"
:hint="targetOptionHint"
:items="targetOptions"
<smart-toggle
label="Target creature"
:value="model.target"
:options="[
{name: 'Action Target', value: 'target'},
{name: 'Self', value: 'self'},
]"
: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"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
:error-messages="errors.tags"
@change="change('tags', ...arguments)"
/>
<smart-switch
label="Don't show in log"
:value="model.silent"
:error-messages="errors.silent"
@change="change('silent', ...arguments)"
/>
<form-section
v-if="$slots.children"
name="Children"
standalone
>
<slot name="children" />
</form-section>
<form-sections>
<form-section name="Log">
<smart-switch
label="Don't show in log"
:value="model.silent"
:error-messages="errors.silent"
@change="change('silent', ...arguments)"
/>
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -87,25 +63,5 @@ import propertyFormMixin from '/imports/client/ui/properties/forms/shared/proper
export default {
mixins: [saveListMixin, propertyFormMixin],
computed: {
targetOptions() {
return [
{
text: 'Self',
value: 'self',
}, {
text: 'Target',
value: 'target',
},
];
},
targetOptionHint() {
let hints = {
self: 'The save will be applied to the character taking the action',
target: 'The save will be applied to the targets of the action',
};
return hints[this.model.target];
}
},
};
</script>

View File

@@ -1,42 +1,49 @@
<template lang="html">
<div class="skill-form">
<div class="layout wrap">
<text-field
ref="focusFirst"
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 formulae to reference this skill"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
<smart-combobox
label="Ability"
:value="model.ability"
style="flex-basis: 300px;"
hint="Which ability is this skill based off of"
:items="abilityScoreList"
:error-messages="errors.ability"
@change="change('ability', ...arguments)"
/>
</div>
<smart-select
label="Type"
clearable
:items="skillTypes"
:value="model.skillType"
:error-messages="errors.skillType"
:menu-props="{auto: true, lazy: true}"
:hint="skillTypeHints[model.skillType]"
@change="change('skillType', ...arguments)"
/>
<v-row dense>
<v-col
cols="12"
md="6"
>
<text-field
label="Variable name"
:value="model.variableName"
style="flex-basis: 300px;"
hint="Use this name in formulae to reference this skill"
:error-messages="errors.variableName"
@change="change('variableName', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-combobox
label="Ability"
:value="model.ability"
style="flex-basis: 300px;"
hint="Which ability is this skill based off of"
:items="abilityScoreList"
:error-messages="errors.ability"
@change="change('ability', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Type"
clearable
:items="skillTypes"
:value="model.skillType"
:error-messages="errors.skillType"
:menu-props="{auto: true, lazy: true}"
:hint="skillTypeHints[model.skillType]"
@change="change('skillType', ...arguments)"
/>
</v-col>
</v-row>
<inline-computation-field
label="Description"
:model="model.description"
@@ -46,39 +53,33 @@
/>
<form-sections>
<form-section
v-if="$slots.children"
name="Children"
>
<slot name="children" />
</form-section>
<form-section name="Advanced">
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
:value="model.tags"
@change="change('tags', ...arguments)"
/>
<div class="layout justify-center">
<computed-field
label="Base Value"
hint="This is the value of the skill before effects are applied"
:model="model.baseValue"
:error-messages="errors.baseValue"
@change="({path, value, ack}) =>
$emit('change', {path: ['baseValue', ...path], value, ack})"
/>
<proficiency-select
style="flex-basis: 300px;"
label="Base Proficiency"
:value="model.baseProficiency"
:error-messages="errors.baseProficiency"
@change="change('baseProficiency', ...arguments)"
/>
</div>
<form-section name="Base Values">
<v-row dense>
<v-col
cols="12"
md="6"
>
<proficiency-select
label="Base Proficiency"
:value="model.baseProficiency"
:error-messages="errors.baseProficiency"
@change="change('baseProficiency', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<computed-field
label="Base Value"
hint="This is the value of the skill before effects are applied"
:model="model.baseValue"
:error-messages="errors.baseValue"
@change="({path, value, ack}) =>
$emit('change', {path: ['baseValue', ...path], value, ack})"
/>
</v-col>
</v-row>
</form-section>
</form-sections>
</div>

View File

@@ -1,114 +1,23 @@
<template lang="html">
<div class="slot-filler-form">
<v-row
dense
align="start"
>
<v-col
cols="12"
sm="9"
md="10"
>
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</v-col>
<v-col
cols="12"
sm="3"
md="2"
>
<icon-picker
:value="model.icon"
:error-messages="errors.icon"
height="56"
width="100%"
button-style="margin-bottom: 30px;"
@change="change('icon', ...arguments)"
/>
</v-col>
</v-row>
<text-area
label="Description"
:value="model.description"
:error-messages="errors.description"
@change="change('description', ...arguments)"
/>
<text-field
label="Picture URL"
hint="A link to an image representing this property"
:value="model.picture"
:error-messages="errors.picture"
@change="change('picture', ...arguments)"
/>
<smart-select
label="Type"
style="flex-basis: 300px;"
clearable
hint="The property type that this slot filler pretends to be when being searched for by a slot"
:items="slotTypes"
:value="model.slotFillerType"
:error-messages="errors.slotFillerType"
@change="change('slotFillerType', ...arguments)"
/>
<text-field
label="Quantity"
type="number"
min="0"
hint="How many properties this counts as when filling a slot"
:value="model.slotQuantityFilled"
:error-messages="errors.slotQuantityFilled"
@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"
:value="model.slotFillerCondition"
:error-messages="errors.slotFillerCondition"
@change="change('slotFillerCondition', ...arguments)"
/>
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this slot filler in a library"
:value="model.tags"
:error-messages="errors.tags"
@change="change('tags', ...arguments)"
/>
<form-section
v-if="$slots.children"
name="Children"
standalone
<form-sections
v-if="$slots.default"
>
<slot name="children" />
</form-section>
<slot />
</form-sections>
</div>
</template>
<script lang="js">
import propertyFormMixin from '/imports/client/ui/properties/forms/shared/propertyFormMixin.js';
import PROPERTIES from '/imports/constants/PROPERTIES.js';
export default {
mixins: [propertyFormMixin],
inject: {
context: { default: {} }
},
data() {
let slotTypes = [];
for (let key in PROPERTIES) {
slotTypes.push({ text: PROPERTIES[key].name, value: key });
}
return { slotTypes };
},
};
</script>

View File

@@ -1,155 +1,97 @@
<template lang="html">
<div class="slot-form">
<v-row
v-if="model.type === 'class'"
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-row dense>
<v-col cols="12">
<smart-select
label="Type"
clearable
hint="What property type is needed to fill this slot"
placeholder="Any type"
persistent-placeholder
:items="slotTypes"
:value="model.slotType"
:error-messages="errors.slotType"
@change="change('slotType', ...arguments)"
/>
</v-col>
<v-col cols="12">
<tag-targeting
:model="model"
:errors="errors"
tag-field="slotTags"
tag-hint="Find library properties that have all of these tags"
or-hint="Also library properties that have all of these tags instead"
not-hint="Ignore library properties that have any of these tags"
@change="e => $emit('change', e)"
@push="e => $emit('push', e)"
@pull="e => $emit('pull', e)"
/>
</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)"
<computed-field
label="Quantity"
hint="How many matching properties must be used to fill this slot"
placeholder="unlimited"
persistent-placeholder
:model="model.quantityExpected"
:error-messages="errors.quantityExpected"
@change="({path, value, ack}) =>
$emit('change', {path: ['quantityExpected', ...path], value, ack})"
/>
</v-col>
</v-row>
<text-field
v-else
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<smart-select
v-if="model.type !== 'class'"
label="Type"
style="flex-basis: 300px;"
clearable
hint="What property type is needed to fill this slot"
:items="slotTypes"
:value="model.slotType"
:error-messages="errors.slotType"
@change="change('slotType', ...arguments)"
/>
<v-layout align-center>
<v-btn
icon
style="margin-top: -30px;"
class="mr-2"
:loading="addExtraTagsLoading"
:disabled="extraTagsFull"
@click="addExtraTags"
<v-col
cols="12"
md="6"
>
<v-icon>
mdi-plus
</v-icon>
</v-btn>
<smart-combobox
label="Tags Required"
hint="The slot must be filled with a property which has all the listed tags"
multiple
chips
deletable-chips
:value="model.slotTags"
:error-messages="errors.slotTags"
@change="change('slotTags', ...arguments)"
/>
</v-layout>
<v-slide-x-transition group>
<div
v-for="(extras, i) in model.extraTags"
:key="extras._id"
class="extra-tags layout align-center justify-space-between"
style="transition: all 0.3s !important;"
<computed-field
label="Condition"
hint="A caclulation to determine if this slot should be active"
placeholder="Always active"
persistent-placeholder
:model="model.slotCondition"
:error-messages="errors.slotCondition"
@change="({path, value, ack}) =>
$emit('change', {path: ['slotCondition', ...path], value, ack})"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Operation"
style="width: 90px; flex-grow: 0;"
:items="extraTagOperations"
:value="extras.operation"
:error-messages="errors.extraTags && errors.extraTags[i]"
@change="change(['extraTags', i, 'operation'], ...arguments)"
v-if="model.type !== 'class'"
label="Unique"
style="flex-basis: 300px;"
clearable
hint="Do the properties that fill this slot need to be unique?"
placeholder="Allow duplicate values"
persistent-placeholder
:items="uniqueOptions"
:value="model.unique"
:error-messages="errors.unique"
@change="change('unique', ...arguments)"
/>
<smart-combobox
label="Tags"
:hint="extras.operation === 'OR' ? 'The slot can be filled with a property that has all of these tags instead' : 'The slot cannot be filled with a property that has any of these tags'"
class="mx-2"
multiple
chips
deletable-chips
:value="extras.tags"
@change="change(['extraTags', i, 'tags'], ...arguments)"
/>
<v-btn
icon
style="margin-top: -30px;"
@click="$emit('pull', {path: ['extraTags', i]})"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</div>
</v-slide-x-transition>
<computed-field
label="Quantity"
hint="How many matching properties must be used to fill this slot, 0 is unlimited"
:model="model.quantityExpected"
:error-messages="errors.quantityExpected"
@change="({path, value, ack}) =>
$emit('change', {path: ['quantityExpected', ...path], value, ack})"
/>
<computed-field
label="Condition"
hint="A caclulation to determine if this slot should be active"
placeholder="Always active"
:model="model.slotCondition"
:error-messages="errors.slotCondition"
@change="({path, value, ack}) =>
$emit('change', {path: ['slotCondition', ...path], value, ack})"
/>
<smart-select
v-if="model.type !== 'class'"
label="Unique"
style="flex-basis: 300px;"
clearable
hint="Do the properties that fill this slot need to be unique?"
:items="uniqueOptions"
:value="model.unique"
:error-messages="errors.unique"
@change="change('unique', ...arguments)"
/>
<v-layout justify-center>
<v-btn
v-if="context.isLibraryForm"
color="accent"
class="ma-2 mb-4"
data-id="test-slot-button"
@click="testSlot"
</v-col>
<v-col
cols="12"
md="6"
>
Test Slot
</v-btn>
</v-layout>
<v-layout justify-center>
<v-btn
v-if="context.isLibraryForm"
color="accent"
class="ma-2 mb-4"
data-id="test-slot-button"
@click="testSlot"
>
Test Slot
</v-btn>
</v-layout>
</v-col>
</v-row>
<inline-computation-field
label="Description"
:model="model.description"
@@ -166,35 +108,37 @@
<slot name="children" />
</form-section>
<form-section name="Advanced">
<div class="layout wrap justify-space-between">
<smart-switch
label="Hide when full"
style="width: 200px; flex-grow: 0;"
class="mx-2"
:value="model.hideWhenFull"
:error-messages="errors.hideWhenFull"
@change="change('hideWhenFull', ...arguments)"
/>
<smart-switch
label="Ignored"
style="width: 200px; flex-grow: 0;"
class="mx-2"
:value="model.ignored"
:error-messages="errors.ignored"
@change="change('ignored', ...arguments)"
/>
</div>
<smart-combobox
label="Tags"
hint="This slot's own tags which will be used to fill other slots"
multiple
chips
deletable-chips
:value="model.tags"
@change="change('tags', ...arguments)"
/>
<form-section name="Behavior">
<v-row dense>
<v-col
cols="12"
md="6"
>
<smart-switch
label="Hide when full"
style="width: 200px; flex-grow: 0;"
class="mx-2"
:value="model.hideWhenFull"
:error-messages="errors.hideWhenFull"
@change="change('hideWhenFull', ...arguments)"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-switch
label="Ignored"
style="width: 200px; flex-grow: 0;"
class="mx-2"
:value="model.ignored"
:error-messages="errors.ignored"
@change="change('ignored', ...arguments)"
/>
</v-col>
</v-row>
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -203,19 +147,17 @@
import propertyFormMixin from '/imports/client/ui/properties/forms/shared/propertyFormMixin.js';
import FormSection from '/imports/client/ui/properties/forms/shared/FormSection.vue';
import PROPERTIES from '/imports/constants/PROPERTIES.js';
import { SlotSchema } from '/imports/api/properties/Slots.js';
import TagTargeting from '/imports/client/ui/properties/forms/shared/TagTargeting.vue';
export default {
components: {
FormSection,
TagTargeting,
},
mixins: [propertyFormMixin],
inject: {
context: { default: {} }
},
props: {
classForm: Boolean,
},
data() {
let slotTypes = [];
for (let key in PROPERTIES) {
@@ -223,8 +165,6 @@ export default {
}
return {
slotTypes,
addExtraTagsLoading: false,
extraTagOperations: ['OR', 'NOT'],
uniqueOptions: [{
text: 'Each property inside this slot should be unique',
value: 'uniqueInSlot',
@@ -234,29 +174,7 @@ export default {
}],
};
},
computed: {
extraTagsFull() {
if (!this.model.extraTags) return false;
let maxCount = SlotSchema.get('extraTags', 'maxCount');
return this.model.extraTags.length >= maxCount;
}
},
methods: {
acknowledgeAddResult() {
this.addExtraTagsLoading = false;
},
addExtraTags() {
this.addExtraTagsLoading = true;
this.$emit('push', {
path: ['extraTags'],
value: {
_id: Random.id(),
operation: 'OR',
tags: [],
},
ack: this.acknowledgeAddResult,
});
},
testSlot() {
if (!this.context.isLibraryForm) return;
this.$store.commit('pushDialogStack', {

View File

@@ -1,17 +1,5 @@
<template lang="html">
<div class="spell-form">
<v-row
justify="center"
class="mb-3"
>
<v-col cols="12">
<icon-color-menu
:model="model"
:errors="errors"
@change="e => $emit('change', e)"
/>
</v-col>
</v-row>
<v-row dense>
<v-col
cols="12"
@@ -19,6 +7,7 @@
md="4"
>
<smart-switch
class="ml-2"
label="Always prepared"
:value="model.alwaysPrepared"
:error-messages="errors.alwaysPrepared"
@@ -32,6 +21,7 @@
md="4"
>
<smart-switch
class="ml-2"
label="Prepared"
:value="model.prepared"
:error-messages="errors.prepared"
@@ -45,6 +35,7 @@
md="4"
>
<smart-switch
class="ml-2"
label="Cast without spell slots"
:value="model.castWithoutSpellSlots"
:error-messages="errors.castWithoutSpellSlots"
@@ -53,18 +44,6 @@
</v-col>
</v-row>
<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"
@@ -189,12 +168,15 @@
cols="12"
md="6"
>
<smart-select
label="Target"
:items="targetOptions"
<smart-toggle
label="Target creature"
:value="model.target"
:options="[
{name: 'Single Target', value: 'singleTarget'},
{name: 'Multiple Targets', value: 'multipleTargets'},
{name: 'Self', value: 'self'},
]"
:error-messages="errors.target"
:menu-props="{auto: true, lazy: true}"
@change="change('target', ...arguments)"
/>
</v-col>
@@ -205,6 +187,7 @@
<v-slide-x-transition mode="out-in">
<v-switch
v-if="!isAttack"
class="ml-4"
label="Attack roll"
:value="attackSwitch"
@change="e => attackSwitch = e"
@@ -218,7 +201,18 @@
:error-messages="errors.attackRoll"
@change="({path, value, ack}) =>
$emit('change', {path: ['attackRoll', ...path], value, ack})"
/>
>
<template #prepend>
<v-btn
:disabled="!!(model.attackRoll && model.attackRoll.calculation)"
icon
style="margin-top: -12px;"
@click="attackSwitch = false"
>
<v-icon>mdi-close</v-icon>
</v-btn>
</template>
</computed-field>
</v-slide-x-transition>
</v-col>
</v-row>
@@ -285,25 +279,7 @@
@change="change('reset', ...arguments)"
/>
</form-section>
<form-section
v-if="$slots.children"
name="Children"
>
<slot name="children" />
</form-section>
<form-section name="Advanced">
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
@change="change('tags', ...arguments)"
/>
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -311,7 +287,6 @@
<script lang="js">
import FormSection, { FormSections } from '/imports/client/ui/properties/forms/shared/FormSection.vue';
import propertyFormMixin from '/imports/client/ui/properties/forms/shared/propertyFormMixin.js';
import IconColorMenu from '/imports/client/ui/properties/forms/shared/IconColorMenu.vue';
import ResourcesForm from '/imports/client/ui/properties/forms/ResourcesForm.vue';
import ResetSelector from '/imports/client/ui/components/ResetSelector.vue';
@@ -319,7 +294,6 @@ export default {
components: {
FormSections,
FormSection,
IconColorMenu,
ResourcesForm,
ResetSelector,
},
@@ -386,18 +360,6 @@ export default {
value: 9,
},
],
targetOptions: [
{
text: 'Self',
value: 'self',
}, {
text: 'Single target',
value: 'singleTarget',
}, {
text: 'Multiple targets',
value: 'multipleTargets',
},
],
attackSwitch: false,
};
},

View File

@@ -1,14 +1,59 @@
<template lang="html">
<div class="attribute-form">
<div class="layout wrap">
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
</div>
<div class="spell-list-form">
<v-row dense>
<v-col
cols="12"
md="6"
>
<computed-field
label="Maximum prepared spells"
hint="How many spells can be prepared"
:model="model.maxPrepared"
:error-messages="errors.maxPrepared"
@change="({path, value, ack}) =>
$emit('change', {path: ['maxPrepared', ...path], value, ack})"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<smart-combobox
label="Spellcasting ability"
:value="model.ability"
hint="Which ability is used to cast spells in this spell list"
:items="abilityScoreList"
:error-messages="errors.ability"
@change="changeAbility"
/>
</v-col>
<v-col
cols="12"
md="6"
>
<computed-field
label="Spell save DC"
hint="The spell save DC of spells in this list"
: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"
>
<computed-field
label="Attack roll bonus"
hint="The attack roll bonus of spell attacks made by spells in this list"
:model="model.attackRollBonus"
:error-messages="errors.attackRollBonus"
@change="({path, value, ack}) =>
$emit('change', {path: ['attackRollBonus', ...path], value, ack})"
/>
</v-col>
</v-row>
<inline-computation-field
label="Description"
@@ -18,59 +63,11 @@
$emit('change', {path: ['description', ...path], value, ack})"
/>
<computed-field
label="Maximum prepared spells"
hint="How many spells can be prepared"
:model="model.maxPrepared"
:error-messages="errors.maxPrepared"
@change="({path, value, ack}) =>
$emit('change', {path: ['maxPrepared', ...path], value, ack})"
/>
<smart-combobox
label="Spellcasting ability"
:value="model.ability"
hint="Which ability is used to cast spells in this spell list"
:items="abilityScoreList"
:error-messages="errors.ability"
@change="changeAbility"
/>
<computed-field
label="Spell save DC"
hint="The spell save DC of spells in this list"
:model="model.dc"
:error-messages="errors.dc"
@change="({path, value, ack}) =>
$emit('change', {path: ['dc', ...path], value, ack})"
/>
<computed-field
label="Attack roll bonus"
hint="The attack roll bonus of spell attacks made by spells in this list"
:model="model.attackRollBonus"
:error-messages="errors.attackRollBonus"
@change="({path, value, ack}) =>
$emit('change', {path: ['attackRollBonus', ...path], value, ack})"
/>
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
@change="change('tags', ...arguments)"
/>
<form-section
v-if="$slots.children"
name="Children"
standalone
<form-sections
v-if="$slots.default"
>
<slot name="children" />
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -95,8 +92,9 @@ export default {
const attackRollBonus = this.model.attackRollBonus?.calculation;
if (
!attackRollBonus ||
attackRollBonus === `proficiencyBonus + ${oldValue}.modifier`
value &&
(!attackRollBonus ||
attackRollBonus === `proficiencyBonus + ${oldValue}.modifier`)
) {
this.$emit('change', {
path: ['attackRollBonus', 'calculation'],
@@ -106,8 +104,9 @@ export default {
const dc = this.model.dc?.calculation;
if (
!dc ||
dc === `8 + proficiencyBonus + ${oldValue}.modifier`
value &&
(!dc ||
dc === `8 + proficiencyBonus + ${oldValue}.modifier`)
) {
this.$emit('change', {
path: ['dc', 'calculation'],
@@ -118,6 +117,3 @@ export default {
}
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,18 +1,6 @@
<template lang="html">
<div class="feature-form">
<div class="toggle-form">
<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"
@@ -25,71 +13,57 @@
@change="change('variableName', ...arguments)"
/>
</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)"
<smart-toggle
label="Active"
:value="radioSelection"
:options="[
{name: 'Enabled', value: 'enabled'},
{name: 'Disabled', value: 'disabled'},
{name: 'Calculated', value: 'calculated'},
]"
:error-messages="errors.enabled"
@change="radioChange"
/>
</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-expand-transition>
<v-col
v-show="radioSelection === 'calculated'"
cols="12"
>
<computed-field
label="Condition"
hint="When this calculation returns a value that isn't false or zero the children will be active"
:model="model.condition"
:error-messages="errors.condition"
@change="({path, value, ack}) =>
$emit('change', {path: ['condition', ...path], value, ack})"
/>
</v-col>
</v-expand-transition>
</v-row>
<v-fade-transition>
<computed-field
v-show="radioSelection === 'calculated'"
label="Condition"
hint="When this calculation returns a value that isn't false or zero the children will be active"
:model="model.condition"
:error-messages="errors.condition"
@change="({path, value, ack}) =>
$emit('change', {path: ['condition', ...path], value, ack})"
/>
</v-fade-transition>
<smart-combobox
label="Tags"
multiple
chips
deletable-chips
hint="Used to let slots find this property in a library, should otherwise be left blank"
:value="model.tags"
@change="change('tags', ...arguments)"
/>
<form-section
v-if="$slots.children"
name="Children"
standalone
>
<slot name="children" />
</form-section>
<form-sections>
<form-section name="Behavior">
<v-col
cols="12"
md="6"
>
<smart-switch
class="ml-2"
label="Show on character sheet"
:value="model.showUI"
:error-messages="errors.showUI"
@change="change('showUI', ...arguments)"
/>
</v-col>
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -110,16 +84,16 @@ export default {
}
},
methods: {
radioChange(value) {
radioChange(value, ack) {
if (value === 'enabled') {
this.$emit('change', { path: ['enabled'], value: true });
this.$emit('change', { path: ['disabled'], value: false });
this.$emit('change', { path: ['enabled'], value: true, ack });
this.$emit('change', { path: ['disabled'], value: false, ack });
} else if (value === 'disabled') {
this.$emit('change', { path: ['disabled'], value: true });
this.$emit('change', { path: ['enabled'], value: false });
this.$emit('change', { path: ['disabled'], value: true, ack });
this.$emit('change', { path: ['enabled'], value: false, ack });
} else if (value === 'calculated') {
this.$emit('change', { path: ['disabled'], value: false });
this.$emit('change', { path: ['enabled'], value: false });
this.$emit('change', { path: ['disabled'], value: false, ack });
this.$emit('change', { path: ['enabled'], value: false, ack });
}
}
}

View File

@@ -1,117 +1,79 @@
<template lang="html">
<div class="trigger-form">
<text-field
ref="focusFirst"
label="Name"
:value="model.name"
:error-messages="errors.name"
@change="change('name', ...arguments)"
/>
<smart-select
label="Timing"
style="flex-basis: 300px;"
hint="When this trigger will fire"
:items="timingOptions"
:value="model.timing"
:error-messages="errors.timing"
@change="change('timing', ...arguments)"
/>
<smart-select
label="Event"
style="flex-basis: 300px;"
hint="What causes this trigger to fire"
:items="eventOptions"
:value="model.event"
:error-messages="errors.event"
@change="change('event', ...arguments)"
/>
<smart-select
v-if="model.event === 'doActionProperty' || model.event === 'receiveActionProperty'"
label="Event Type"
style="flex-basis: 300px;"
hint="Which action event causes this trigger to fire"
:items="actionPropertyTypeOptions"
:value="model.actionPropertyType"
:error-messages="errors.actionPropertyType"
@change="change('actionPropertyType', ...arguments)"
/>
<v-layout
v-show="showTags"
align-center
>
<v-btn
icon
style="margin-top: -30px;"
class="mr-2"
:loading="addExtraTagsLoading"
:disabled="extraTagsFull"
@click="addExtraTags"
>
<v-icon>
mdi-plus
</v-icon>
</v-btn>
<smart-combobox
label="Tags Required"
hint="The trigger will be fired by a property which has all the listed tags"
multiple
chips
deletable-chips
:value="model.targetTags"
:error-messages="errors.targetTags"
@change="change('targetTags', ...arguments)"
/>
</v-layout>
<v-slide-x-transition
v-show="showTags"
group
>
<div
v-for="(extras, i) in model.extraTags"
:key="extras._id"
class="extra-tags layout align-center justify-space-between"
<v-row dense>
<v-col
cols="12"
md="6"
>
<smart-select
label="Operation"
style="width: 90px; flex-grow: 0;"
:items="extraTagOperations"
:value="extras.operation"
:error-messages="errors.extraTags && errors.extraTags[i]"
@change="change(['extraTags', i, 'operation'], ...arguments)"
label="Timing"
style="flex-basis: 300px;"
hint="When this trigger will fire"
:items="timingOptions"
:value="model.timing"
:error-messages="errors.timing"
@change="change('timing', ...arguments)"
/>
<smart-combobox
label="Tags"
:hint="extras.operation === 'OR' ? 'The trigger can be fired by a property that has all of these tags instead' : 'The trigger won\'t be fired by a property that has any of these tags'"
class="mx-2"
multiple
chips
deletable-chips
:value="extras.tags"
@change="change(['extraTags', i, 'tags'], ...arguments)"
</v-col>
<v-col
cols="12"
md="6"
>
<smart-select
label="Event"
style="flex-basis: 300px;"
hint="What causes this trigger to fire"
:items="eventOptions"
:value="model.event"
:error-messages="errors.event"
@change="change('event', ...arguments)"
/>
<v-btn
icon
style="margin-top: -30px;"
@click="$emit('pull', {path: ['extraTags', i]})"
</v-col>
<v-col
cols="12"
md="6"
>
<computed-field
label="Condition"
hint="A calculation to determine if this trigger should fire"
placeholder="Always active"
persistent-placeholder
:model="model.condition"
:error-messages="errors.condition"
@change="({path, value, ack}) =>
$emit('change', {path: ['condition', ...path], value, ack})"
/>
</v-col>
<v-expand-transition>
<v-col
v-if="model.event === 'doActionProperty' || model.event === 'receiveActionProperty'"
cols="12"
md="6"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</div>
</v-slide-x-transition>
<computed-field
label="Condition"
hint="A caclulation to determine if this trigger should fire"
placeholder="Always active"
:model="model.condition"
:error-messages="errors.condition"
@change="({path, value, ack}) =>
$emit('change', {path: ['condition', ...path], value, ack})"
/>
<smart-select
label="Event Type"
style="flex-basis: 300px;"
hint="Which action event causes this trigger to fire"
:items="actionPropertyTypeOptions"
:value="model.actionPropertyType"
:error-messages="errors.actionPropertyType"
@change="change('actionPropertyType', ...arguments)"
/>
</v-col>
</v-expand-transition>
<v-col cols="12">
<tag-targeting
:model="model"
:errors="errors"
@change="e => $emit('change', e)"
@push="e => $emit('push', e)"
@pull="e => $emit('pull', e)"
/>
</v-col>
</v-row>
<inline-computation-field
class="mt-6"
label="Description"
hint="The rest of the description that doesn't fit in the summary goes here"
:model="model.description"
@@ -122,24 +84,8 @@
<form-sections>
<form-section
v-if="$slots.children"
name="Children"
name="Log"
>
<slot name="children" />
</form-section>
<form-section
name="Advanced"
>
<smart-combobox
label="Tags"
hint="This trigger's own tags"
multiple
chips
deletable-chips
:value="model.tags"
@change="change('tags', ...arguments)"
/>
<smart-switch
label="Don't show in log"
:value="model.silent"
@@ -147,6 +93,7 @@
@change="change('silent', ...arguments)"
/>
</form-section>
<slot />
</form-sections>
</div>
</template>
@@ -157,10 +104,12 @@ import FormSection from '/imports/client/ui/properties/forms/shared/FormSection.
import {
TriggerSchema, eventOptions, timingOptions, actionPropertyTypeOptions
} from '/imports/api/properties/Triggers.js';
import TagTargeting from '/imports/client/ui/properties/forms/shared/TagTargeting.vue';
export default {
components: {
FormSection,
TagTargeting,
},
mixins: [propertyFormMixin],
inject: {