Merge branch 'develop' into version-2-tabletop
@@ -1,8 +1,14 @@
|
||||
import { createS3FilesCollection } from '/imports/api/files/s3FileStorage.js';
|
||||
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { incrementFileStorageUsed } from '/imports/api/users/methods/updateFileStorageUsed.js';
|
||||
import { CreaturePropertySchema } from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { CreatureSchema } from '/imports/api/creature/creatures/Creatures.js';
|
||||
let createS3FilesCollection;
|
||||
if (Meteor.isServer) {
|
||||
createS3FilesCollection = require('/imports/api/files/server/s3FileStorage.js').createS3FilesCollection
|
||||
} else {
|
||||
createS3FilesCollection = require('/imports/api/files/client/s3FileStorage.js').createS3FilesCollection
|
||||
}
|
||||
|
||||
const ArchiveCreatureFiles = createS3FilesCollection({
|
||||
collectionName: 'archiveCreatureFiles',
|
||||
|
||||
@@ -83,13 +83,13 @@ export function resetProperties(creatureId, resetFilter, actionContext) {
|
||||
const attributeFilter = {
|
||||
...filter,
|
||||
type: 'attribute',
|
||||
damage: { $ne: 0 },
|
||||
damage: { $nin: [0, undefined] },
|
||||
}
|
||||
CreatureProperties.find(attributeFilter).forEach(prop => {
|
||||
damagePropertyWork({
|
||||
prop,
|
||||
operation: 'increment',
|
||||
value: -prop.damage,
|
||||
value: -prop.damage ?? 0,
|
||||
actionContext,
|
||||
logFunction(increment) {
|
||||
actionContext.addLog({
|
||||
@@ -105,7 +105,7 @@ export function resetProperties(creatureId, resetFilter, actionContext) {
|
||||
type: {
|
||||
$in: ['action', 'spell']
|
||||
},
|
||||
usesUsed: { $ne: 0 },
|
||||
usesUsed: { $nin: [0, undefined] },
|
||||
};
|
||||
CreatureProperties.find(actionFilter, {
|
||||
fields: { name: 1, usesUsed: 1 }
|
||||
|
||||
@@ -165,7 +165,7 @@ function rollAttack(attack, scope) {
|
||||
}
|
||||
scope['$attackDiceRoll'] = { value };
|
||||
const result = value + attack.value;
|
||||
scope['$attackRoll'] = { result };
|
||||
scope['$attackRoll'] = { value: result };
|
||||
const { criticalHit, criticalMiss } = applyCrits(value, scope);
|
||||
return { resultPrefix, result, value, criticalHit, criticalMiss };
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { createS3FilesCollection } from '/imports/api/files/s3FileStorage.js';
|
||||
let createS3FilesCollection;
|
||||
if (Meteor.isServer) {
|
||||
createS3FilesCollection = require('/imports/api/files/server/s3FileStorage.js').createS3FilesCollection
|
||||
} else {
|
||||
createS3FilesCollection = require('/imports/api/files/client/s3FileStorage.js').createS3FilesCollection
|
||||
}
|
||||
|
||||
const UserImages = createS3FilesCollection({
|
||||
collectionName: 'userImages',
|
||||
|
||||
24
app/imports/api/files/client/s3FileStorage.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/aws-s3-integration.md
|
||||
import { FilesCollection } from 'meteor/ostrio:files';
|
||||
|
||||
const createS3FilesCollection = function ({
|
||||
collectionName,
|
||||
storagePath,
|
||||
onBeforeUpload,
|
||||
onAfterUpload,
|
||||
debug,// = !Meteor.isProduction,
|
||||
allowClientCode = false,
|
||||
}) {
|
||||
const collection = new FilesCollection({
|
||||
collectionName,
|
||||
storagePath,
|
||||
onBeforeUpload,
|
||||
onAfterUpload,
|
||||
debug,
|
||||
allowClientCode,
|
||||
});
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
export { createS3FilesCollection };
|
||||
@@ -1,2 +0,0 @@
|
||||
import S3 from 'aws-sdk/clients/s3';
|
||||
export default S3;
|
||||
@@ -4,9 +4,7 @@ import { each, clone } from 'lodash';
|
||||
import { Random } from 'meteor/random';
|
||||
import { FilesCollection } from 'meteor/ostrio:files';
|
||||
import stream from 'stream';
|
||||
if (Meteor.isServer) {
|
||||
import S3 from '/imports/api/files/server/s3.js';
|
||||
}
|
||||
import S3 from 'aws-sdk/clients/s3';
|
||||
|
||||
/* See fs-extra and graceful-fs NPM packages */
|
||||
/* For better i/o performance */
|
||||
@@ -31,7 +29,7 @@ let createS3FilesCollection;
|
||||
|
||||
/* Check settings existence in `Meteor.settings` */
|
||||
/* This is the best practice for app security */
|
||||
if (Meteor.isServer && Meteor.settings.useS3) {
|
||||
if (Meteor.settings.useS3) {
|
||||
// Create a new S3 object
|
||||
const s3 = new S3({
|
||||
accessKeyId: s3Conf.key,
|
||||
@@ -236,13 +234,11 @@ if (Meteor.isServer && Meteor.settings.useS3) {
|
||||
allowClientCode,
|
||||
});
|
||||
|
||||
if (Meteor.isServer) {
|
||||
// Use the normal file system to read files
|
||||
collection.readJSONFile = async function (file) {
|
||||
const fileString = await fsp.readFile(file.path, 'utf8');
|
||||
return JSON.parse(fileString);
|
||||
};
|
||||
}
|
||||
// Use the normal file system to read files
|
||||
collection.readJSONFile = async function (file) {
|
||||
const fileString = await fsp.readFile(file.path, 'utf8');
|
||||
return JSON.parse(fileString);
|
||||
};
|
||||
|
||||
return collection;
|
||||
}
|
||||
@@ -39,9 +39,6 @@ export default {
|
||||
|
||||
.column-layout>div,
|
||||
.column-layout>span>div {
|
||||
/*
|
||||
Table and width set because firefox does not support break-inside: avoid
|
||||
*/
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<v-icon
|
||||
class="handle"
|
||||
v-bind="$attrs"
|
||||
@click.stop="() => { }"
|
||||
@touchstart.native.stop="() => { }"
|
||||
@click.native="e => { }"
|
||||
@touchstart.native.stop="e => { }"
|
||||
@touchend.native="portalEvent"
|
||||
>
|
||||
mdi-drag
|
||||
|
||||
@@ -218,30 +218,30 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
changeShowTreeTab(value) {
|
||||
let currentTab = this.$store.getters.tabNameById(this.model._id);
|
||||
if (!value && currentTab === 'tree') {
|
||||
this.$store.commit(
|
||||
'setTabForCharacterSheet',
|
||||
{ id: this.model._id, tab: 'build' }
|
||||
);
|
||||
}
|
||||
this.$emit('change', {
|
||||
path: ['settings', 'showTreeTab'],
|
||||
value: !!value
|
||||
});
|
||||
let currentTab = this.$store.getters.tabById(this.model._id);
|
||||
if (!value && currentTab === 5) {
|
||||
this.$store.commit(
|
||||
'setTabForCharacterSheet',
|
||||
{ id: this.model._id, tab: 4 }
|
||||
);
|
||||
}
|
||||
},
|
||||
changeHideSpellsTab(value) {
|
||||
let currentTab = this.$store.getters.tabNameById(this.model._id);
|
||||
if (!value && currentTab === 'spells') {
|
||||
this.$store.commit(
|
||||
'setTabForCharacterSheet',
|
||||
{ id: this.model._id, tab: 'actions' }
|
||||
);
|
||||
}
|
||||
this.$emit('change', {
|
||||
path: ['settings', 'hideSpellsTab'],
|
||||
value: !value
|
||||
});
|
||||
let currentTab = this.$store.getters.tabById(this.model._id);
|
||||
if (!value && currentTab === 3) {
|
||||
this.$store.commit(
|
||||
'setTabForCharacterSheet',
|
||||
{ id: this.model._id, tab: 4 }
|
||||
);
|
||||
}
|
||||
},
|
||||
allUserLibrariesChange(value, ack) {
|
||||
toggleAllUserLibraries.call({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:class="{
|
||||
'empty': !hasChildren,
|
||||
}"
|
||||
:data-id="`build-tree-node-${node._id}`"
|
||||
:data-id="`tree-node-${node._id}`"
|
||||
>
|
||||
<div
|
||||
class="layout align-center justify-start tree-node-title"
|
||||
|
||||
@@ -195,7 +195,7 @@ export default {
|
||||
} else {
|
||||
this.$store.commit(
|
||||
'setTabForCharacterSheet',
|
||||
{id: creatureId, tab: 5}
|
||||
{id: creatureId, tab: 'build'}
|
||||
);
|
||||
this.$emit('pop', creatureId);
|
||||
defer(() => {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</v-toolbar-title>
|
||||
<div>
|
||||
<p v-if="name">
|
||||
Type "{{ name }}" to permanenetly delete the character
|
||||
Type "{{ name }}" to permanently delete the character
|
||||
</p>
|
||||
<v-text-field
|
||||
v-if="name"
|
||||
|
||||
@@ -46,9 +46,6 @@
|
||||
<v-tab-item>
|
||||
<stats-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<features-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<actions-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
@@ -58,6 +55,9 @@
|
||||
<v-tab-item>
|
||||
<inventory-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<features-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
<v-tab-item>
|
||||
<character-tab :creature-id="creatureId" />
|
||||
</v-tab-item>
|
||||
@@ -96,22 +96,22 @@
|
||||
<span>Stats</span>
|
||||
<v-icon>mdi-chart-box</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span>Features</span>
|
||||
<v-icon>mdi-text</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span>Actions</span>
|
||||
<v-icon>mdi-lightning-bolt</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span v-if="!creature.settings.hideSpellsTab">Spells</span>
|
||||
<v-btn v-if="!creature.settings.hideSpellsTab">
|
||||
<span>Spells</span>
|
||||
<v-icon>mdi-fire</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span>Inventory</span>
|
||||
<v-icon>mdi-cube</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span>Features</span>
|
||||
<v-icon>mdi-text</v-icon>
|
||||
</v-btn>
|
||||
<v-btn>
|
||||
<span>Journal</span>
|
||||
<v-icon>mdi-book-open-variant</v-icon>
|
||||
|
||||
@@ -39,27 +39,45 @@
|
||||
<v-icon>mdi-dots-vertical</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list v-if="editPermission">
|
||||
<v-list-item @click="deleteCharacter">
|
||||
<v-list>
|
||||
<v-list-item :to="printUrl">
|
||||
<v-list-item-title>
|
||||
<v-icon>mdi-delete</v-icon> Delete
|
||||
<v-icon left>
|
||||
mdi-printer
|
||||
</v-icon> Print
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="showCharacterForm">
|
||||
<template v-if="editPermission">
|
||||
<v-list-item @click="deleteCharacter">
|
||||
<v-list-item-title>
|
||||
<v-icon left>
|
||||
mdi-delete
|
||||
</v-icon> Delete
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="showCharacterForm">
|
||||
<v-list-item-title>
|
||||
<v-icon left>
|
||||
mdi-pencil
|
||||
</v-icon> Edit details
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="showShareDialog">
|
||||
<v-list-item-title>
|
||||
<v-icon left>
|
||||
mdi-share-variant
|
||||
</v-icon> Sharing
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list-item
|
||||
v-else
|
||||
@click="unshareWithMe"
|
||||
>
|
||||
<v-list-item-title>
|
||||
<v-icon>mdi-pencil</v-icon> Edit details
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="showShareDialog">
|
||||
<v-list-item-title>
|
||||
<v-icon>mdi-share-variant</v-icon> Sharing
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-list v-else>
|
||||
<v-list-item @click="unshareWithMe">
|
||||
<v-list-item-title>
|
||||
<v-icon>mdi-delete</v-icon> Unshare with me
|
||||
<v-icon left>
|
||||
mdi-delete
|
||||
</v-icon> Unshare with me
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
@@ -101,9 +119,6 @@
|
||||
<v-tab>
|
||||
Stats
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
Features
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
Actions
|
||||
</v-tab>
|
||||
@@ -113,6 +128,9 @@
|
||||
<v-tab>
|
||||
Inventory
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
Features
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
Journal
|
||||
</v-tab>
|
||||
@@ -144,6 +162,7 @@ import isDarkColor from '/imports/client/ui/utility/isDarkColor.js';
|
||||
import CharacterSheetFab from '/imports/client/ui/creature/character/CharacterSheetFab.vue';
|
||||
import getThemeColor from '/imports/client/ui/utility/getThemeColor.js';
|
||||
import SharedIcon from '/imports/client/ui/components/SharedIcon.vue';
|
||||
import getCreatureUrlName from '/imports/api/creature/creatures/getCreatureUrlName.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -167,6 +186,9 @@ export default {
|
||||
isDark() {
|
||||
return isDarkColor(this.toolbarColor);
|
||||
},
|
||||
printUrl() {
|
||||
return `/print-character/${this.creature._id}/${getCreatureUrlName(this.creature)}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
|
||||
@@ -58,8 +58,20 @@ export default {
|
||||
}},
|
||||
meteor: {
|
||||
actions() {
|
||||
return CreatureProperties.find({
|
||||
const folderIds = CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
type: 'folder',
|
||||
groupStats: true,
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: folderIds,
|
||||
},
|
||||
type: 'action',
|
||||
actionType: { $ne: 'event' },
|
||||
removed: { $ne: true },
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<build-tree-node-list
|
||||
:children="slotBuildTree"
|
||||
class="mx-2"
|
||||
@selected="_id => propertyClicked({_id, prefix: 'build-tree-node-'})"
|
||||
@selected="_id => propertyClicked({_id, prefix: 'tree-node-'})"
|
||||
/>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
@@ -56,8 +56,20 @@ export default {
|
||||
},
|
||||
meteor: {
|
||||
features() {
|
||||
return CreatureProperties.find({
|
||||
const folderIds = CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
type: 'folder',
|
||||
groupStats: true,
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: folderIds,
|
||||
},
|
||||
type: 'feature',
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
|
||||
@@ -141,9 +141,22 @@ export default {
|
||||
};
|
||||
},
|
||||
meteor: {
|
||||
containers() {
|
||||
folderIds() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
type: 'folder',
|
||||
groupStats: true,
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
},
|
||||
containers() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.folderIds,
|
||||
},
|
||||
type: 'container',
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
@@ -166,7 +179,7 @@ export default {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.containerIds
|
||||
$nin: [...this.containerIds, ...this.folderIds],
|
||||
},
|
||||
type: 'container',
|
||||
removed: { $ne: true },
|
||||
@@ -179,7 +192,7 @@ export default {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.containerIds
|
||||
$nin: [...this.containerIds, ...this.folderIds],
|
||||
},
|
||||
type: 'item',
|
||||
equipped: { $ne: true },
|
||||
|
||||
@@ -60,8 +60,20 @@ export default {
|
||||
},
|
||||
meteor: {
|
||||
notes(){
|
||||
return CreatureProperties.find({
|
||||
const folderIds = CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
type: 'folder',
|
||||
groupStats: true,
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: folderIds,
|
||||
},
|
||||
type: 'note',
|
||||
removed: {$ne: true},
|
||||
inactive: {$ne: true},
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
@remove="softRemove"
|
||||
/>
|
||||
<div
|
||||
v-if="spellSlots && spellSlots.length || hasSpells"
|
||||
v-if="hasSpellSlots || hasSpells"
|
||||
class="spell-slots"
|
||||
>
|
||||
<spell-slot-card
|
||||
@@ -77,9 +77,33 @@ export default {
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
spellSlots() {
|
||||
folderIds() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
type: 'folder',
|
||||
groupStats: true,
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
},
|
||||
hasSpellSlots() {
|
||||
return !!CreatureProperties.findOne({
|
||||
'ancestors.id': this.creatureId,
|
||||
inactive: { $ne: true },
|
||||
removed: { $ne: true },
|
||||
overridden: { $ne: true },
|
||||
level: { $ne: 0 },
|
||||
type: 'attribute',
|
||||
attributeType: 'spellSlot',
|
||||
});
|
||||
},
|
||||
spellSlots() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.folderIds,
|
||||
},
|
||||
inactive: { $ne: true },
|
||||
removed: { $ne: true },
|
||||
overridden: { $ne: true },
|
||||
@@ -89,11 +113,16 @@ export default {
|
||||
{ hideWhenTotalZero: true, total: 0 },
|
||||
{ hideWhenValueZero: true, value: 0 },
|
||||
],
|
||||
}, {
|
||||
sort: { order: 1 }
|
||||
});
|
||||
},
|
||||
spellLists() {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': this.creatureId,
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.folderIds,
|
||||
},
|
||||
type: 'spellList',
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
@@ -113,7 +142,7 @@ export default {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.spellListIds,
|
||||
$nin: [...this.spellListIds, ...this.folderIds],
|
||||
},
|
||||
type: 'spell',
|
||||
removed: { $ne: true },
|
||||
@@ -130,7 +159,7 @@ export default {
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.creatureId,
|
||||
$nin: this.spellListIds,
|
||||
$nin: [...this.spellListIds, ...this.folderIds],
|
||||
},
|
||||
type: 'spellList',
|
||||
removed: { $ne: true },
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@remove="softRemove"
|
||||
/>
|
||||
<div
|
||||
v-if="!creature.settings.hideRestButtons || (properties.action.event && properties.action.event.length)"
|
||||
v-if="!creature.settings.hideRestButtons || (properties.action && properties.action.event && properties.action.event.length)"
|
||||
class="character-buttons"
|
||||
>
|
||||
<v-card>
|
||||
@@ -161,13 +161,13 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="properties.hitDice && properties.hitDice.length"
|
||||
v-if="properties.attribute.hitDice && properties.attribute.hitDice.length"
|
||||
class="hit-dice"
|
||||
>
|
||||
<v-card>
|
||||
<v-list>
|
||||
<v-subheader>Hit Dice</v-subheader>
|
||||
<template v-for="(hitDie, index) in hitDice">
|
||||
<template v-for="(hitDie, index) in properties.attribute.hitDice">
|
||||
<v-divider
|
||||
v-if="index !== 0"
|
||||
:key="hitDie._id + 'divider'"
|
||||
@@ -427,10 +427,10 @@ const propertyHandlers = {
|
||||
folder(prop) {
|
||||
let skipChildren;
|
||||
let propPath = null;
|
||||
if (prop.hideStatsGroup) {
|
||||
return { skipChildren: true}
|
||||
if (prop.groupStats && prop.hideStatsGroup) {
|
||||
skipChildren = true;
|
||||
}
|
||||
if (prop.tab === 'stats') {
|
||||
if (prop.groupStats && prop.tab === 'stats') {
|
||||
propPath = ['folder', prop.location]
|
||||
}
|
||||
return { skipChildren, propPath }
|
||||
@@ -546,7 +546,7 @@ export default {
|
||||
if (creature.settings.hideUnusedStats) {
|
||||
filter.hide = { $ne: true };
|
||||
}
|
||||
const allProps = CreatureProperties.find(filter, { sort: { order: 1 } });
|
||||
const allProps = CreatureProperties.find(filter, { sort: { order: -1 } });
|
||||
const forest = nodeArrayToTree(allProps);
|
||||
const properties = { folder: {}, attribute: {}, skill: {} };
|
||||
walkDown(forest, node => {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
light
|
||||
>
|
||||
<div class="page pa-3">
|
||||
<div class="px-3 d-flex align-center">
|
||||
<div class="title-block px-3 d-flex align-center">
|
||||
<div class="logo-background" />
|
||||
<div class="creature-name mr-3">
|
||||
{{ creature.name }}
|
||||
@@ -42,7 +42,7 @@
|
||||
{{ creature.alignment }} {{ background }}
|
||||
</div>
|
||||
<dir v-if="race || creature.gender">
|
||||
{{ race }} {{ creature.gender }}
|
||||
{{ creature.gender }} {{ race }}
|
||||
</dir>
|
||||
<div v-if="level && classes && classes.length === 1">
|
||||
Level {{ level }} {{ classes[0].name }}
|
||||
@@ -236,9 +236,33 @@ export default {
|
||||
color: black;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.character-sheet-printed * {
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
cursor: unset !important;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.character-sheet-printed .column-layout, .character-sheet-printed .column-layout.wide-columns {
|
||||
position:relative;
|
||||
width: 100%;
|
||||
widows: 0;
|
||||
orphans: 0;
|
||||
-webkit-column-fill: balance-all;
|
||||
column-fill: balance-all;
|
||||
}
|
||||
|
||||
.character-sheet-printed .column-layout>div {
|
||||
position:relative;
|
||||
}
|
||||
.character-sheet-printed .column-layout > div > * {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.character-sheet-printed .inactive {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
@@ -253,8 +277,6 @@ export default {
|
||||
background-image: url(/crown-dice-logo-cropped-transparent.png);
|
||||
background-size: contain;
|
||||
background-position: 0 center;
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
|
||||
.character-sheet-printed .v-divider {
|
||||
@@ -265,39 +287,26 @@ export default {
|
||||
.character-sheet-printed .double-border {
|
||||
position: relative;
|
||||
padding: 11px 10px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.character-sheet-printed .double-border::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-image-source: url(/images/print/doubleLineImageBorder.png);
|
||||
border-image-slice: 110 126 fill;
|
||||
border-image-width: 16px;
|
||||
border-image-repeat: stretch;
|
||||
box-sizing: content-box;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.character-sheet-printed .octagon-border {
|
||||
position: relative;
|
||||
padding: 4px 20px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.character-sheet-printed .octagon-border::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-image: url(/images/print/octagonBorder.png) 124 118 fill;
|
||||
border-image-width: 22px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.character-sheet-printed .span-all {
|
||||
page-break-after: avoid;
|
||||
break-after: avoid;
|
||||
}
|
||||
.span-all + div {
|
||||
page-break-before: avoid;
|
||||
break-before: avoid;
|
||||
}
|
||||
|
||||
.character-sheet-printed .stats .label {
|
||||
@@ -326,10 +335,32 @@ export default {
|
||||
}
|
||||
}
|
||||
@media print {
|
||||
header {
|
||||
display: none !important;
|
||||
@page {
|
||||
size: auto;
|
||||
margin: 8mm 8mm 8mm 8mm;
|
||||
}
|
||||
nav {
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
.character-sheet-printed .page {
|
||||
width: 100%;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.character-sheet-printed .column-layout {
|
||||
padding: 4px 0 !important;
|
||||
}
|
||||
.character-sheet-printed .title-block {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 4px !important;
|
||||
}
|
||||
.v-main, .v-application, .v-application--wrap, .character-sheet-printed {
|
||||
display: block !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
html {
|
||||
background-color: white !important;
|
||||
}
|
||||
header, nav, .v-snack, .dialog-stack {
|
||||
display: none !important;
|
||||
}
|
||||
.v-main {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<v-app-bar
|
||||
app
|
||||
class="character-sheet-printed-toolbar"
|
||||
:color="toolbarColor"
|
||||
:dark="isDark"
|
||||
:light="!isDark"
|
||||
clipped-right
|
||||
:extended="$vuetify.breakpoint.smAndUp"
|
||||
:tabs="$vuetify.breakpoint.smAndUp"
|
||||
dense
|
||||
>
|
||||
<v-app-bar-nav-icon @click="toggleDrawer" />
|
||||
<v-btn
|
||||
icon
|
||||
:to="characterUrl"
|
||||
>
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>
|
||||
<v-fade-transition mode="out-in">
|
||||
<div :key="$store.state.pageTitle">
|
||||
{{ $store.state.pageTitle }}
|
||||
</div>
|
||||
</v-fade-transition>
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<div
|
||||
slot="extension"
|
||||
style="width: 100%"
|
||||
>
|
||||
<v-btn
|
||||
class="print-fab"
|
||||
color="accent"
|
||||
elevation="4"
|
||||
fab
|
||||
@click="print"
|
||||
>
|
||||
<v-icon>mdi-printer</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import { mapMutations } from 'vuex';
|
||||
import isDarkColor from '/imports/client/ui/utility/isDarkColor.js';
|
||||
import getThemeColor from '/imports/client/ui/utility/getThemeColor.js';
|
||||
import getCreatureUrlName from '/imports/api/creature/creatures/getCreatureUrlName.js';
|
||||
|
||||
export default {
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
computed: {
|
||||
creatureId() {
|
||||
return this.$route.params.id;
|
||||
},
|
||||
toolbarColor() {
|
||||
if (this.creature && this.creature.color) {
|
||||
return this.creature.color;
|
||||
} else {
|
||||
return getThemeColor('secondary');
|
||||
}
|
||||
},
|
||||
isDark() {
|
||||
return isDarkColor(this.toolbarColor);
|
||||
},
|
||||
characterUrl() {
|
||||
if (!this.creature) return;
|
||||
return `/character/${this.creature._id}/${getCreatureUrlName(this.creature)}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'toggleDrawer',
|
||||
]),
|
||||
print() {
|
||||
print();
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
creature() {
|
||||
return Creatures.findOne(this.creatureId);
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.print-fab {
|
||||
position: absolute;
|
||||
bottom: -24px;
|
||||
right: 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,6 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
class="inventory"
|
||||
style="page-break-before: always;"
|
||||
>
|
||||
<column-layout wide-columns>
|
||||
<div class="span-all">
|
||||
@@ -62,7 +61,7 @@
|
||||
>
|
||||
<div
|
||||
:key="container._id"
|
||||
class="span-all container-header"
|
||||
class="span-all"
|
||||
>
|
||||
<printed-container
|
||||
class="octagon-border"
|
||||
@@ -232,22 +231,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.octagon-border {
|
||||
position: relative;
|
||||
padding: 4px 20px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.octagon-border::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-image: url(/images/print/octagonBorder.png) 124 118 fill;
|
||||
border-image-width: 22px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14pt;
|
||||
@@ -262,9 +245,4 @@ export default {
|
||||
.inventory-stat > .v-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.container-header {
|
||||
page-break-after: avoid;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
class="spells"
|
||||
style="page-break-before: always;"
|
||||
>
|
||||
<column-layout wide-columns>
|
||||
<div class="span-all">
|
||||
|
||||
@@ -2,97 +2,104 @@
|
||||
<div class="stats">
|
||||
<column-layout>
|
||||
<div
|
||||
v-if="abilities.length"
|
||||
class="ability-scores"
|
||||
v-for="ability in abilities"
|
||||
:key="ability._id"
|
||||
>
|
||||
<div class="layout flex column">
|
||||
<div
|
||||
v-for="ability in abilities"
|
||||
:key="ability._id"
|
||||
class="ability"
|
||||
>
|
||||
<div class="score">
|
||||
<div class="double-border top big-number">
|
||||
<template v-if="creature.settings.swapScoresAndMods">
|
||||
{{ ability.total }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ numberToSignedString(ability.modifier) }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<template v-if="creature.settings.swapScoresAndMods">
|
||||
{{ numberToSignedString(ability.modifier) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ ability.total }}
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
class="ability"
|
||||
>
|
||||
<div class="score">
|
||||
<div class="double-border top big-number">
|
||||
<template v-if="creature.settings.swapScoresAndMods">
|
||||
{{ ability.total }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ numberToSignedString(ability.modifier) }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="double-border name label">
|
||||
{{ ability.name }}
|
||||
<div class="bottom">
|
||||
<template v-if="creature.settings.swapScoresAndMods">
|
||||
{{ numberToSignedString(ability.modifier) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ ability.total }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="double-border name label">
|
||||
{{ ability.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="toggle in toggles"
|
||||
:key="toggle._id"
|
||||
class="number-label"
|
||||
>
|
||||
<div class="box double-border" />
|
||||
<div class="label double-border">
|
||||
{{ toggle.name }}
|
||||
<div
|
||||
class="number-label"
|
||||
>
|
||||
<div class="box double-border" />
|
||||
<div class="label double-border">
|
||||
{{ toggle.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="stat in stats"
|
||||
:key="stat._id"
|
||||
class="number-label"
|
||||
:class="stat.variableName == 'armor' && 'shield-number-label'"
|
||||
>
|
||||
<div
|
||||
:class="stat.variableName == 'armor' ? 'shield-border' : 'octagon-border'"
|
||||
class="number big-number"
|
||||
class="number-label"
|
||||
:class="stat.variableName == 'armor' && 'shield-number-label'"
|
||||
>
|
||||
{{ stat.value }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ stat.name }}
|
||||
<div
|
||||
:class="stat.variableName == 'armor' ? 'shield-border' : 'octagon-border'"
|
||||
class="number big-number"
|
||||
>
|
||||
{{ stat.value }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ stat.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="modifier in modifiers"
|
||||
:key="modifier._id"
|
||||
class="number-label"
|
||||
>
|
||||
<div class="number octagon-border big-number">
|
||||
{{ numberToSignedString(modifier.value) }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ modifier.name }}
|
||||
<div
|
||||
class="number-label"
|
||||
>
|
||||
<div class="number octagon-border big-number">
|
||||
{{ numberToSignedString(modifier.value) }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ modifier.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="check in checks"
|
||||
:key="check._id"
|
||||
class="number-label"
|
||||
>
|
||||
<div class="number octagon-border big-number">
|
||||
{{ numberToSignedString(check.value) }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ check.name }}
|
||||
<div
|
||||
class="number-label"
|
||||
>
|
||||
<div class="number octagon-border big-number">
|
||||
{{ numberToSignedString(check.value) }}
|
||||
</div>
|
||||
<div class="label double-border">
|
||||
{{ check.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="healthBar in healthBars"
|
||||
:key="healthBar._id"
|
||||
class="m-2"
|
||||
>
|
||||
<div class="double-border">
|
||||
<div class="label">
|
||||
@@ -115,7 +122,6 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="hitDice.length"
|
||||
class="hit-dice m-2"
|
||||
>
|
||||
<div class="double-border">
|
||||
<div>
|
||||
@@ -528,21 +534,10 @@ export default {
|
||||
position: relative;
|
||||
aspect-ratio: 0.87;
|
||||
padding: 12px;
|
||||
}
|
||||
.shield-border::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: url(/images/print/shieldBorder.png);
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
z-index: -1;
|
||||
}
|
||||
.shield-number-label {
|
||||
align-items: center !important;
|
||||
@@ -571,23 +566,13 @@ export default {
|
||||
font-size: 10pt;
|
||||
position: relative;
|
||||
padding: 0 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
.ability .bottom::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border: solid white;
|
||||
border-image-source: url(/images/print/upwardPointingBorder.png);
|
||||
border-image-slice: 0 85 fill;
|
||||
border-image-width: 0 16px;
|
||||
border-image-outset: 0px 0px;
|
||||
border-image-repeat: stretch;
|
||||
box-sizing: content-box;
|
||||
z-index: -1;
|
||||
z-index: 2;
|
||||
}
|
||||
.ability .name {
|
||||
margin-top: 10px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="inventory-container">
|
||||
<div class="d-flex justify-center">
|
||||
<property-icon
|
||||
class="ml-2"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang="html">
|
||||
<v-list-item-content style="min-height: 60px;">
|
||||
<v-list-item-content :style="dense ? undefined : 'min-height: 60px;'">
|
||||
<v-list-item-title class="d-flex align-center">
|
||||
<div
|
||||
v-if="!renaming"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template lang="html">
|
||||
<v-list
|
||||
expand
|
||||
:nav="nav"
|
||||
:dense="dense"
|
||||
class="creature-folder-list"
|
||||
>
|
||||
<creature-list
|
||||
@@ -14,7 +16,7 @@
|
||||
v-for="folder in folders"
|
||||
:key="folder._id"
|
||||
v-model="openFolders[folder._id]"
|
||||
group="folder"
|
||||
:dense="dense"
|
||||
>
|
||||
<template #activator>
|
||||
<creature-folder-header
|
||||
@@ -60,6 +62,7 @@ export default {
|
||||
default: undefined,
|
||||
},
|
||||
dense: Boolean,
|
||||
nav: Boolean,
|
||||
},
|
||||
data(){return{
|
||||
openFolders: {},
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
<v-list-item
|
||||
v-bind="$attrs"
|
||||
:class="isSelected && 'primary--text v-list-item--active'"
|
||||
:dense="dense"
|
||||
v-on="selection ? { click() {$emit('click')} } : {}"
|
||||
>
|
||||
<v-list-item-avatar
|
||||
:color="isSelected ? 'red darken-1' : model.color || 'grey'"
|
||||
:size="dense ? 30 : undefined"
|
||||
class="white--text"
|
||||
style="transition: background 0.3s;"
|
||||
>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
class="slot-card d-flex flex-column"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
@click="$emit('click')"
|
||||
@click="fillSlot"
|
||||
>
|
||||
<card-highlight
|
||||
:active="hover"
|
||||
@@ -28,7 +28,7 @@
|
||||
<v-btn
|
||||
icon
|
||||
color="accent"
|
||||
@click.stop="$emit('ignore')"
|
||||
@click.stop="ignoreProp"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
@@ -39,6 +39,9 @@
|
||||
<script lang="js">
|
||||
import CardHighlight from '/imports/client/ui/components/CardHighlight.vue';
|
||||
import PropertyDescription from '/imports/client/ui/properties/viewers/shared/PropertyDescription.vue';
|
||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue.js';
|
||||
import updateCreatureProperty from '/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -51,6 +54,9 @@ export default {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
context: {
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
@@ -72,5 +78,45 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fillSlot() {
|
||||
const slotId = this.model._id;
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'slot-fill-dialog',
|
||||
elementId: `slot-card-${slotId}`,
|
||||
data: {
|
||||
slotId,
|
||||
creatureId: this.context.creatureId,
|
||||
},
|
||||
callback(nodeIds){
|
||||
if (!nodeIds || !nodeIds.length) return;
|
||||
insertPropertyFromLibraryNode.call({
|
||||
nodeIds,
|
||||
parentRef: {
|
||||
'id': slotId,
|
||||
'collection': 'creatureProperties',
|
||||
},
|
||||
}, error => {
|
||||
if (error){
|
||||
console.error(error);
|
||||
snackbar({text: error.reason || error.message || error.toString()});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
ignoreProp(){
|
||||
updateCreatureProperty.call({
|
||||
_id: this.model._id,
|
||||
path: ['ignored'],
|
||||
value: true
|
||||
}, error => {
|
||||
if (error){
|
||||
console.error(error);
|
||||
snackbar({text: error.reason || error.message || error.toString()});
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<column-layout wide-columns class="slots-to-fill">
|
||||
<column-layout
|
||||
wide-columns
|
||||
class="slots-to-fill"
|
||||
>
|
||||
<v-fade-transition
|
||||
group
|
||||
leave-absolute
|
||||
@@ -39,7 +42,6 @@ import SlotCard from '/imports/client/ui/creature/slots/SlotCard.vue';
|
||||
import PointBuyCard from '/imports/client/ui/properties/components/pointBuy/PointBuyCard.vue';
|
||||
import ColumnLayout from '/imports/client/ui/components/ColumnLayout.vue';
|
||||
import updateCreatureProperty from '/imports/api/creature/creatureProperties/methods/updateCreatureProperty.js';
|
||||
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue.js';
|
||||
|
||||
export default {
|
||||
@@ -64,31 +66,6 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
fillSlot(slotId){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'slot-fill-dialog',
|
||||
elementId: `slot-card-${slotId}`,
|
||||
data: {
|
||||
slotId,
|
||||
creatureId: this.context.creatureId,
|
||||
},
|
||||
callback(nodeIds){
|
||||
if (!nodeIds || !nodeIds.length) return;
|
||||
insertPropertyFromLibraryNode.call({
|
||||
nodeIds,
|
||||
parentRef: {
|
||||
'id': slotId,
|
||||
'collection': 'creatureProperties',
|
||||
},
|
||||
}, error => {
|
||||
if (error){
|
||||
console.error(error);
|
||||
snackbar({text: error.reason || error.message || error.toString()});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
editPointBuy(_id){
|
||||
this.$store.commit('pushDialogStack', {
|
||||
component: 'creature-property-dialog',
|
||||
@@ -101,10 +78,21 @@ export default {
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
slots(){
|
||||
return CreatureProperties.find({
|
||||
type: 'propertySlot',
|
||||
slots() {
|
||||
const folderIds = CreatureProperties.find({
|
||||
'ancestors.id': this.context.creatureId,
|
||||
type: 'folder',
|
||||
hideStatsGroup: true,
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, { fields: { _id: 1 } }).map(folder => folder._id);
|
||||
|
||||
return CreatureProperties.find({
|
||||
'ancestors.id': {
|
||||
$eq: this.context.creatureId,
|
||||
$nin: folderIds,
|
||||
},
|
||||
type: 'propertySlot',
|
||||
ignored: { $ne: true },
|
||||
$and: [
|
||||
{
|
||||
|
||||
@@ -63,21 +63,14 @@
|
||||
},
|
||||
watch: {
|
||||
dialogs(newDialogs) {
|
||||
let el = document.documentElement;
|
||||
const el = document.documentElement;
|
||||
if (newDialogs.length) {
|
||||
this.top = el.scrollTop;
|
||||
if (el.scrollHeight > el.clientHeight){
|
||||
el.style.position = 'fixed';
|
||||
el.style.top = `${-this.top}px`;
|
||||
el.style.left = 0;
|
||||
el.style.right = 0;
|
||||
el.style.overflowY = 'scroll';
|
||||
el.style.overflowY = 'hidden';
|
||||
el.scrollTop = this.top;
|
||||
}
|
||||
} else {
|
||||
el.style.position = null;
|
||||
el.style.top = null;
|
||||
el.style.left = null;
|
||||
el.style.right = null;
|
||||
el.style.overflowY = null;
|
||||
el.scrollTop = this.top;
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@
|
||||
cols="12"
|
||||
>
|
||||
<text-area
|
||||
auto-grow
|
||||
label="Body"
|
||||
:rows="20"
|
||||
:value="doc.description"
|
||||
@change="(value, ack) => change({path: ['description'], value, ack})"
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
Sign in
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<v-list>
|
||||
<v-list
|
||||
nav
|
||||
class="links"
|
||||
>
|
||||
<v-list-item v-if="signedIn">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
@@ -39,6 +42,7 @@
|
||||
:key="i"
|
||||
:to="link.to"
|
||||
:href="link.href"
|
||||
:target="link.href ? '_blank': undefined"
|
||||
>
|
||||
<v-list-item-action>
|
||||
<v-icon>{{ link.icon }}</v-icon>
|
||||
@@ -91,7 +95,7 @@ export default {
|
||||
let isLoggedIn = !!Meteor.userId();
|
||||
let links = [
|
||||
{ title: 'Home', icon: 'mdi-home', to: '/' },
|
||||
{ title: 'Characters', icon: 'mdi-account-group', to: '/characterList', requireLogin: true },
|
||||
{ title: 'Characters', icon: 'mdi-account-group', to: '/character-list', requireLogin: true },
|
||||
{ title: 'Library', icon: 'mdi-library-shelves', to: '/library', requireLogin: true },
|
||||
//{title: 'Tabletops', icon: 'api', to: '/tabletops', requireLogin: true},
|
||||
//{title: 'Friends', icon: 'people', to: '/friends', requireLogin: true},
|
||||
@@ -100,7 +104,7 @@ export default {
|
||||
{ title: 'About', icon: 'mdi-sign-text', to: '/about' },
|
||||
{ title: 'Documentation', icon: 'mdi-book-open-variant', to: '/docs' },
|
||||
{ title: 'Patreon', icon: 'mdi-patreon', href: 'https://www.patreon.com/dicecloud' },
|
||||
{ title: 'Github', icon: 'mdi-github', href: 'https://github.com/ThaumRystra/DiceCloud/tree/version-2' },
|
||||
{ title: 'Github', icon: 'mdi-github', href: 'https://github.com/ThaumRystra/DiceCloud/' },
|
||||
];
|
||||
return links.filter(link => !link.requireLogin || isLoggedIn);
|
||||
},
|
||||
@@ -138,3 +142,9 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.links .v-list-item:not(:last-child):not(:only-child) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div>
|
||||
<section>
|
||||
<v-parallax
|
||||
src="/images/paper-dice-crown-with-candy.png"
|
||||
height="400"
|
||||
src="/images/paper-dice-crown.webp"
|
||||
height="300"
|
||||
>
|
||||
<v-layout
|
||||
column
|
||||
@@ -12,7 +12,7 @@
|
||||
class="white--text"
|
||||
>
|
||||
<p
|
||||
class="white--text ma-2 text-h5 text-center"
|
||||
class="white--text ma-2 text-center"
|
||||
style="max-width: 1200px;"
|
||||
>
|
||||
DiceCloud is a single-developer project started in 2014 with the aim of
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
style="height: 100%"
|
||||
>
|
||||
<v-container>
|
||||
<v-row justify="center">
|
||||
<v-row
|
||||
justify="center"
|
||||
class="mb-16"
|
||||
>
|
||||
<v-col
|
||||
cols="12"
|
||||
xl="8"
|
||||
|
||||
@@ -1,29 +1,75 @@
|
||||
<template>
|
||||
<div
|
||||
class="content layout column justify-space-between"
|
||||
class="home content layout column justify-space-between"
|
||||
style="min-height: 100%;"
|
||||
>
|
||||
<section
|
||||
class="py-12 px-4"
|
||||
>
|
||||
<v-row
|
||||
align="end"
|
||||
justify="center"
|
||||
class="mb-8"
|
||||
>
|
||||
<v-col
|
||||
class="text-center"
|
||||
cols="12"
|
||||
>
|
||||
<h1 class="text-h4 mb-4">
|
||||
Free, Auditable, real-time character tracking for 5th edition
|
||||
</h1>
|
||||
<h4 class="subheading">
|
||||
Spend less time shuffling paper, and more time playing the game
|
||||
</h4>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-layout
|
||||
v-if="!signedIn"
|
||||
align-center
|
||||
justify-center
|
||||
>
|
||||
<v-btn
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
to="/register"
|
||||
class="mr-4"
|
||||
>
|
||||
Register
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
rounded
|
||||
outlined
|
||||
large
|
||||
to="/sign-in"
|
||||
>
|
||||
Sign In
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<v-layout
|
||||
v-else
|
||||
align-center
|
||||
justify-center
|
||||
>
|
||||
<v-btn
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
to="/character-list"
|
||||
class="mr-4"
|
||||
>
|
||||
My Characters
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</section>
|
||||
<section>
|
||||
<v-parallax
|
||||
src="/images/paper-dice-crown.png"
|
||||
src="/images/crown-dice-on-ipad.webp"
|
||||
height="300"
|
||||
>
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="white--text"
|
||||
>
|
||||
<h1 class="white--text mb-2 text-h4 text-center">
|
||||
DiceCloud - Free, Auditable, real-time character tracking for 5th edition
|
||||
</h1>
|
||||
<div class="subheading mb-3 text-center">
|
||||
Spend less time shuffling paper, and more time playing the game
|
||||
</div>
|
||||
</v-layout>
|
||||
</v-parallax>
|
||||
/>
|
||||
</section>
|
||||
<section class="text-center">
|
||||
<section class="text-center py-8 px-4">
|
||||
<v-layout
|
||||
wrap
|
||||
justify-space-around
|
||||
@@ -43,7 +89,7 @@
|
||||
Free, open source, community funded
|
||||
</h3>
|
||||
<p>
|
||||
DiceCloud is free to use. Its hosting is funded via Patreon,
|
||||
DiceCloud is free to use, funded via Patreon,
|
||||
and the source code is available on Github under a GPL license.
|
||||
</p>
|
||||
</v-layout>
|
||||
@@ -58,11 +104,11 @@
|
||||
mdi-ballot-outline
|
||||
</v-icon>
|
||||
<h3 class="mb-2">
|
||||
Character sheets optimised for one ruleset
|
||||
Custom everything
|
||||
</h3>
|
||||
<p>
|
||||
By having a narrrow scope, DiceCloud can be the best at what it
|
||||
does: being a fully automated character tracker
|
||||
Add new ability scores, skills, health-bars, and stats to your character.
|
||||
The entire sheet is under your control.
|
||||
</p>
|
||||
</v-layout>
|
||||
<v-layout
|
||||
@@ -76,31 +122,37 @@
|
||||
mdi-file-tree-outline
|
||||
</v-icon>
|
||||
<h3 class="mb-2">
|
||||
Inventory manager
|
||||
Advanced Character Engine
|
||||
</h3>
|
||||
<p>
|
||||
Equiping items changes your characters stats automatically.
|
||||
Characters are computed in real-time based on their equipment,
|
||||
features, and buffs.
|
||||
</p>
|
||||
</v-layout>
|
||||
</v-layout>
|
||||
</section>
|
||||
<section
|
||||
v-if="!signedIn"
|
||||
class="ma-5"
|
||||
>
|
||||
<v-layout
|
||||
align-center
|
||||
justify-space-around
|
||||
>
|
||||
<v-btn
|
||||
color="accent"
|
||||
rounded
|
||||
large
|
||||
to="/sign-in"
|
||||
<section class="pa-8">
|
||||
<v-row>
|
||||
<v-col
|
||||
v-for="(card, index) in highlightCards"
|
||||
:key="index"
|
||||
v-bind="cols"
|
||||
>
|
||||
Sign In
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<v-card
|
||||
tile
|
||||
:elevation="0"
|
||||
>
|
||||
<v-img
|
||||
class="white--text align-end"
|
||||
:src="'/images/screenshots/' + card.img"
|
||||
gradient="to bottom, rgba(0,0,0,0), rgba(0,0,0,.5)"
|
||||
height="360px"
|
||||
>
|
||||
<v-card-title v-text="card.text" />
|
||||
</v-img>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</section>
|
||||
<section class="text-center grey darken-3 white--text pa-5">
|
||||
<h1>
|
||||
@@ -120,11 +172,16 @@
|
||||
]"
|
||||
:key="btn.name"
|
||||
:href="btn.link"
|
||||
text
|
||||
outlined
|
||||
large
|
||||
color="primary"
|
||||
dark
|
||||
>
|
||||
{{ btn.name }}
|
||||
<v-icon
|
||||
right
|
||||
>
|
||||
mdi-open-in-new
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</section>
|
||||
@@ -133,6 +190,25 @@
|
||||
|
||||
<script lang="js">
|
||||
export default {
|
||||
data() {return {
|
||||
cols: {
|
||||
cols: 12,
|
||||
sm: 6,
|
||||
md: 4,
|
||||
lg: 3,
|
||||
xl: 2,
|
||||
},
|
||||
highlightCards: [
|
||||
{ text: 'Automated actions', img: 'actions.webp' },
|
||||
{ text: 'Auditable stats', img: 'auditable.webp' },
|
||||
{ text: 'Dice rolling', img: 'automated-dice-rolls.webp' },
|
||||
{ text: 'Hackable character builder', img: 'build-system.webp' },
|
||||
{ text: 'Drag and drop inventory manager', img: 'inventory.webp' },
|
||||
{ text: 'Custom libraries of content', img: 'libraries-of-content.webp' },
|
||||
{ text: 'Discord webhooks', img: 'send-to-discord.webp' },
|
||||
{ text: 'Printed character sheets', img: 'printing.webp' },
|
||||
],
|
||||
}},
|
||||
meteor: {
|
||||
signedIn() {
|
||||
return Meteor.userId();
|
||||
@@ -145,4 +221,7 @@ export default {
|
||||
.selling-points>* {
|
||||
max-width: 400px;
|
||||
}
|
||||
.dark-gradient {
|
||||
background: linear-gradient(0deg, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -39,7 +39,10 @@
|
||||
>
|
||||
Reset Password
|
||||
</v-btn>
|
||||
<div class="error--text">
|
||||
<div
|
||||
v-if="error"
|
||||
class="error--text"
|
||||
>
|
||||
{{ error }}
|
||||
</div>
|
||||
<v-layout>
|
||||
@@ -59,6 +62,13 @@
|
||||
Register
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<div class="text-caption mt-4 px-4">
|
||||
<p>
|
||||
DiceCloud Version 2 requires a new account to use.
|
||||
</p><p>
|
||||
Version 1 is still available at <a href="https://v1.dicecloud.com">v1.dicecloud.com</a>
|
||||
</p>
|
||||
</div>
|
||||
</v-layout>
|
||||
</v-form>
|
||||
<v-divider class="ma-4" />
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
:model="prop"
|
||||
:data-id="prop._id"
|
||||
@click="$emit('click-property', {_id: prop._id})"
|
||||
@sub-click="_id => $emit('sub-click', _id)"
|
||||
@click-property="e => $emit('click-property', e)"
|
||||
@sub-click="e => $emit('sub-click', e)"
|
||||
@remove="$emit('remove', prop._id)"
|
||||
/>
|
||||
</v-card>
|
||||
@@ -27,15 +28,15 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
|
||||
import propComponents from '/imports/client/ui/properties/components/folders/propertyComponentIndex.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
...propComponents,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
Object.assign(this.$options.components, propComponents);
|
||||
},
|
||||
meteor: {
|
||||
properties() {
|
||||
const props = [];
|
||||
@@ -50,6 +51,7 @@ export default {
|
||||
deactivatedByAncestor: { $ne: true },
|
||||
},
|
||||
{
|
||||
type: { $ne: 'toggle' },
|
||||
inactive: { $ne: true }
|
||||
},
|
||||
],
|
||||
@@ -60,7 +62,7 @@ export default {
|
||||
}, {
|
||||
sort: { order: 1 },
|
||||
}).forEach(prop => {
|
||||
if (this.$options.components[prop.type]) {
|
||||
if (propComponents[prop.type]) {
|
||||
props.push(prop);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,44 +1,55 @@
|
||||
<template>
|
||||
<div class="attribute">
|
||||
<ability-list-tile
|
||||
v-if="model.attributeType === 'ability'"
|
||||
<div>
|
||||
<div
|
||||
class="attribute"
|
||||
:data-id="dataId"
|
||||
>
|
||||
<ability-list-tile
|
||||
v-if="model.attributeType === 'ability'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<hit-dice-list-tile
|
||||
v-else-if="model.attributeType === 'hitDice'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@change="({ type, value }) => damageProperty({type, value: -value})"
|
||||
/>
|
||||
<health-bar
|
||||
v-else-if="model.attributeType === 'healthBar'"
|
||||
:model="model"
|
||||
@change="damageProperty"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<spell-slot-list-tile
|
||||
v-else-if="model.attributeType === 'spellSlot'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<resource-card-content
|
||||
v-else-if="model.attributeType === 'resource'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@change="({ type, value }) => damageProperty({type, value: -value})"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
/>
|
||||
<attribute-card-content
|
||||
v-else-if="model.attributeType !== 'utility'"
|
||||
class="pointer"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
/>
|
||||
<card-highlight :active="hover" />
|
||||
</div>
|
||||
<folder-group-children
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@click-property="e => $emit('click-property', e)"
|
||||
@sub-click="e => $emit('sub-click', e)"
|
||||
@remove="e => $emit('remove', e)"
|
||||
/>
|
||||
<hit-dice-list-tile
|
||||
v-else-if="model.attributeType === 'hitDice'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@change="({ type, value }) => damageProperty({type, value: -value})"
|
||||
/>
|
||||
<health-bar
|
||||
v-else-if="model.attributeType === 'healthBar'"
|
||||
:model="model"
|
||||
@change="damageProperty"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<spell-slot-list-tile
|
||||
v-else-if="model.attributeType === 'spellSlot'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<resource-card-content
|
||||
v-else-if="model.attributeType === 'resource'"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@change="({ type, value }) => damageProperty({type, value: -value})"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
/>
|
||||
<attribute-card-content
|
||||
v-else-if="model.attributeType !== 'utility'"
|
||||
class="pointer"
|
||||
:model="model"
|
||||
@click="$emit('click')"
|
||||
@mouseover="hover = true"
|
||||
@mouseleave="hover = false"
|
||||
/>
|
||||
<card-highlight :active="hover" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,6 +61,7 @@ import SpellSlotListTile from '/imports/client/ui/properties/components/attribut
|
||||
import ResourceCardContent from '/imports/client/ui/properties/components/attributes/ResourceCardContent.vue';
|
||||
import AttributeCardContent from '/imports/client/ui/properties/components/attributes/AttributeCardContent.vue';
|
||||
import CardHighlight from '/imports/client/ui/components/CardHighlight.vue';
|
||||
import FolderGroupChildren from '/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue';
|
||||
|
||||
import damageProperty from '/imports/api/creature/creatureProperties/methods/damageProperty.js';
|
||||
|
||||
@@ -62,12 +74,17 @@ export default {
|
||||
ResourceCardContent,
|
||||
AttributeCardContent,
|
||||
CardHighlight,
|
||||
FolderGroupChildren,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
dataId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -81,6 +98,10 @@ export default {
|
||||
value: change.value
|
||||
});
|
||||
},
|
||||
log({_id}) {
|
||||
console.log(...arguments)
|
||||
this.$emit('click-property', { _id });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="properties && properties.length"
|
||||
>
|
||||
<component
|
||||
:is="prop.type"
|
||||
v-for="prop in properties"
|
||||
:key="prop._id"
|
||||
:model="prop"
|
||||
:data-id="prop._id"
|
||||
@click="$emit('click-property', {_id: prop._id})"
|
||||
@click-property="(e) => $emit('click-property', e)"
|
||||
@sub-click="(e) => $emit('sub-click', e)"
|
||||
@remove="$emit('remove', prop._id)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import propComponents from '/imports/client/ui/properties/components/folders/propertyComponentIndex.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
Object.assign(this.$options.components, propComponents);
|
||||
},
|
||||
meteor: {
|
||||
properties() {
|
||||
const props = [];
|
||||
CreatureProperties.find({
|
||||
'parent.id': this.model._id,
|
||||
removed: { $ne: true },
|
||||
overridden: { $ne: true },
|
||||
$or: [
|
||||
{
|
||||
type: 'toggle',
|
||||
showUI: true,
|
||||
deactivatedByAncestor: { $ne: true },
|
||||
},
|
||||
{
|
||||
type: { $ne: 'toggle' },
|
||||
inactive: { $ne: true },
|
||||
},
|
||||
],
|
||||
$nor: [
|
||||
{ hideWhenTotalZero: true, total: 0 },
|
||||
{ hideWhenValueZero: true, value: 0 },
|
||||
],
|
||||
}, {
|
||||
sort: { order: 1 },
|
||||
}).forEach(prop => {
|
||||
if (propComponents[prop.type]) {
|
||||
props.push(prop);
|
||||
}
|
||||
});
|
||||
return props;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<build-tree-node-list
|
||||
:children="slotBuildTree"
|
||||
class="mx-2"
|
||||
@selected="_id => $emit('sub-click', _id)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree.js';
|
||||
import BuildTreeNodeList from '/imports/client/ui/creature/buildTree/BuildTreeNodeList.vue';
|
||||
|
||||
function traverse(tree, callback, parents = []){
|
||||
tree.forEach(node => {
|
||||
callback(node, parents);
|
||||
traverse(node.children, callback, [...parents, node]);
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BuildTreeNodeList,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
slotBuildTree() {
|
||||
const slots = CreatureProperties.find({
|
||||
$and: [ {
|
||||
$or: [
|
||||
{ 'ancestors.id': this.model._id, },
|
||||
{ '_id': this.model._id, },
|
||||
],
|
||||
}, {
|
||||
$or:
|
||||
[
|
||||
{ 'slotCondition.value': { $nin: [false, 0, ''] } },
|
||||
{ 'slotCondition.value': { $exists: false } },
|
||||
{ 'slotCondition': { $exists: false } },
|
||||
],
|
||||
} ],
|
||||
type: { $in: ['propertySlot', 'pointBuy'] },
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
}, {
|
||||
sort: { order: 1 }
|
||||
});
|
||||
const slotIds = slots.map(s => s._id);
|
||||
const slotChildren = CreatureProperties.find({
|
||||
'parent.id': { $in: slotIds },
|
||||
removed: { $ne: true },
|
||||
}, {
|
||||
sort: { order: 1 },
|
||||
});
|
||||
const tree = nodeArrayToTree([
|
||||
...slots.fetch(),
|
||||
...slotChildren.fetch()
|
||||
]);
|
||||
traverse(tree, (child, parents) => {
|
||||
const model = child.node;
|
||||
const isSlotWithSpace = model.type === 'propertySlot' && (
|
||||
model.spaceLeft > 0 ||
|
||||
!model.quantityExpected ||
|
||||
model.quantityExpected.value === 0
|
||||
);
|
||||
if (isSlotWithSpace) {
|
||||
model._canFill = true;
|
||||
parents.forEach(node => {
|
||||
node.node._descendantCanFill = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
return tree;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -17,16 +17,17 @@ import item from '/imports/client/ui/properties/components/inventory/ItemListTil
|
||||
import note from '/imports/client/ui/properties/components/persona/NoteCard.vue';
|
||||
//import pointBuy from '';
|
||||
//import proficiency from '';
|
||||
//import propertySlot from '';
|
||||
import propertySlot from '/imports/client/ui/properties/components/folders/folderGroupComponents/SlotBuildTree.vue';
|
||||
//import reference from '';
|
||||
//import roll from '';
|
||||
//import savingThrow from '';
|
||||
import skill from '/imports/client/ui/properties/components/skills/SkillListTile.vue';
|
||||
//import slotFiller from '';
|
||||
//import spellList from '';
|
||||
//import spell from '';
|
||||
import spellList from '/imports/client/ui/properties/components/spells/SpellListCard.vue';
|
||||
import spell from '/imports/client/ui/properties/components/spells/SpellListTile.vue';
|
||||
import toggle from '/imports/client/ui/properties/components/toggles/ToggleCard.vue';
|
||||
//import trigger from '';
|
||||
import FolderGroupChildren from '/imports/client/ui/properties/components/folders/folderGroupComponents/FolderGroupChildren.vue';
|
||||
|
||||
export default {
|
||||
action,
|
||||
@@ -43,19 +44,19 @@ export default {
|
||||
//damageMultiplier,
|
||||
//effect,
|
||||
feature,
|
||||
//folder,
|
||||
// folder // Like actions, we don't show sub-folders
|
||||
item,
|
||||
note,
|
||||
//pointBuy,
|
||||
//proficiency,
|
||||
//propertySlot,
|
||||
propertySlot,
|
||||
//reference,
|
||||
//roll,
|
||||
//savingThrow,
|
||||
skill,
|
||||
//slotFiller,
|
||||
//spellList,
|
||||
//spell,
|
||||
slotFiller: FolderGroupChildren,
|
||||
spellList,
|
||||
spell,
|
||||
toggle,
|
||||
//trigger,
|
||||
};
|
||||
|
||||
@@ -5,11 +5,21 @@
|
||||
@toolbarclick="clickSpellList(model._id)"
|
||||
>
|
||||
<template slot="toolbar">
|
||||
<v-toolbar-title>
|
||||
<v-toolbar-title
|
||||
v-if="!preparingSpells"
|
||||
>
|
||||
{{ model.name }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer v-if="!preparingSpells && preparedError" />
|
||||
<v-toolbar-title
|
||||
v-if="preparingSpells || preparedError"
|
||||
:class="{'error--text' : preparedError}"
|
||||
>
|
||||
{{ numPrepared }}/{{ model.maxPrepared.value }} spells prepared
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-menu
|
||||
v-if="!preparingSpells"
|
||||
bottom
|
||||
left
|
||||
transition="slide-y-transition"
|
||||
@@ -33,22 +43,29 @@
|
||||
/>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
<v-expand-transition>
|
||||
<v-card-text
|
||||
v-if="preparedError || preparingSpells"
|
||||
:class="{'error--text' : preparedError}"
|
||||
class="pb-0"
|
||||
<v-btn
|
||||
v-else
|
||||
icon
|
||||
@click.stop="preparingSpells = false"
|
||||
>
|
||||
<div v-if="model.maxPrepared && model.maxPrepared.value">
|
||||
{{ numPrepared }}/{{ model.maxPrepared.value }} spells prepared
|
||||
</div>
|
||||
<v-switch
|
||||
v-model="preparingSpells"
|
||||
label="Change prepared spells"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-expand-transition>
|
||||
<v-icon>mdi-check</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<!-- Disabled because it changes the height of the card
|
||||
<v-card-text
|
||||
v-if="preparedError || preparingSpells"
|
||||
:class="{'error--text' : preparedError}"
|
||||
class="pb-0"
|
||||
>
|
||||
<div v-if="model.maxPrepared && model.maxPrepared.value">
|
||||
{{ numPrepared }}/{{ model.maxPrepared.value }} spells prepared
|
||||
</div>
|
||||
<v-switch
|
||||
v-model="preparingSpells"
|
||||
label="Change prepared spells"
|
||||
/>
|
||||
</v-card-text>
|
||||
-->
|
||||
<spell-list
|
||||
:spells="spells"
|
||||
:parent-ref="{id: model._id, collection: 'creatureProperties'}"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<v-expand-transition>
|
||||
<div v-if="model.groupStats">
|
||||
<smart-switch
|
||||
label="Hide children from stats tab"
|
||||
label="Hide children from their default locations"
|
||||
:value="model.hideStatsGroup"
|
||||
:error-messages="errors.hideStatsGroup"
|
||||
@change="change('hideStatsGroup', ...arguments)"
|
||||
|
||||
@@ -13,6 +13,7 @@ const CharacterSheetPage = () => import('/imports/client/ui/pages/CharacterSheet
|
||||
const CharacterSheetToolbar = () => import('/imports/client/ui/creature/character/CharacterSheetToolbar.vue');
|
||||
const CharacterSheetRightDrawer = () => import('/imports/client/ui/creature/character/CharacterSheetRightDrawer.vue');
|
||||
const CharacterSheetPrinted = () => import('/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue');
|
||||
const CharacterSheetPrintedToolbar = () => import('/imports/client/ui/creature/character/printedCharacterSheet/CharacterSheetPrintedToolbar.vue');
|
||||
const SignIn = () => import('/imports/client/ui/pages/SignIn.vue');
|
||||
const Register = () => import('/imports/client/ui/pages/Register.vue');
|
||||
const IconAdmin = () => import('/imports/client/ui/icons/IconAdmin.vue');
|
||||
@@ -185,11 +186,14 @@ RouterFactory.configure(router => {
|
||||
alias: '/print-character/:id/:urlName',
|
||||
components: {
|
||||
default: CharacterSheetPrinted,
|
||||
toolbar: CharacterSheetPrintedToolbar,
|
||||
},
|
||||
meta: {
|
||||
title: 'Print Character Sheet',
|
||||
},
|
||||
}, {
|
||||
},
|
||||
/* Not ready for prime time <3
|
||||
{
|
||||
path: '/tabletops',
|
||||
name: 'tabletops',
|
||||
component: Tabletops,
|
||||
@@ -203,7 +207,9 @@ RouterFactory.configure(router => {
|
||||
rightDrawer: TabletopRightDrawer,
|
||||
},
|
||||
beforeEnter: ensureLoggedIn,
|
||||
}, {
|
||||
},
|
||||
*/
|
||||
{
|
||||
path: '/friends',
|
||||
components: {
|
||||
default: NotImplemented,
|
||||
|
||||
37
app/imports/client/ui/styles/body.css
Normal file
@@ -0,0 +1,37 @@
|
||||
html {
|
||||
--scrollbarBG: #f0f0f0;
|
||||
--thumbBG: #cdcdcd;
|
||||
scrollbar-gutter: stable;
|
||||
background-color: var(--scrollbarBG);
|
||||
}
|
||||
|
||||
html:has(#app.theme--dark) {
|
||||
--scrollbarBG: #212121;
|
||||
--thumbBG: #404040;
|
||||
}
|
||||
|
||||
#app.theme--dark {
|
||||
--scrollbarBG: #212121;
|
||||
--thumbBG: #404040;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: var(--scrollbarBG);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: var(--thumbBG);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import './body.css';
|
||||
import './cardColors.css';
|
||||
import './cardTitles.css';
|
||||
import './centeredInputs.css';
|
||||
|
||||
@@ -2,8 +2,8 @@ import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import dialogStackStore from '/imports/client/ui/dialogStack/dialogStackStore.js';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
const tabs = ['stats', 'features', 'actions', 'spells', 'inventory', 'journal', 'build', 'tree'];
|
||||
const tabsWithoutSpells = ['stats', 'features', 'actions', 'inventory', 'journal', 'build', 'tree'];
|
||||
const tabs = ['stats', 'actions', 'spells', 'inventory', 'features', 'journal', 'build', 'tree'];
|
||||
const tabsWithoutSpells = ['stats', 'actions', 'inventory', 'features', 'journal', 'build', 'tree'];
|
||||
|
||||
Vue.use(Vuex);
|
||||
const store = new Vuex.Store({
|
||||
@@ -50,6 +50,19 @@ const store = new Vuex.Store({
|
||||
document.title = value;
|
||||
},
|
||||
setTabForCharacterSheet(state, { tab, id }) {
|
||||
// Convert tab names to tab numbers
|
||||
if (typeof tab === 'string') {
|
||||
const creature = Creatures.findOne(id);
|
||||
if (creature?.settings?.hideSpellsTab) {
|
||||
tab = tabsWithoutSpells.indexOf(tab);
|
||||
} else {
|
||||
tab = tabs.indexOf(tab);
|
||||
}
|
||||
if (!(tab > -1)) {
|
||||
throw 'Could not find requested tab';
|
||||
}
|
||||
console.log('resolved: ', tab);
|
||||
}
|
||||
Vue.set(state.characterSheetTabs, id, tab);
|
||||
},
|
||||
setShowDetailsDialog(state, value) {
|
||||
|
||||
@@ -30,7 +30,7 @@ const STORAGE_LIMITS = Object.freeze({
|
||||
rollCount: 64,
|
||||
statsToTarget: 64,
|
||||
tagCount: 64,
|
||||
writersCount: 20,
|
||||
writersCount: 32,
|
||||
libraryCollectionCount: 32,
|
||||
pointBuyRowsCount: 32,
|
||||
});
|
||||
|
||||
@@ -10,14 +10,25 @@
|
||||
"paths": {
|
||||
"/*": [
|
||||
"./*"
|
||||
],
|
||||
"meteor/aldeed:collection2": [
|
||||
"packages\\collection2\\collection2.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
"checkJs": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"target": 2,
|
||||
"target": 2
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/node_modules/*"
|
||||
]
|
||||
"**/node_modules/*",
|
||||
".meteor"
|
||||
],
|
||||
"typeAcquisition": {
|
||||
"include": [
|
||||
"meteor"
|
||||
]
|
||||
}
|
||||
}
|
||||
114
app/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dicecloud",
|
||||
"version": "2.0.43",
|
||||
"version": "2.0.45",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -56,11 +56,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz",
|
||||
"integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==",
|
||||
"version": "7.20.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz",
|
||||
"integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.10"
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
}
|
||||
},
|
||||
"@chenfengyuan/vue-countdown": {
|
||||
@@ -185,14 +185,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz",
|
||||
"integrity": "sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
|
||||
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.43.0",
|
||||
"@typescript-eslint/type-utils": "5.43.0",
|
||||
"@typescript-eslint/utils": "5.43.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/type-utils": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -222,14 +222,14 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz",
|
||||
"integrity": "sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
|
||||
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.43.0",
|
||||
"@typescript-eslint/types": "5.43.0",
|
||||
"@typescript-eslint/typescript-estree": "5.43.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -245,23 +245,23 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz",
|
||||
"integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
|
||||
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.43.0",
|
||||
"@typescript-eslint/visitor-keys": "5.43.0"
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz",
|
||||
"integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz",
|
||||
"integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.43.0",
|
||||
"@typescript-eslint/utils": "5.43.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -278,19 +278,19 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz",
|
||||
"integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
|
||||
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz",
|
||||
"integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
|
||||
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.43.0",
|
||||
"@typescript-eslint/visitor-keys": "5.43.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -319,16 +319,16 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz",
|
||||
"integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
|
||||
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.43.0",
|
||||
"@typescript-eslint/types": "5.43.0",
|
||||
"@typescript-eslint/typescript-estree": "5.43.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -355,12 +355,12 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz",
|
||||
"integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
|
||||
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.43.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -530,9 +530,9 @@
|
||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
|
||||
},
|
||||
"aws-sdk": {
|
||||
"version": "2.1258.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1258.0.tgz",
|
||||
"integrity": "sha512-siqNFXlhJZVN1BizPZebJViFXtTUPgcA+yLfHKl2eC4Ied7kE7spOjZmAzpuiGUTzFagk1oWCaJ1Hit4llIoGg==",
|
||||
"version": "2.1262.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1262.0.tgz",
|
||||
"integrity": "sha512-XbaK/XUIxwLEBnHANhJ0RTZtiU288lFRj5FllSihQ5Kb0fibKyW8kJFPsY+NzzDezLH5D3WdGbTKb9fycn5TbA==",
|
||||
"requires": {
|
||||
"buffer": "4.9.2",
|
||||
"events": "1.1.1",
|
||||
@@ -1575,9 +1575,9 @@
|
||||
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
|
||||
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA=="
|
||||
},
|
||||
"ignore-styles": {
|
||||
"version": "5.0.1",
|
||||
@@ -1850,9 +1850,9 @@
|
||||
}
|
||||
},
|
||||
"marked": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.2.tgz",
|
||||
"integrity": "sha512-JjBTFTAvuTgANXx82a5vzK9JLSMoV6V3LBVn4Uhdso6t7vXrGx7g1Cd2r6NYSsxrYbQGFCMqBDhFHyK5q2UvcQ=="
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz",
|
||||
"integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw=="
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
@@ -3018,9 +3018,9 @@
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.10",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz",
|
||||
"integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw=="
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"regexpp": {
|
||||
"version": "3.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dicecloud",
|
||||
"version": "2.0.44",
|
||||
"version": "2.0.51",
|
||||
"description": "Unofficial Online Realtime D&D 5e App",
|
||||
"license": "GPL-3.0",
|
||||
"repository": {
|
||||
@@ -20,10 +20,10 @@
|
||||
"npm": "6.13.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.1",
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@chenfengyuan/vue-countdown": "^1.1.5",
|
||||
"@tozd/vue-observer-utils": "^0.5.0",
|
||||
"aws-sdk": "^2.1258.0",
|
||||
"aws-sdk": "^2.1262.0",
|
||||
"bcrypt": "^5.1.0",
|
||||
"chroma-js": "^2.4.2",
|
||||
"css-box-shadow": "^1.0.0-3",
|
||||
@@ -31,10 +31,10 @@
|
||||
"ddp-rate-limiter-mixin": "^1.1.10",
|
||||
"discord.js": "^12.5.3",
|
||||
"dompurify": "^2.4.1",
|
||||
"ignore": "^5.2.0",
|
||||
"ignore": "^5.2.1",
|
||||
"ignore-styles": "^5.0.1",
|
||||
"lodash": "^4.17.20",
|
||||
"marked": "^4.2.2",
|
||||
"marked": "^4.2.3",
|
||||
"meteor-node-stubs": "^1.2.5",
|
||||
"minify-css-string": "^1.0.0",
|
||||
"moo": "^0.5.2",
|
||||
@@ -58,8 +58,8 @@
|
||||
"vuex": "^3.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.44.0",
|
||||
"@typescript-eslint/parser": "^5.44.0",
|
||||
"@vue/compiler-dom": "^3.2.45",
|
||||
"chai": "^4.3.7",
|
||||
"eslint": "^7.32.0",
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
# Computed fields
|
||||
|
||||
Some fields in DiceCloud creature properties expect calculations. These fields are then computed by the DiceCloud engine.
|
||||
|
||||
Some fields, like the value of an attirbute, resolve down to a single number, while others, like the damage to deal in an attack, only simplify their calculation as far as they can, and then resolve down to a number when applied. Avoid adding dice rolls to calculations that expect to resolve down to a number, because they will re-roll every time the creature is recalculated, causing instability in the creature's stats.
|
||||
|
||||
## Parser
|
||||
|
||||
The DiceCloud parser can understand the following syntax:
|
||||
|
||||
| | |
|
||||
| :- | :- |
|
||||
| **Numbers** | `13`, `3.14` |
|
||||
| **Dice rolls** | `3d6`, `(1 + 2)d4`|
|
||||
| **Strings of text** | `'Some text'`, `"some other text"` |
|
||||
| **Boolean values** | `true` or `false`. When DiceCloud expects a boolean, `0`, an empty string `''` and `false` are all considered false by DiceCloud's engine, every other value is considered true. |
|
||||
| **Variable names** | `variableName` |
|
||||
| **Addition and subtraction** | `1 + 2 + 3`, `12 - 6` |
|
||||
| **Multiplication** | `6 * 4`, `12 * 2` = `24` |
|
||||
| **Exponents** | `3 ^ 2` Raise 3 to the power of 2 |
|
||||
| **Modulo** | Returns the remainder of a division operation `15 % 6` = `3` |
|
||||
| **AND** | `&` or `&&`: Returns the value of the right hand side if the left side is true `true & 'cat'` = `'cat'` |
|
||||
| **OR** | `|` or `||`: Returns the left hand side if it is true, otherwise returns the right hand side `'dog' || 'cat'` = `'dog'` |
|
||||
| **NOT** | `!` returns false if the value after it is true, otherwise returns false |
|
||||
| **Comparisons** | greater than: `>`, less than: `<`, greater than or equal to: `>=`, less than or equal to: `<=`, equal: `=` or `==` or `===`, not equal: `!=` or `!==` |
|
||||
| **If-else** | `condition ? resultIfTrue : resultIfFalse`, `level > 10 ? 'high tier' : 'low tier'` |
|
||||
| **Arrays** | lists of values `[3, 6, 9, 12]`. |
|
||||
| **Array Indexes** | A value can be chosen from an array using another set of square brackets: `[3, 6, 9, 12][2]` = `[6]` because `[2]` fetches the 2nd value in the array. Arrays start at 1 in DiceCloud so that level tables can have 20 entries and be accessed by `array[level]`. |
|
||||
| **Function calls** | `functionName(argument1, argument1)` See [Functions](/docs/functions) for a full list of available functions. |
|
||||
|
||||
## Special variables
|
||||
|
||||
### Built-in variables
|
||||
|
||||
These variables are added to the creature automatically when relevant. They can be overriden if needed by creating a property with the same variable name. They can also be targetted by effects.
|
||||
|
||||
- `xp` A total of all the experiences with xp added to the character sheet
|
||||
- `milestoneLevels` A total of all the experiences with milestone levels added to the character sheet
|
||||
- `itemsAttuned` Number of items the creature is attuned to
|
||||
- `weightEquipment` Total weight of all equipment on the creature
|
||||
- `valueEquipment` Total value of all equipment on the creature
|
||||
- `weightTotal` Total weight of the creature's entire inventory
|
||||
- `valueTotal` Total value of the creature's entire inventory
|
||||
- `weightCarried` Total weight of all carried items and containers
|
||||
- `valueCarried` Total value of all carried items and containers
|
||||
- `level` The current level of the creature, including all class levels
|
||||
- `criticalHitTarget` Defaults to 20, the natural roll needed to consider an attack roll as a critical hit
|
||||
|
||||
### Action variables
|
||||
|
||||
These variables are available during an action after the relevant property has been applied.
|
||||
|
||||
For Advanced users, a [Roll](/docs/property/roll) can set these variables, overriding the default behavior.
|
||||
|
||||
#### [Actions](/docs/property/action)
|
||||
|
||||
- `$attackDiceRoll` The value of the d20 roll before any modifiers were applied.
|
||||
- `$attackRoll` The total attack roll after modifiers.
|
||||
- `$criticalHit` Set to `true` if the attack roll's d20 is a natural 20. If `criticalHitTarget` is set, the attack roll's d20 must instead be equal to or greater than `criticalHitTarget` for this to be set to `true`.
|
||||
- `$criticalMiss` Set to `true` if the attack roll was not a critical hit and rolled a natural 1 on the d20 roll.
|
||||
- `$attackHit` If the attack roll is higher than or equal to the target's AC or a critical hit this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical hit.
|
||||
- `$attackMiss` If the attack roll is lower than the target's AC or a critical miss, this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical miss.
|
||||
|
||||
#### [Damage](/docs/property/damage)
|
||||
|
||||
- `$lastDamageType` The type of damage dealt last, any damage that has the `extra` type will use this damage type instead
|
||||
|
||||
#### [Saving throws](/docs/property/saving-throw)
|
||||
|
||||
- `$saveFailed` Set to `true` if the target failed its saving throw or there are no targets for the saving throw
|
||||
- `$saveSucceeded` Set to `true` if the target made its saving throw or there are no targets for the saving throw
|
||||
- `$saveDiceRoll` The unmodified d20 roll the target made to save
|
||||
- `$saveRoll` The final value of the saving throw roll after modifiers
|
||||
|
||||
## Ancestor references
|
||||
|
||||
The ancestors of a property can be accessed directly using the `#ancestorType` syntax.
|
||||
|
||||
For example, a spell might need to know the save DC of the spell list that it is inside of, it can use `#spellList.dc`.
|
||||
|
||||
Triggers and their children work differently: They don't have access to their own ancestors, but rather inherit the ancestors of the property that caused them to fire. For example, a trigger at the root of the creature's tree might be fired by a spell being cast, you can still use references to ancestors like `#spellList.attackRollBonus` inside that trigger as if it were under the spell itself.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Dependency loops
|
||||
|
||||
When a variable is referenced in a calculation, that calculation can be said to depend on that variable. In order for the calculation to compute, the value of the variable needs to be known.
|
||||
|
||||
But consider the following property values that could be added to a creature
|
||||
|
||||
- The creature's Strength base value is set to `dexterity + 1` so that it will always have 1 more strength than dexterity
|
||||
- The creature's Dexterity base value is set to `constitution + 1` so that it will always have 1 more dexterity than constitution
|
||||
- The creature's Constitution base value is set to `strength` so that its constitution is always equal to its strength
|
||||
|
||||
It is not possible to resolve these calculations, not just because no values exist which satisfy the constraints, but because strength depends on dexterity which depends on constitution which depends on strength. None can be computed before the others have finalized their values. This is a dependency loop.
|
||||
|
||||
Most dependency loops that appear in actual DiceCloud creatures are less trivial than this example, but they cause the same result: a sheet that can't be accurately computed. In these cases, DiceCloud does its best, chooses an order to resolve the calculations arbitrarily, and continues calculating. An error will show on the Build tab to let you know that something went wrong.
|
||||
|
||||

|
||||
|
||||
## Toggles
|
||||
|
||||
Calculated [Toggles](/docs/property/toggle) are the main source of dependency loops on creatures, because they create a dependency that isn't as obvious as a calculation might be. When a toggle is in calculated mode, its children do not know whether they are active or not until the calulation is resolved. Because of this, every calculation under the toggle depends on the toggles calaculation, making the chance for a loop to be formed more likely the more children are under a toggle.
|
||||
|
||||
Consider this example
|
||||
|
||||
- A calculated toggle that is active if `strength < 10`
|
||||
- An effect under that toggle that adds 2 to `strength`
|
||||
|
||||
The effect can't compute, because it does not know if it is active yet, so the toggle must compute its calculation first. The toggle needs to know if `strength` is greater than 10. Strength depends on all of the effects targeting it, it must know if the +2 effect is active or not. This creates a dependency loop, because there is no valid order in which everything can be calculated.
|
||||
|
||||
## Troubleshooting a dependency loop
|
||||
|
||||
- First, identify all the properties that make up the dependency loop. These are linked in the depdency loop error message. The field names in square brackets after the property name indicates which calculations on the property are directly involved.
|
||||
- Move any properties in the loop out from being children of calculated Toggles
|
||||
- Use static values in place of variables where they are not stricly needed
|
||||
- Ask for [help](/feedback)
|
||||
@@ -1,39 +0,0 @@
|
||||
# DiceCloud Docs
|
||||
|
||||
## Properties
|
||||
|
||||
- ### [Action](/docs/property/action)
|
||||
- ### [Attribute](/docs/property/attribute)
|
||||
- ### [Attribute Damage](/docs/property/attribute-damage)
|
||||
- ### [Buff](/docs/property/buff)
|
||||
- ### [Remove Buff](/docs/property/remove-buff)
|
||||
- ### [Branch](/docs/property/branch)
|
||||
- ### [Class](/docs/property/class)
|
||||
- ### [Class Level](/docs/property/class-level)
|
||||
- ### [Constant](/docs/property/constant)
|
||||
- ### [Container](/docs/property/container)
|
||||
- ### [Damage](/docs/property/damage)
|
||||
- ### [Damage Multiplier](/docs/property/damage-multiplier)
|
||||
- ### [Effect](/docs/property/effect)
|
||||
- ### [Feature](/docs/property/feature)
|
||||
- ### [Item](/docs/property/item)
|
||||
- ### [Note](/docs/property/note)
|
||||
- ### [Point Buy](/docs/property/point-buy)
|
||||
- ### [Proficiency](/docs/property/proficiency)
|
||||
- ### [Roll](/docs/property/roll)
|
||||
- ### [Saving Throw](/docs/property/saving-throw)
|
||||
- ### [Skill](/docs/property/skill)
|
||||
- ### [Slot](/docs/property/slot)
|
||||
- ### [Slot Filler](/docs/property/slot-filler)
|
||||
- ### [Spell List](/docs/property/spell-list)
|
||||
- ### [Spell](/docs/property/spell)
|
||||
- ### [Toggle](/docs/property/toggle)
|
||||
- ### [Trigger](/docs/property/trigger)
|
||||
|
||||
## Topics
|
||||
|
||||
- ### [Computed fields](/docs/computed-fields)
|
||||
- ### [Inline Calculations](/docs/inline-calculations)
|
||||
- ### [Dependency Loops](/docs/dependency-loops)
|
||||
- ### [Functions](/docs/functions)
|
||||
- ### [Tags](/docs/tags)
|
||||
@@ -1,11 +0,0 @@
|
||||
# Inline Calculations
|
||||
|
||||
Most long-format fields allow inline [calculations](/docs/computed-fields) to be included. Calculations inside of curly bracers will be computed down to numbers using the characters stats.
|
||||
|
||||
For example a creature's strength attribute may have the following in its description: `Your carrying capacity is {strength * 15} lbs.`
|
||||
|
||||
When the creature is calculated, if it has 8 strength, the action description will become: "Your carrying capacity is 120 lbs."
|
||||
|
||||
If a description includes a dice roll, only the part that can be calculated to a single number should be included in the calulation bracers: `The attack does an extra {paladin.level}d8 damage`, which becomes `The attack does an extra 4d8 damage`.
|
||||
|
||||
Do not inlclude the dice roll in the calaculation: `The attack does an extra {(paladin.level)d8} damage`, because it will become `The attack does an extra 16 damage` but the number 16 will change every time the creature recalculates.
|
||||
@@ -1,113 +0,0 @@
|
||||
# Actions
|
||||
|
||||
Actions are things your character can do. When an action is taken, all the properties under it are applied.
|
||||
|
||||
Add actions to your character sheet, then add children under the action to determine what happenes when the action is applied.
|
||||
|
||||
When an action is applied it will create an entry in the character's log detailing all the properties that were applied and what their results were.
|
||||
|
||||
The following properties can all be applied by an action:
|
||||
|
||||
- [Attribute Damage](/docs/property/attribute-damage)
|
||||
- [Branches](/docs/property/branch)
|
||||
- [Buffs](/docs/property/buff)
|
||||
- [Buff Removers](/docs/property/remove-buff)
|
||||
- [Damage](/docs/property/damage)
|
||||
- [Notes](/docs/property/note)
|
||||
- [Rolls](/docs/property/roll)
|
||||
- [Saving Throws](/docs/property/saving-throw)
|
||||
- Other actions
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the action.
|
||||
|
||||
### Action type
|
||||
|
||||
How long the action takes to perform.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Attack roll
|
||||
|
||||
A [computed field](/docs/computed-fields) which calculates the attack roll modifier. If this field is empty, no attack roll will be made. Use 0 to make an attack roll without a modifier.
|
||||
|
||||
The following variables may be added to the action scope when attack rolls are made:
|
||||
|
||||
- `$attackDiceRoll` The value of the d20 roll before any modifiers were applied.
|
||||
- `$attackRoll` The total attack roll after modifiers.
|
||||
- `$criticalHit` Set to `true` if the attack roll's d20 is a natural 20. If `criticalHitTarget` is set, the attack roll's d20 must instead be equal to or greater than `criticalHitTarget` for this to be set to `true`.
|
||||
- `$criticalMiss` Set to `true` if the attack roll was not a critical hit and rolled a natural 1 on the d20 roll.
|
||||
- `$attackHit` If the attack roll is higher than or equal to the target's AC or a critical hit this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical hit.
|
||||
- `$attackMiss` If the attack roll is lower than the target's AC or a critical miss, this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical miss.
|
||||
|
||||
### Summary
|
||||
|
||||
A brief overview of what the action does. This will appear in the action card, and shows in the log when the action is applied.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Description
|
||||
|
||||
A more detailed description of the action. The description does not show in the action card or the log when the action is applied.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Resource
|
||||
|
||||
A resource can be any attribute that has a variable name. If the resource attribute is less than the amount required, the action can't be applied.
|
||||
|
||||
If you want to reduce an attribute when taking the action, but want the action to be applied regardless of the value of that attribute, consider using an [Attribute Damage](/docs/property/attribute-damage) property as a child of the action instead. Also use Attribute Damage when the amount to reduce the attribute is determined by a dice roll rather than a stable computed number.
|
||||
|
||||
#### Resource attribute
|
||||
|
||||
The variable name of the attribute that will be consumed when taking this action.
|
||||
|
||||
#### Resource quantity
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how much of the attribute is required to apply this action. This amount will be deducted from the attribute every time the action is taken.
|
||||
|
||||
### Ammo
|
||||
|
||||
Ammo represents items that are requied to take the action. If an item is not selected, or there is insufficient quantity of the selected item, the action can't be appled.
|
||||
|
||||
#### Ammo item
|
||||
|
||||
Specify what tag an item must have to be considered valid ammo for this action. Any item with this tag can be selected as ammo for this action.
|
||||
|
||||
#### Ammo quantity
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how many of the selected items are required to take this action. The quantity is deducted from the total quantity of the item when this action is applied.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Target
|
||||
|
||||
Who this action should apply to. The properties under the action will be applied to the Targets.
|
||||
|
||||
- **Self** The action will apply its properties to the creature taking the action
|
||||
- **Single Target** The action will apply its properties without a target (for now)
|
||||
- **Multiple Targets** The action will apply its properties without a target (for now)
|
||||
|
||||
### Uses
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how many times this action can be used before it needs to be reset.
|
||||
|
||||
### Uses used
|
||||
|
||||
How many of this action's uses have already been used. Should ideally be between 0 and the total uses available. This number is set to 0 when the action has uses and its uses are reset.
|
||||
|
||||
### Don't show in log
|
||||
|
||||
When this is true, the action does not show up in the log. This does not stop the action's children from appearing in the log when they are applied.
|
||||
|
||||
### Reset
|
||||
|
||||
If set, the uses used field is set to 0 at the appropriate time.
|
||||
|
||||
- **Long rest** Reset when the long rest button is pushed
|
||||
- **Short rest** Reset when either the long or short rest button is pushed
|
||||
@@ -1,33 +0,0 @@
|
||||
# Attribute Damage
|
||||
|
||||
When applied, attribute damage reduces the value of the attribute by some amount or set the value of an attribute to some amount. Attribute damage can by applied by actions or triggers.
|
||||
|
||||
Using a negative value to damage an attribute will heal the attribute instead.
|
||||
|
||||
---
|
||||
|
||||
### Attribute
|
||||
|
||||
The variable name of the attribute to target.
|
||||
|
||||
### Amount
|
||||
|
||||
A [computed field](/docs/computed-fields) which determined the amount to damage the attribute or set the attribute's value to.
|
||||
|
||||
### Operation
|
||||
|
||||
- **Damage** Reduce the value of the attribute by the amount, negative values heal the attribute instead
|
||||
- **Set** Set the value of the attribute to the amount
|
||||
|
||||
### Target
|
||||
|
||||
- **Target** Apply the attribute damage to the same target as the action applying this property
|
||||
- **Self** Apply the attribute damage to the creature taking the action
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
When this is set, the attribute damage is applied, but does not show in the log.
|
||||
@@ -1,76 +0,0 @@
|
||||
# Attribute
|
||||
|
||||
Attributes represent the numerical values of the creature.
|
||||
|
||||
Attributes can be targeted by [effects](/docs/property/effect) which can change their total value in a non-destructive way. For example, if a class level gives you an ability score increase of +2 strength when it is taken, instead of directly editing the strength attribute, you add an effect to the class level that adds 2 to strength. The total value of strength will increase by 2 and it will show a record of that ability score increase and where it came from.
|
||||
|
||||
Attributes, [skills](/docs/properties/skill), and [effects](/docs/property/effect) are the core properties of DiceCloud's creature engine.
|
||||
|
||||
Attributes have the following fields that can be accessed in calculations with `variableName.field`:
|
||||
|
||||
- `.total` The total of the attribute before being damaged
|
||||
- `.damage` the amount of damage the attribute has taken
|
||||
- `.value` The current value of the attribute including damage. `variableName` and `variableName.value` are equivalent.
|
||||
- `.modifier` If the attribute is an ability, this is its roll modifier, eg. `strength.modifier` is +2 when `strength.value` is 14
|
||||
|
||||
---
|
||||
|
||||
### Base value
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines the starting value of the attribute before it is modified by effects and other properties. Multiple properties can set the base value for a given variable name, when this happens the highest base value is chosen, and then all other effects are applied.
|
||||
|
||||
### Name
|
||||
|
||||
The name of the attribute
|
||||
|
||||
### Variable name
|
||||
|
||||
The name used to refer to the attribute in calculations and by effects. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
If multiple attributes share a variable name, only the last attribute on the [character tree](/docs/tree) will count as the defining attribute and appear on the sheet, while other attributes with that variable name will be used as base value [effects](/docs/property/effect).
|
||||
|
||||
### Attribute type
|
||||
|
||||
- **Ability** Ablity scores like Strength, Dexterity, etc. Ability scores get a modifier which can be accessed in calculations as `variableName.modifier`,
|
||||
- **Stat** Any numerical value that appears on the sheet. Speed, armor class.
|
||||
- **Modifier** Any numical value that appears on the sheet with a `+` or `-` sign, eg. Proficiency bonus.
|
||||
- **Hit Dice** Hit dice let you select the appropriate hit dice size. Creatures regain half their total hit dice on long rest.
|
||||
- **Health Bar** Health bars can by made to take or ignore damage in a specified order
|
||||
- **Resource** Rages, sourcery points, things that are spent to use actions.
|
||||
- **Spell Slot** Spell slots have a specific level and are used to cast spells.
|
||||
- **Utility** Utility attributes don't show up anywhere on the sheet, but can still be used for calculations
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the attribute.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Health bar settings
|
||||
|
||||
Health bars can take or ignore damage and healing from applied damage properties targeting a creature. A lower ordered health bar will take damage before a higher ordered one.
|
||||
|
||||
Health bars can also change color depending on their value. At 50%+ full they are their property color, between 50% and 0% they fade from their half-full color to their empty color.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Allow decimal values
|
||||
|
||||
If this is set, the attribute will not round-down when its value has a decimal.
|
||||
|
||||
### Can be damaged into negative values
|
||||
|
||||
If this is set the attribute can be damaged past zero into negative values.
|
||||
|
||||
### Can be incremented above total
|
||||
|
||||
If this is set the attribute can have negative damage such that the value exceeds the total. This can be useful if you are using the attribute to count, it can start at zero and be healed upwards to keep count.
|
||||
|
||||
### Reset
|
||||
|
||||
If set, the damage on this attribute is reset to 0 at the appropriate time.
|
||||
|
||||
- **Long rest** Reset when the long rest button is pushed
|
||||
- **Short rest** Reset when either the long or short rest button is pushed
|
||||
@@ -1,24 +0,0 @@
|
||||
# Branches
|
||||
|
||||
Branches are applied by actions, when they are applied they can control which of their immediate children are applied.
|
||||
|
||||
---
|
||||
|
||||
### Branch type
|
||||
|
||||
- **If condition is true** Apply children if the condition (a [computed field](/docs/computed-fields)) resolves to `true` or a non-zero number
|
||||
- **Attack hit** Apply children if the attack roll hit the target
|
||||
- **Attack hit** Apply children if the attack roll missed the target
|
||||
- **Save failed** Apply children if target failed its saving throw
|
||||
- **Save suceeded** Apply children if target made its saving throw
|
||||
- **Apply to each target** Apply children separately to each target
|
||||
- **Random** Apply one of the immediate children at random
|
||||
- **Calculated Index** Use the index (a [computed field](/docs/computed-fields)) to choose which child to apply, starting at 1 for the first child.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
When this is set, the branch is applied, but does not show in the log. This does not prevent its children from appearing in the log.
|
||||
@@ -1,44 +0,0 @@
|
||||
# Buffs
|
||||
|
||||
Buffs are temporary changes to a character sheet that can be applied by actions. When a buff is applied, it is copied to the target character along with all of its children properties.
|
||||
|
||||
Buffs can either be manually removed from the stats page, or be removed by an action applying a [buff remover](/docs/property/remove-buff/) property.
|
||||
|
||||
### Variable freezing
|
||||
|
||||
When a buff is applied, all the calculations in the child properties have their variables frozen to their values at the time the buff is applied. You can prevent this behavior for the whole buff by using the `don't freeze variables` option, or on an individual variable reference by prefixing the variable with the keyword `$target.`.
|
||||
|
||||
For example, if a character has 10 strength and 16 dexterity, and applies a buff with some child property containing the calculation `$target.strength + dexterity` the property's calculation will become `strength + 16` when it is copied to the target character.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the buff.
|
||||
|
||||
### Description
|
||||
|
||||
Description of the applied buff.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Target
|
||||
|
||||
- **Target** Apply the buff to the target of the action
|
||||
- **Self** Apply the buff to the creature taking the action
|
||||
|
||||
### Hide remove button
|
||||
|
||||
If this is set, the remove button next to the buff on the stats page will be hidden. Use this when you expect the buff to be removed automatically by another action.
|
||||
|
||||
### Don't show in log
|
||||
|
||||
If set, the buff will not show its name and description in the log when applied.
|
||||
|
||||
### Don't freeze variables
|
||||
|
||||
Prevent the buff from freezing variables in child property calculations to their value at the time the buff was applied.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,29 +0,0 @@
|
||||
# Class level
|
||||
|
||||
A class level is a property that represents a single level in a class. It is generally used as a child of a [Class property](/docs/property/class).
|
||||
|
||||
Features and bonuses that are given by a class level get added as children of the class level.
|
||||
|
||||
---
|
||||
|
||||
### Level
|
||||
|
||||
Which level this property represents.
|
||||
|
||||
### Name
|
||||
|
||||
The name of the class or subclass this level is part of
|
||||
|
||||
### Variable name
|
||||
|
||||
The same variable name of the class this level belongs to.
|
||||
|
||||
### Description
|
||||
|
||||
A description of the benefits gained with this level.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,37 +0,0 @@
|
||||
# Classes
|
||||
|
||||
A class is a property that expects [class levels](/docs/property/class-level) as its immediate children.
|
||||
|
||||
Leveling up a class means choosing, or manually adding, class level properties to it. Class levels with the same variable name as the class, and that match all the required tags are found in libraries and added to the class.
|
||||
|
||||
The total level of the class can be accessed in calculations using `classVariableName.level`.
|
||||
|
||||
## Making your own class
|
||||
|
||||
See [Create a Class](/docs/walkthroughs/create-a-class)
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the class
|
||||
|
||||
### Variable name
|
||||
|
||||
The name used to refer to the class in calculations. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
### Description
|
||||
|
||||
A description of the class.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Tags required
|
||||
|
||||
Only class levels with the same variable name as the class, and with tags that match the tags required will be returned from libraries when leveling up this class.
|
||||
|
||||
### Condition
|
||||
|
||||
A [computed field](/docs/computed-fields) to determine if the class is allowed to level up. If this field results in `true` or a number that is not 0, the class can be levelled, otherwise leveling is disabled.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Constants
|
||||
|
||||
Constants are properties that store some primitive value in a variable name for use in other calculations.
|
||||
|
||||
Unlike attributes, constants can store more than just numbers:
|
||||
|
||||
- Arrays: `[1,2,3,4]`
|
||||
- Text strings: `'I am a cat'`
|
||||
- Numbers: `3.14`
|
||||
- Boolean values: `true`, `false`
|
||||
- Dice rolls: `1d20 + 2`
|
||||
|
||||
Constants just can't use other variables in their calculations.
|
||||
|
||||
### Overriding constants
|
||||
|
||||
If multiple constants have the same variable name, only the last active constant in the [character tree](/docs/tree) will be used as the definition for that variable name.
|
||||
|
||||
This can be used to re-write the value of some constant by ensuring there is a new active constant later in the sheet.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the constants
|
||||
|
||||
### Variable Name
|
||||
|
||||
The name used to refer to the constant in calculations. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
### Value
|
||||
|
||||
A [calculation](/docs/computed-fields) of the final value of the constant.
|
||||
@@ -1,35 +0,0 @@
|
||||
# Containers
|
||||
|
||||
Containers are things that [items](/docs/property/item) can be put inside of.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the container
|
||||
|
||||
### Carried
|
||||
|
||||
If this is set the weight of the container and its contents will be added to the character's weight carried.
|
||||
|
||||
### Value
|
||||
|
||||
The value of the container in gold pieces. Silver pieces are worth 0.1 gp and copper pieces are worth 0.01 gp. So a container that is worth 2 gp 4 sp 7 cp will have a value of 2.47 gp.
|
||||
|
||||
### Weight
|
||||
|
||||
The weight of the container in lb.
|
||||
|
||||
### Description
|
||||
|
||||
A description of the container.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Contents are weightless
|
||||
|
||||
If this is set and the container is carried, only the container's own weight will be added to the weight carried by the creature.
|
||||
@@ -1,33 +0,0 @@
|
||||
# Damage multipliers
|
||||
|
||||
Damage multipliers are used to define vulnerability, resistance, and immunity to damage types.
|
||||
|
||||
A single multiplier can apply to multiple damage types, and choose whether or not to apply to an incoming source of damage based on the tags present on that damage.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the feature that gives this damage multiplier
|
||||
|
||||
### Value
|
||||
|
||||
- **Immunity** The creature takes no damage from matching damage sources
|
||||
- **Resistance** Damage from matching sources is halved.
|
||||
- **Vulnerability** Damage from matching sources is doubled.
|
||||
|
||||
### Damage types
|
||||
|
||||
A list of damage types that this property applies to. Custom types can be used.
|
||||
|
||||
### Damage tags required
|
||||
|
||||
This damage multiplier will only be applied if the incoming damage has all of these tags present.
|
||||
|
||||
### Damage tags excluded
|
||||
|
||||
This damage multiplier will only apply if the incoming damage has none of these tags present.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Damage
|
||||
|
||||
Damage can be applied by an action to damage a target creature's [health bars](/docs/property/attribute). The damage will be modified by [damage multipliers](/docs/property/damage-multiplier), which apply vulnerability, resistance, and immunity before the damage is applied.
|
||||
|
||||
---
|
||||
|
||||
### Damage
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines how much damage to do to the target creature.
|
||||
|
||||
### Damage type
|
||||
|
||||
Damage type determines how the damage is treated by [damage multipliers](/docs/property/damage-multiplier). A custom type can be used, or one of the existing types can be selected.
|
||||
|
||||
There are two special damage types:
|
||||
|
||||
**Extra damage** Damage with the `extra` type will take on the damage type of whatever damage was applied before it by an action. So if an action deals 12 `piercing` damage and `3` extra damage, it will instead deal 15 `piercing` damage.
|
||||
|
||||
**Healing** Damage with the `healing` type will heal a creature instead of damaging them.
|
||||
|
||||
### Target
|
||||
|
||||
- **Target** Apply the damage to the target of the action
|
||||
- **Self** Apply the damage to the creature taking the action
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
If set, the damage will be applied but not show in the log.
|
||||
@@ -1,60 +0,0 @@
|
||||
# Effects
|
||||
|
||||
Effects are the core of the DiceCloud engine. Effect change the values of attributes, skills, and calculations in a way that is transparent and auditable, keeping character sheets organized and understandable, even when using intricate homebrew rules on high level characters.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the feature that causes this effect.
|
||||
|
||||
### Operation
|
||||
|
||||
The operation determines what the effect will do to the affected property or calcualtion.
|
||||
|
||||
- **Base Value** Set the base value of the affected property. If a property has multiple base values, the highest is used
|
||||
- **Add** Add the value to the affected property or calculation
|
||||
- **Muliply** Multiply the affected property by the value
|
||||
- **Minimum** Prevent the affected property from having a value less than the effect value
|
||||
- **Maximum** Prevent the affected property from having a value greater than the effect value
|
||||
- **Maximum** Prevent the affected property from having a value greater than the effect value
|
||||
- **Set** Set the value affected property to the effect value
|
||||
- **Advantage** Give advantage to checks made using the affected property
|
||||
- **Disadvantage** Give disadvantage to checks made using the affected property
|
||||
- **Passive bonus** Add the effect value to the passive scores based on the affected property
|
||||
- **Fail** Checks made using the affected property automatically fail
|
||||
- **Conditional benefit** Add some text to the affected property describing the benefit recieved
|
||||
|
||||
### Value
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines the value of the effect.
|
||||
|
||||
### Text
|
||||
|
||||
If the operation is a conditional benefit, the note text that will show on affected properties.
|
||||
|
||||
### Target stats by variable name
|
||||
|
||||
If selected the effect will apply to all properties that have the given variable names.
|
||||
|
||||
### Variable names
|
||||
|
||||
A list of variable names of properties to target with this effect.
|
||||
|
||||
### Target properties by tags
|
||||
|
||||
When targeting properties by tag, any property can be targeted with an effect. If the property is one that can usually be targeted by variable name, the effect will apply as ususal, however if the effect targets another property, it will apply to a [computed field](/docs/computed-fields) on the property instead.
|
||||
|
||||
These effects can be used for adding a bonus to a specific attack or damage roll, or manipulating any computed field on the creature.
|
||||
|
||||
### Tags required
|
||||
|
||||
Only properties that match the required tags will be targeted by the effect.
|
||||
|
||||
### Target field
|
||||
|
||||
If a property has multiple computed fields, which field should be targeted by this effect.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,25 +0,0 @@
|
||||
# Features
|
||||
|
||||
Features appear on the features tab. Classes, backgrounds, and race can all give a creature features.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the feature.
|
||||
|
||||
### Summary
|
||||
|
||||
A summary of the feature. This will appear on the feature card.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the feature.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,17 +0,0 @@
|
||||
# Folders
|
||||
|
||||
Folders allow the [character tree](/docs/tree) to be organized.
|
||||
|
||||
### Folders in actions
|
||||
|
||||
When a folder is the child of an action, it and its children will not show on the action card, but will still appear in the detail view of the action and be applied when the action is taken.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the folder.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,57 +0,0 @@
|
||||
# Items
|
||||
|
||||
Items are shown on the Inventory tab. Items can be carried, put in containers, or equipped on a creature. The children of an item are not active unless the item is equipped.
|
||||
|
||||
---
|
||||
|
||||
### Icon
|
||||
|
||||
An icon representing the item.
|
||||
|
||||
### Equipped
|
||||
|
||||
If set, the item appears in the equipment list on the inventory tab and its children become active on the creature.
|
||||
|
||||
### Name
|
||||
|
||||
The name of the item.
|
||||
|
||||
### Plural name
|
||||
|
||||
The name to use if the quantity of the item is higher than 1.
|
||||
|
||||
### Value
|
||||
|
||||
The value of a single item in gold pieces. Silver pieces are worth 0.1 gp and copper pieces are worth 0.01 gp. So an item that is worth 2 gp 4 sp 7 cp will have a value of 2.47 gp.
|
||||
|
||||
### Weight
|
||||
|
||||
The weight of a single item in lb.
|
||||
|
||||
### Quantity
|
||||
|
||||
Number of items. The value and quantity will be multiplied by the quantity to get the total value and weight of this stack of items.
|
||||
|
||||
### Description
|
||||
|
||||
A description of the item.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Show increment button
|
||||
|
||||
If this is set, the item will show an increment button in the detail view and on the inventory tab. This button can be used to quickly adjust the quantity of the item.
|
||||
|
||||
### Requires attunemnt
|
||||
|
||||
If set, the item requires attunemnt to use.
|
||||
|
||||
### Attuned
|
||||
|
||||
If set, the item is attuned and counts towards the total number of attuned items for the creature.
|
||||
|
||||
If a child property needs to determine if its parent item is attuned it can use `#item.attuned` in calculations, see *Ancestor references* in [computed fields](/docs/computed-fields).
|
||||
@@ -1,25 +0,0 @@
|
||||
# Notes
|
||||
|
||||
Notes are used to store text on the creature that does not have a direct mechanical impact. Notes appear on the journal tab when active on the character, or are shown in the log when applied by an [action](/docs/property/action).
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
Name of the note.
|
||||
|
||||
### Summary
|
||||
|
||||
A summary of the note. This will appear on the note card and in the log when applied by an [action](/docs/property/action).
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the feature.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,39 +0,0 @@
|
||||
# Point buy
|
||||
|
||||
A point buy is a set of rows that lets the user choose a set of stats based on a cost per stat.
|
||||
|
||||
---
|
||||
|
||||
### Table name
|
||||
|
||||
The name of the point buy table.
|
||||
|
||||
### Min
|
||||
|
||||
The lowest value available for each row
|
||||
|
||||
### Max
|
||||
|
||||
The highest value available for each row
|
||||
|
||||
### Cost
|
||||
|
||||
A function that uses `value` as the value of a row and determines the cost of that value. For standard D&D 5e 27 point buy, this function is `[0, 1, 2, 3, 4, 5, 7, 9][value - 7]`
|
||||
|
||||
### Total available points
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines how many points are available to spend in total
|
||||
|
||||
## Rows
|
||||
|
||||
Up to 32 rows can be added to a point buy table
|
||||
|
||||
### Row name
|
||||
|
||||
The name of the row that will appear in the table
|
||||
|
||||
### Row variable name
|
||||
|
||||
The variable name of the row that can be used in calculations. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
If the variable name matches an attribute with the same variable name, the row's value will be used as a base value for that attribute.
|
||||
@@ -1,21 +0,0 @@
|
||||
# Proficiencies
|
||||
|
||||
Proficiencies add proficiency to an existing skill on the creature. If you need to add a tool or language proficiency to a creature, use a [Skill](/docs/property/skill) instead.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
Name of the feature that is adding this proficiency
|
||||
|
||||
### Skills
|
||||
|
||||
A list of variable names of the skills to add proficiency to.
|
||||
|
||||
### Proficiency
|
||||
|
||||
How much proficiency to add to the skill. If a skill has multiple proficiencies added to it, the highest one will be used.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Remove Buff
|
||||
|
||||
This property can remove a specific buff from a targeted creature.
|
||||
|
||||
### Name
|
||||
|
||||
The name of the property. This shows in the log when the property is applied.
|
||||
|
||||
### Remove parent buff
|
||||
|
||||
When this is set and the property is applied, the property will remove the nearest parent buff. If this property is not the child of any buffs, it will log an error.
|
||||
|
||||
### Remove all
|
||||
|
||||
When this is set, all buffs that match the target tags will be removed from the targeted creature. If not set, only the first buff found with the matching tags will be removed.
|
||||
|
||||
### Target
|
||||
|
||||
- **Target** Matching buffs will be removed from the targeted creature
|
||||
- **Self** Matching buffs will be removed from the creature that applied the action
|
||||
|
||||
### Tags required
|
||||
|
||||
Any buff that has all of the required tags will be removed when the property is applied.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
When this is set, the property is applied, but does not show in the log.
|
||||
@@ -1,27 +0,0 @@
|
||||
# Rolls
|
||||
|
||||
Rolls are properties that store the result of a calculation to a variable name when applied by an [action](/docs/property/action). The variable name only exists for the duration of that particalar action.
|
||||
|
||||
Rolls can be useful if you need to deal the same damage to multiple targets, or if damage needs to be rolled then halved by succeeding on a saving throw.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
Name of the roll. This will be shown in the log when the roll is applied.
|
||||
|
||||
### Variable name
|
||||
|
||||
The variable name to store the result of the roll for the duration of the action. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
### Roll
|
||||
|
||||
A [computed field](/docs/computed-fields) that is computed when the roll is applied by an action.
|
||||
|
||||
### Don't show in log
|
||||
|
||||
If set, the roll will be applied and store its result in the variable name, but not be shown in the log.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,35 +0,0 @@
|
||||
# Saving throws
|
||||
|
||||
Saving throws are properties that cause the target to make a saving throw when applied. If you want to add a type of saving throw like Strength Save to a creature, use a [skill](/docs/property/skill) instead.
|
||||
|
||||
When a saving throw is applied, the following variables are added to the scope of that action:
|
||||
|
||||
- `$saveFailed` Set to `true` if the target failed its saving throw or there are no targets for the saving throw
|
||||
- `$saveSucceeded` Set to `true` if the target made its saving throw or there are no targets for the saving throw
|
||||
- `$saveDiceRoll` The unmodified d20 roll the target made to save
|
||||
- `$saveRoll` The final value of the saving throw roll after modifiers
|
||||
|
||||
### Name
|
||||
|
||||
The name of the saving throw. Usually the ability saving throw targeted: "Strength Save".
|
||||
|
||||
### DC
|
||||
|
||||
The DC of the saving throw that the target needs to meet
|
||||
|
||||
### Save
|
||||
|
||||
The variable name of the skill that will be used to make the saving throw.
|
||||
|
||||
### Target
|
||||
|
||||
- **Target** Apply the saving throw to the targets of the action. Each target will make the saving throw in turn. Child properties will be applied to each target separately with the results of their individual saving throw. If a value like damage needs to be shared between targets, it should be calculated in a [Roll](/docs/property/roll) before the saving throw.
|
||||
- **Self** Apply the saving throw to the creature taking the action. The creature taking the action will become the target for all child properties.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
If set, the saving throw will not show in the log when applied, but will still be rolled and apply its children.
|
||||
@@ -1,39 +0,0 @@
|
||||
# Slot filler
|
||||
|
||||
A slot filler is a property that can be used to add more complex behavior to filling a [slot](/docs/property/slot) from a library.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the slot filler that will show when choosing the filler from the library.
|
||||
|
||||
### Icon
|
||||
|
||||
Icon of the slot filler
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the slot filler.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Picture URL
|
||||
|
||||
A link to an image to use for this slot filler when being chosen from a library.
|
||||
|
||||
### Type
|
||||
|
||||
Slot fillers can pretend to be any type of property when a slot is being filled.
|
||||
|
||||
### Quantity
|
||||
|
||||
How many spaces the slot filler will take up in a slot.
|
||||
|
||||
### Condition
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines whether this slot filler can be added to a character.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,53 +0,0 @@
|
||||
# Slots
|
||||
|
||||
Slots are the main way creatures interact with libraries. A slot can be filled by choosing a property from a library that fits that particular slot.
|
||||
|
||||
In a complete library, a creature can be built entirely by choosing which properties to fill each slot with.
|
||||
|
||||
Slots show up on the build tab, and are highlighted when they have space that can be filled.
|
||||
|
||||
If you are building a creature without a library, you should either ignore slots entirely, or fill them with your own custom properties.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the slot.
|
||||
|
||||
### Type
|
||||
|
||||
What kind of property this slot expects to fill it.
|
||||
|
||||
### Tags required
|
||||
|
||||
Properties in a library must have the required tags to fill the slot.
|
||||
|
||||
### Quantity
|
||||
|
||||
How many properties are expected to fill this slot. Use 0 for allowing an unlimited number of properties.
|
||||
|
||||
### Condition
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines whether this slot can accept new properties.
|
||||
|
||||
### Unique
|
||||
|
||||
The slot can control how it deals with the uniqueness of properties that fill it.
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the attribute.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Hide when full
|
||||
|
||||
When set the slot will hide itself when it is filled.
|
||||
|
||||
### Ignored
|
||||
|
||||
When set the slot will not show a prompt card on the build tab.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,115 +0,0 @@
|
||||
# Spells
|
||||
|
||||
Spells work similarly to [actions](/docs/property/action). They appear on the spells tab and can be cast with or without using up spell slots.
|
||||
|
||||
---
|
||||
|
||||
### Always prepared
|
||||
|
||||
A spell that is always prepared does not count towards the spell list's maximum prepared spells and is always active and ready to cast.
|
||||
|
||||
### Prepared
|
||||
|
||||
A prepared spell is ready to cast and counts against a spell list's maximum prepared spells.
|
||||
|
||||
### Cast without spell slots
|
||||
|
||||
When set, this spell can be cast without consuming spell slots. It will however consume its own uses and resources.
|
||||
|
||||
### School
|
||||
|
||||
What school the spell belongs to.
|
||||
|
||||
### Casting time
|
||||
|
||||
How long the spell takes to Cast
|
||||
|
||||
### Range
|
||||
|
||||
The range of the spell
|
||||
|
||||
### Duration
|
||||
|
||||
How long the spell lasts
|
||||
|
||||
### Components
|
||||
|
||||
Whether the spell requires verbal, somatic, or material components and whether the spell is a ritual or requires concentration.
|
||||
|
||||
### Target
|
||||
|
||||
Who this spell should apply to. The properties under the spell will be applied to the targets.
|
||||
|
||||
- **Self** The spell will apply its properties to the creature casting the spell
|
||||
- **Single Target** The spell will apply its properties without a target (for now)
|
||||
- **Multiple Targets** The spell will apply its properties without a target (for now)
|
||||
|
||||
### Attack roll
|
||||
|
||||
A [computed field](/docs/computed-fields) which calculates the spell attack roll modifier. If this field is empty, no attack roll will be made. Use 0 to make an attack roll without a modifier. To use the spell list's attack roll bonus use `#spellList.attackRollBonus`.
|
||||
|
||||
The following variables may be added to the action scope when attack rolls are made:
|
||||
|
||||
- `$attackDiceRoll` The value of the d20 roll before any modifiers were applied.
|
||||
- `$attackRoll` The total attack roll after modifiers.
|
||||
- `$criticalHit` Set to `true` if the attack roll's d20 is a natural 20. If `criticalHitTarget` is set, the attack roll's d20 must instead be equal to or greater than `criticalHitTarget` for this to be set to `true`.
|
||||
- `$criticalMiss` Set to `true` if the attack roll was not a critical hit and rolled a natural 1 on the d20 roll.
|
||||
- `$attackHit` If the attack roll is higher than or equal to the target's AC or a critical hit this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical hit.
|
||||
- `$attackMiss` If the attack roll is lower than the target's AC or a critical miss, this is set to `true`. Remains unset if there is no target for the attack unless the attack is a critical miss.
|
||||
|
||||
### Summary
|
||||
|
||||
A brief overview of what the spell does. This will show in the log when the spell is cast.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Description
|
||||
|
||||
A more detailed description of the spell. The description does not show in the log when the spell is cast.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Resource
|
||||
|
||||
A resource can be any attribute that has a variable name. If the resource attribute is less than the amount required, the spell can't be cast.
|
||||
|
||||
If you want to reduce an attribute when casting the spell, but want the spell to be applied regardless of the value of that attribute, consider using an [Attribute Damage](/docs/property/attribute-damage) property as a child of the spell instead. Also use Attribute Damage when the amount to reduce the attribute is determined by a dice roll rather than a stable computed number.
|
||||
|
||||
#### Resource attribute
|
||||
|
||||
The variable name of the attribute that will be consumed when casting this spell.
|
||||
|
||||
#### Resource quantity
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how much of the attribute is required to apply this spell. This amount will be deducted from the attribute every time the spell is cast
|
||||
### Ammo
|
||||
|
||||
Ammo represents items that are requied to cast the spell. If an item is not selected, or there is insufficient quantity of the selected item, the spell can't be appled.
|
||||
|
||||
#### Ammo item
|
||||
|
||||
Specify what tag an item must have to be considered valid ammo for this spell. Any item with this tag can be selected as ammo for this spell.
|
||||
|
||||
#### Ammo quantity
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how many of the selected items are required to cast this spell. The quantity is deducted from the total quantity of the item when this spell is applied.
|
||||
|
||||
### Uses
|
||||
|
||||
A [computed field](/docs/computed-fields) which determines how many times this spell can be used before it needs to be reset.
|
||||
|
||||
### Uses used
|
||||
|
||||
How many of this spell's uses have already been used. Should ideally be between 0 and the total uses available. This number is set to 0 when the spell has uses and its uses are reset.
|
||||
|
||||
### Reset
|
||||
|
||||
If set, the uses used field is set to 0 at the appropriate time.
|
||||
|
||||
- **Long rest** Reset when the long rest button is pushed
|
||||
- **Short rest** Reset when either the long or short rest button is pushed
|
||||
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
@@ -1,36 +0,0 @@
|
||||
# Toggles
|
||||
|
||||
Toggles are a way to turn on and off parts of a creature. When a toggle is off, none of its children will be active.
|
||||
|
||||
Calculated toggles should be avoided if possible, because while they offer a lot of power and flexibility to the creature engine, they often create [dependency loops](/docs/dependency-loops) that can be difficult to troubleshoot, causing parts of a creature to calculate incorrectly.
|
||||
|
||||
Calculated toggles can be applied by [actions](/docs/property/action) and will apply their children if the condition is true, but they should be avoided in favor of [conditional branches](/docs/property/branch) which can do the same, but are more efficient.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the toggle.
|
||||
|
||||
### Variable name
|
||||
|
||||
The name used to refer to the value of the toggle in calculations. Must start with a letter and be made up of only letters and numbers without spaces, symbols, or punctiation.
|
||||
|
||||
### Show on character sheet
|
||||
|
||||
If set, the toggle with show a checkbox on the character sheet. A calculated toggle will show a disabled checkbox, filled in if the toggle's calculation returned `true` or a value that isn't 0.
|
||||
|
||||
### State
|
||||
|
||||
- **Enabled** The toggle and its children are active
|
||||
- **Disabled** The toggle and its children are inactive
|
||||
- **Calculated** The active status of the toggle depends on the result of the condition. Use with caution.
|
||||
|
||||
### Condition
|
||||
|
||||
A [computed field](/docs/computed-fields) that determines if the toggle is active. Use with caution.
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# Triggers
|
||||
|
||||
Triggers apply their children whenever their condition is met. They work like [actions](/docs/property/action) that are taken automatically.
|
||||
|
||||
---
|
||||
|
||||
### Name
|
||||
|
||||
The name of the trigger.
|
||||
|
||||
### Timing
|
||||
|
||||
- **Before** The trigger is applied before the triggering event takes place
|
||||
- **After** The trigger is fired after the triggering event
|
||||
|
||||
### Event
|
||||
|
||||
- **Do action** While the creature is doing an action, the action property specified in *Event type* is applied
|
||||
- **Roll check** The creature makes a check
|
||||
- **Attribute damaged or healed** One of the creature's attributes changed value through attribute damage or manual adjustment
|
||||
- **Short or long rest**
|
||||
- **Short rest**
|
||||
- **Long Rest**
|
||||
|
||||
### Event type
|
||||
|
||||
The trigger will apply when this property type is applied by the action
|
||||
|
||||
### Tags required
|
||||
|
||||
If this trigger is fired by a property, the property must match these tags for the trigger to fire.
|
||||
|
||||
### Condition
|
||||
|
||||
A [computed field](/docs/computed-fields) to determine if the trigger should fire. The trigger will fire if the condition field is empty or if it returns `true` or a value that isn't 0.
|
||||
|
||||
### Description
|
||||
|
||||
A detailed description of the trigger.
|
||||
|
||||
Allows [inline calculations](/docs/inline-calculations).
|
||||
|
||||
### Tags
|
||||
|
||||
See [Tags](/docs/tags)
|
||||
|
||||
### Don't show in log
|
||||
|
||||
When this is true, the trigger does not show up in the log. This does not stop the trigger's children from appearing in the log when they are applied.
|
||||
@@ -1,14 +0,0 @@
|
||||
# Tags
|
||||
|
||||
Tags are used to reference multiple similar properties at once. A slot can require only properties from your library that has matching tags, effects and some other properties can also target properties to apply to by tags.
|
||||
|
||||
## Built in tags
|
||||
|
||||
Properties have specific tags automatically for use with tag-targeting. These aren't relevant for slots and finding properties in a library with specific tags.
|
||||
|
||||
- `#type` Actions will have the `#action` tag, etc. Damage will either have the tag `#damage` or the tag `#healing` if the damage type is healing
|
||||
- `variableName` if a property has a variable name it will be included as a tag
|
||||
- The type of damage done by a [damage](/docs/property/damage) property: `bludgeoning`, `slashing`, `...`
|
||||
- The skill type of a [skill](/docs/property/skill) property: `skill`, `save`, `check`, `tool`, `weapon`, `armor`, `language`, `utility`
|
||||
- The attribute type of an [attribute](/docs/property/attribute) property: `ability`, `stat`, `modifier`, `hitDice`, `healthBar`, `resource`, `spellSlot`, `utility`
|
||||
- When the property resets: `longRest`, `shortRest`
|
||||
@@ -1,47 +0,0 @@
|
||||
# Create a Class
|
||||
|
||||
This is a guide on creating a custom class in a character sheet. If possible, it is always faster to use an existing library that contains the class you want to use. Before continuing, check the #libraries channel of the [official discord](https://discord.gg/qEvdfeB) to see if a library exists with the class you are creating.
|
||||
|
||||
This guide assumes you are using the ruleset provided in the [5e System Reference Document library](/library/qkv8aptJH2fCXARcJ). If you are using a different ruleset for your character, there may be some discrepancies.
|
||||
|
||||
## Adding the class property
|
||||
|
||||
On the build tab of your character, in the card labeled **Slots**, expand the rulset, then click the slot where you would like to place the custom class, if it is your starting class in an SRD character, this would be the Class slot. Be sure to click the name of the slot, not the **+** button.
|
||||
|
||||

|
||||
|
||||
This opens the slot in detail view, showing you how the slot expected to be filled from a library, instead of filling the slot, we will be manually adding a class to the slot that we create ourselves.
|
||||
|
||||
Click the **Edit** button in the top right of the slot detail dialog.
|
||||
|
||||

|
||||
|
||||
Expand the children of the class slot, and click the plus button to add a child property.
|
||||
|
||||

|
||||
|
||||
This brings up the create a property dialog, we are creating a class, so select the class property type.
|
||||
|
||||

|
||||
|
||||
Now that we have selected the class property type, the create tab is selected where we can enter the details of our class, fill in the form and click **Create**.
|
||||
|
||||

|
||||
|
||||
Now that our custom class is created, we can close the class slot dialog.
|
||||
|
||||
On the Build tab, in the card with the title **Level**, you will see your new class, with a button to **Level Up**, clicking the level up button would usually search your libraries for class levels that match the variable name of the class, however, since it's a custom class, it will probably not find any levels.
|
||||
|
||||
Instead, as we did with the class slot, click on the class name to bring up the class detail dialog, click **Edit**, expand children and click the **+** button to add a child to the class. Here we will add all of the things our class gives the character.
|
||||
|
||||
Add an [Effect](/docs/property/effect) which targets `hitPoints` to add the starting hitpoints of the class. Add a [proficiencies](/docs/property/proficiency) for all the skill and saving throw proficiencies the class gives. Add [skills](/docs/property/skill) for all the tool and weapon proficiencies of the class, making sure to set the base proficiency of those skills to proficient. Add any text [features](/docs/property/feature) the class gives you, along with [actions](/docs/property/action) which may be children of those features, or direct children of the class.
|
||||
|
||||
Once you have added Everything the class gives you, it's time to add class levels. As a child of the class, add a [class level](/docs/property/class-level) property. Set the level to 1 and the name and variable name to match the variable name of the class.
|
||||
|
||||
Once the class level is created, open the class level and edit it. Use the **+** button in the children of the class level to add all the properties the class level gives your character.
|
||||
|
||||
Repeat this for every level of the class until your character is at the correct level.
|
||||
|
||||
You can use a separate character with levels in a class that is available in your libraries as an example of what properties you may want to add to your class and class levels.
|
||||
|
||||

|
||||
BIN
app/public/images/crown-dice-on-ipad.webp
Normal file
|
After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 582 KiB |
BIN
app/public/images/paper-dice-crown.webp
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/public/images/screenshots/actions.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/public/images/screenshots/auditable.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/public/images/screenshots/automated-dice-rolls.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/public/images/screenshots/build-system.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/public/images/screenshots/inventory.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/public/images/screenshots/libraries-of-content.webp
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/public/images/screenshots/printing.webp
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
app/public/images/screenshots/send-to-discord.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |