Refactored character insertion and continued work on creation dialog

This commit is contained in:
Stefan Zermatten
2018-12-18 14:20:17 +02:00
parent dcc460d9e6
commit 13669fdc91
31 changed files with 131 additions and 192 deletions

View File

@@ -51,3 +51,4 @@ static-html
aldeed:collection2@3.0.0
aldeed:schema-index
akryum:vue-component
autopublish

View File

@@ -12,6 +12,7 @@ akryum:vue-router2@0.2.2
aldeed:collection2@3.0.0
aldeed:schema-index@3.0.0
allow-deny@1.1.0
autopublish@1.0.7
autoupdate@1.4.1
babel-compiler@7.1.1
babel-runtime@1.2.7

View File

@@ -1,9 +1,9 @@
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import SimpleSchema from 'simpl-schema';
import Effects from "/imports/api/creature/Effects.js"
import Effects from "/imports/api/creature/properties/Effects.js"
import deathSaveSchema from "/imports/api/creature/subSchemas/DeathSavesSchema.js"
import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js";
import getDefaultCreatureDocs from "/imports/api/creature/CreatureDefaults.js";
import getDefaultCreatureDocs from "/imports/api/creature/getDefaultCreatureDocs.js";
//set up the collection for creatures
Creatures = new Mongo.Collection("creatures");
@@ -62,55 +62,6 @@ let creatureSchema = new SimpleSchema({
Creatures.attachSchema(creatureSchema);
Creatures.attachSchema(ColorSchema);
Creatures.calculate = {
xpLevel: function(charId){
var xp = Creatures.calculate.experience(charId);
for (var i = 0; i < 19; i++){
if (xp < XP_TABLE[i]){
return i;
}
}
if (xp > 355000) return 20;
return 0;
},
};
const insertCharacter = new ValidatedMethod({
name: "Creatures.methods.insertCharacter", // DDP method name
validate: new SimpleSchema({
name: {
type: String,
optional: true,
},
}).validator(),
run({name}) {
if (!this.userId) {
throw new Meteor.Error("Creatures.methods.insert.denied",
"You need to be logged in to insert a creature");
}
// Create the creature document
let charId = Creatures.insert({name, owner: this.userId});
this.unblock();
//Add all the required attributes to it
if (Meteor.isServer){
addDefaultStats(charId);
}
return charId;
},
});
const addDefaultStats = function(charId){
const defaultDocs = getDefaultCreatureDocs(charId);
Attributes.rawCollection().insert(defaultDocs.attributes, {ordered: false});
Skills.rawCollection().insert(defaultDocs.skills, {ordered: false});
DamageMultipliers.rawCollection().insert(defaultDocs.damageMultipliers, {ordered: false});
};
//clean up all data related to that creature before removing it
if (Meteor.isServer){
Creatures.after.remove(function(userId, creature) {
@@ -145,91 +96,6 @@ if (Meteor.isServer){
doc.settings.newUserExperience = true;
}
});
//give characters default items
Creatures.after.insert(function(userId, char) {
if (Meteor.isServer){
var containerId = Containers.insert({
name: "Coin Pouch",
charId: char._id,
isCarried: true,
description: "A sturdy pouch for coins",
color: "d",
});
Items.insert({
name: "Gold piece",
plural: "Gold pieces",
charId: char._id,
quantity: 0,
weight: 0.02,
value: 1,
color: "n",
parent: {
id: containerId,
collection: "Containers",
},
settings: {
showIncrement: true,
},
});
Items.insert({
name: "Silver piece",
plural: "Silver pieces",
charId: char._id,
quantity: 0,
weight: 0.02,
value: 0.1,
color: "q",
parent: {
id: containerId,
collection: "Containers",
},
settings: {
showIncrement: true,
},
});
Items.insert({
name: "Copper piece",
plural: "Copper pieces",
charId: char._id,
quantity: 0,
weight: 0.02,
value: 0.01,
color: "s",
parent: {
id: containerId,
collection: "Containers",
},
settings: {
showIncrement: true,
},
});
}
});
}
Creatures.allow({
insert: function(userId, doc) {
// the user must be logged in, and the document must be owned by the user
return (userId && doc.owner === userId);
},
update: function(userId, doc, fields, modifier) {
// can only change documents you have write access to
return doc.owner === userId ||
_.contains(doc.writers, userId);
},
remove: function(userId, doc) {
// can only remove your own documents
return doc.owner === userId;
},
fetch: ["owner", "writers"],
});
Creatures.deny({
update: function(userId, docs, fields, modifier) {
// can't change owners
return _.contains(fields, "owner");
}
});
export default Creatures;

View File

@@ -1,4 +1,4 @@
{
export default {
"attributes": [
{"name": "Strength", "variableName": "strength", "baseValue": 10, "type": "ability"},
{"name": "Dexterity", "variableName": "dexterity", "baseValue": 10, "type": "ability"},

View File

@@ -1,18 +1,34 @@
import DEFAULT_CHARACTER_STATS from '/imports/api/creature/DEFAULT_CHARACTER_STATS.js';
getDefaultCreatureDocs = function(charId, creatureType = "pc"){
let docs = {attributes: [], skills: [], damageMultipliers: [], effects: []};
// Setup the docs object which will be returned
let docs = {
attributes: [],
skills: [],
damageMultipliers: [],
effects: []
};
// Get the default character stats
let stats;
if (creatureType === "pc"){
const stats = DEFAULT_CHARACTER_STATS;
stats = DEFAULT_CHARACTER_STATS;
} else {
stats = null;
throw new Meteor.Error("Not implemented",
"Default stats for non-player characters aren't implemented yet");
}
// Setup the variables we'll need to share
let order = 0;
const baseParent = {
collection: "Characters",
id: charId,
group: "default",
};
let name, variableName, parent, attribute, skill, ability, dm, type, baseValue;
let name, variableName, parent, attribute, skill, dm, type, baseValue;
// Attributes
for (type in stats.attributes){
for (let i in stats.attributes[type]){
attribute = stats.attributes[type][i];
@@ -32,6 +48,8 @@ getDefaultCreatureDocs = function(charId, creatureType = "pc"){
order++;
}
}
// Skills
order = 0;
for (type in stats.skills){
for (let i in stats.skills[type]){
@@ -49,26 +67,36 @@ getDefaultCreatureDocs = function(charId, creatureType = "pc"){
order++;
}
}
// Damage Multipliers
order = 0;
for (let i in stats.damageMultipliers){
dm = stats.damageMultipliers[i];
docs.damageMultipliers.push({
_id: Random.id,
charId,
order,
name: dm.name,
variableName: dm.variableName,
parent: _.clone(baseParent),
});
order++;
}
// Effects
order = 0;
for (let i in stats.effects){
eff = stats.effects[i];
docs.effects.push({
_id: Random.id,
charId,
order,
name: eff.name,
stat: eff.stat,
operation: eff.operation,
calculation:eff.calculation,
});
order++;
}
return docs;
}

View File

@@ -0,0 +1,39 @@
import getDefaultCreatureDocs from '/imports/api/creature/getDefaultCreatureDocs.js';
const addDefaultStats = function(charId){
const defaultDocs = getDefaultCreatureDocs(charId);
Attributes.rawCollection().insert(getDefa.attributes, {ordered: false});
Skills.rawCollection().insert(getDefa.skills, {ordered: false});
DamageMultipliers.rawCollection().insert(getDefa.damageMultipliers, {ordered: false});
};
const insertCreature = new ValidatedMethod({
name: "Creatures.methods.insertCharacter", // DDP method name
validate: new SimpleSchema({
name: {
type: String,
optional: true,
},
}).validator(),
run({name}) {
if (!this.userId) {
throw new Meteor.Error("Creatures.methods.insert.denied",
"You need to be logged in to insert a creature");
}
// Create the creature document
let charId = Creatures.insert({name, owner: this.userId});
this.unblock();
//Add all the required attributes to it
if (Meteor.isServer){
addDefaultStats(charId);
}
return charId;
},
});
export default insertCreature;

View File

@@ -1,5 +1,5 @@
import SimpleSchema from 'simpl-schema';
import Attributes from "/imports/api/creature/Attributes.js";
import Attributes from "/imports/api/creature/properties/Attributes.js";
import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js";
import {makeParent} from "/imports/api/parenting.js";

View File

@@ -1,5 +1,5 @@
import Creatures from "/imports/api/creature/Creatures.js";
import Parties from "/imports/api/campaign/Party.js";
import Parties from '/imports/api/campaign/Parties.js';
Meteor.publish("characterList", function(){
var userId = this.userId;

View File

@@ -1,20 +1,20 @@
import Characters from "/imports/api/creature/Creatures.js";
import Actions from "/imports/api/creature/Actions.js";
import Attacks from "/imports/api/creature/Attacks.js";
import Attributes from "/imports/api/creature/Attributes.js";
import Buffs from "/imports/api/creature/Buffs.js";
import Classes from "/imports/api/creature/Classes.js";
import Conditions from "/imports/api/creature/Conditions.js";
import CustomBuffs from "/imports/api/creature/CustomBuffs.js";
import DamageMultipliers from "/imports/api/creature/DamageMultipliers.js";
import Effects from "/imports/api/creature/Effects.js";
import Experiences from "/imports/api/creature/Experiences.js";
import Features from "/imports/api/creature/Features.js";
import Notes from "/imports/api/creature/Notes.js";
import Skills from "/imports/api/creature/Skills.js";
import Spells from "/imports/api/creature/Spells.js";
import SpellLists from "/imports/api/creature/SpellLists.js";
import Proficiencies from "/imports/api/creature/Proficiencies.js";
import Actions from "/imports/api/creature/properties/Actions.js";
import Attacks from "/imports/api/creature/properties/Attacks.js";
import Attributes from "/imports/api/creature/properties/Attributes.js";
import Buffs from "/imports/api/creature/properties/Buffs.js";
import Classes from "/imports/api/creature/properties/Classes.js";
import Conditions from "/imports/api/creature/properties/Conditions.js";
import CustomBuffs from "/imports/api/creature/properties/CustomBuffs.js";
import DamageMultipliers from "/imports/api/creature/properties/DamageMultipliers.js";
import Effects from "/imports/api/creature/properties/Effects.js";
import Experiences from "/imports/api/creature/properties/Experiences.js";
import Features from "/imports/api/creature/properties/Features.js";
import Notes from "/imports/api/creature/properties/Notes.js";
import Skills from "/imports/api/creature/properties/Skills.js";
import Spells from "/imports/api/creature/properties/Spells.js";
import SpellLists from "/imports/api/creature/properties/SpellLists.js";
import Proficiencies from "/imports/api/creature/properties/Proficiencies.js";
import Containers from "/imports/api/inventory/Containers.js";
import Items from "/imports/api/inventory/Items.js";

View File

@@ -198,10 +198,10 @@
14: 7,
15: 9,
};
if (costs[score]){
if (costs[score] || costs[score] === 0){
return costs[score];
} else {
return null;
return NaN;
}
};
export default {

View File

@@ -31,7 +31,7 @@
</v-list>
<v-list dense>
<v-list-tile
v-for="character in charactersWithNoParty"
v-for="character in CreaturesWithNoParty"
:href="character.url"
:key="character._id"
>
@@ -63,6 +63,9 @@
</template>
<script>
import Creatures from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
export default {
meteor: {
$subscribe: {
@@ -78,7 +81,7 @@
links(){
return [
{title: "Home", icon: "home", to: "/"},
{title: "Characters", icon: "group", to: "characterList", vif: Meteor.userId()},
{title: "Creatures", icon: "group", to: "characterList", vif: Meteor.userId()},
{title: "Send Feedback", icon: "bug_report", to: "feedback"},
{title: "Patreon", icon: "", href: "https://www.patreon.com/dicecloud"},
{title: "Github", icon: "", href: "https://github.com/ThaumRystra/DiceCloud1"},
@@ -89,9 +92,9 @@
{owner: Meteor.userId()},
{sort: {name: 1}},
).map(party => {
party.characterDocs = Characters.find(
party.characterDocs = Creatures.find(
{
_id: {$in: party.characters},
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
sort: {name: 1},
@@ -104,11 +107,11 @@
return party;
});
},
charactersWithNoParty() {
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.characters);
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Characters.find(
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],

View File

@@ -1,7 +1,3 @@
import store from "/imports/ui/vuexStore.js";
const offset = 16;
const duration = 400;
let dialogStack = {};
dialogStack.dialogs = [];
@@ -32,14 +28,17 @@ const dialogStackStore = {
if (!dialog) return;
if (dialog.callback) dialog.callback(result);
},
setCurrentResult (state, result){
state.currentResult = result;
},
},
actions: {
popDialogStack(context, result){
if (history && history.state && history.state.openDialogs){
context.state.currentResult = result;
context.commit("setCurrentResult", result);
history.back();
} else {
context.commit("popDialogStackMutation", result)
context.commit("popDialogStackMutation", result);
}
}
}

View File

@@ -1,10 +1,10 @@
<template>
<toolbar-layout>
<span slot="toolbar">Characters</span>
<span slot="toolbar">Creatures</span>
<v-card class="ma-4">
<v-list v-if="charactersWithNoParty.length">
<v-list v-if="CreaturesWithNoParty.length">
<v-list-tile
v-for="character in charactersWithNoParty"
v-for="character in CreaturesWithNoParty"
:key="character._id"
:to="character.url"
>
@@ -72,6 +72,8 @@
</template>
<script>
import Creatures from '/imports/api/creature/Creatures.js';
import Parties from '/imports/api/campaign/Parties.js';
import store from "/imports/ui/vuexStore.js";
import ToolbarLayout from "/imports/ui/layouts/ToolbarLayout.vue";
import LabeledFab from "/imports/ui/components/LabeledFab.vue";
@@ -96,9 +98,9 @@
{owner: Meteor.userId()},
{sort: {name: 1}},
).map(party => {
party.characterDocs = Characters.find(
party.characterDocs = Creatures.find(
{
_id: {$in: party.characters},
_id: {$in: party.Creatures},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],
}, {
sort: {name: 1},
@@ -107,11 +109,11 @@
return party;
});
},
charactersWithNoParty() {
CreaturesWithNoParty() {
var userId = Meteor.userId();
var charArrays = Parties.find({owner: userId}).map(p => p.characters);
var charArrays = Parties.find({owner: userId}).map(p => p.Creatures);
var partyChars = _.uniq(_.flatten(charArrays));
return Characters.find(
return Creatures.find(
{
_id: {$nin: partyChars},
$or: [{readers: userId}, {writers: userId}, {owner: userId}],

View File

@@ -1,14 +1,14 @@
import Attacks from "/imports/api/creature/Attacks.js";
import Buffs from "/imports/api/creature/Buffs.js";
import Classes from "/imports/api/creature/Classes.js";
import CustomBuffs from "/imports/api/creature/CustomBuffs.js";
import Effects from "/imports/api/creature/Effects.js";
import Experiences from "/imports/api/creature/Experiences.js";
import Features from "/imports/api/creature/Features.js";
import Notes from "/imports/api/creature/Notes.js";
import Proficiencies from "/imports/api/creature/Proficiencies.js";
import SpellLists from "/imports/api/creature/SpellLists.js";
import Spells from "/imports/api/creature/Spells.js";
import Attacks from "/imports/api/creature/properties/Attacks.js";
import Buffs from "/imports/api/creature/properties/Buffs.js";
import Classes from "/imports/api/creature/properties/Classes.js";
import CustomBuffs from "/imports/api/creature/properties/CustomBuffs.js";
import Effects from "/imports/api/creature/properties/Effects.js";
import Experiences from "/imports/api/creature/properties/Experiences.js";
import Features from "/imports/api/creature/properties/Features.js";
import Notes from "/imports/api/creature/properties/Notes.js";
import Proficiencies from "/imports/api/creature/properties/Proficiencies.js";
import SpellLists from "/imports/api/creature/properties/SpellLists.js";
import Spells from "/imports/api/creature/properties/Spells.js";
import Containers from "/imports/api/inventory/Containers.js";
import Items from "/imports/api/inventory/Items.js";