UI work to improve look and feel of Viewers
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import _variable from './computeByType/computeVariable.js';
|
import _variable from './computeByType/computeVariable.js';
|
||||||
import action from './computeByType/computeAction.js';
|
import action from './computeByType/computeAction.js';
|
||||||
import attribute from './computeByType/computeAttribute.js';
|
import attribute from './computeByType/computeAttribute.js';
|
||||||
|
import skill from './computeByType/computeSkill.js';
|
||||||
import slot from './computeByType/computeSlot.js';
|
import slot from './computeByType/computeSlot.js';
|
||||||
import container from './computeByType/computeContainer.js';
|
import container from './computeByType/computeContainer.js';
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ export default Object.freeze({
|
|||||||
action,
|
action,
|
||||||
attribute,
|
attribute,
|
||||||
container,
|
container,
|
||||||
|
skill,
|
||||||
slot,
|
slot,
|
||||||
spell: action,
|
spell: action,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// If we compute this skill without a variable name, it just
|
||||||
|
// uses its base value, proficiency, and damage since no effects can target it
|
||||||
|
// If this skill does have a variable name, it is recomputed later
|
||||||
|
// by computeVariableAsSkill
|
||||||
|
export default function computeSkill(computation, node){
|
||||||
|
const prop = node.data;
|
||||||
|
prop.proficiency = prop.baseProficiency;
|
||||||
|
let profBonus = computation.scope['proficiencyBonus']?.value || 0;
|
||||||
|
// Multiply the proficiency bonus by the actual proficiency
|
||||||
|
if(prop.proficiency === 0.49){
|
||||||
|
// Round down proficiency bonus in the special case
|
||||||
|
profBonus = Math.floor(profBonus * 0.5);
|
||||||
|
} else {
|
||||||
|
profBonus = Math.ceil(profBonus * prop.proficiency);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ability = computation.scope[prop.ability];
|
||||||
|
prop.abilityMod = ability?.modifier || 0;
|
||||||
|
|
||||||
|
const base = prop.baseValue?.value || 0;
|
||||||
|
|
||||||
|
let result = base + prop.abilityMod + profBonus;
|
||||||
|
if (Number.isFinite(result)){
|
||||||
|
result = Math.floor(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
prop.value = result;
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ export default function(){
|
|||||||
assert.equal(scope('strength').modifier, 1);
|
assert.equal(scope('strength').modifier, 1);
|
||||||
assert.equal(prop('referencesDexId').value, 4);
|
assert.equal(prop('referencesDexId').value, 4);
|
||||||
assert.equal(prop('hitDiceId').constitutionMod, 5);
|
assert.equal(prop('hitDiceId').constitutionMod, 5);
|
||||||
|
assert.equal(prop('overriddenDexId').overridden, true, 'override properties with the same variable name');
|
||||||
assert.equal(
|
assert.equal(
|
||||||
prop('parseErrorId').baseValue.value, null,
|
prop('parseErrorId').baseValue.value, null,
|
||||||
'Parse errors should null the value'
|
'Parse errors should null the value'
|
||||||
@@ -44,11 +45,22 @@ var testProperties = [
|
|||||||
calculation: '12'
|
calculation: '12'
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
clean({
|
||||||
|
_id: 'overriddenDexId',
|
||||||
|
variableName: 'dexterity',
|
||||||
|
type: 'attribute',
|
||||||
|
attributeType: 'ability',
|
||||||
|
order: 1,
|
||||||
|
baseValue: {
|
||||||
|
calculation: '15'
|
||||||
|
},
|
||||||
|
}),
|
||||||
clean({
|
clean({
|
||||||
_id: 'dexterityId',
|
_id: 'dexterityId',
|
||||||
variableName: 'dexterity',
|
variableName: 'dexterity',
|
||||||
type: 'attribute',
|
type: 'attribute',
|
||||||
attributeType: 'ability',
|
attributeType: 'ability',
|
||||||
|
order: 2,
|
||||||
baseValue: {
|
baseValue: {
|
||||||
calculation: '15'
|
calculation: '15'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ let SkillSchema = createPropertySchema({
|
|||||||
regEx: VARIABLE_NAME_REGEX,
|
regEx: VARIABLE_NAME_REGEX,
|
||||||
min: 2,
|
min: 2,
|
||||||
max: STORAGE_LIMITS.variableName,
|
max: STORAGE_LIMITS.variableName,
|
||||||
|
optional: true,
|
||||||
},
|
},
|
||||||
// The variable name of the ability this skill relies on
|
// The variable name of the ability this skill relies on
|
||||||
ability: {
|
ability: {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const unaryOperator = {
|
|||||||
},
|
},
|
||||||
resolve(fn, node, scope, context){
|
resolve(fn, node, scope, context){
|
||||||
const {result: rightNode} = resolve(fn, node.right, scope, context);
|
const {result: rightNode} = resolve(fn, node.right, scope, context);
|
||||||
if (rightNode.parseType !== 'number'){
|
if (rightNode.valueType !== 'number'){
|
||||||
return {
|
return {
|
||||||
result: unaryOperator.create({
|
result: unaryOperator.create({
|
||||||
operator: node.operator,
|
operator: node.operator,
|
||||||
|
|||||||
@@ -39,13 +39,15 @@
|
|||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
children(){
|
children(){
|
||||||
return nodesToTree({
|
const children = nodesToTree({
|
||||||
collection: CreatureProperties,
|
collection: CreatureProperties,
|
||||||
ancestorId: this.root.id,
|
ancestorId: this.root.id,
|
||||||
filter: this.filter,
|
filter: this.filter,
|
||||||
includeFilteredDocAncestors: true,
|
includeFilteredDocAncestors: true,
|
||||||
includeFilteredDocDescendants: true,
|
includeFilteredDocDescendants: true,
|
||||||
});
|
});
|
||||||
|
this.$emit('length', children.length);
|
||||||
|
return children;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -41,28 +41,34 @@
|
|||||||
This property can't be viewed yet.
|
This property can't be viewed yet.
|
||||||
</p>
|
</p>
|
||||||
</v-fade-transition>
|
</v-fade-transition>
|
||||||
<template v-if="!editing && !embedded">
|
<property-field
|
||||||
<v-divider class="my-2" />
|
v-if="!editing && !embedded && childrenLength"
|
||||||
|
name="Child properties"
|
||||||
|
:cols="{cols: 12}"
|
||||||
|
>
|
||||||
<creature-properties-tree
|
<creature-properties-tree
|
||||||
v-if="!editing"
|
style="width: 100%;"
|
||||||
:root="{collection: 'creatureProperties', id: model._id}"
|
:root="{collection: 'creatureProperties', id: model._id}"
|
||||||
|
@length="childrenLength = $event"
|
||||||
@selected="selectSubProperty"
|
@selected="selectSubProperty"
|
||||||
/>
|
/>
|
||||||
<v-btn
|
</property-field>
|
||||||
text
|
|
||||||
data-id="insert-creature-property-btn"
|
|
||||||
@click="addProperty"
|
|
||||||
>
|
|
||||||
<v-icon>mdi-plus</v-icon>
|
|
||||||
Property
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
v-if="!embedded"
|
v-if="!embedded"
|
||||||
slot="actions"
|
slot="actions"
|
||||||
class="layout justify-end"
|
class="layout"
|
||||||
>
|
>
|
||||||
|
<v-btn
|
||||||
|
v-if="!editing && !embedded"
|
||||||
|
text
|
||||||
|
data-id="insert-creature-property-btn"
|
||||||
|
@click="addProperty"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-plus</v-icon>
|
||||||
|
Property
|
||||||
|
</v-btn>
|
||||||
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
text
|
text
|
||||||
@click="$store.dispatch('popDialogStack')"
|
@click="$store.dispatch('popDialogStack')"
|
||||||
@@ -99,6 +105,7 @@ import { getHighestOrder } from '/imports/api/parenting/order.js';
|
|||||||
import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty.js';
|
||||||
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
import Breadcrumbs from '/imports/ui/creature/creatureProperties/Breadcrumbs.vue';
|
||||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||||
|
import PropertyField from '/imports/ui/properties/viewers/shared/PropertyField.vue';
|
||||||
|
|
||||||
let formIndex = {};
|
let formIndex = {};
|
||||||
for (let key in propertyFormIndex){
|
for (let key in propertyFormIndex){
|
||||||
@@ -119,6 +126,7 @@ export default {
|
|||||||
PropertyToolbar,
|
PropertyToolbar,
|
||||||
CreaturePropertiesTree,
|
CreaturePropertiesTree,
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
|
PropertyField,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
_id: String,
|
_id: String,
|
||||||
@@ -130,6 +138,7 @@ export default {
|
|||||||
// CurrentId lags behind Id by one tick so that events fired by destroying
|
// CurrentId lags behind Id by one tick so that events fired by destroying
|
||||||
// forms keyed to the old ID are applied before the new ID overwrites it
|
// forms keyed to the old ID are applied before the new ID overwrites it
|
||||||
currentId: undefined,
|
currentId: undefined,
|
||||||
|
childrenLength: 0,
|
||||||
}},
|
}},
|
||||||
meteor: {
|
meteor: {
|
||||||
model(){
|
model(){
|
||||||
|
|||||||
@@ -70,8 +70,8 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="model.summary">
|
<template v-if="model.summary">
|
||||||
<property-description
|
<markdown-text
|
||||||
:model="model.summary"
|
:markdown="model.summary.value || model.summary.text"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,14 +84,14 @@ import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
|||||||
import doAction from '/imports/api/engine/actions/doAction.js';
|
import doAction from '/imports/api/engine/actions/doAction.js';
|
||||||
import AttributeConsumedView from '/imports/ui/properties/components/actions/AttributeConsumedView.vue';
|
import AttributeConsumedView from '/imports/ui/properties/components/actions/AttributeConsumedView.vue';
|
||||||
import ItemConsumedView from '/imports/ui/properties/components/actions/ItemConsumedView.vue';
|
import ItemConsumedView from '/imports/ui/properties/components/actions/ItemConsumedView.vue';
|
||||||
import PropertyDescription from '/imports/ui/properties/viewers/shared/PropertyDescription.vue';
|
|
||||||
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
|
||||||
|
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
AttributeConsumedView,
|
AttributeConsumedView,
|
||||||
ItemConsumedView,
|
ItemConsumedView,
|
||||||
PropertyDescription,
|
MarkdownText,
|
||||||
PropertyIcon,
|
PropertyIcon,
|
||||||
},
|
},
|
||||||
inject: {
|
inject: {
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
@click="click"
|
@click="click"
|
||||||
>
|
>
|
||||||
<div class="layout align-center">
|
<div class="layout align-center">
|
||||||
<v-card-title class="value text-h4">
|
<v-card-title class="value text-h4 flex-shrink-0">
|
||||||
{{ computedValue }}
|
{{ computedValue }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-title class="name text-subtitle-1 text-truncate pl-0">
|
<v-card-title class="name text-subtitle-1 text-truncate d-block pl-0">
|
||||||
{{ model.name }}
|
{{ model.name }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,14 +28,10 @@
|
|||||||
return this.$listeners && !!this.$listeners.click
|
return this.$listeners && !!this.$listeners.click
|
||||||
},
|
},
|
||||||
computedValue(){
|
computedValue(){
|
||||||
if (this.model.type === 'attribute'){
|
if (this.model.attributeType === 'modifier' || this.model.type === 'skill'){
|
||||||
if (this.model.attributeType === 'modifier'){
|
return numberToSignedString(this.model.value);
|
||||||
return numberToSignedString(this.model.value);
|
|
||||||
} else {
|
|
||||||
return this.model.value
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return this.model.value;
|
return this.model.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="attribute-viewer">
|
<div class="attribute-viewer">
|
||||||
<v-layout
|
<v-row
|
||||||
column
|
dense
|
||||||
align-center
|
align="stretch"
|
||||||
|
justify="center"
|
||||||
|
justify-sm="start"
|
||||||
>
|
>
|
||||||
<v-layout v-if="model.value !== undefined">
|
<property-field
|
||||||
|
:name="model.damage !== undefined ? 'Value / Total': 'Value'"
|
||||||
|
center
|
||||||
|
>
|
||||||
|
<v-spacer />
|
||||||
<div
|
<div
|
||||||
class="text-h4 mr-3"
|
class="text-h4 mr-3"
|
||||||
>
|
>
|
||||||
@@ -17,93 +23,171 @@
|
|||||||
{{ model.value }}
|
{{ model.value }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<v-spacer />
|
||||||
<increment-button
|
<increment-button
|
||||||
v-if="context.creatureId"
|
v-if="context.creatureId"
|
||||||
icon
|
|
||||||
large
|
|
||||||
outlined
|
outlined
|
||||||
|
icon
|
||||||
|
tile
|
||||||
color="primary"
|
color="primary"
|
||||||
:value="model.value"
|
:value="model.value"
|
||||||
@change="damageProperty"
|
@change="damageProperty"
|
||||||
>
|
>
|
||||||
<v-icon>$vuetify.icons.abacus</v-icon>
|
<v-icon>
|
||||||
|
$vuetify.icons.abacus
|
||||||
|
</v-icon>
|
||||||
</increment-button>
|
</increment-button>
|
||||||
</v-layout>
|
</property-field>
|
||||||
<div
|
<property-field
|
||||||
v-if="model.modifier !== undefined"
|
v-if="model.modifier !== undefined"
|
||||||
class="text-h6"
|
name="Modifier"
|
||||||
|
center
|
||||||
|
:value="isFinite(model.modifier) ?
|
||||||
|
numberToSignedString(model.modifier) :
|
||||||
|
model.modifier"
|
||||||
>
|
>
|
||||||
{{ numberToSignedString(model.modifier) }}
|
<div class="text-h6">
|
||||||
</div>
|
{{ numberToSignedString(model.modifier) }}
|
||||||
</v-layout>
|
</div>
|
||||||
<div>
|
</property-field>
|
||||||
<property-name :value="model.name" />
|
<property-field
|
||||||
<property-variable-name :value="model.variableName" />
|
name="Variable Name"
|
||||||
</div>
|
:value="model.variableName"
|
||||||
<property-field
|
|
||||||
v-if="model.attributeType === 'hitDice' && model.hitDiceSize"
|
|
||||||
name="Hit dice size"
|
|
||||||
:value="model.hitDiceSize"
|
|
||||||
/>
|
|
||||||
<property-field
|
|
||||||
v-if="reset && model.attributeType !== 'hitDice'"
|
|
||||||
name="Reset"
|
|
||||||
:value="reset"
|
|
||||||
/>
|
|
||||||
<property-description
|
|
||||||
:model="model.description"
|
|
||||||
/>
|
|
||||||
<v-list>
|
|
||||||
<attribute-effect
|
|
||||||
v-for="effect in baseEffects"
|
|
||||||
:key="effect._id"
|
|
||||||
:model="effect"
|
|
||||||
:hide-breadcrumbs="effect._id === model._id"
|
|
||||||
:data-id="effect._id"
|
|
||||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
|
||||||
/>
|
/>
|
||||||
<attribute-effect
|
<property-field
|
||||||
v-for="effect in effects"
|
name="Type"
|
||||||
:key="effect._id"
|
:value="attributeTypes[model.attributeType]"
|
||||||
:model="effect"
|
|
||||||
:data-id="effect._id"
|
|
||||||
@click="clickEffect(effect._id)"
|
|
||||||
/>
|
/>
|
||||||
</v-list>
|
<property-field
|
||||||
|
v-if="model.attributeType === 'hitDice' && model.hitDiceSize"
|
||||||
|
name="Hit dice size"
|
||||||
|
:value="model.hitDiceSize"
|
||||||
|
/>
|
||||||
|
<property-field
|
||||||
|
v-if="model.attributeType === 'hitDice'"
|
||||||
|
name="Constitution modifier"
|
||||||
|
:value="isFinite(model.constitutionMod) ?
|
||||||
|
numberToSignedString(model.constitutionMod) :
|
||||||
|
model.constitutionMod"
|
||||||
|
/>
|
||||||
|
<property-field
|
||||||
|
v-if="model.attributeType === 'spellSlot' && model.spellSlotLevel"
|
||||||
|
name="Spell slot level"
|
||||||
|
:value="model.spellSlotLevel.value !== undefined ? model.spellSlotLevel.value : model.spellSlotLevel.calculation"
|
||||||
|
/>
|
||||||
|
<property-field
|
||||||
|
v-if="model.attributeType === 'ability' && model.proficiency !== undefined"
|
||||||
|
name="Proficiency"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
style="height: 12px"
|
||||||
|
class="ml-1 mr-2"
|
||||||
|
>
|
||||||
|
{{ proficiencyIcon }}
|
||||||
|
</v-icon>
|
||||||
|
<div>
|
||||||
|
{{ proficiencyText[model.proficiency] }}
|
||||||
|
</div>
|
||||||
|
</property-field>
|
||||||
|
<property-field
|
||||||
|
v-if="reset && model.attributeType !== 'hitDice'"
|
||||||
|
name="Reset"
|
||||||
|
:value="reset"
|
||||||
|
/>
|
||||||
|
<property-field
|
||||||
|
v-if="model.overridden"
|
||||||
|
:cols="{cols: 6, md: 12}"
|
||||||
|
name="Overridden"
|
||||||
|
value="Overriden by another property with the same variable name"
|
||||||
|
/>
|
||||||
|
</v-row>
|
||||||
|
<v-row dense>
|
||||||
|
<property-description
|
||||||
|
label="Description"
|
||||||
|
:model="model.description"
|
||||||
|
/>
|
||||||
|
</v-row>
|
||||||
|
<v-row dense>
|
||||||
|
<property-field
|
||||||
|
v-if="baseEffects.length || effects.length"
|
||||||
|
:cols="{col: 12}"
|
||||||
|
name="Effects"
|
||||||
|
>
|
||||||
|
<v-list>
|
||||||
|
<attribute-effect
|
||||||
|
v-for="effect in baseEffects"
|
||||||
|
:key="effect._id"
|
||||||
|
:model="effect"
|
||||||
|
:hide-breadcrumbs="effect._id === model._id"
|
||||||
|
:data-id="effect._id"
|
||||||
|
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||||
|
/>
|
||||||
|
<attribute-effect
|
||||||
|
v-for="effect in effects"
|
||||||
|
:key="effect._id"
|
||||||
|
:model="effect"
|
||||||
|
:data-id="effect._id"
|
||||||
|
@click="clickEffect(effect._id)"
|
||||||
|
/>
|
||||||
|
</v-list>
|
||||||
|
</property-field>
|
||||||
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
|
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js'
|
||||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||||
import AttributeEffect from '/imports/ui/properties/components/attributes/AttributeEffect.vue';
|
import AttributeEffect from '/imports/ui/properties/components/attributes/AttributeEffect.vue';
|
||||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||||
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||||
import IncrementButton from '/imports/ui/components/IncrementButton.vue';
|
import IncrementButton from '/imports/ui/components/IncrementButton.vue';
|
||||||
|
import getProficiencyIcon from '/imports/ui/utility/getProficiencyIcon.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
AttributeEffect,
|
AttributeEffect,
|
||||||
IncrementButton,
|
IncrementButton,
|
||||||
},
|
},
|
||||||
mixins: [propertyViewerMixin],
|
mixins: [propertyViewerMixin],
|
||||||
inject: {
|
inject: {
|
||||||
context: { default: {} }
|
context: { default: {} }
|
||||||
},
|
},
|
||||||
computed: {
|
data(){return {
|
||||||
reset(){
|
attributeTypes: {
|
||||||
let reset = this.model.reset
|
ability: 'Ability score',
|
||||||
if (reset === 'shortRest'){
|
stat: 'Stat',
|
||||||
return 'Reset on a short rest';
|
modifier: 'Modifier',
|
||||||
} else if (reset === 'longRest'){
|
hitDice: 'Hit dice',
|
||||||
return 'Reset on a long rest';
|
healthBar: 'Health bar',
|
||||||
}
|
resource: 'Resource',
|
||||||
|
spellSlot: 'Spell slot',
|
||||||
|
utility: 'Utility',
|
||||||
|
},
|
||||||
|
proficiencyText: {
|
||||||
|
0: 'Not proficient',
|
||||||
|
1: 'Proficient',
|
||||||
|
0.49: 'Half proficiency bonus rounded down',
|
||||||
|
0.5: 'Half proficiency bonus rounded up',
|
||||||
|
2: 'Double proficiency bonus',
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
computed: {
|
||||||
|
reset(){
|
||||||
|
let reset = this.model.reset
|
||||||
|
if (reset === 'shortRest'){
|
||||||
|
return 'Reset on a short rest';
|
||||||
|
} else if (reset === 'longRest'){
|
||||||
|
return 'Reset on a long rest';
|
||||||
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
},
|
||||||
},
|
proficiencyIcon(){
|
||||||
methods: {
|
return getProficiencyIcon(this.model.proficiency);
|
||||||
numberToSignedString,
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
numberToSignedString,
|
||||||
clickEffect(id){
|
clickEffect(id){
|
||||||
this.$store.commit('pushDialogStack', {
|
this.$store.commit('pushDialogStack', {
|
||||||
component: 'creature-property-dialog',
|
component: 'creature-property-dialog',
|
||||||
@@ -118,7 +202,7 @@
|
|||||||
value: value
|
value: value
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
baseEffects(){
|
baseEffects(){
|
||||||
if (this.context.creatureId && this.model.variableName){
|
if (this.context.creatureId && this.model.variableName){
|
||||||
@@ -155,20 +239,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.ability-value {
|
.ability-value {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 24px !important;
|
font-size: 24px !important;
|
||||||
color: rgba(0, 0, 0, 0.54);
|
color: rgba(0, 0, 0, 0.54);
|
||||||
}
|
}
|
||||||
.mod, .ability-value {
|
.mod, .ability-value {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.attribute-value {
|
.attribute-value {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,84 +1,114 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="skill-viewer">
|
<div class="skill-viewer">
|
||||||
<v-layout
|
<v-row
|
||||||
column
|
dense
|
||||||
align-center
|
justify="center"
|
||||||
|
justify-sm="start"
|
||||||
>
|
>
|
||||||
<div
|
<property-field
|
||||||
v-if="model.value !== undefined"
|
v-if="model.value !== undefined"
|
||||||
class="text-h4 layout align-center"
|
center
|
||||||
|
large
|
||||||
|
name="Roll bonus"
|
||||||
|
:value="isFinite(model.value) ?
|
||||||
|
numberToSignedString(model.value) :
|
||||||
|
model.value"
|
||||||
|
/>
|
||||||
|
<property-field
|
||||||
|
v-if="model.proficiency !== undefined"
|
||||||
|
name="Proficiency"
|
||||||
>
|
>
|
||||||
<v-icon class="mr-4">
|
<v-icon
|
||||||
|
style="height: 12px"
|
||||||
|
class="ml-1 mr-2"
|
||||||
|
>
|
||||||
{{ icon }}
|
{{ icon }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
<div v-if="isFinite(model.value)">
|
<div>
|
||||||
{{ numberToSignedString(model.value) }}
|
{{ proficiencyText[model.proficiency] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</property-field>
|
||||||
</v-layout>
|
<property-field
|
||||||
<property-name :value="model.name" />
|
name="Variable Name"
|
||||||
<property-variable-name :value="model.variableName" />
|
:value="model.variableName"
|
||||||
<property-field
|
/>
|
||||||
name="Ability"
|
<property-field
|
||||||
:value="model.ability"
|
name="Ability"
|
||||||
/>
|
:value="model.ability"
|
||||||
<property-field
|
/>
|
||||||
name="Type"
|
<property-field
|
||||||
:value="model.skillType"
|
name="Skill type"
|
||||||
/>
|
:value="model.skillType"
|
||||||
<property-field
|
/>
|
||||||
name="Base value"
|
</v-row>
|
||||||
:value="model.baseValue"
|
|
||||||
/>
|
|
||||||
<property-field
|
|
||||||
name="Base proficiency"
|
|
||||||
:value="model.baseProficiency"
|
|
||||||
/>
|
|
||||||
<property-description
|
<property-description
|
||||||
:string="model.description"
|
:string="model.description"
|
||||||
:calculations="model.descriptionCalculations"
|
:calculations="model.descriptionCalculations"
|
||||||
:inactive="model.inactive"
|
:inactive="model.inactive"
|
||||||
/>
|
/>
|
||||||
|
<v-row
|
||||||
<attribute-effect
|
v-if="baseEffects.length || ability || effects.length"
|
||||||
v-for="effect in baseEffects"
|
dense
|
||||||
:key="effect._id"
|
>
|
||||||
:model="effect"
|
<property-field
|
||||||
:hide-breadcrumbs="effect._id === model._id"
|
:cols="{col: 12}"
|
||||||
:data-id="effect._id"
|
name="Effects"
|
||||||
@click="effect._id !== model._id && clickEffect(effect._id)"
|
>
|
||||||
/>
|
<v-list style="width: 100%">
|
||||||
<attribute-effect
|
<attribute-effect
|
||||||
v-if="ability"
|
v-for="effect in baseEffects"
|
||||||
:key="ability._id"
|
:key="effect._id === model._id ? 'this_base' : effect._id"
|
||||||
:model="ability"
|
:model="effect"
|
||||||
:data-id="ability._id"
|
:hide-breadcrumbs="effect._id === model._id"
|
||||||
@click="clickEffect(ability._id)"
|
:data-id="effect._id"
|
||||||
/>
|
@click="effect._id !== model._id && clickEffect(effect._id)"
|
||||||
<attribute-effect
|
/>
|
||||||
v-for="effect in effects"
|
<attribute-effect
|
||||||
:key="effect._id"
|
v-if="ability"
|
||||||
:model="effect"
|
:key="ability._id"
|
||||||
:data-id="effect._id"
|
:model="ability"
|
||||||
@click="clickEffect(effect._id)"
|
:data-id="ability._id"
|
||||||
/>
|
@click="clickEffect(ability._id)"
|
||||||
<skill-proficiency
|
/>
|
||||||
v-for="proficiency in baseProficiencies"
|
<attribute-effect
|
||||||
:key="proficiency._id"
|
v-for="effect in effects"
|
||||||
:model="proficiency"
|
:key="effect._id"
|
||||||
:proficiency-bonus="proficiencyBonus"
|
:model="effect"
|
||||||
:hide-breadcrumbs="proficiency._id === model._id"
|
:data-id="effect._id"
|
||||||
:data-id="proficiency._id"
|
@click="clickEffect(effect._id)"
|
||||||
@click="clickEffect(proficiency._id)"
|
/>
|
||||||
/>
|
</v-list>
|
||||||
<skill-proficiency
|
</property-field>
|
||||||
v-for="proficiency in proficiencies"
|
</v-row>
|
||||||
:key="proficiency._id"
|
<v-row
|
||||||
:model="proficiency"
|
v-if="baseProficiencies.length || proficiencies.length"
|
||||||
:proficiency-bonus="proficiencyBonus"
|
dense
|
||||||
:data-id="proficiency._id"
|
>
|
||||||
@click="clickEffect(proficiency._id)"
|
<property-field
|
||||||
/>
|
:cols="{col: 12}"
|
||||||
|
name="Proficiencies"
|
||||||
|
>
|
||||||
|
<v-list style="width: 100%">
|
||||||
|
<skill-proficiency
|
||||||
|
v-for="proficiency in baseProficiencies"
|
||||||
|
:key="proficiency._id"
|
||||||
|
:model="proficiency"
|
||||||
|
:proficiency-bonus="proficiencyBonus"
|
||||||
|
:hide-breadcrumbs="proficiency._id === model._id"
|
||||||
|
:data-id="proficiency._id"
|
||||||
|
@click="clickEffect(proficiency._id)"
|
||||||
|
/>
|
||||||
|
<skill-proficiency
|
||||||
|
v-for="proficiency in proficiencies"
|
||||||
|
:key="proficiency._id"
|
||||||
|
:model="proficiency"
|
||||||
|
:proficiency-bonus="proficiencyBonus"
|
||||||
|
:data-id="proficiency._id"
|
||||||
|
@click="clickEffect(proficiency._id)"
|
||||||
|
/>
|
||||||
|
</v-list>
|
||||||
|
</property-field>
|
||||||
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -100,6 +130,15 @@ export default {
|
|||||||
inject: {
|
inject: {
|
||||||
context: { default: {} }
|
context: { default: {} }
|
||||||
},
|
},
|
||||||
|
data(){return {
|
||||||
|
proficiencyText: {
|
||||||
|
0: 'Not proficient',
|
||||||
|
1: 'Proficient',
|
||||||
|
0.49: 'Half proficiency bonus rounded down',
|
||||||
|
0.5: 'Half proficiency bonus rounded up',
|
||||||
|
2: 'Double proficiency bonus',
|
||||||
|
},
|
||||||
|
}},
|
||||||
computed: {
|
computed: {
|
||||||
displayedModifier(){
|
displayedModifier(){
|
||||||
let mod = this.model.value;
|
let mod = this.model.value;
|
||||||
@@ -139,23 +178,23 @@ export default {
|
|||||||
name: 'Skill base value',
|
name: 'Skill base value',
|
||||||
operation: 'base',
|
operation: 'base',
|
||||||
calculation: prop.baseValueCalculation,
|
calculation: prop.baseValueCalculation,
|
||||||
result: prop.baseValue,
|
amount: {value: prop.baseValue?.value},
|
||||||
stats: [prop.variableName],
|
stats: [prop.variableName],
|
||||||
ancestors: prop.ancestors,
|
ancestors: prop.ancestors,
|
||||||
}) ).filter(effect => effect.result);
|
}) ).filter(effect => effect.amount?.value);
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
effects(){
|
effects(){
|
||||||
if (this.context.creatureId){
|
if (this.context.creatureId && this.model.variableName){
|
||||||
let creatureId = this.context.creatureId;
|
let creatureId = this.context.creatureId;
|
||||||
return CreatureProperties.find({
|
return CreatureProperties.find({
|
||||||
'ancestors.id': creatureId,
|
'ancestors.id': creatureId,
|
||||||
stats: this.model.variableName,
|
stats: this.model.variableName,
|
||||||
type: 'effect',
|
type: 'effect',
|
||||||
removed: {$ne: true},
|
removed: {$ne: true},
|
||||||
});
|
}).fetch();
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -189,7 +228,7 @@ export default {
|
|||||||
type: 'proficiency',
|
type: 'proficiency',
|
||||||
removed: {$ne: true},
|
removed: {$ne: true},
|
||||||
inactive: {$ne: true},
|
inactive: {$ne: true},
|
||||||
});
|
}).fetch();
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -211,7 +250,7 @@ export default {
|
|||||||
_id: abilityProp._id,
|
_id: abilityProp._id,
|
||||||
name: abilityProp.name,
|
name: abilityProp.name,
|
||||||
operation: 'base',
|
operation: 'base',
|
||||||
result: abilityProp.modifier,
|
amount: {value: abilityProp.modifier},
|
||||||
stats: [this.model.variableName],
|
stats: [this.model.variableName],
|
||||||
ancestors: abilityProp.ancestors,
|
ancestors: abilityProp.ancestors,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,32 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<markdown-text
|
<property-field
|
||||||
v-if="model"
|
v-if="model"
|
||||||
:markdown="model.value"
|
:name="label"
|
||||||
/>
|
:cols="{col: 12}"
|
||||||
|
>
|
||||||
|
<markdown-text
|
||||||
|
:markdown="model.value || model.text"
|
||||||
|
/>
|
||||||
|
</property-field>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
|
||||||
|
import PropertyField from '/imports/ui/properties/viewers/shared/PropertyField.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MarkdownText,
|
MarkdownText,
|
||||||
|
PropertyField,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
model: {
|
model: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,42 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div v-if="value !== undefined || $slots.default">
|
<v-col
|
||||||
<div class="text-caption">
|
v-if="value !== undefined || ($slots.default && $slots.default.length)"
|
||||||
{{ name }}
|
v-bind="cols"
|
||||||
</div>
|
class="mb-2"
|
||||||
<p class="ml-2 subheading">
|
>
|
||||||
<slot>
|
<v-sheet
|
||||||
{{ value }}
|
outlined
|
||||||
</slot>
|
rounded
|
||||||
</p>
|
class="pa-2 layout column align-start fill-height"
|
||||||
</div>
|
>
|
||||||
|
<v-sheet
|
||||||
|
v-if="name"
|
||||||
|
class="text-caption px-1 name"
|
||||||
|
style="margin-top: -18px;"
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</v-sheet>
|
||||||
|
<div
|
||||||
|
class="flex-grow-1 layout align-center"
|
||||||
|
style="width: 100%;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="layout align-center"
|
||||||
|
:class="{
|
||||||
|
'text-body-1': !large,
|
||||||
|
'text-h4': large,
|
||||||
|
'justify-center': center,
|
||||||
|
}"
|
||||||
|
style="overflow-x: auto;"
|
||||||
|
v-bind="$attrs"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
{{ value }}
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-sheet>
|
||||||
|
</v-col>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
@@ -16,9 +44,21 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
value: [String, Number, Boolean],
|
value: [String, Number, Boolean],
|
||||||
}
|
center: Boolean,
|
||||||
|
large: Boolean,
|
||||||
|
cols: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({cols: 12, sm: 6, md: 4}),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
.name {
|
||||||
|
color: rgba(0,0,0,.6);
|
||||||
|
}
|
||||||
|
.theme--dark .name {
|
||||||
|
color: rgba(255,255,255,.7);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user