Added action form, but without buffs
This commit is contained in:
@@ -26,10 +26,6 @@ let ActionSchema = schema({
|
||||
type: String,
|
||||
optional: true,
|
||||
},
|
||||
enabled: {
|
||||
type: Boolean,
|
||||
defaultValue: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
optional: true,
|
||||
@@ -44,6 +40,7 @@ let ActionSchema = schema({
|
||||
// Who is the action directed at
|
||||
target: {
|
||||
type: String,
|
||||
defaultValue: 'singleTarget',
|
||||
allowedValues: [
|
||||
'self',
|
||||
'singleTarget',
|
||||
|
||||
@@ -43,14 +43,9 @@ let StoredBuffSchema = new SimpleSchema({
|
||||
target: {
|
||||
type: String,
|
||||
allowedValues: [
|
||||
// the character who took the buff
|
||||
'self',
|
||||
// the singular `target` of the buff
|
||||
'target',
|
||||
// rolled once for `each` target
|
||||
'each',
|
||||
// rolled once and applied to `every` target
|
||||
'every'
|
||||
'self', // the character who took the buff
|
||||
'each', // rolled once for `each` target
|
||||
'every', // rolled once and applied to `every` target
|
||||
],
|
||||
},
|
||||
}).extend(BuffSchema);
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { Random } from 'meteor/random';
|
||||
import DAMAGE_TYPES from '/imports/constants/DAMAGE_TYPES.js';
|
||||
|
||||
const AdjustmentSchema = new SimpleSchema({
|
||||
// The calculation that determines the adjustment
|
||||
roll: {
|
||||
_id: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
autoValue(){
|
||||
if (this.isSet) return;
|
||||
return Random.id();
|
||||
}
|
||||
},
|
||||
// The roll that determines how much to damage the attribute
|
||||
damage: {
|
||||
type: String,
|
||||
optional: true,
|
||||
defaultValue: '1',
|
||||
},
|
||||
// Who this adjustment applies to
|
||||
target: {
|
||||
type: String,
|
||||
defaultValue: 'every',
|
||||
allowedValues: [
|
||||
// the character who took the action
|
||||
'self',
|
||||
// the singular `target` of the action
|
||||
'target',
|
||||
// rolled once for `each` target
|
||||
'each',
|
||||
// rolled once and applied to `every` target
|
||||
'every'
|
||||
'self', // the character who took the action
|
||||
'each', // rolled once for `each` target
|
||||
'every', // rolled once and applied to `every` target
|
||||
],
|
||||
},
|
||||
// The stat this rolls applies to, if damage type is set, this is ignored
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<template lang="html">
|
||||
<v-expansion-panel popout>
|
||||
<v-expansion-panel-content>
|
||||
<div slot="header" class="subheading">
|
||||
Advanced
|
||||
</div>
|
||||
<v-card-text>
|
||||
<slot/>
|
||||
</v-card-text>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
34
app/imports/ui/components/forms/FormSection.vue
Normal file
34
app/imports/ui/components/forms/FormSection.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template lang="html">
|
||||
<form-sections v-if="standalone">
|
||||
<v-expansion-panel-content>
|
||||
<div slot="header" class="subheading">
|
||||
{{name}}
|
||||
</div>
|
||||
<v-card-text>
|
||||
<slot/>
|
||||
</v-card-text>
|
||||
</v-expansion-panel-content>
|
||||
</form-sections>
|
||||
<v-expansion-panel-content v-else>
|
||||
<div slot="header" class="subheading">
|
||||
{{name}}
|
||||
</div>
|
||||
<v-card-text>
|
||||
<slot/>
|
||||
</v-card-text>
|
||||
</v-expansion-panel-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormSections from '/imports/ui/components/forms/FormSections.vue';
|
||||
export default {
|
||||
components: {
|
||||
FormSections,
|
||||
},
|
||||
props: {
|
||||
name: String,
|
||||
standalone: Boolean,
|
||||
},
|
||||
}
|
||||
export { FormSections };
|
||||
</script>
|
||||
9
app/imports/ui/components/forms/FormSections.vue
Normal file
9
app/imports/ui/components/forms/FormSections.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template lang="html">
|
||||
<v-expansion-panel popout expand>
|
||||
<slot/>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
@@ -32,6 +32,22 @@ const schemaFormMixin = {
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
push(modifier, ack){
|
||||
for (let key in modifier){
|
||||
this.model[key].push(modifier[key]);
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
changeAtIndex(field, index, modifier, ack){
|
||||
for (let key in modifier){
|
||||
this.$set(this.model[field][index], key, modifier[key])
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
removeAtIndex(field, index, ack){
|
||||
this.model[field].splice(index, 1);
|
||||
if (ack) ack();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
171
app/imports/ui/creature/properties/actions/ActionForm.vue
Normal file
171
app/imports/ui/creature/properties/actions/ActionForm.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template lang="html">
|
||||
<div class="action-form">
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="model.name"
|
||||
@change="(name, ack) => $emit('change', {name}, ack)"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<smart-select
|
||||
label="Type"
|
||||
:items="actionTypes"
|
||||
:value="model.type"
|
||||
:error-messages="errors.type"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(type, ack) => $emit('change', {type}, ack)"
|
||||
:hint="actionTypeHints[model.type]"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<form-sections>
|
||||
<form-section name="Advanced">
|
||||
<smart-select
|
||||
label="Target"
|
||||
style="flex-basis: 300px;"
|
||||
:items="targetOptions"
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(target, ack) => $emit('change', {target}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<div class="layout row wrap">
|
||||
<text-field
|
||||
label="Uses"
|
||||
hint="How many times this action can be used before needing to be reset"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.uses"
|
||||
@change="(uses, ack) => $emit('change', {uses}, ack)"
|
||||
:error-messages="errors.uses"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Uses used"
|
||||
type="number"
|
||||
hint="How many times this action has already been used"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.usesUsed"
|
||||
@change="(uses, ack) => $emit('change', {uses}, ack)"
|
||||
:error-messages="errors.uses"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
<smart-select
|
||||
label="Reset"
|
||||
clearable
|
||||
style="flex-basis: 300px;"
|
||||
:items="resetOptions"
|
||||
:value="model.reset"
|
||||
:error-messages="errors.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(reset, ack) => $emit('change', {reset}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</form-section>
|
||||
<form-section name="Adjustments">
|
||||
<div class="caption">
|
||||
Adjustments can be used to automatically spend resources or deal
|
||||
damage when taking an action.
|
||||
They apply damage to an attribute each time the action is taken.
|
||||
</div>
|
||||
<adjustment-list-form
|
||||
:model="model.adjustments"
|
||||
:parent-target="model.target"
|
||||
@push="(adjustments, ack) => $emit('push', {adjustments}, ack)"
|
||||
@changeAtIndex="(index, modifier, ack) => $emit('changeAtIndex', 'adjustments', index, modifier, ack)"
|
||||
@removeAtIndex="(index, ack) => $emit('removeAtIndex', 'adjustments', index, ack)"
|
||||
/>
|
||||
</form-section>
|
||||
</form-sections>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormSection, {FormSections} from '/imports/ui/components/forms/FormSection.vue';
|
||||
import AdjustmentListForm from '/imports/ui/creature/properties/adjustments/AdjustmentListForm.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FormSection,
|
||||
FormSections,
|
||||
AdjustmentListForm,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){
|
||||
let data = {
|
||||
actionTypes: [
|
||||
{
|
||||
text: 'Action',
|
||||
value: 'action',
|
||||
}, {
|
||||
text: 'Bonus action',
|
||||
value: 'bonus',
|
||||
}, {
|
||||
text: 'Attack action',
|
||||
value: 'attack',
|
||||
help: 'Attack actions replace a single attack when you choose to use your Action to attack',
|
||||
}, {
|
||||
text: 'Reaction',
|
||||
value: 'reaction',
|
||||
}, {
|
||||
text: 'Free action',
|
||||
value: 'free',
|
||||
help: 'You can take one free action on your turn without using an action or bonus action'
|
||||
}, {
|
||||
text: 'Long action',
|
||||
value: 'long',
|
||||
help: 'Long actions take longer than one turn to complete'
|
||||
},
|
||||
],
|
||||
targetOptions: [
|
||||
{
|
||||
text: 'Self',
|
||||
value: 'self',
|
||||
}, {
|
||||
text: 'Single target',
|
||||
value: 'singleTarget',
|
||||
}, {
|
||||
text: 'Multiple targets',
|
||||
value: 'multipleTargets',
|
||||
},
|
||||
],
|
||||
resetOptions: [
|
||||
{
|
||||
text: 'Short rest',
|
||||
value: 'shortRest',
|
||||
}, {
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
],
|
||||
};
|
||||
data.actionTypeHints = {};
|
||||
data.actionTypes.forEach(type => {
|
||||
data.actionTypeHints[type.value] = type.help;
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.no-flex {
|
||||
flex: initial;
|
||||
}
|
||||
.layout.row.wrap {
|
||||
margin-right: -8px;
|
||||
}
|
||||
.layout.row.wrap > *{
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,105 @@
|
||||
<template lang="html">
|
||||
<div class="layout row align-center">
|
||||
<div style="flex-grow: 1;">
|
||||
<div class="layout row wrap">
|
||||
<text-field
|
||||
label="Attribute"
|
||||
hint="The attribute this adjustment will apply to"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.stat"
|
||||
@change="(stat, ack) => $emit('change', {stat}, ack)"
|
||||
:error-messages="errors.stat"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Damage"
|
||||
hint="The amount of damage to apply to the selected stat, can be a calculation or roll"
|
||||
style="flex-basis: 300px;"
|
||||
:value="model.damage"
|
||||
@change="(damage, ack) => $emit('change', {damage}, ack)"
|
||||
:error-messages="errors.damage"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
<smart-select
|
||||
v-if="parentTarget !== 'self'"
|
||||
label="Target"
|
||||
:hint="targetOptionHint"
|
||||
:items="targetOptions"
|
||||
:value="model.target"
|
||||
:error-messages="errors.target"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(target, ack) => $emit('change', {target}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<v-btn outline icon large class="ma-3" @click="$emit('remove')">
|
||||
<v-icon>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
parentTarget: {
|
||||
type: String,
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
computed: {
|
||||
targetOptions(){
|
||||
if (this.parentTarget === 'singleTarget') {
|
||||
return [
|
||||
{
|
||||
text: 'Self',
|
||||
value: 'self',
|
||||
}, {
|
||||
text: 'Target',
|
||||
value: 'every',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
text: 'Self',
|
||||
value: 'self',
|
||||
}, {
|
||||
text: 'Roll once for each target',
|
||||
value: 'each',
|
||||
}, {
|
||||
text: 'Roll once and apply to every target',
|
||||
value: 'every',
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
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',
|
||||
};
|
||||
if (this.parentTarget === 'singleTarget'){
|
||||
hints.each = hints.target;
|
||||
hints.every = hints.target;
|
||||
}
|
||||
return hints[this.model.target];
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<v-slide-x-transition group>
|
||||
<div
|
||||
v-for="(adjustment, i) in model"
|
||||
:key="adjustment._id || i"
|
||||
>
|
||||
<v-divider v-if="i !== 0"/>
|
||||
<adjustment-form
|
||||
class="mt-4"
|
||||
:model="adjustment"
|
||||
:parent-target="parentTarget"
|
||||
@change="(modifier, ack) => $emit('changeAtIndex', i, modifier, ack)"
|
||||
@remove="(ack) => $emit('removeAtIndex', i, ack)"
|
||||
/>
|
||||
</div>
|
||||
</v-slide-x-transition>
|
||||
<div class="layout row justify-end">
|
||||
<v-btn
|
||||
:loading="addAdjustmentLoading"
|
||||
:disabled="addAdjustmentLoading"
|
||||
outline
|
||||
@click="addAdjustment"
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
Add Adjustment
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AdjustmentForm from '/imports/ui/creature/properties/adjustments/AdjustmentForm.vue';
|
||||
import AdjustmentSchema from '/imports/api/creature/subSchemas/AdjustmentSchema.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AdjustmentForm,
|
||||
},
|
||||
data(){return {
|
||||
addAdjustmentLoading: false,
|
||||
}},
|
||||
methods: {
|
||||
acknowledgeAddAdjustment(){
|
||||
this.addAdjustmentLoading = false;
|
||||
},
|
||||
addAdjustment(){
|
||||
this.addAdjustmentLoading = true;
|
||||
this.$emit('push', AdjustmentSchema.clean({}), this.acknowledgeAddAdjustment);
|
||||
},
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
parentTarget: {
|
||||
type: String,
|
||||
},
|
||||
debounceTime: Number,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -40,7 +40,7 @@
|
||||
:hint="attributeTypeHints[model.type]"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<advanced-section>
|
||||
<form-section name="Advanced" standalone>
|
||||
<div class="layout column align-center">
|
||||
<v-switch
|
||||
label="Allow decimal values"
|
||||
@@ -86,15 +86,16 @@
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
</advanced-section>
|
||||
</form-section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AdvancedSection from '/imports/ui/components/forms/AdvancedSection.vue';
|
||||
import FormSection from '/imports/ui/components/forms/FormSection.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AdvancedSection,
|
||||
FormSection,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
@@ -149,7 +150,7 @@
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
]
|
||||
],
|
||||
};
|
||||
data.attributeTypeHints = {};
|
||||
data.attributeTypes.forEach(type => {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import ActionForm from '/imports/ui/creature/properties/actions/ActionForm.vue';
|
||||
import AttributeForm from '/imports/ui/creature/properties/attributes/AttributeForm.vue';
|
||||
|
||||
export default {
|
||||
action: ActionForm,
|
||||
attribute: AttributeForm,
|
||||
};
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<template lang="html">
|
||||
<dialog-base :override-back-button="() => $emit('back')">
|
||||
<div slot="toolbar">Add {{propertyName}}</div>
|
||||
<v-card-text>
|
||||
<component
|
||||
v-if="type"
|
||||
:is="type"
|
||||
class="library-node-form"
|
||||
:model="model"
|
||||
:errors="errors"
|
||||
@change="change"
|
||||
/>
|
||||
</v-card-text>
|
||||
<component
|
||||
v-if="type"
|
||||
:is="type"
|
||||
class="library-node-form"
|
||||
:model="model"
|
||||
:errors="errors"
|
||||
@change="change"
|
||||
@push="push"
|
||||
@changeAtIndex="changeAtIndex"
|
||||
@removeAtIndex="removeAtIndex"
|
||||
/>
|
||||
<div
|
||||
slot="actions"
|
||||
class="layout row justify-end"
|
||||
@@ -54,6 +55,10 @@ export default {
|
||||
model.libraryNodeType = newType;
|
||||
this.model = model;
|
||||
},
|
||||
model(newModel){
|
||||
console.log('model changed');
|
||||
console.log(newModel);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insert(){
|
||||
|
||||
Reference in New Issue
Block a user