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';
const magicSchools = [
@@ -13,7 +13,7 @@ const magicSchools = [
];
let SpellSchema = new SimpleSchema({})
.extend(AttackSchema)
.extend(ActionSchema)
.extend({
name: {
type: String,
@@ -29,6 +29,10 @@ let SpellSchema = new SimpleSchema({})
castWithoutSpellSlots: {
type: Boolean,
optional: true,
},
hasAttackRoll: {
type: Boolean,
optional: true,
},
// Spell lists that this spell appears on
spellLists: {
@@ -87,6 +91,11 @@ let SpellSchema = new SimpleSchema({})
defaultValue: 'abjuration',
allowedValues: magicSchools,
},
// Set better defaults for the action
actionType: {
type: String,
defaultValue: 'spell',
},
});
export { SpellSchema };

View File

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

View File

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

View File

@@ -100,30 +100,42 @@
:debounce-time="debounceTime"
@change="(value, ack) => $emit('change', {path: ['description'], value, ack})"
/>
<form-section
name="Advanced"
standalone
>
<v-combobox
label="Spell lists"
multiple
chips
deletable-chips
box
:value="model.spellLists"
:error-messages="errors.spellLists"
@change="(value) => $emit('change', {path: ['spellLists'], value})"
/>
</form-section>
<form-sections>
<form-section
name="Advanced"
>
<v-combobox
label="Spell lists"
multiple
chips
deletable-chips
box
:value="model.spellLists"
:error-messages="errors.spellLists"
@change="(value) => $emit('change', {path: ['spellLists'], value})"
/>
</form-section>
<form-section
name="Casting"
>
<action-form
v-bind="$props"
v-on="$listeners"
/>
</form-section>
</form-sections>
</div>
</template>
<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 {
components: {
FormSections,
FormSection,
ActionForm,
},
props: {
model: {

View File

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