Merge branch 'version-2' into version-2-tabletop
This commit is contained in:
@@ -38,9 +38,7 @@
|
||||
:disabled="model.insufficientResources || !context.editPermission || !!targetingError"
|
||||
@click.stop="doAction"
|
||||
>
|
||||
<property-icon
|
||||
:model="model"
|
||||
/>
|
||||
<property-icon :model="model" />
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
@@ -50,9 +48,7 @@
|
||||
@mouseleave="hovering = false"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<div
|
||||
class="action-title my-1"
|
||||
>
|
||||
<div class="action-title my-1">
|
||||
{{ model.name || propertyName }}
|
||||
</div>
|
||||
<div class="action-sub-title layout align-center">
|
||||
@@ -97,10 +93,15 @@
|
||||
/>
|
||||
</template>
|
||||
<template v-if="model.summary">
|
||||
<markdown-text
|
||||
:markdown="model.summary.value || model.summary.text"
|
||||
/>
|
||||
<markdown-text :markdown="model.summary.value || model.summary.text" />
|
||||
</template>
|
||||
<v-divider v-if="children && children.length" />
|
||||
<tree-node-list
|
||||
v-if="children && children.length"
|
||||
start-expanded
|
||||
:children="children"
|
||||
@selected="e => $emit('sub-click', e)"
|
||||
/>
|
||||
</div>
|
||||
<card-highlight :active="hovering" />
|
||||
</v-card>
|
||||
@@ -115,8 +116,12 @@ import ItemConsumedView from '/imports/ui/properties/components/actions/ItemCons
|
||||
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
||||
import RollPopup from '/imports/ui/components/RollPopup.vue';
|
||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||
import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
|
||||
import TreeNodeList from '/imports/ui/components/tree/TreeNodeList.vue';
|
||||
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { some } from 'lodash';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -125,7 +130,8 @@ export default {
|
||||
MarkdownText,
|
||||
PropertyIcon,
|
||||
RollPopup,
|
||||
CardHighlight
|
||||
CardHighlight,
|
||||
TreeNodeList,
|
||||
},
|
||||
inject: {
|
||||
context: {
|
||||
@@ -147,20 +153,22 @@ export default {
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data(){return {
|
||||
activated: undefined,
|
||||
doActionLoading: false,
|
||||
hovering: false,
|
||||
}},
|
||||
data() {
|
||||
return {
|
||||
activated: undefined,
|
||||
doActionLoading: false,
|
||||
hovering: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rollBonus(){
|
||||
rollBonus() {
|
||||
if (!this.model.attackRoll) return;
|
||||
return numberToSignedString(this.model.attackRoll.value);
|
||||
},
|
||||
rollBonusTooLong(){
|
||||
rollBonusTooLong() {
|
||||
return this.rollBonus && this.rollBonus.length > 3;
|
||||
},
|
||||
propertyName(){
|
||||
propertyName() {
|
||||
return getPropertyName(this.model.type);
|
||||
},
|
||||
cardClasses() {
|
||||
@@ -185,12 +193,41 @@ export default {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
children() {
|
||||
const indicesOfTerminatingProps = [];
|
||||
const decendants = CreatureProperties.find({
|
||||
'ancestors.id': this.model._id,
|
||||
'removed': { $ne: true },
|
||||
}, {
|
||||
sort: {order: 1}
|
||||
}).map(prop => {
|
||||
// Get all the props we don't want to show the decendants of and
|
||||
// where they might appear in the ancestor list
|
||||
if (prop.type === 'buff' || prop.type === 'folder') {
|
||||
indicesOfTerminatingProps.push({
|
||||
id: prop._id,
|
||||
ancestorIndex: prop.ancestors.length,
|
||||
});
|
||||
}
|
||||
return prop;
|
||||
}).filter(prop => {
|
||||
// Filter out folders entirely
|
||||
if (prop.type === 'folder') return false;
|
||||
// Filter out decendants of terminating props
|
||||
return !some(indicesOfTerminatingProps, buffIndex => {
|
||||
return prop.ancestors[buffIndex.ancestorIndex]?.id === buffIndex.id;
|
||||
});
|
||||
});
|
||||
return nodeArrayToTree(decendants);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
doAction({advantage}){
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
doAction({ advantage }) {
|
||||
this.doActionLoading = true;
|
||||
this.shwing();
|
||||
doAction.call({
|
||||
@@ -201,13 +238,13 @@ export default {
|
||||
}
|
||||
}, error => {
|
||||
this.doActionLoading = false;
|
||||
if (error){
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({text: error.reason});
|
||||
snackbar({ text: error.reason });
|
||||
}
|
||||
});
|
||||
},
|
||||
shwing(){
|
||||
shwing() {
|
||||
this.activated = true;
|
||||
setTimeout(() => {
|
||||
this.activated = undefined;
|
||||
@@ -222,9 +259,11 @@ export default {
|
||||
transition: box-shadow .4s cubic-bezier(0.25, 0.8, 0.25, 1),
|
||||
transform 0.075s ease;
|
||||
}
|
||||
|
||||
.action-card.active {
|
||||
transform: scale(0.92);
|
||||
}
|
||||
|
||||
.action-title {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
@@ -235,9 +274,10 @@ export default {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: .3s cubic-bezier(.25,.8,.5,1);
|
||||
transition: .3s cubic-bezier(.25, .8, .5, 1);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action-sub-title {
|
||||
color: #9e9e9e;
|
||||
flex-grow: 0;
|
||||
@@ -249,15 +289,19 @@ export default {
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action-child {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.theme--light.muted-text {
|
||||
color: rgba(0,0,0,.3) !important;
|
||||
color: rgba(0, 0, 0, .3) !important;
|
||||
}
|
||||
|
||||
.theme--dark.muted-text {
|
||||
color: hsla(0,0%,100%,.3) !important;
|
||||
color: hsla(0, 0%, 100%, .3) !important;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
transition: transform 0.15s cubic;
|
||||
}
|
||||
@@ -265,12 +309,14 @@ export default {
|
||||
|
||||
<style lang="css">
|
||||
.action-card.theme--light.muted-text .v-icon {
|
||||
color: rgba(0,0,0,.3) !important;
|
||||
color: rgba(0, 0, 0, .3) !important;
|
||||
}
|
||||
|
||||
.action-card.theme--dark.muted-text .v-icon {
|
||||
color: hsla(0,0%,100%,.3) !important;
|
||||
color: hsla(0, 0%, 100%, .3) !important;
|
||||
}
|
||||
.action-card .property-description > p:last-of-type {
|
||||
|
||||
.action-card .property-description>p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import RollPopup from '/imports/ui/components/RollPopup.vue';
|
||||
import doCheck from '/imports/api/engine/actions/doCheck.js';
|
||||
import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -66,23 +66,25 @@ export default {
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
model: {type: Object, required: true},
|
||||
},
|
||||
data(){return {
|
||||
checkLoading: false,
|
||||
}},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
props: {
|
||||
model: { type: Object, required: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasClickListener() {
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
check({advantage}){
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
numberToSignedString,
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
check({ advantage }) {
|
||||
this.checkLoading = true;
|
||||
doCheck.call({
|
||||
propId: this.model._id,
|
||||
@@ -91,15 +93,15 @@ export default {
|
||||
},
|
||||
}, error => {
|
||||
this.checkLoading = false;
|
||||
if (error){
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({text: error.reason});
|
||||
snackbar({ text: error.reason });
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
swapScoresAndMods(){
|
||||
swapScoresAndMods() {
|
||||
let user = Meteor.user();
|
||||
return user &&
|
||||
user.preferences &&
|
||||
@@ -110,26 +112,32 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.ability-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.ability-list-tile >>> .v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
.ability-list-tile >>> .v-list__tile__action--stack {
|
||||
justify-content: center;
|
||||
}
|
||||
.value {
|
||||
font-weight: 600;
|
||||
font-size: 24px !important;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
.theme--dark .value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
.mod, .value {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
min-width: 42px;
|
||||
}
|
||||
.ability-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.ability-list-tile>>>.v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
|
||||
.ability-list-tile>>>.v-list__tile__action--stack {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: 600;
|
||||
font-size: 24px !important;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.theme--dark .value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
|
||||
.mod,
|
||||
.value {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
min-width: 42px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
<div class="text-body-1 mb-1">
|
||||
{{ displayedText }}
|
||||
</div>
|
||||
<div v-if="!hideBreadcrumbs && model.ancestors">
|
||||
<div v-if="!hideBreadcrumbs && ancestors">
|
||||
<breadcrumbs
|
||||
:model="model"
|
||||
:model="{...model, ancestors}"
|
||||
class="text-caption"
|
||||
no-links
|
||||
no-icons
|
||||
@@ -41,94 +41,101 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
||||
import { isFinite } from 'lodash';
|
||||
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { isFinite } from 'lodash';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumbs,
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumbs,
|
||||
},
|
||||
props: {
|
||||
hideBreadcrumbs: Boolean,
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
hideBreadcrumbs: Boolean,
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
displayedText(){
|
||||
if (this.model.operation === 'conditional'){
|
||||
return this.model.text || this.model.name || this.operation
|
||||
} else {
|
||||
return this.model.name || this.operation
|
||||
}
|
||||
},
|
||||
resolvedValue(){
|
||||
let amount = this.model.amount;
|
||||
if (!amount) return;
|
||||
return amount.value !== undefined ? amount.value : amount.calculation;
|
||||
},
|
||||
effectIcon(){
|
||||
let value = this.resolvedValue;
|
||||
return getEffectIcon(this.model.operation, value);
|
||||
},
|
||||
operation(){
|
||||
switch(this.model.operation) {
|
||||
case 'base': return 'Base value';
|
||||
case 'add': return 'Add';
|
||||
case 'mul': return 'Multiply';
|
||||
case 'min': return 'Minimum';
|
||||
case 'max': return 'Maximum';
|
||||
case 'advantage': return 'Advantage';
|
||||
case 'disadvantage': return 'Disadvantage';
|
||||
case 'passiveAdd': return 'Passive bonus';
|
||||
case 'fail': return 'Always fail';
|
||||
case 'conditional': return 'Conditional benefit' ;
|
||||
default: return '';
|
||||
}
|
||||
},
|
||||
showValue(){
|
||||
switch(this.model.operation) {
|
||||
case 'base': return true;
|
||||
case 'add': return true;
|
||||
case 'mul': return true;
|
||||
case 'min': return true;
|
||||
case 'max': return true;
|
||||
case 'advantage': return false;
|
||||
case 'disadvantage': return false;
|
||||
case 'passiveAdd': return true;
|
||||
case 'fail': return false;
|
||||
case 'conditional': return false;
|
||||
default: return false;
|
||||
}
|
||||
},
|
||||
displayedValue(){
|
||||
let value = this.resolvedValue;
|
||||
switch(this.model.operation) {
|
||||
case 'base': return value;
|
||||
case 'add': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'mul': return value;
|
||||
case 'min': return value;
|
||||
case 'max': return value;
|
||||
case 'advantage': return;
|
||||
case 'disadvantage': return;
|
||||
case 'passiveAdd': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'fail': return;
|
||||
case 'conditional': return undefined;
|
||||
default: return undefined;
|
||||
}
|
||||
displayedText(){
|
||||
if (this.model.operation === 'conditional'){
|
||||
return this.model.text || this.model.name || this.operation
|
||||
} else {
|
||||
return this.model.name || this.operation
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
resolvedValue() {
|
||||
let amount = this.model.amount;
|
||||
if (!amount) return;
|
||||
return amount.value !== undefined ? amount.value : amount.calculation;
|
||||
},
|
||||
};
|
||||
effectIcon(){
|
||||
let value = this.resolvedValue;
|
||||
return getEffectIcon(this.model.operation, value);
|
||||
},
|
||||
operation(){
|
||||
switch(this.model.operation) {
|
||||
case 'base': return 'Base value';
|
||||
case 'add': return 'Add';
|
||||
case 'mul': return 'Multiply';
|
||||
case 'min': return 'Minimum';
|
||||
case 'max': return 'Maximum';
|
||||
case 'advantage': return 'Advantage';
|
||||
case 'disadvantage': return 'Disadvantage';
|
||||
case 'passiveAdd': return 'Passive bonus';
|
||||
case 'fail': return 'Always fail';
|
||||
case 'conditional': return 'Conditional benefit' ;
|
||||
default: return '';
|
||||
}
|
||||
},
|
||||
showValue(){
|
||||
switch(this.model.operation) {
|
||||
case 'base': return true;
|
||||
case 'add': return true;
|
||||
case 'mul': return true;
|
||||
case 'min': return true;
|
||||
case 'max': return true;
|
||||
case 'advantage': return false;
|
||||
case 'disadvantage': return false;
|
||||
case 'passiveAdd': return true;
|
||||
case 'fail': return false;
|
||||
case 'conditional': return false;
|
||||
default: return false;
|
||||
}
|
||||
},
|
||||
displayedValue(){
|
||||
let value = this.resolvedValue;
|
||||
switch(this.model.operation) {
|
||||
case 'base': return value;
|
||||
case 'add': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'mul': return value;
|
||||
case 'min': return value;
|
||||
case 'max': return value;
|
||||
case 'advantage': return;
|
||||
case 'disadvantage': return;
|
||||
case 'passiveAdd': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'fail': return;
|
||||
case 'conditional': return undefined;
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
ancestors() {
|
||||
const prop = CreatureProperties.findOne(this.model._id);
|
||||
return prop && prop.ancestors || [];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
style="height: 100%; transform-origin: left; transition: all 0.5s ease;"
|
||||
:style="{
|
||||
backgroundColor: barColor,
|
||||
transform: `scaleX(${value / maxValue})`,
|
||||
transform: `scaleX(${fillFraction})`,
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
@@ -92,87 +92,102 @@ import IncrementMenu from '/imports/ui/components/IncrementMenu.vue';
|
||||
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||
import chroma from 'chroma-js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IncrementMenu
|
||||
},
|
||||
inject: {
|
||||
theme: {
|
||||
default: {
|
||||
isDark: false,
|
||||
},
|
||||
export default {
|
||||
components: {
|
||||
IncrementMenu
|
||||
},
|
||||
inject: {
|
||||
theme: {
|
||||
default: {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
value: Number,
|
||||
maxValue: Number,
|
||||
name: String,
|
||||
color: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$vuetify.theme.currentTheme.primary
|
||||
},
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
maxValue: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default() {
|
||||
return this.$vuetify.theme.currentTheme.primary
|
||||
},
|
||||
midColor: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
lowColor: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
_id: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editing: false,
|
||||
hover: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
barColor() {
|
||||
const fraction = this.value / this.maxValue;
|
||||
if (!Number.isFinite(fraction)) return this.color;
|
||||
if (fraction > 0.5){
|
||||
return this.color;
|
||||
} else if (this.midColor && this.lowColor) {
|
||||
return chroma.mix(this.lowColor, this.midColor, fraction * 2).hex();
|
||||
} else if (this.midColor){
|
||||
return this.midColor;
|
||||
}
|
||||
},
|
||||
midColor: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
lowColor: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
_id: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editing: false,
|
||||
hover: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
fillFraction() {
|
||||
let fraction = this.value / this.maxValue;
|
||||
if (fraction < 0) fraction = 0;
|
||||
if (fraction > 1) fraction = 1;
|
||||
return fraction;
|
||||
},
|
||||
barColor() {
|
||||
const fraction = this.value / this.maxValue;
|
||||
if (!Number.isFinite(fraction)) return this.color;
|
||||
if (fraction > 0.5) {
|
||||
return this.color;
|
||||
},
|
||||
barBackgroundColor(){
|
||||
return chroma(this.barColor)
|
||||
} else if (this.midColor && this.lowColor) {
|
||||
return chroma.mix(this.lowColor, this.midColor, fraction * 2).hex();
|
||||
} else if (this.midColor) {
|
||||
return this.midColor;
|
||||
}
|
||||
return this.color;
|
||||
},
|
||||
barBackgroundColor() {
|
||||
return chroma(this.barColor)
|
||||
.darken(1.5)
|
||||
.desaturate(1.5)
|
||||
.hex();
|
||||
},
|
||||
isTextLight(){
|
||||
return isDarkColor(this.barBackgroundColor);
|
||||
/* Change color at the halfway mark
|
||||
const fraction = this.value / this.maxValue;
|
||||
if (fraction >= 0.5){
|
||||
return isDarkColor(this.barColor);
|
||||
} else {
|
||||
return isDarkColor(this.barBackgroundColor);
|
||||
}
|
||||
*/
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
edit() {
|
||||
this.editing = true;
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editing = false;
|
||||
},
|
||||
changeIncrementMenu(e){
|
||||
this.$emit('change', e);
|
||||
this.editing = false;
|
||||
isTextLight() {
|
||||
return isDarkColor(this.barBackgroundColor);
|
||||
/* Change color at the halfway mark
|
||||
const fraction = this.value / this.maxValue;
|
||||
if (fraction >= 0.5){
|
||||
return isDarkColor(this.barColor);
|
||||
} else {
|
||||
return isDarkColor(this.barBackgroundColor);
|
||||
}
|
||||
},
|
||||
};
|
||||
*/
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
edit() {
|
||||
this.editing = true;
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editing = false;
|
||||
},
|
||||
changeIncrementMenu(e) {
|
||||
this.$emit('change', e);
|
||||
this.editing = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -187,70 +202,85 @@ import chroma from 'chroma-js';
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.health-bar {
|
||||
background: inherit;
|
||||
}
|
||||
.name {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
min-width: 150px;
|
||||
flex-basis: 150px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.name:hover {
|
||||
font-weight: 500;
|
||||
}
|
||||
.bar {
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
.bar:hover {
|
||||
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.filled.theme--light {
|
||||
background: #fff !important;
|
||||
}
|
||||
.filled.theme--dark {
|
||||
background: #424242 !important;
|
||||
}
|
||||
.background-transition-enter-active,
|
||||
.background-transition-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.background-transition-enter,
|
||||
.background-transition-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.transition-enter-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.transition-leave-active {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.transition-enter-to,
|
||||
.transition-leave {
|
||||
opacity: 1;
|
||||
transform: scaleY(1) !important;
|
||||
}
|
||||
.transition-enter,
|
||||
.transition-leave-to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0) !important;
|
||||
}
|
||||
.page-tint {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
z-index: 6;
|
||||
}
|
||||
.health-bar {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.name {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
min-width: 150px;
|
||||
flex-basis: 150px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.name:hover {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bar {
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.bar:hover {
|
||||
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12) !important;
|
||||
}
|
||||
|
||||
.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.theme--dark .hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
|
||||
.filled.theme--light {
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.filled.theme--dark {
|
||||
background: #424242 !important;
|
||||
}
|
||||
|
||||
.background-transition-enter-active,
|
||||
.background-transition-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.background-transition-enter,
|
||||
.background-transition-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.transition-enter-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.transition-leave-active {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.transition-enter-to,
|
||||
.transition-leave {
|
||||
opacity: 1;
|
||||
transform: scaleY(1) !important;
|
||||
}
|
||||
|
||||
.transition-enter,
|
||||
.transition-leave-to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0) !important;
|
||||
}
|
||||
|
||||
.page-tint {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
z-index: 6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import HealthBar from '/imports/ui/properties/components/attributes/HealthBar.vue';
|
||||
import HealthBar from '/imports/ui/properties/components/attributes/HealthBar.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HealthBar,
|
||||
},
|
||||
props: {
|
||||
attributes: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
HealthBar,
|
||||
},
|
||||
props: {
|
||||
attributes: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -12,60 +12,60 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||
|
||||
import HealthBarCard from '/imports/ui/properties/components/attributes/HealthBarCard.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import HealthBarCard from '/imports/ui/properties/components/attributes/HealthBarCard.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HealthBarCard,
|
||||
},
|
||||
props: {
|
||||
creatureId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
creature(){
|
||||
return Creatures.findOne(this.creatureId, {fields: {settings: 1}});
|
||||
},
|
||||
attributes(){
|
||||
let creature = this.creature;
|
||||
if (!creature) return;
|
||||
let filter = {
|
||||
'ancestors.id': creature._id,
|
||||
type: 'attribute',
|
||||
attributeType: 'healthBar',
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
overridden: {$ne: true},
|
||||
};
|
||||
if (creature.settings.hideUnusedStats){
|
||||
filter.hide = {$ne: true};
|
||||
}
|
||||
return CreatureProperties.find(filter, {
|
||||
sort: {order: 1}
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
healthBarClicked({_id}){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
healthBarChanged({_id, change}){
|
||||
damageProperty.call({
|
||||
_id,
|
||||
operation: change.type,
|
||||
value: change.value
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
HealthBarCard,
|
||||
},
|
||||
props: {
|
||||
creatureId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
creature() {
|
||||
return Creatures.findOne(this.creatureId, { fields: { settings: 1 } });
|
||||
},
|
||||
attributes() {
|
||||
let creature = this.creature;
|
||||
if (!creature) return;
|
||||
let filter = {
|
||||
'ancestors.id': creature._id,
|
||||
type: 'attribute',
|
||||
attributeType: 'healthBar',
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
overridden: { $ne: true },
|
||||
};
|
||||
if (creature.settings.hideUnusedStats) {
|
||||
filter.hide = { $ne: true };
|
||||
}
|
||||
return CreatureProperties.find(filter, {
|
||||
sort: { order: 1 }
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
healthBarClicked({ _id }) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
healthBarChanged({ _id, change }) {
|
||||
damageProperty.call({
|
||||
_id,
|
||||
operation: change.type,
|
||||
value: change.value
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
|
||||
<v-layout
|
||||
align-end
|
||||
>
|
||||
<v-layout align-end>
|
||||
<div class="text-h4">
|
||||
{{ model.value }}
|
||||
</div>
|
||||
@@ -63,60 +61,71 @@ export default {
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
props: {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hover: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
signedConMod(){
|
||||
signedConMod() {
|
||||
return numberToSignedString(this.model.constitutionMod);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value){
|
||||
this.$emit('change', {type: 'increment', value})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value) {
|
||||
this.$emit('change', { type: 'increment', value })
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.hit-dice-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.hit-dice-list-tile >>> .v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
.left {
|
||||
height: 100%;
|
||||
}
|
||||
.buttons {
|
||||
height: 100%;
|
||||
}
|
||||
.buttons > .v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
.hit-dice-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .hit-dice-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
.hit-dice-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.hit-dice-list-tile>>>.v-list__tile {
|
||||
height: 88px;
|
||||
}
|
||||
|
||||
.left {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.buttons>.v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hit-dice-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.theme--dark .hit-dice-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.max-value {
|
||||
color: rgba(0, 0, 0, .54);
|
||||
}
|
||||
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<v-btn
|
||||
icon
|
||||
small
|
||||
:disabled="model.value >= model.total || context.editPermission === false"
|
||||
:disabled="(model.value >= model.total && !model.ignoreUpperLimit) || context.editPermission === false"
|
||||
@click="increment(1)"
|
||||
>
|
||||
<v-icon>mdi-chevron-up</v-icon>
|
||||
@@ -16,19 +16,20 @@
|
||||
<v-btn
|
||||
icon
|
||||
small
|
||||
:disabled="model.value <= 0 || context.editPermission === false"
|
||||
:disabled="(model.value <= 0 && !model.ignoreLowerLimit) || context.editPermission === false"
|
||||
@click="increment(-1)"
|
||||
>
|
||||
<v-icon>mdi-chevron-down</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
class="layout align-center value pl-2 pr-3"
|
||||
>
|
||||
<div class="layout align-center value pl-2 pr-3">
|
||||
<div class="text-h4">
|
||||
{{ model.value }}
|
||||
</div>
|
||||
<div class="text-h6 ml-2 max-value">
|
||||
<div
|
||||
v-if="model.total !== 0"
|
||||
class="text-h6 ml-2 max-value"
|
||||
>
|
||||
/{{ model.total }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,55 +51,64 @@
|
||||
<script lang="js">
|
||||
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CardHighlight,
|
||||
export default {
|
||||
components: {
|
||||
CardHighlight,
|
||||
},
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hover: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
increment(value) {
|
||||
this.$emit('change', { type: 'increment', value })
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
increment(value){
|
||||
this.$emit('change', {type: 'increment', value})
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.resource-card {
|
||||
transition: box-shadow .4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
.resource-card > div {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.buttons, .value {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
.buttons > .v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
.resource-card {
|
||||
transition: box-shadow .4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.resource-card>div {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.buttons,
|
||||
.value {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.buttons>.v-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.max-value {
|
||||
color: rgba(0, 0, 0, .54);
|
||||
}
|
||||
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
v-on="hasClickListener ? {click} : {}"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title
|
||||
v-if="Number.isFinite(model.total)"
|
||||
>
|
||||
<v-list-item-title v-if="Number.isFinite(model.total)">
|
||||
<div
|
||||
v-if="model.total > 4"
|
||||
class="layout value"
|
||||
@@ -57,50 +55,56 @@
|
||||
<script lang="js">
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
dark: Boolean,
|
||||
hideCastButton: Boolean,
|
||||
disabled: Boolean,
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
},
|
||||
computed: {
|
||||
hasClickListener() {
|
||||
return this.$listeners && !!this.$listeners.click;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
signed: numberToSignedString,
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
signed: numberToSignedString,
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.spell-slot-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
.v-list__tile__action {
|
||||
width: 112px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.spell-slot-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
.theme--dark .spell-slot-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
.max-value {
|
||||
color: rgba(0,0,0,.54);
|
||||
}
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
.spell-slot-list-tile {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
.v-list__tile__action {
|
||||
width: 112px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.spell-slot-list-tile.hover {
|
||||
background: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.theme--dark .spell-slot-list-tile.hover {
|
||||
background: #515151 !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.max-value {
|
||||
color: rgba(0, 0, 0, .54);
|
||||
}
|
||||
|
||||
.theme--dark .max-value {
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
</template>
|
||||
<v-card-text v-if="model.summary">
|
||||
<v-card-text v-if="summaryText">
|
||||
<property-description
|
||||
text
|
||||
:model="model.summary"
|
||||
@@ -20,21 +20,31 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
|
||||
import PropertyDescription from '/imports/ui/properties/viewers/shared/PropertyDescription.vue'
|
||||
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
|
||||
import PropertyDescription from '/imports/ui/properties/viewers/shared/PropertyDescription.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ToolbarCard,
|
||||
PropertyDescription,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
export default {
|
||||
components: {
|
||||
ToolbarCard,
|
||||
PropertyDescription,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
summaryText() {
|
||||
if (!this.model || !this.model.summary) return;
|
||||
if (typeof this.model.summary.value === 'string') {
|
||||
return this.model.summary.value;
|
||||
} else {
|
||||
return this.model.summary.text
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
>
|
||||
$vuetify.icons.two_coins
|
||||
</v-icon>
|
||||
<coin-value
|
||||
:value="value"
|
||||
/>
|
||||
<coin-value :value="value" />
|
||||
</v-toolbar-title>
|
||||
</template>
|
||||
<v-card-text class="px-0">
|
||||
@@ -52,57 +50,57 @@ import CoinValue from '/imports/ui/components/CoinValue.vue';
|
||||
import stripFloatingPointOddities from '/imports/api/engine/computation/utility/stripFloatingPointOddities.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ToolbarCard,
|
||||
components: {
|
||||
ToolbarCard,
|
||||
ItemList,
|
||||
CoinValue,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
weight(){
|
||||
weight() {
|
||||
const contentWeight = this.model.contentsWeightless ?
|
||||
0 :
|
||||
this.model.contentsWeight || 0;
|
||||
const ownWeight = this.model.weight || 0;
|
||||
return stripFloatingPointOddities(contentWeight + ownWeight);
|
||||
},
|
||||
value(){
|
||||
value() {
|
||||
const contentValue = this.model.contentsValue || 0;
|
||||
const ownValue = this.model.value || 0;
|
||||
return contentValue + ownValue;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickContainer(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
clickProperty(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `tree-node-${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickContainer(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
clickProperty(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `tree-node-${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
items(){
|
||||
items() {
|
||||
return CreatureProperties.find({
|
||||
'parent.id': this.model._id,
|
||||
type: {$in: ['item', 'container']},
|
||||
removed: {$ne: true},
|
||||
equipped: {$ne: true},
|
||||
deactivatedByAncestor: {$ne: true},
|
||||
type: { $in: ['item', 'container'] },
|
||||
removed: { $ne: true },
|
||||
equipped: { $ne: true },
|
||||
deactivatedByAncestor: { $ne: true },
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
sort: { order: 1 },
|
||||
});
|
||||
},
|
||||
}
|
||||
@@ -110,4 +108,5 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -52,40 +52,42 @@ export default {
|
||||
preparingSpells: Boolean,
|
||||
equipment: Boolean,
|
||||
},
|
||||
data(){ return {
|
||||
dataItems: [],
|
||||
}},
|
||||
data() {
|
||||
return {
|
||||
dataItems: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
levels(){
|
||||
levels() {
|
||||
let levels = new Set();
|
||||
this.items.forEach(item => levels.add(item.level));
|
||||
return levels;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
items(value){
|
||||
items(value) {
|
||||
this.dataItems = value;
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
mounted() {
|
||||
this.dataItems = this.items;
|
||||
},
|
||||
methods: {
|
||||
clickProperty(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: _id,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
change({added, moved}){
|
||||
clickProperty(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: _id,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
change({ added, moved }) {
|
||||
let event = added || moved;
|
||||
if (event){
|
||||
if (event) {
|
||||
// If this item is now adjacent to another, set the order accordingly
|
||||
let order;
|
||||
let before = this.dataItems[event.newIndex - 1];
|
||||
let after = this.dataItems[event.newIndex + 1];
|
||||
if (before && before._id){
|
||||
if (before && before._id) {
|
||||
order = before.order + 0.5;
|
||||
} else if (after && after._id) {
|
||||
order = after.order - 0.5;
|
||||
@@ -101,7 +103,7 @@ export default {
|
||||
parentRef: this.parentRef,
|
||||
order,
|
||||
});
|
||||
if (doc.type === 'item' && doc.equipped != this.equipment){
|
||||
if (doc.type === 'item' && doc.equipped != this.equipment) {
|
||||
updateCreatureProperty.call({
|
||||
_id: doc._id,
|
||||
path: ['equipped'],
|
||||
@@ -111,6 +113,6 @@ export default {
|
||||
}
|
||||
setTimeout(() => this.dataItems = this.items, 0);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -49,10 +49,10 @@ import treeNodeViewMixin from '/imports/ui/properties/treeNodeViews/treeNodeView
|
||||
import PROPERTIES from '/imports/constants/PROPERTIES.js';
|
||||
import adjustQuantity from '/imports/api/creature/creatureProperties/methods/adjustQuantity.js';
|
||||
import IncrementButton from '/imports/ui/components/IncrementButton.vue';
|
||||
import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
|
||||
export default {
|
||||
components:{
|
||||
components: {
|
||||
IncrementButton,
|
||||
},
|
||||
mixins: [treeNodeViewMixin],
|
||||
@@ -62,20 +62,22 @@ export default {
|
||||
props: {
|
||||
preparingSpells: Boolean,
|
||||
},
|
||||
data(){return {
|
||||
incrementLoading: false,
|
||||
}},
|
||||
data() {
|
||||
return {
|
||||
incrementLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
hasClickListener() {
|
||||
return this.$listeners && !!this.$listeners.click;
|
||||
},
|
||||
title(){
|
||||
title() {
|
||||
let model = this.model;
|
||||
if (!model) return;
|
||||
if (model.quantity !== 1){
|
||||
if (model.plural){
|
||||
if (model.quantity !== 1) {
|
||||
if (model.plural) {
|
||||
return `${model.quantity} ${model.plural}`;
|
||||
} else if (model.name){
|
||||
} else if (model.name) {
|
||||
return `${model.quantity} ${model.name}`;
|
||||
}
|
||||
} else if (model.name) {
|
||||
@@ -86,10 +88,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
changeQuantity({type, value}) {
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
changeQuantity({ type, value }) {
|
||||
this.incrementLoading = true;
|
||||
adjustQuantity.call({
|
||||
_id: this.model._id,
|
||||
@@ -97,8 +99,8 @@ export default {
|
||||
value: value
|
||||
}, error => {
|
||||
this.incrementLoading = false;
|
||||
if (error){
|
||||
snackbar({text: error.reason});
|
||||
if (error) {
|
||||
snackbar({ text: error.reason });
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
@@ -111,6 +113,7 @@ export default {
|
||||
.item-avatar {
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.item {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PropertyDescription,
|
||||
components: {
|
||||
PropertyDescription,
|
||||
CardHighlight,
|
||||
},
|
||||
},
|
||||
inject: {
|
||||
theme: {
|
||||
default: {
|
||||
@@ -42,31 +42,34 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data(){ return{
|
||||
hover: false,
|
||||
}},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hover: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isDark(){
|
||||
isDark() {
|
||||
return isDarkColor(this.model.color);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickProperty(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickProperty(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<v-card
|
||||
v-if="model"
|
||||
v-bind="$attrs"
|
||||
:data-id="`point-buy-card-${model._id}`"
|
||||
:style="`border: solid 1px ${accentColor};`"
|
||||
hover
|
||||
class="slot-card d-flex flex-column"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<card-highlight
|
||||
:active="hover"
|
||||
/>
|
||||
<v-card-title>
|
||||
{{ model.name || 'Point Buy' }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
{{ model.spent }}
|
||||
<template v-if="model.total && (typeof model.total.value === 'number')">
|
||||
/ {{ model.total && model.total.value }}
|
||||
</template>
|
||||
</v-card-text>
|
||||
<v-spacer />
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
color="accent"
|
||||
@click.stop="$emit('ignore')"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import CardHighlight from '/imports/ui/components/CardHighlight.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CardHighlight,
|
||||
},
|
||||
inject: {
|
||||
theme: {
|
||||
default: {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
hover: false,
|
||||
}},
|
||||
computed: {
|
||||
accentColor(){
|
||||
if (this.theme.isDark){
|
||||
return this.$vuetify.theme.themes.dark.primary;
|
||||
} else {
|
||||
return this.$vuetify.theme.themes.light.primary;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -8,7 +8,7 @@
|
||||
<v-list-item-title class="d-flex align-center">
|
||||
<roll-popup
|
||||
v-if="!hideModifier"
|
||||
class="prof-mod mr-1"
|
||||
class="prof-mod mr-1 flex-shrink-0"
|
||||
button-class="pl-3 pr-2"
|
||||
text
|
||||
:roll-text="displayedModifier"
|
||||
@@ -43,7 +43,7 @@
|
||||
:value="model.proficiency"
|
||||
class="prof-icon ml-3 mr-2"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-truncate">
|
||||
{{ model.name }}
|
||||
<template v-if="model.conditionalBenefits && model.conditionalBenefits.length">
|
||||
*
|
||||
@@ -62,7 +62,7 @@ import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import ProficiencyIcon from '/imports/ui/properties/shared/ProficiencyIcon.vue';
|
||||
import RollPopup from '/imports/ui/components/RollPopup.vue';
|
||||
import doCheck from '/imports/api/engine/actions/doCheck.js';
|
||||
import {snackbar} from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -74,37 +74,39 @@ export default {
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
hideModifier: Boolean,
|
||||
},
|
||||
data(){return {
|
||||
checkLoading: false,
|
||||
}},
|
||||
computed: {
|
||||
displayedModifier(){
|
||||
let mod = this.model.value;
|
||||
if (this.model.fail){
|
||||
return 'fail';
|
||||
} else {
|
||||
return numberToSignedString(mod);
|
||||
}
|
||||
},
|
||||
hasClickListener(){
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayedModifier() {
|
||||
let mod = this.model.value;
|
||||
if (this.model.fail) {
|
||||
return 'fail';
|
||||
} else {
|
||||
return numberToSignedString(mod);
|
||||
}
|
||||
},
|
||||
hasClickListener() {
|
||||
return this.$listeners && this.$listeners.click
|
||||
},
|
||||
passiveScore(){
|
||||
},
|
||||
passiveScore() {
|
||||
return 10 + this.model.value + this.model.passiveBonus;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
check({advantage}){
|
||||
},
|
||||
methods: {
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
check({ advantage }) {
|
||||
this.checkLoading = true;
|
||||
doCheck.call({
|
||||
propId: this.model._id,
|
||||
@@ -113,24 +115,26 @@ export default {
|
||||
},
|
||||
}, error => {
|
||||
this.checkLoading = false;
|
||||
if (error){
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({text: error.reason});
|
||||
snackbar({ text: error.reason });
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.prof-icon {
|
||||
min-width: 30px;
|
||||
}
|
||||
.prof-mod {
|
||||
min-width: 32px;
|
||||
}
|
||||
.v-icon.theme--light {
|
||||
color: rgba(0, 0, 0, 0.54) !important;
|
||||
}
|
||||
.prof-icon {
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
.prof-mod {
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.v-icon.theme--light {
|
||||
color: rgba(0, 0, 0, 0.54) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -91,6 +91,20 @@
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
key="ritual-dummy-slot"
|
||||
class="spell-slot-list-tile"
|
||||
:class="{ 'primary--text': selectedSlotId === 'ritual' }"
|
||||
value="ritual"
|
||||
:disabled="!canCastSpellWithSlot(selectedSpell, 'ritual')"
|
||||
@click="selectedSlotId = 'ritual'"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
Cast as ritual
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<spell-slot-list-tile
|
||||
v-for="spellSlot in spellSlots"
|
||||
:key="spellSlot._id"
|
||||
@@ -105,13 +119,13 @@
|
||||
</template>
|
||||
<template slot="right">
|
||||
<div
|
||||
key="spell-title"
|
||||
key="spell-title-right"
|
||||
class="text-h6 my-3"
|
||||
>
|
||||
Spell
|
||||
</div>
|
||||
<v-list-item-group
|
||||
key="slot-list"
|
||||
key="slot-list-right"
|
||||
v-model="selectedSpellId"
|
||||
>
|
||||
<template v-for="spell in computedSpells">
|
||||
@@ -145,10 +159,24 @@
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
<roll-popup
|
||||
v-if="selectedSpell && selectedSpell.attackRoll"
|
||||
text
|
||||
color="primary"
|
||||
class="mx-2"
|
||||
:disabled="!canCast"
|
||||
:name="selectedSpell.name"
|
||||
:advantage="selectedSpell.attackRoll && selectedSpell.attackRoll.advantage"
|
||||
@roll="cast"
|
||||
>
|
||||
Cast
|
||||
</roll-popup>
|
||||
<v-btn
|
||||
v-else
|
||||
text
|
||||
:disabled="!canCast"
|
||||
class="primary--text"
|
||||
class="mx-2 px-4"
|
||||
color="primary"
|
||||
@click="cast"
|
||||
>
|
||||
Cast
|
||||
@@ -164,20 +192,22 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
|
||||
import spellsWithSubheaders from '/imports/ui/properties/components/spells/spellsWithSubheaders.js';
|
||||
import SpellSlotListTile from '/imports/ui/properties/components/attributes/SpellSlotListTile.vue';
|
||||
import SpellListTile from '/imports/ui/properties/components/spells/SpellListTile.vue';
|
||||
import RollPopup from '/imports/ui/components/RollPopup.vue';
|
||||
import { find } from 'lodash';
|
||||
|
||||
const slotFilter = {
|
||||
type: 'attribute',
|
||||
attributeType: 'spellSlot',
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
overridden: {$ne: true},
|
||||
'spellSlotLevel.value': {$gte: 1},
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
overridden: { $ne: true },
|
||||
'spellSlotLevel.value': { $gte: 1 },
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DialogBase,
|
||||
RollPopup,
|
||||
SplitListLayout,
|
||||
SpellSlotListTile,
|
||||
SpellListTile,
|
||||
@@ -196,36 +226,38 @@ export default {
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data(){ return {
|
||||
searchString: undefined,
|
||||
selectedSlotId: this.slotId,
|
||||
selectedSpellId: this.spellId,
|
||||
selectedSlot: undefined,
|
||||
selectedSpell: undefined,
|
||||
searchValue: undefined,
|
||||
searchError: undefined,
|
||||
filterMenuOpen: false,
|
||||
booleanFilters: {
|
||||
verbal: {name: 'Verbal', enabled: false, value: false},
|
||||
somatic: {name: 'Somatic', enabled: false, value: false},
|
||||
material: {name: 'Material', enabled: false, value: false},
|
||||
concentration: {name: 'Concentration', enabled: false, value: false},
|
||||
ritual: {name: 'Ritual', enabled: false, value: false},
|
||||
},
|
||||
}},
|
||||
data() {
|
||||
return {
|
||||
searchString: undefined,
|
||||
selectedSlotId: this.slotId,
|
||||
selectedSpellId: this.spellId,
|
||||
selectedSlot: undefined,
|
||||
selectedSpell: undefined,
|
||||
searchValue: undefined,
|
||||
searchError: undefined,
|
||||
filterMenuOpen: false,
|
||||
booleanFilters: {
|
||||
verbal: { name: 'Verbal', enabled: false, value: true },
|
||||
somatic: { name: 'Somatic', enabled: false, value: true },
|
||||
material: { name: 'Material', enabled: false, value: true },
|
||||
concentration: { name: 'Concentration', enabled: false, value: true },
|
||||
ritual: { name: 'Ritual', enabled: false, value: true },
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedSpells(){
|
||||
computedSpells() {
|
||||
return spellsWithSubheaders(this.spells);
|
||||
},
|
||||
canCast(){
|
||||
canCast() {
|
||||
if (!this.selectedSpell || !this.selectedSlotId) return false;
|
||||
return this.canCastSpellWithSlot(
|
||||
this.selectedSpell, this.selectedSlotId, this.selectedSlot
|
||||
);
|
||||
},
|
||||
filtersApplied(){
|
||||
for (let key in this.booleanFilters){
|
||||
if (this.booleanFilters[key].enabled){
|
||||
filtersApplied() {
|
||||
for (let key in this.booleanFilters) {
|
||||
if (this.booleanFilters[key].enabled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -234,79 +266,82 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
selectedSpellId: {
|
||||
handler(spellId){
|
||||
handler(spellId) {
|
||||
this.selectedSpell = CreatureProperties.findOne(spellId)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
selectedSpell: {
|
||||
handler(spell){
|
||||
handler(spell) {
|
||||
if (!spell) return;
|
||||
if(spell.level === 0 || spell.castWithoutSpellSlots){
|
||||
this.selectedSlotId = 'no-slot';
|
||||
} else if (
|
||||
!this.selectedSlotId ||
|
||||
this.selectedSlotId == 'no-slot' ||
|
||||
this.selectedSlot.spellSlotLevel.value < spell.level
|
||||
if (this.selectedSlotId && this.canCastSpellWithSlot(
|
||||
spell, this.selectedSlotId, this.selectedSlot
|
||||
)) return;
|
||||
if (
|
||||
(spell.level === 0 || spell.castWithoutSpellSlots)
|
||||
) {
|
||||
this.selectedSlotId = 'no-slot';
|
||||
} else {
|
||||
const newSlot = find(
|
||||
CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
...slotFilter
|
||||
}, {
|
||||
sort: {'spellSlotLevel.value': 1, order: 1},
|
||||
sort: { 'spellSlotLevel.value': 1, order: 1 },
|
||||
}).fetch(),
|
||||
slot => {
|
||||
return this.canCastSpellWithSlot(spell, slot._id, slot)
|
||||
}
|
||||
);
|
||||
if (newSlot){
|
||||
if (newSlot) {
|
||||
this.selectedSlotId = newSlot._id;
|
||||
} else if (spell.ritual) {
|
||||
this.selectedSlotId = 'ritual';
|
||||
}
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
selectedSlotId: {
|
||||
handler(slotId){
|
||||
handler(slotId) {
|
||||
this.selectedSlot = CreatureProperties.findOne(slotId);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
selectedSlot:{
|
||||
handler(slot){
|
||||
selectedSlot: {
|
||||
handler(slot) {
|
||||
if (!slot) return;
|
||||
if (!this.selectedSpell) return;
|
||||
if(this.selectedSpell.level > slot.spellSlotLevel.value){
|
||||
if (this.selectedSpell.level > slot.spellSlotLevel.value) {
|
||||
this.selectedSpellId = undefined;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted(){
|
||||
if (this.selectedSpellId){
|
||||
this.$vuetify.goTo('.spell.v-list-item--active', {container: '.right'});
|
||||
mounted() {
|
||||
if (this.selectedSpellId) {
|
||||
this.$vuetify.goTo('.spell.v-list-item--active', { container: '.right' });
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clearBooleanFilters(){
|
||||
for (let key in this.booleanFilters){
|
||||
clearBooleanFilters() {
|
||||
for (let key in this.booleanFilters) {
|
||||
this.booleanFilters[key].enabled = false;
|
||||
}
|
||||
},
|
||||
spellDialog(_id){
|
||||
spellDialog(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `spell-info-btn-${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `spell-info-btn-${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
searchChanged(val, ack){
|
||||
searchChanged(val, ack) {
|
||||
this.searchValue = val;
|
||||
setTimeout(ack, 200);
|
||||
},
|
||||
canCastSpellWithSlot(spell, slotId, slot){
|
||||
canCastSpellWithSlot(spell, slotId, slot) {
|
||||
if (slot && !slot.value) return false;
|
||||
if (!spell) return true;
|
||||
if (!slotId) return true;
|
||||
@@ -314,66 +349,69 @@ export default {
|
||||
spell.castWithoutSpellSlots &&
|
||||
spell.insufficientResources
|
||||
) return false;
|
||||
return (!spell.level || spell.castWithoutSpellSlots) ? (
|
||||
if (spell.ritual && slotId === 'ritual') return true;
|
||||
if (!spell.level || spell.castWithoutSpellSlots) {
|
||||
// Cantrips and no-slot spells
|
||||
slotId && slotId === 'no-slot'
|
||||
) : (
|
||||
return slotId && slotId === 'no-slot'
|
||||
} else {
|
||||
// Leveled spells
|
||||
slotId !== 'no-slot' &&
|
||||
slot && spell && (
|
||||
spell.level <= slot.spellSlotLevel.value
|
||||
)
|
||||
)
|
||||
return slotId !== 'no-slot' && slot && spell && (
|
||||
spell.level <= slot.spellSlotLevel.value
|
||||
);
|
||||
}
|
||||
},
|
||||
cast(){
|
||||
cast({ advantage }) {
|
||||
let selectedSlotId = this.selectedSlotId;
|
||||
if (selectedSlotId === 'no-slot') selectedSlotId = undefined;
|
||||
const ritual = selectedSlotId === 'ritual';
|
||||
if (selectedSlotId === 'no-slot' || selectedSlotId === 'ritual') selectedSlotId = undefined;
|
||||
this.$store.dispatch('popDialogStack', {
|
||||
spellId: this.selectedSpellId,
|
||||
slotId: selectedSlotId,
|
||||
})
|
||||
advantage,
|
||||
ritual,
|
||||
});
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
spells(){
|
||||
spells() {
|
||||
let filter = {
|
||||
'ancestors.id': this.creatureId,
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
$or: [
|
||||
{prepared: true},
|
||||
{alwaysPrepared: true},
|
||||
{ prepared: true },
|
||||
{ alwaysPrepared: true },
|
||||
],
|
||||
};
|
||||
|
||||
// Apply the filters from the filter menu
|
||||
for (let key in this.booleanFilters){
|
||||
if (this.booleanFilters[key].enabled){
|
||||
for (let key in this.booleanFilters) {
|
||||
if (this.booleanFilters[key].enabled) {
|
||||
let value = this.booleanFilters[key].value;
|
||||
if (key === 'material'){
|
||||
filter[key] = {$exists: this.booleanFilters[key].value};
|
||||
if (key === 'material') {
|
||||
filter[key] = { $exists: this.booleanFilters[key].value };
|
||||
} else {
|
||||
filter[key] = value ? true: {$ne: true};
|
||||
filter[key] = value ? true : { $ne: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply the search string to the name field
|
||||
if (this.searchValue){
|
||||
if (this.searchValue) {
|
||||
filter.name = {
|
||||
$regex: this.searchValue.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||
$options: 'i'
|
||||
};
|
||||
}
|
||||
return CreatureProperties.find(filter, {
|
||||
sort: {order: 1}
|
||||
sort: { order: 1 }
|
||||
});
|
||||
},
|
||||
spellSlots(){
|
||||
spellSlots() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
...slotFilter
|
||||
}, {
|
||||
sort: {'spellSlotLevel.value': 1, order: 1},
|
||||
sort: { 'spellSlotLevel.value': 1, order: 1 },
|
||||
});
|
||||
},
|
||||
},
|
||||
@@ -381,10 +419,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.v-list {
|
||||
flex-basis: 200px;
|
||||
}
|
||||
.v-list.spells {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.v-list {
|
||||
flex-basis: 200px;
|
||||
}
|
||||
|
||||
.v-list.spells {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,48 +62,50 @@ export default {
|
||||
},
|
||||
preparingSpells: Boolean,
|
||||
},
|
||||
data(){ return {
|
||||
dataSpells: [],
|
||||
}},
|
||||
data() {
|
||||
return {
|
||||
dataSpells: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
levels(){
|
||||
levels() {
|
||||
let levels = new Set();
|
||||
this.spells.forEach(spell => levels.add(spell.level));
|
||||
return levels;
|
||||
},
|
||||
computedSpells: {
|
||||
get(){
|
||||
get() {
|
||||
return spellsWithSubheaders(this.dataSpells);
|
||||
},
|
||||
set(value){
|
||||
set(value) {
|
||||
this.dataSpells = value;
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
spells(value){
|
||||
spells(value) {
|
||||
this.dataSpells = spellsWithSubheaders(value);
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
mounted() {
|
||||
this.dataSpells = spellsWithSubheaders(this.spells);
|
||||
},
|
||||
methods: {
|
||||
clickProperty(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `spell-list-tile-${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
change({added, moved}){
|
||||
clickProperty(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `spell-list-tile-${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
change({ added, moved }) {
|
||||
let event = added || moved;
|
||||
if (event){
|
||||
if (event) {
|
||||
// If this spell is now adjacent to another, set the order accordingly
|
||||
let order;
|
||||
let before = this.dataSpells[event.newIndex - 1];
|
||||
let after = this.dataSpells[event.newIndex + 1];
|
||||
if (before && before._id){
|
||||
if (before && before._id) {
|
||||
order = before.order + 0.5;
|
||||
} else if (after && after._id) {
|
||||
order = after.order - 0.5;
|
||||
@@ -121,9 +123,10 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -63,32 +63,34 @@ import SpellList from '/imports/ui/properties/components/spells/SpellList.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ToolbarCard,
|
||||
components: {
|
||||
ToolbarCard,
|
||||
SpellList,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
organize: Boolean,
|
||||
},
|
||||
data(){ return {
|
||||
preparingSpells: false,
|
||||
}},
|
||||
organize: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
preparingSpells: false,
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
spells(){
|
||||
spells() {
|
||||
let filter = {
|
||||
'ancestors.id': this.model._id,
|
||||
type: 'spell',
|
||||
removed: {$ne: true},
|
||||
removed: { $ne: true },
|
||||
};
|
||||
if (this.preparingSpells){
|
||||
filter.deactivatedByAncestor = {$ne: true};
|
||||
filter.deactivatedByToggle = {$ne: true};
|
||||
if (this.preparingSpells) {
|
||||
filter.deactivatedByAncestor = { $ne: true };
|
||||
filter.deactivatedByToggle = { $ne: true };
|
||||
} else {
|
||||
filter.inactive = {$ne: true};
|
||||
filter.inactive = { $ne: true };
|
||||
}
|
||||
return CreatureProperties.find(filter, {
|
||||
sort: {
|
||||
@@ -97,35 +99,36 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
numPrepared(){
|
||||
numPrepared() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': this.model._id,
|
||||
type: 'spell',
|
||||
removed: {$ne: true},
|
||||
removed: { $ne: true },
|
||||
prepared: true,
|
||||
alwaysPrepared: {$ne: true},
|
||||
deactivatedByAncestor: {$ne: true},
|
||||
deactivatedByToggle: {$ne: true},
|
||||
alwaysPrepared: { $ne: true },
|
||||
deactivatedByAncestor: { $ne: true },
|
||||
deactivatedByToggle: { $ne: true },
|
||||
}).count();
|
||||
},
|
||||
preparedError(){
|
||||
preparedError() {
|
||||
if (!this.model.maxPrepared) return;
|
||||
let numPrepared = this.numPrepared;
|
||||
let maxPrepared = this.model.maxPrepared.value || 0;
|
||||
return numPrepared !== maxPrepared
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickSpellList(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: {_id},
|
||||
});
|
||||
},
|
||||
}
|
||||
methods: {
|
||||
clickSpellList(_id) {
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
elementId: `${_id}`,
|
||||
data: { _id },
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -67,10 +67,10 @@ export default {
|
||||
disabled: Boolean,
|
||||
},
|
||||
computed: {
|
||||
hasClickListener(){
|
||||
hasClickListener() {
|
||||
return this.$listeners && !!this.$listeners.click;
|
||||
},
|
||||
spellComponents(){
|
||||
spellComponents() {
|
||||
let components = [];
|
||||
if (this.model.ritual) components.push('R');
|
||||
if (this.model.concentration) components.push('C');
|
||||
@@ -81,10 +81,10 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click(e){
|
||||
this.$emit('click', e);
|
||||
},
|
||||
setPrepared(val, ack){
|
||||
click(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
setPrepared(val, ack) {
|
||||
updateCreatureProperty.call({
|
||||
_id: this.model._id,
|
||||
path: ['prepared'],
|
||||
@@ -99,13 +99,17 @@ export default {
|
||||
.spell-avatar {
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.spell {
|
||||
background-color: inherit;
|
||||
}
|
||||
.primary--text .v-icon, .primary--text .v-list__tile__sub-title {
|
||||
|
||||
.primary--text .v-icon,
|
||||
.primary--text .v-list__tile__sub-title {
|
||||
color: #b71c1c
|
||||
}
|
||||
.theme--light.info-icon{
|
||||
color: rgba(0,0,0,.54) !important;
|
||||
|
||||
.theme--light.info-icon {
|
||||
color: rgba(0, 0, 0, .54) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user