Made spells into a special kind of action

This commit is contained in:
Thaum Rystra
2020-04-16 15:21:31 +02:00
parent e06196a54c
commit 1717ee4bc7
7 changed files with 389 additions and 251 deletions

View File

@@ -1,4 +1,4 @@
import { AttackSchema } from '/imports/api/properties/Attacks.js'; import { ActionSchema } from '/imports/api/properties/Actions.js';
import SimpleSchema from 'simpl-schema'; import SimpleSchema from 'simpl-schema';
const magicSchools = [ const magicSchools = [
@@ -13,7 +13,7 @@ const magicSchools = [
]; ];
let SpellSchema = new SimpleSchema({}) let SpellSchema = new SimpleSchema({})
.extend(AttackSchema) .extend(ActionSchema)
.extend({ .extend({
name: { name: {
type: String, type: String,
@@ -29,6 +29,10 @@ let SpellSchema = new SimpleSchema({})
castWithoutSpellSlots: { castWithoutSpellSlots: {
type: Boolean, type: Boolean,
optional: true, optional: true,
},
hasAttackRoll: {
type: Boolean,
optional: true,
}, },
// Spell lists that this spell appears on // Spell lists that this spell appears on
spellLists: { spellLists: {
@@ -87,6 +91,11 @@ let SpellSchema = new SimpleSchema({})
defaultValue: 'abjuration', defaultValue: 'abjuration',
allowedValues: magicSchools, allowedValues: magicSchools,
}, },
// Set better defaults for the action
actionType: {
type: String,
defaultValue: 'spell',
},
}); });
export { SpellSchema }; export { SpellSchema };

View File

@@ -1,92 +1,115 @@
<template> <template>
<div class="character-sheet layout column"> <div class="character-sheet layout column">
<v-toolbar <v-toolbar
app clipped-left app
:color="character.color || 'secondary'" clipped-left
:dark="isDarkColor(character.color || theme.primary)" :color="character.color || 'secondary'"
> :dark="isDarkColor(character.color || theme.primary)"
<v-btn v-if="showMenuButton" flat icon @click="toggleDrawer"> >
<v-btn
v-if="showMenuButton"
flat
icon
@click="toggleDrawer"
>
<v-icon>menu</v-icon> <v-icon>menu</v-icon>
</v-btn> </v-btn>
<div class="flex">{{character.name}}</div> <div class="flex">
<v-btn flat icon @click="recompute(character._id)"> {{ character.name }}
</div>
<v-btn
flat
icon
@click="recompute(character._id)"
>
<v-icon>refresh</v-icon> <v-icon>refresh</v-icon>
</v-btn> </v-btn>
<v-menu bottom left transition="slide-y-transition" data-id="creature-menu"> <v-menu
<template v-slot:activator="{ on }"> bottom
<v-btn icon v-on="on"> left
<v-icon>more_vert</v-icon> transition="slide-y-transition"
</v-btn> data-id="creature-menu"
</template> >
<v-list> <template #activator="{ on }">
<v-list-tile @click="deleteCharacter"> <v-btn
<v-list-tile-title> icon
<v-icon>delete</v-icon> Delete v-on="on"
</v-list-tile-title> >
</v-list-tile> <v-icon>more_vert</v-icon>
<v-list-tile @click="showCharacterForm"> </v-btn>
<v-list-tile-title> </template>
<v-icon>create</v-icon> Edit details <v-list>
</v-list-tile-title> <v-list-tile @click="deleteCharacter">
</v-list-tile> <v-list-tile-title>
<v-list-tile @click="showShareDialog"> <v-icon>delete</v-icon> Delete
<v-list-tile-title> </v-list-tile-title>
<v-icon>share</v-icon> Sharing </v-list-tile>
</v-list-tile-title> <v-list-tile @click="showCharacterForm">
</v-list-tile> <v-list-tile-title>
</v-list> <v-icon>create</v-icon> Edit details
</v-menu> </v-list-tile-title>
<v-tabs </v-list-tile>
v-model="tab" <v-list-tile @click="showShareDialog">
slot="extension" <v-list-tile-title>
centered <v-icon>share</v-icon> Sharing
grow </v-list-tile-title>
> </v-list-tile>
<v-tab> </v-list>
Stats </v-menu>
</v-tab> <v-tabs
<v-tab> slot="extension"
Features v-model="tab"
</v-tab> centered
<v-tab> grow
Inventory >
</v-tab> <v-tab>
<v-tab> Stats
Spells </v-tab>
</v-tab> <v-tab>
<v-tab> Features
Persona </v-tab>
</v-tab> <v-tab>
<v-tab> Inventory
Tree </v-tab>
</v-tab> <v-tab>
</v-tabs> Spells
</v-tab>
<v-tab>
Persona
</v-tab>
<v-tab>
Tree
</v-tab>
</v-tabs>
</v-toolbar> </v-toolbar>
<v-content class="flex" v-if="$subReady.singleCharacter"> <v-content
<v-tabs-items v-model="tab"> v-if="$subReady.singleCharacter"
<v-tab-item> class="flex"
<stats-tab :creature-id="creatureId"/> >
</v-tab-item> <v-tabs-items v-model="tab">
<v-tab-item> <v-tab-item>
<features-tab :creature-id="creatureId"/> <stats-tab :creature-id="creatureId" />
</v-tab-item> </v-tab-item>
<v-tab-item> <v-tab-item>
<inventory-tab :creature-id="creatureId"/> <features-tab :creature-id="creatureId" />
</v-tab-item> </v-tab-item>
<v-tab-item> <v-tab-item>
<spells-tab :creature-id="creatureId"/> <inventory-tab :creature-id="creatureId" />
</v-tab-item> </v-tab-item>
<v-tab-item> <v-tab-item>
<persona-tab :creature-id="creatureId"/> <spells-tab :creature-id="creatureId" />
</v-tab-item> </v-tab-item>
<v-tab-item> <v-tab-item>
<tree-tab :creature-id="creatureId"/> <persona-tab :creature-id="creatureId" />
</v-tab-item> </v-tab-item>
</v-tabs-items> <v-tab-item>
<tree-tab :creature-id="creatureId" />
</v-tab-item>
</v-tabs-items>
</v-content>
<v-content v-else>
<v-progress-circular indeterminate />
</v-content> </v-content>
<v-content v-else>
<v-progress-circular indeterminate />
</v-content>
</div> </div>
</template> </template>
@@ -94,7 +117,7 @@
import Creatures from '/imports/api/creature/Creatures.js'; import Creatures from '/imports/api/creature/Creatures.js';
import removeCreature from '/imports/api/creature/removeCreature.js'; import removeCreature from '/imports/api/creature/removeCreature.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js'; import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import { mapMutations } from "vuex"; import { mapMutations } from 'vuex';
import { theme } from '/imports/ui/theme.js'; import { theme } from '/imports/ui/theme.js';
import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue'; import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue';
import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue'; import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue';
@@ -105,10 +128,6 @@
import { recomputeCreature } from '/imports/api/creature/computation/recomputeCreature.js'; import { recomputeCreature } from '/imports/api/creature/computation/recomputeCreature.js';
export default { export default {
props: {
showMenuButton: Boolean,
creatureId: String,
},
components: { components: {
StatsTab, StatsTab,
FeaturesTab, FeaturesTab,
@@ -117,13 +136,20 @@
PersonaTab, PersonaTab,
TreeTab, TreeTab,
}, },
props: {
showMenuButton: Boolean,
creatureId: {
type: String,
required: true,
},
},
data(){return { data(){return {
theme, theme,
tab: 0, tab: 0,
}}, }},
methods: { methods: {
...mapMutations([ ...mapMutations([
"toggleDrawer", 'toggleDrawer',
]), ]),
recompute(charId){ recompute(charId){
recomputeCreature.call({charId}); recomputeCreature.call({charId});
@@ -160,7 +186,7 @@
}, },
callback(confirmation){ callback(confirmation){
if(!confirmation) return; if(!confirmation) return;
removeCreature.call({charId: that.creatureId}, (error, result) => { removeCreature.call({charId: that.creatureId}, (error) => {
if (error) { if (error) {
console.error(error); console.error(error);
} else { } else {
@@ -174,7 +200,7 @@
}, },
meteor: { meteor: {
$subscribe: { $subscribe: {
'singleCharacter'(){ 'singleCharacter'(){
return [this.creatureId]; return [this.creatureId];
}, },
}, },
@@ -182,6 +208,9 @@
return Creatures.findOne(this.creatureId) || {}; return Creatures.findOne(this.creatureId) || {};
}, },
}, },
provide: {
creature: this.character,
}
} }
</script> </script>

View File

@@ -1,130 +1,172 @@
<template lang="html"> <template lang="html">
<div class="stats-tab ma-2"> <div class="stats-tab ma-2">
<div class="px-2 pt-2">
<health-bar-card-container :creature-id="creatureId" />
</div>
<div class="px-2 pt-2"> <column-layout>
<health-bar-card-container :creature-id="creatureId"/> <div class="ability-scores">
</div> <v-card>
<v-list>
<template v-for="(ability, index) in abilities">
<v-divider
v-if="index !== 0"
:key="index"
/>
<ability-list-tile
:key="ability._id"
v-bind="ability"
:data-id="ability._id"
@click="clickProperty({_id: ability._id})"
/>
</template>
</v-list>
</v-card>
</div>
<column-layout> <div
v-for="stat in stats"
:key="stat._id"
class="stat"
>
<attribute-card
v-bind="stat"
:data-id="stat._id"
@click="clickProperty({_id: stat._id})"
/>
</div>
<div class="ability-scores"> <div
<v-card> v-for="modifier in modifiers"
<v-list> :key="modifier._id"
<template v-for="(ability, index) in abilities"> class="modifier"
<v-divider v-if="index !== 0"/> >
<ability-list-tile <attribute-card
v-bind="ability" modifier
:key="ability._id" v-bind="modifier"
:data-id="ability._id" :data-id="modifier._id"
@click="clickProperty({_id: ability._id})" @click="clickProperty({_id: modifier._id})"
/> />
</template> </div>
</v-list>
</v-card>
</div>
<div v-for="stat in stats" class="stat" :key="stat._id"> <div
<attribute-card v-for="check in checks"
v-bind="stat" :key="check._id"
:data-id="stat._id" class="check"
@click="clickProperty({_id: stat._id})" >
/> <attribute-card
</div> modifier
v-bind="check"
:data-id="check._id"
@click="clickProperty({_id: check._id})"
/>
</div>
<div v-for="modifier in modifiers" class="modifier" :key="modifier._id"> <div class="hit-dice">
<attribute-card modifier <v-card>
v-bind="modifier" <v-list>
:data-id="modifier._id" <v-subheader>Hit Dice</v-subheader>
@click="clickProperty({_id: modifier._id})" <template v-for="(hitDie, index) in hitDice">
/> <v-divider
</div> v-if="index !== 0"
:key="hitDie._id + 'divider'"
/>
<hit-dice-list-tile
:key="hitDie._id"
v-bind="hitDie"
:data-id="hitDie._id"
@click="clickProperty({_id: hitDie._id})"
@change="e => incrementChange(hitDie._id, e)"
/>
</template>
</v-list>
</v-card>
</div>
<div v-for="check in checks" class="check" :key="check._id"> <div
<attribute-card modifier v-show="true"
v-bind="check" class="saving-throws"
:data-id="check._id" >
@click="clickProperty({_id: check._id})" <v-card>
/> <v-list>
</div> <v-subheader>Saving Throws</v-subheader>
<skill-list-tile
v-for="save in savingThrows"
:key="save._id"
v-bind="save"
:data-id="save._id"
@click="clickProperty({_id: save._id})"
/>
</v-list>
</v-card>
</div>
<div class="hit-dice"> <div class="skills">
<v-card> <v-card>
<v-list> <v-list>
<v-subheader>Hit Dice</v-subheader> <v-subheader>Skills</v-subheader>
<template v-for="(hitDie, index) in hitDice"> <skill-list-tile
<v-divider v-if="index !== 0" :key="hitDice._id + 'divider'"/> v-for="skill in skills"
<hit-dice-list-tile :key="skill._id"
v-bind="hitDie" v-bind="skill"
:data-id="hitDie._id" :data-id="skill._id"
:key="hitDice._id" @click="clickProperty({_id: skill._id})"
@click="clickProperty({_id: hitDie._id})" />
@change="e => incrementChange(hitDie._id, e)" </v-list>
/> </v-card>
</template> </div>
</v-list>
</v-card>
</div>
<div class="saving-throws" v-show="true"> <div
<v-card> v-for="resource in resources"
<v-list> :key="resource._id"
<v-subheader>Saving Throws</v-subheader> class="resource"
<skill-list-tile >
v-for="save in savingThrows" <resource-card
v-bind="save" v-bind="resource"
:key="save._id" :data-id="resource._id"
:data-id="save._id" @click="clickProperty({_id: resource._id})"
@click="clickProperty({_id: save._id})" @change="e => incrementChange(resource._id, e)"
/> />
</v-list> </div>
</v-card>
</div>
<div class="skills"> <div
<v-card> v-if="spellSlots.length"
<v-list> class="spell-slots"
<v-subheader>Skills</v-subheader> >
<skill-list-tile <v-card>
v-for="skill in skills" <v-list>
v-bind="skill" <v-subheader>Spell Slots</v-subheader>
:key="skill._id" <spell-slot-list-tile
:data-id="skill._id" v-for="spellSlot in spellSlots"
@click="clickProperty({_id: skill._id})" :key="spellSlot._id"
/> v-bind="spellSlot"
</v-list> :data-id="spellSlot._id"
</v-card> @click="clickProperty({_id: spellSlot._id})"
</div> @change="e => incrementChange(spellSlot._id, e)"
/>
</v-list>
</v-card>
</div>
<div <div
v-for="resource in resources" v-if="actions.length"
:key="resource._id" class="actions"
class="resource" >
> <v-card>
<resource-card <v-list>
v-bind="resource" <v-subheader>Actions</v-subheader>
:data-id="resource._id" <action-list-tile
@click="clickProperty({_id: resource._id})" v-for="action in actions"
@change="e => incrementChange(resource._id, e)" :key="action._id"
/> :model="action"
</div> :data-id="action._id"
@click="clickProperty({_id: action._id})"
<div class="spell-slots" v-if="spellSlots.length"> />
<v-card> </v-list>
<v-list> </v-card>
<v-subheader>Spell Slots</v-subheader> </div>
<spell-slot-list-tile </column-layout>
v-for="spellSlot in spellSlots" </div>
v-bind="spellSlot"
:key="spellSlot._id"
:data-id="spellSlot._id"
@click="clickProperty({_id: spellSlot._id})"
@change="e => incrementChange(spellSlot._id, e)"
/>
</v-list>
</v-card>
</div>
</column-layout>
</div>
</template> </template>
<script> <script>
@@ -137,8 +179,7 @@
import SkillListTile from '/imports/ui/properties/components/skills/SkillListTile.vue'; import SkillListTile from '/imports/ui/properties/components/skills/SkillListTile.vue';
import ResourceCard from '/imports/ui/properties/components/attributes/ResourceCard.vue'; import ResourceCard from '/imports/ui/properties/components/attributes/ResourceCard.vue';
import SpellSlotListTile from '/imports/ui/properties/components/attributes/SpellSlotListTile.vue'; import SpellSlotListTile from '/imports/ui/properties/components/attributes/SpellSlotListTile.vue';
import ActionListTile from '/imports/ui/properties/components/actions/ActionListTile.vue';
let adjustAttribute = insertAttribute = () => console.error("this shit isn't defined");
const getAttributeOfType = function(charId, type){ const getAttributeOfType = function(charId, type){
return CreatureProperties.find({ return CreatureProperties.find({
@@ -164,9 +205,6 @@
}; };
export default { export default {
props: {
creatureId: String,
},
components: { components: {
AbilityListTile, AbilityListTile,
AttributeCard, AttributeCard,
@@ -176,6 +214,13 @@
SkillListTile, SkillListTile,
ResourceCard, ResourceCard,
SpellSlotListTile, SpellSlotListTile,
ActionListTile,
},
props: {
creatureId: {
type: String,
required: true,
},
}, },
meteor: { meteor: {
abilities(){ abilities(){
@@ -247,6 +292,14 @@
sort: {order: 1}, sort: {order: 1},
}); });
}, },
actions(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'action',
}, {
sort: {order: 1},
});
},
}, },
methods: { methods: {
clickProperty({_id}){ clickProperty({_id}){

View File

@@ -0,0 +1,34 @@
<template lang="html">
<v-list-tile
class="ability-list-tile"
v-on="hasClickListener ? {click} : {}"
>
<v-list-tile-content>
{{ model.name }}
</v-list-tile-content>
</v-list-tile>
</template>
<script>
export default {
props: {
model: {
type: Object,
required: true,
}
},
computed: {
hasClickListener(){
return this.$listeners && this.$listeners.click
},
},
methods: {
click(e){
this.$emit('click', e);
},
}
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,22 +1,23 @@
<template lang="html"> <template lang="html">
<v-list-tile class="ability-list-tile" v-on="hasClickListener ? {click} : {}"> <v-list-tile
class="ability-list-tile"
v-on="hasClickListener ? {click} : {}"
>
<v-list-tile-action class="mr-4">
<div class="display-1 mod">
{{ numberToSignedString(mod) }}
</div>
<div class="title value">
{{ value }}
</div>
</v-list-tile-action>
<v-list-tile-action class="mr-4"> <v-list-tile-content>
<div class="display-1 mod"> <v-list-tile-title>
{{numberToSignedString(mod)}} {{ name }}
</div> </v-list-tile-title>
<div class="title value"> </v-list-tile-content>
{{value}} </v-list-tile>
</div>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{name}}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template> </template>
<script> <script>
@@ -27,16 +28,16 @@ export default {
mod: Number, mod: Number,
name: String, name: String,
}, },
computed: {
hasClickListener(){
return this.$listeners && this.$listeners.click
},
},
methods: { methods: {
numberToSignedString, numberToSignedString,
click(e){ click(e){
this.$emit('click', e); this.$emit('click', e);
}, },
},
computed: {
hasClickListener(){
return this.$listeners && this.$listeners.click
},
} }
} }
</script> </script>

View File

@@ -100,30 +100,42 @@
:debounce-time="debounceTime" :debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['description'], value, ack})" @change="(value, ack) => $emit('change', {path: ['description'], value, ack})"
/> />
<form-section <form-sections>
name="Advanced" <form-section
standalone name="Advanced"
> >
<v-combobox <v-combobox
label="Spell lists" label="Spell lists"
multiple multiple
chips chips
deletable-chips deletable-chips
box box
:value="model.spellLists" :value="model.spellLists"
:error-messages="errors.spellLists" :error-messages="errors.spellLists"
@change="(value) => $emit('change', {path: ['spellLists'], value})" @change="(value) => $emit('change', {path: ['spellLists'], value})"
/> />
</form-section> </form-section>
<form-section
name="Casting"
>
<action-form
v-bind="$props"
v-on="$listeners"
/>
</form-section>
</form-sections>
</div> </div>
</template> </template>
<script> <script>
import FormSection from '/imports/ui/properties/forms/shared/FormSection.vue'; import FormSection, { FormSections } from '/imports/ui/properties/forms/shared/FormSection.vue';
import ActionForm from '/imports/ui/properties/forms/ActionForm.vue'
export default { export default {
components: { components: {
FormSections,
FormSection, FormSection,
ActionForm,
}, },
props: { props: {
model: { model: {

View File

@@ -68,7 +68,7 @@
} }
], ],
"parserOptions": { "parserOptions": {
"ecmaVersion": 6 "ecmaVersion": 2018
}, },
"env": { "env": {
"es6": true, "es6": true,