Added action form, but without buffs

This commit is contained in:
Stefan Zermatten
2019-07-19 14:07:22 +02:00
parent 0c002ae5cd
commit a0dc36557c
13 changed files with 444 additions and 57 deletions

View File

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

View File

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

View File

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

View File

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

View 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>

View File

@@ -0,0 +1,9 @@
<template lang="html">
<v-expansion-panel popout expand>
<slot/>
</v-expansion-panel>
</template>
<script>
export default {}
</script>

View File

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

View 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>

View File

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

View File

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

View File

@@ -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 => {

View File

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

View File

@@ -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(){