Got healthbars persisting data to the database
This commit is contained in:
@@ -12,7 +12,11 @@ Creatures = new Mongo.Collection("creatures");
|
|||||||
let creatureSchema = new SimpleSchema({
|
let creatureSchema = new SimpleSchema({
|
||||||
//strings
|
//strings
|
||||||
name: {type: String, defaultValue: "", trim: false, optional: true},
|
name: {type: String, defaultValue: "", trim: false, optional: true},
|
||||||
urlName: {type: String, defaultValue: "-", trim: false, optional: true},
|
urlName: {type: String, trim: false, optional: true,
|
||||||
|
autoValue: function() {
|
||||||
|
return getSlug(this.field("name").value, {maintainCase: true}) || "-";
|
||||||
|
},
|
||||||
|
},
|
||||||
alignment: {type: String, defaultValue: "", trim: false, optional: true},
|
alignment: {type: String, defaultValue: "", trim: false, optional: true},
|
||||||
gender: {type: String, defaultValue: "", trim: false, optional: true},
|
gender: {type: String, defaultValue: "", trim: false, optional: true},
|
||||||
race: {type: String, defaultValue: "", trim: false, optional: true},
|
race: {type: String, defaultValue: "", trim: false, optional: true},
|
||||||
@@ -62,21 +66,4 @@ let creatureSchema = new SimpleSchema({
|
|||||||
Creatures.attachSchema(creatureSchema);
|
Creatures.attachSchema(creatureSchema);
|
||||||
Creatures.attachSchema(ColorSchema);
|
Creatures.attachSchema(ColorSchema);
|
||||||
|
|
||||||
//Keep the urlName up to date
|
|
||||||
if (Meteor.isServer){
|
|
||||||
Creatures.after.update(function(userId, doc, fieldNames, modifier, options) {
|
|
||||||
if (_.contains(fieldNames, "name")){
|
|
||||||
var urlName = getSlug(doc.name, {maintainCase: true}) || "-";
|
|
||||||
Creatures.update(doc._id, {$set: {urlName}});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Creatures.before.insert(function(userId, doc) {
|
|
||||||
doc.urlName = getSlug(doc.name, {maintainCase: true}) || "-";
|
|
||||||
// The first creature a user creates should have the new user experience
|
|
||||||
if (!Creatures.find({owner: userId}).count()){
|
|
||||||
doc.settings.newUserExperience = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Creatures;
|
export default Creatures;
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ export const recomputeCreature = new ValidatedMethod({
|
|||||||
'You do not have permission to recompute this creature');
|
'You do not have permission to recompute this creature');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Work
|
// Work, call this direcly if you are already in a method that has checked
|
||||||
computeCreatureById(charId);
|
// for permission to edit a given character
|
||||||
|
recomputeCreatureById(charId);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ export const recomputeCreature = new ValidatedMethod({
|
|||||||
* @returns {Object} An in-memory description of the character as
|
* @returns {Object} An in-memory description of the character as
|
||||||
* computed and written to the database
|
* computed and written to the database
|
||||||
*/
|
*/
|
||||||
function computeCreatureById(charId){
|
export function recomputeCreatureById(charId){
|
||||||
let char = buildCreature(charId);
|
let char = buildCreature(charId);
|
||||||
char = computeCreature(char);
|
char = computeCreature(char);
|
||||||
writeCreature(char);
|
writeCreature(char);
|
||||||
@@ -82,6 +83,7 @@ function computeCreatureById(charId){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the in-memory creature to the database docs
|
* Write the in-memory creature to the database docs
|
||||||
|
* This could be optimized to only write changed fields to the database
|
||||||
*
|
*
|
||||||
* @param {Object} char in-memory char object
|
* @param {Object} char in-memory char object
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import {makeChild} from "/imports/api/parenting.js";
|
import {makeChild} from "/imports/api/parenting.js";
|
||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js";
|
import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js";
|
||||||
|
import { canEditCreature } from '/imports/api/creature/creaturePermission.js';
|
||||||
|
import { recomputeCreatureById } from '/imports/api/creature/creatureComputation.js'
|
||||||
|
import pickKeysAsOptional from '/imports/api/pickKeysAsOptional.js';
|
||||||
|
|
||||||
let Attributes = new Mongo.Collection("attributes");
|
let Attributes = new Mongo.Collection("attributes");
|
||||||
|
|
||||||
@@ -62,10 +65,6 @@ attributeSchema = new SimpleSchema({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
enabled: {
|
|
||||||
type: Boolean,
|
|
||||||
defaultValue: true,
|
|
||||||
},
|
|
||||||
reset: {
|
reset: {
|
||||||
type: String,
|
type: String,
|
||||||
optional: true,
|
optional: true,
|
||||||
@@ -76,12 +75,110 @@ attributeSchema = new SimpleSchema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
color: ColorSchema(),
|
||||||
});
|
});
|
||||||
|
|
||||||
Attributes.attachSchema(attributeSchema);
|
Attributes.attachSchema(attributeSchema);
|
||||||
Attributes.attachSchema(ColorSchema);
|
|
||||||
|
|
||||||
//Attributes.attachBehaviour("softRemovable");
|
//Attributes.attachBehaviour("softRemovable");
|
||||||
makeChild(Attributes, ["enabled"]); //children of lots of things
|
makeChild(Attributes, ["enabled"]); //children of lots of things
|
||||||
|
|
||||||
|
let updateAttributeSchema = pickKeysAsOptional(attributeSchema, [
|
||||||
|
'name',
|
||||||
|
'variableName',
|
||||||
|
'type',
|
||||||
|
'baseValue',
|
||||||
|
'decimal',
|
||||||
|
'reset',
|
||||||
|
'resetMultiplier',
|
||||||
|
'color',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const updateAttribute = new ValidatedMethod({
|
||||||
|
|
||||||
|
name: "Attributes.methods.update",
|
||||||
|
|
||||||
|
validate: new SimpleSchema({
|
||||||
|
_id: {
|
||||||
|
type: String,
|
||||||
|
regEx: SimpleSchema.RegEx.Id,
|
||||||
|
},
|
||||||
|
update: updateAttributeSchema,
|
||||||
|
}).validator(),
|
||||||
|
|
||||||
|
run({_id, update}) {
|
||||||
|
let currentAttribute = Attributes.findOne(_id);
|
||||||
|
if (!currentAttribute){
|
||||||
|
throw new Meteor.Error("Attributes.methods.update.denied",
|
||||||
|
`No attributes exist with the id: ${_id}`);
|
||||||
|
}
|
||||||
|
let charId = currentAttribute.charId;
|
||||||
|
if (canEditCreature(charId, this.userId)){
|
||||||
|
Attributes.update(_id, {$set: update});
|
||||||
|
recomputeCreatureById(charId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const adjustAttribute = new ValidatedMethod({
|
||||||
|
|
||||||
|
name: "Attributes.methods.adjust",
|
||||||
|
|
||||||
|
validate: new SimpleSchema({
|
||||||
|
_id: {
|
||||||
|
type: String,
|
||||||
|
regEx: SimpleSchema.RegEx.Id,
|
||||||
|
},
|
||||||
|
increment: {
|
||||||
|
type: Number,
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
set: {
|
||||||
|
type: Number,
|
||||||
|
optional: true,
|
||||||
|
custom() {
|
||||||
|
if (!this.isSet && !this.field('increment').isSet) {
|
||||||
|
// either set or increment must exist
|
||||||
|
return SimpleSchema.ErrorTypes.REQUIRED;
|
||||||
|
} else if (this.isSet && this.field('increment').isSet){
|
||||||
|
return 'Can\'t increment and set an attritbute adjustment in one operation';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).validator(),
|
||||||
|
|
||||||
|
run({_id, increment, set}) {
|
||||||
|
let currentAttribute = Attributes.findOne(_id);
|
||||||
|
if (!currentAttribute){
|
||||||
|
throw new Meteor.Error("Attributes.methods.update.denied",
|
||||||
|
`No attributes exist with the id: ${_id}`);
|
||||||
|
}
|
||||||
|
let charId = currentAttribute.charId;
|
||||||
|
if (canEditCreature(charId, this.userId)){
|
||||||
|
if (typeof set === 'number'){
|
||||||
|
let val = currentAttribute.value;
|
||||||
|
// Set represents what we want the value to be after adjustment
|
||||||
|
// So we need the actual adjustment to get to that value
|
||||||
|
let adjustment = set - val;
|
||||||
|
// Ajustment can't exceed total value
|
||||||
|
if (-adjustment > val) adjustment = -val;
|
||||||
|
// Adjustment must be negative
|
||||||
|
if (adjustment > 0) adjustment = 0;
|
||||||
|
Attributes.update(_id, {$set: {adjustment}});
|
||||||
|
} else if (typeof increment === 'number'){
|
||||||
|
let remaining = currentAttribute.value + currentAttribute.adjustment;
|
||||||
|
let adj = currentAttribute.adjustment;
|
||||||
|
// Can't decrease adjustment below remaining value
|
||||||
|
if (-increment > remaining) increment = -remaining;
|
||||||
|
// Can't increase adjustment above zero
|
||||||
|
if (increment > -adj) increment = -adj;
|
||||||
|
Attributes.update(_id, {$inc: {adjustment: increment}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
export default Attributes;
|
export default Attributes;
|
||||||
|
export { updateAttribute, adjustAttribute };
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
|
|
||||||
const ColorSchema = new SimpleSchema({
|
const ColorSchema = ({optional = false} = {}) => ({
|
||||||
color: {
|
type: String,
|
||||||
type: String,
|
defaultValue: "#9E9E9E",
|
||||||
defaultValue: "#9E9E9E",
|
// match hex colors of the form #A23 or #A23f56
|
||||||
// match hex colors of the form #A23 or #A23f56
|
regEx: /^#([a-f0-9]{3}){1,2}\b$/i,
|
||||||
regEx: /^#([a-f0-9]{3}){1,2}\b$/i,
|
optional
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default ColorSchema;
|
export default ColorSchema;
|
||||||
|
|||||||
9
app/imports/api/pickKeysAsOptional.js
Normal file
9
app/imports/api/pickKeysAsOptional.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export default function pickKeysAsOptional(schema, keys){
|
||||||
|
let newSchema = schema.pick(...keys);
|
||||||
|
let optionalSchema = {};
|
||||||
|
for (let i of keys){
|
||||||
|
optionalSchema[i] = {optional: true}
|
||||||
|
};
|
||||||
|
newSchema.extend(optionalSchema);
|
||||||
|
return newSchema;
|
||||||
|
};
|
||||||
@@ -2,16 +2,7 @@
|
|||||||
<div class="stats-tab ma-2">
|
<div class="stats-tab ma-2">
|
||||||
|
|
||||||
<div class="px-2 pt-2">
|
<div class="px-2 pt-2">
|
||||||
<v-card>
|
<health-bar-card-container :charId="charId"/>
|
||||||
<v-card-text>
|
|
||||||
<health-bar
|
|
||||||
v-for="healthBar in healthBars"
|
|
||||||
:key="healthBar._id"
|
|
||||||
:value="healthBar.value + (healthBar.adjustment || 0)"
|
|
||||||
:maxValue="healthBar.value"
|
|
||||||
/>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<column-layout>
|
<column-layout>
|
||||||
@@ -97,7 +88,7 @@
|
|||||||
import AttributeCard from '/imports/ui/components/AttributeCard.vue';
|
import AttributeCard from '/imports/ui/components/AttributeCard.vue';
|
||||||
import AbilityListTile from '/imports/ui/components/AbilityListTile.vue';
|
import AbilityListTile from '/imports/ui/components/AbilityListTile.vue';
|
||||||
import ColumnLayout from "/imports/ui/components/ColumnLayout.vue";
|
import ColumnLayout from "/imports/ui/components/ColumnLayout.vue";
|
||||||
import HealthBar from '/imports/ui/components/HealthBar.vue';
|
import HealthBarCardContainer from '/imports/ui/components/HealthBarCardContainer.vue';
|
||||||
import HitDiceListTile from '/imports/ui/components/HitDiceListTile.vue';
|
import HitDiceListTile from '/imports/ui/components/HitDiceListTile.vue';
|
||||||
import SkillListTile from '/imports/ui/components/SkillListTile.vue';
|
import SkillListTile from '/imports/ui/components/SkillListTile.vue';
|
||||||
|
|
||||||
@@ -113,20 +104,11 @@
|
|||||||
AbilityListTile,
|
AbilityListTile,
|
||||||
AttributeCard,
|
AttributeCard,
|
||||||
ColumnLayout,
|
ColumnLayout,
|
||||||
HealthBar,
|
HealthBarCardContainer,
|
||||||
HitDiceListTile,
|
HitDiceListTile,
|
||||||
SkillListTile,
|
SkillListTile,
|
||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
healthBars(){
|
|
||||||
return Attributes.find({
|
|
||||||
charId: this.charId,
|
|
||||||
type: 'healthBar',
|
|
||||||
value: {$ne: 0},
|
|
||||||
}, {
|
|
||||||
sort: {order: 1},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
abilities(){
|
abilities(){
|
||||||
return getAttributeOfType(this.charId, 'ability');
|
return getAttributeOfType(this.charId, 'ability');
|
||||||
},
|
},
|
||||||
|
|||||||
26
app/imports/ui/components/HealthBarCard.vue
Normal file
26
app/imports/ui/components/HealthBarCard.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<v-card>
|
||||||
|
<v-card-text>
|
||||||
|
<health-bar
|
||||||
|
v-for="attribute in attributes"
|
||||||
|
:key="attribute._id"
|
||||||
|
:value="attribute.value + (attribute.adjustment || 0)"
|
||||||
|
:maxValue="attribute.value"
|
||||||
|
@change="e => $emit('change', {_id: attribute._id, change: e})"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HealthBar from '/imports/ui/components/HealthBar.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
attributes: Array,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
HealthBar,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
40
app/imports/ui/components/HealthBarCardContainer.vue
Normal file
40
app/imports/ui/components/HealthBarCardContainer.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<health-bar-card
|
||||||
|
:attributes="attributes"
|
||||||
|
@change="healthBarChanged"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Attributes from '/imports/api/creature/properties/Attributes.js';
|
||||||
|
import { adjustAttribute } from '/imports/api/creature/properties/Attributes.js';
|
||||||
|
import HealthBarCard from '/imports/ui/components/HealthBarCard.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HealthBarCard,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
charId: String,
|
||||||
|
},
|
||||||
|
meteor: {
|
||||||
|
attributes(){
|
||||||
|
return Attributes.find({
|
||||||
|
charId: this.charId,
|
||||||
|
type: 'healthBar',
|
||||||
|
value: {$ne: 0},
|
||||||
|
}, {
|
||||||
|
sort: {order: 1},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
healthBarChanged({_id, change}){
|
||||||
|
adjustAttribute.call({
|
||||||
|
_id,
|
||||||
|
[change.type]: change.value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user