Compare commits

..

21 Commits
0.3.1 ... 0.5.0

Author SHA1 Message Date
Stefan Zermatten
2f729070b2 Updated change log 2015-05-22 14:24:22 +02:00
Stefan Zermatten
7aedb9451c Base values now don't look like added values 2015-05-22 14:17:38 +02:00
Stefan Zermatten
c6886dd49e Floaty menus now close when clicking on a sub-button 2015-05-22 14:14:20 +02:00
Stefan Zermatten
038ce490e4 Added subsmanager to stop characters getting forgotten between page changes 2015-05-22 14:11:22 +02:00
Stefan Zermatten
52bef57637 Added encumbrance effects, conditions and encumbrance buffs 2015-05-22 14:04:09 +02:00
Stefan Zermatten
29e9f8c8dc Added quality-of-life UI to determining a character's encumbrance 2015-05-20 16:14:01 +02:00
Stefan Zermatten
fea02811ff Added buffs and standard conditions, no UI yet though 2015-05-20 16:13:25 +02:00
Stefan Zermatten
73cee52fff Fixed a bug in combining multiple resistances/vulnerabilities 2015-05-20 16:11:59 +02:00
Stefan Zermatten
b58c006ed4 Updated change log 2015-05-19 11:45:38 +02:00
Stefan Zermatten
ef44f6c1a5 Fixed migration of attack data 2015-05-19 11:44:06 +02:00
Stefan Zermatten
f455cea43f Fixed maths for strength calculations rounding, rather than rounding down 2015-05-18 14:31:07 +02:00
Stefan Zermatten
e4083bc744 Updated the change log 2015-05-18 14:16:24 +02:00
Stefan Zermatten
baffafb62a Added table of calculated values to strength detail 2015-05-18 14:13:28 +02:00
Stefan Zermatten
4143929667 Resolve merge conflicts 2015-05-18 13:21:28 +02:00
Stefan Zermatten
18286d1b9c Merge remote-tracking branch 'origin/master'
Conflicts:
	rpg-docs/client/style/main.scss
2015-05-18 13:20:24 +02:00
Stefan Zermatten
9f51567162 Added migrations for new data structure 2015-05-18 13:18:37 +02:00
Stefan Zermatten
66d8a3bfbf Moved dice.js and renamed it 2015-05-18 13:18:27 +02:00
Stefan Zermatten
a9648c10cc Fixed line break formatting in dialogs 2015-05-18 13:18:11 +02:00
Stefan Zermatten
679292373c Added item increment buttons 2015-05-18 13:17:40 +02:00
Stefan Zermatten
ae416458b5 Made attacks less rigid, now using inline computations 2015-05-18 13:16:33 +02:00
Stefan Zermatten
0ff4a887ea Updated the change log with v0.3.1 2015-05-16 00:26:00 +02:00
52 changed files with 1151 additions and 157 deletions

View File

@@ -25,3 +25,4 @@ splendido:accounts-meld
email
fourseven:scss@2.1.1
wolves:bourbon
meteorhacks:subs-manager

View File

@@ -50,6 +50,7 @@ logging@1.0.7
matb33:collection-hooks@0.7.13
meteor@1.1.6
meteor-platform@1.2.2
meteorhacks:subs-manager@1.3.0
minifiers@1.1.5
minimongo@1.0.8
mobile-status-bar@1.0.3

View File

@@ -24,18 +24,12 @@ Schemas.Attack = new SimpleSchema({
optional: true,
trim: false,
},
damageBonus: {
damage: {
type: String,
defaultValue: "strengthMod",
defaultValue: "1d8 + {strengthMod}",
optional: true,
trim: false,
},
damageDice: {
type: String,
optional: true,
defaultValue: "1d8",
allowedValues: DAMAGE_DICE,
},
damageType: {
type: String,
allowedValues: [

View File

@@ -1,28 +1,51 @@
Buffs = new Mongo.Collection("buffs");
//buffs are temporary once applied and store things which expire and their expiry time
Schemas.Buff = new SimpleSchema({
//buff id
_id: {
type: String,
regEx: SimpleSchema.RegEx.Id,
autoValue: function(){
if (!this.isSet) return Random.id();
},
},
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
//expiry time
expiry: {type: Number, optional: true},
duration: {type: Number},
name: {
type: String,
trim: false,
},
description: {
type: String,
optional: true,
trim: false,
},
enabled: {
type: Boolean,
defaultValue: true,
},
type: {
type: String,
allowedValues: [
"inate",
"custom",
],
},
"lifeTime.total": {
type: Number,
defaultValue: 0, //0 is infinite
min: 0,
},
"lifeTime.spent": {
type: Number,
defaultValue: 0,
min: 0,
},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Buffs.attachSchema(Schemas.Buff);
Buffs.attachBehaviour("softRemovable");
makeParent(Buffs, "name"); //parents of effects and attacks
makeParent(Buffs, ["name", "enabled"]); //parents of effects
Buffs.allow(CHARACTER_SUBSCHEMA_ALLOW);
Buffs.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -168,21 +168,56 @@ Schemas.Character = new SimpleSchema({
defaultValue: "q",
},
//TODO add per-character settings
"settings.experiencesInc": {type: Number, defaultValue: 20}, //how many experiences to load at a time in XP table
//how many experiences to load at a time in XP table
"settings.experiencesInc": {type: Number, defaultValue: 20},
//slowed down by carrying too much?
"settings.useVariantEncumbrance": {type: Boolean, defaultValue: false},
"settings.useStandardEncumbrance": {type: Boolean, defaultValue: true},
});
Characters.attachSchema(Schemas.Character);
var attributeBase = function(charId, statName){
check(statName, String);
var effects = Effects.find(
{charId: charId, stat: statName, enabled: true}
).fetch();
effects = _.groupBy(effects, "operation");
var value = _.contains(DAMAGE_MULTIPLIERS, statName) ? 1 : 0;
//if it's a damage multiplier, we treat it specially
if (_.contains(DAMAGE_MULTIPLIERS, statName)){
var effects = Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "mul"}
).fetch();
var resistCount = 0;
var vulnCount = 0;
var multiplierEvaluationFail = false;
_.each(effects, function(effect){
var val = evaluateEffect(charId, effect);
if (val === 0.5){ //resistance
resistCount += 1;
} else if (val === 2){ //vulnerability
vulnCount += 1;
} else if (val === 0){ //imunity
return 0; //imunity is absolute
} else {
multiplierEvaluationFail = true;
}
});
if (multiplierEvaluationFail){
//we can't work it out correctly, set the value to 1
//and try work it out using regular maths below
value = 1;
} else if (resistCount && !vulnCount){
return 0.5;
} else if (!resistCount && vulnCount){
return 2;
} else {
return 1;
}
}
var value = 0;
//start with the highest base value
_.each(effects.base, function(effect){
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "base"}
).forEach(function(effect){
var efv = evaluateEffect(charId, effect);
if (efv > value){
value = efv;
@@ -190,23 +225,31 @@ var attributeBase = function(charId, statName){
});
//add all the add values
_.each(effects.add, function(effect){
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "add"}
).forEach(function(effect){
value += evaluateEffect(charId, effect);
});
//multiply all the mul values
_.each(effects.mul, function(effect){
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "mul"}
).forEach(function(effect){
value *= evaluateEffect(charId, effect);
});
//ensure value is >= all mins
_.each(effects.min, function(effect){
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "min"}
).forEach(function(effect){
var min = evaluateEffect(charId, effect);
value = value > min ? value : min;
});
//ensure value is <= all maxes
_.each(effects.max, function(effect){
Effects.find(
{charId: charId, stat: statName, enabled: true, operation: "max"}
).forEach(function(effect){
var max = evaluateEffect(charId, effect);
value = value < max ? value : max;
});

View File

@@ -10,6 +10,7 @@ Schemas.Item = new SimpleSchema({
value: {type: Number, min: 0, defaultValue: 0, decimal: true},
enabled: {type: Boolean, defaultValue: false},
requiresAttunement: {type: Boolean, defaultValue: false},
"settings.showIncrement": {type: Boolean, defaultValue: false},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),

View File

@@ -89,3 +89,8 @@ $thinColumnWidth: 240px;
border-radius: 0 2px 2px 0;
}
}
/* undo pointer cursor on detail box heading */
#globalDetail .card .top {
cursor: auto;
}

View File

@@ -57,6 +57,18 @@ paper-button {
cursor: pointer;
}
.pre-wrap, .prewrap{
white-space: pre-wrap;
}
.padded {
padding: 8px;
}
.fullwidth {
width: 100%;
}
.fab-buffer {
height: 100px;
}

View File

@@ -0,0 +1,18 @@
td {
padding: 8px;
&:nth-child(1) {
min-width: 100px;
}
}
.strengthTable{
width: 100%;
td{
&:nth-child(2) {
text-align: right;
}
&:nth-child(3) {
width: 250px;
}
}
}

View File

@@ -15,21 +15,11 @@
value={{details}}></paper-input>
</div>
<div layout horizontal>
<!--DamageType-->
<paper-dropdown-menu id="damageDiceDropdown" label="Damage Dice">
<paper-dropdown layered class="dropdown">
<core-menu class="menu" selected={{damageDice}}>
{{#each DAMAGE_DICE}}
<paper-item name={{this}} class="containerMenuItem">{{this}}</paper-item>
{{/each}}
</core-menu>
</paper-dropdown>
</paper-dropdown-menu>
<!--damageBonus-->
<paper-input id="damageInput"
label="Damage Bonus"
label="Damage"
floatinglabel
value={{damageBonus}}
value={{damage}}
flex></paper-input>
<!--DamageType-->
<paper-dropdown-menu id="damageTypeDropdown" label="Damage Type">

View File

@@ -1,6 +1,18 @@
var damageTypes = ["bludgeoning", "piercing", "slashing",
"acid", "cold", "fire", "force", "lightning", "necrotic",
"poison", "psychic", "radiant", "thunder"];
var damageTypes = [
"bludgeoning",
"piercing",
"slashing",
"acid",
"cold",
"fire",
"force",
"lightning",
"necrotic",
"poison",
"psychic",
"radiant",
"thunder",
];
Template.attackEdit.events({
"tap #deleteAttack": function(event, instance) {
@@ -13,7 +25,7 @@ Template.attackEdit.events({
},
"change #damageInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {damageBonus: value}});
Attacks.update(this._id, {$set: {damage: value}});
},
"change #detailInput": function(event) {
var value = event.currentTarget.value;
@@ -26,13 +38,6 @@ Template.attackEdit.events({
if (value == this.damageType) return;
Attacks.update(this._id, {$set: {damageType: value}});
},
"core-select #damageDiceDropdown": function(event) {
var detail = event.originalEvent.detail;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if (value == this.damageDice) return;
Attacks.update(this._id, {$set: {damageDice: value}});
}
});
Template.attackEdit.helpers({
@@ -41,5 +46,5 @@ Template.attackEdit.helpers({
},
DAMAGE_DICE: function() {
return DAMAGE_DICE;
}
},
});

View File

@@ -1,11 +1,11 @@
<template name="attackView">
<div class="attackView" layout horizontal>
<div class="headline rightPadded" layout horizontal center>
<div class="headline" style="margin-right: 16px;" layout horizontal center>
{{evaluateSigned charId attackBonus}}
</div>
<div layout vertical>
<div>
{{damageDice}}&nbsp;{{{evaluateSignedSpaced charId damageBonus}}}&nbsp;{{damageType}}
{{evaluateString charId damage}}&nbsp;{{damageType}}
</div>
{{#if details}}
<div class="caption">

View File

@@ -0,0 +1,15 @@
<template name="buffDialog">
{{#with buff}}
{{#baseDialog title=name class=colorClass hideEdit=true}}
{{> buffDetails}}
{{/baseDialog}}
{{/with}}
</template>
<template name="buffDetails">
{{#if description}}
<div class="pre-wrap">{{evaluateString charId description}}</div>
{{/if}}
{{> effectsViewList charId=charId parentId=_id}}
</template>

View File

@@ -0,0 +1,5 @@
Template.buffDialog.helpers({
buff: function(){
return Buffs.findOne(this.buffId);
},
});

View File

@@ -1,3 +1,13 @@
<template name="characterSettings">
{{#with character}}
<div>
<div layout horizontal>
<div>Use variant encumbrance </div>
<paper-toggle-button id="variantEncumbrance"
checked={{settings.useVariantEncumbrance}}
touch-action="pan-y">
</paper-toggle-button>
</div>
</div>
{{/with}}
</template>

View File

@@ -1,3 +1,17 @@
Template.characterSettings.events({
Template.characterSettings.helpers({
character: function() {
return Characters.findOne(this._id, {fields: {settings: 1}});
}
});
Template.characterSettings.events({
"change #variantEncumbrance": function(event, instance){
var value = instance.find("#variantEncumbrance").checked;
if (this.settings.useVariantEncumbrance !== value){
Characters.update(
this._id,
{$set: {"settings.useVariantEncumbrance": value}}
);
}
},
});

View File

@@ -19,6 +19,9 @@
<paper-item id="shareCharacter">
<core-icon icon="social:share"></core-icon>Share
</paper-item>
<paper-item id="characterSettings">
<core-icon icon="settings"></core-icon>Settings
</paper-item>
</core-menu>
</paper-dropdown>
</paper-menu-button>

View File

@@ -1,6 +1,9 @@
Template.characterSheet.created = function(){
Template.characterSheet.onCreated(function() {
//default to the first tab
Session.setDefault(this.data._id + ".selectedTab", "stats");
};
//watch this character and make sure their encumbrance is updated
trackEncumbranceConditions(this.data._id, this);
});
var setTab = function(charId, tab){
return Session.set(charId + ".selectedTab", tab);
@@ -40,4 +43,11 @@ Template.characterSheet.events({
template: "shareDialog",
});
},
"tap #characterSettings": function(event, instance){
GlobalUI.showDialog({
heading: this.name + " Settings",
data: this,
template: "characterSettings",
});
},
});

View File

@@ -32,7 +32,7 @@
{{/if}}
{{#if description}}
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
{{/if}}
{{> effectsViewList charId=charId parentId=_id}}

View File

@@ -34,7 +34,7 @@
{{name}}
</div>
<div>
{{damageDice}}&nbsp;{{{evaluateSignedSpaced ../_id damageBonus}}}&nbsp;{{damageType}}
{{evaluateString ../_id damage}}&nbsp;{{damageType}}
</div>
{{#if details}}
<div class="caption">
@@ -102,7 +102,7 @@
</div>
{{#if description}}
<div flex class="bottom text"
>{{description}}</div>
>{{evaluateString charId description}}</div>
{{/if}}
{{#if hasUses}}
<div layout horizontal center end-justified>

View File

@@ -0,0 +1,22 @@
<template name="carryCapacityBar">
<div class="carryCapacityBar">
<div class="carriedWeightBar"
style="width: {{carriedPercent}}%;
background-color: {{carriedColor}}">
</div>
<div class="tick"
style="width: 33.333%;">
</div>
<div class="tick"
style="width: 66.666%;">
</div>
</div>
{{#if overCarriedPercent}}
<div class="carryCapacityBar">
<div class="carriedWeightBar"
style="width: {{overCarriedPercent}}%;
background-color: {{overCarriedColor}}">
</div>
</div>
{{/if}}
</template>

View File

@@ -0,0 +1,65 @@
var getFractionCarried = function(char) {
//find out the weight
var weight = 0;
Containers.find(
{charId: char._id, isCarried: true}
).forEach(function(container){
weight += container.totalWeight();
});
Items.find(
{charId: char._id, "parent.id": char._id},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
//get strength
var strength = char.attributeValue("strength");
var capacity = strength * 15;
return weight / capacity;
};
Template.carryCapacityBar.onCreated(function() {
var self = this;
self.carriedFraction = new ReactiveVar(0);
self.autorun(function() {
self.carriedFraction.set(getFractionCarried(self.data));
});
});
Template.carryCapacityBar.helpers({
carriedPercent: function() {
var percent = 100 * Template.instance().carriedFraction.get();
return percent > 100 ? 100 : percent;
},
overCarriedPercent: function() {
var percent = 100 * Template.instance().carriedFraction.get();
var overPercent = percent - 100;
if (overPercent < 0) return 0;
if (overPercent > 100) return 100;
return overPercent;
},
carriedColor: function() {
var frac = Template.instance().carriedFraction.get();
if (frac < 1 / 3){
return "#2196F3";
} else if (frac < 2 / 3){
return "#CDDC39";
} else if (frac < 1) {
return "#FFC107";
} else {
return "#F44336";
}
},
overCarriedColor: function() {
var frac = Template.instance().carriedFraction.get();
if (frac < 1 / 3){
return "#2196F3";
} else if (frac < 2 / 3){
return "#CDDC39";
} else if (frac < 1) {
return "#FFC107";
} else {
return "#F44336";
}
},
});

View File

@@ -0,0 +1,14 @@
.carryCapacityBar {
background-color: #7DC580;
background-color: rgba(255,255,255,0.27);
position: relative;
height: 4px;
div{
height: 100%;
position: absolute;
}
.tick {
border-right: solid 2px #E5E5E5;
border-right-color: rgba(255,255,255,0.54);
}
}

View File

@@ -0,0 +1,17 @@
<template name="carryDialog">
{{#baseDialog title="Weight Carried" class=color hideEdit=true}}
<div layout horizontal center-justified end>
<div class="display2">
{{round carriedWeight 1}}
</div>
<div class="display1">
lbs
</div>
</div>
<hr class="vertMargin">
{{> carryCapacityTable}}
{{/baseDialog}}
</template>

View File

@@ -0,0 +1,20 @@
Template.carryDialog.helpers({
carriedWeight: function() {
var weight = 0;
Containers.find(
{charId: this.charId, isCarried: true}
).forEach(function(container){
weight += container.totalWeight();
});
Items.find(
{charId: this.charId, "parent.id": this.charId},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
return weight;
},
color: function() {
if (this.color) return this.color + " white-text";
},
});

View File

@@ -41,6 +41,6 @@
</div>
{{#if description}}
<hr class="vertMargin">
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
{{/if}}
</template>

View File

@@ -3,22 +3,51 @@
<div id="inventory" class="scroll-y" fit>
<div class="column-container">
<!--Net Worth-->
<paper-shadow class="card" layout horizontal>
<div class="indigo white-text subhead left">
Net Worth
</div>
<div class="right" flex>
{{valueString netWorth}}
<paper-shadow class="card">
<div class="white top" layout horizontal center>
<div class="subhead" flex>
Net Worth
</div>
<div>
{{valueString netWorth}}
</div>
</div>
</paper-shadow>
<!--Weight Carried-->
<paper-shadow class="card" layout horizontal>
<div class="green white-text subhead left">
Weight Carried
<paper-shadow class="card"
hero-id="main" {{detailHero "weightCarried" _id}}>
<div class="top green white-text weightCarried"
hero-id="toolbar" {{detailHero "weightCarried" _id}}
layout horizontal center>
<div class="subhead" flex>
Weight Carried
</div>
<div>
{{round weightCarried}}lbs
</div>
</div>
<div class="right" flex>
{{round weightCarried}}lbs
<div class="bottom green" style="padding: 0;">
{{> carryCapacityBar}}
</div>
{{#if encumberedBuffs.count}}
<div class="bottom list">
{{#each encumberedBuffs}}
<div class="item-slot">
<div class="item buff"
hero-id="main" {{detailHero}}
layout horizontal center
draggable="true">
<div flex>
<core-icon icon="work"
style="margin-right: 16px">
</core-icon>
{{name}}
</div>
</div>
</div>
{{/each}}
</div>
{{/if}}
</paper-shadow>
<!--Equipment-->
<paper-shadow class="card equipmentContainer">
@@ -51,7 +80,7 @@
<!--Carried Items-->
<paper-shadow class="card carriedContainer">
<div class="white top" layout horizontal center>
<div class="subhead">
<div class="subhead" flex>
Carried
</div>
<div class="caption" style="margin-right: 8px">
@@ -120,11 +149,24 @@
<template name="inventoryItem">
<div class="item-slot">
<paper-item class="item inventoryItem {{hidden}}" noink
<div class="item {{hidden}} inventoryItem"
hero-id="main" {{detailHero}}
layout horizontal
layout horizontal center
draggable="true">
{{#if ne1 quantity}}{{quantity}}&nbsp;{{/if}}{{pluralName}}
</paper-item>
<div flex class="itemName">
{{#if ne1 quantity}}{{quantity}}&nbsp;{{/if}}{{pluralName}}
</div>
{{#if settings.showIncrement}}
<div class="incrementButtons">
<paper-icon-button class="addItemQuantity"
icon="add"
style="margin-right: -8px"></paper-icon-button>
<paper-icon-button class="subItemQuantity"
disabled={{lt1 quantity}}
icon="remove"
style="margin-right: -8px"></paper-icon-button>
</div>
{{/if}}
</div>
</div>
</template>

View File

@@ -61,6 +61,18 @@ Template.inventory.helpers({
});
return weight;
},
encumberedBuffs: function(){
return Buffs.find({
charId: this._id,
type: "inate",
name: {$in: [
"Encumbered",
"Heavily encumbered",
"Over encumbered",
"Can't move load",
]},
});
},
equipmentValue: function(){
var value = 0;
Items.find(
@@ -136,6 +148,23 @@ Template.inventory.events({
heroId: containerId,
});
},
"tap .weightCarried": function(event) {
var charId = this._id;
GlobalUI.setDetail({
template: "carryDialog",
data: {charId: charId, color: "green"},
heroId: charId + "weightCarried",
});
},
"tap .buff": function(event){
var buffId = this._id;
var charId = Template.parentData()._id;
GlobalUI.setDetail({
template: "buffDialog",
data: {buffId: buffId, charId: charId},
heroId: buffId,
});
},
"tap .inventoryItem": function(event){
var itemId = this._id;
var charId = Template.parentData()._id;
@@ -145,6 +174,17 @@ Template.inventory.events({
heroId: itemId,
});
},
"tap .incrementButtons": function(event) {
event.stopPropagation();
},
"tap .addItemQuantity": function(event) {
var itemId = this._id;
Items.update(itemId, {$set: {quantity: this.quantity + 1}});
},
"tap .subItemQuantity": function(event) {
var itemId = this._id;
Items.update(itemId, {$set: {quantity: this.quantity - 1}});
},
"tap .itemContainer .top": function(event){
GlobalUI.setDetail({
template: "containerDialog",
@@ -167,6 +207,9 @@ Template.inventoryItem.helpers({
ne1: function(num){
return num !== 1;
},
lt1: function(num) {
return num < 1;
},
hidden: function(){
return Session.equals("inventory.dragItemId", this._id) ? "hidden" : null;
},

View File

@@ -19,7 +19,7 @@
</div>
{{#if description}}
<hr class="vertMargin">
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
{{/if}}
{{> effectsViewList charId=charId parentId=_id}}
{{> attacksViewList charId=charId parentId=_id}}
@@ -28,10 +28,25 @@
<template name="itemEdit">
<paper-input class="fullwidth" id="itemNameInput" label="Name" floatinglabel value={{name}}></paper-input>
<div layout horizontal wrap>
<paper-input-decorator label="Quantity" floatinglabel>
<input id="quantityInput" type="number" value={{quantity}}>
<paper-input-decorator label="Quantity"
floatinglabel
style="width: 80px">
<input id="quantityInput"
type="number"
value={{quantity}}>
</paper-input-decorator>
{{# if ne1 quantity}}<paper-input flex id="itemPluralInput" label="Plural Name" floatinglabel value={{plural}}></paper-input>{{/if}}
{{# if ne1 quantity}}
<paper-input flex id="itemPluralInput"
label="Plural Name"
floatinglabel
value={{plural}}></paper-input>
{{/if}}
</div>
<div center horizontal layout>
<div class="padded">Show increment buttons</div>
<paper-checkbox id="incrementCheckbox"
checked={{settings.showIncrement}}>
</paper-checkbox>
</div>
<hr class="vertMargin">
@@ -53,7 +68,9 @@
</div>
<div center horizontal layout>
<div class="padded">Requires Attunement</div>
<paper-checkbox id="attunementCheckbox" checked={{requiresAttunement}}></paper-checkbox>
<paper-checkbox id="attunementCheckbox"
checked={{requiresAttunement}}>
</paper-checkbox>
</div>
</div>

View File

@@ -50,7 +50,7 @@ Template.itemEdit.onRendered(function(){
Template.itemEdit.helpers({
ne1: function(num){
return num != 1;
}
},
});
Template.itemEdit.events({
@@ -87,6 +87,10 @@ Template.itemEdit.events({
Meteor.call("unequipItem", this._id, this.charId);
}
},
"change #incrementCheckbox": function(event){
var value = event.currentTarget.checked;
Items.update(this._id, {$set: {"settings.showIncrement": value}});
},
"change #attunementCheckbox": function(event){
var value = event.currentTarget.checked;
Items.update(this._id, {$set: {requiresAttunement: value}});

View File

@@ -3,6 +3,9 @@ Template.classDialog.onRendered(function(){
});
Template.classDialog.events({
"color-change": function(event, instance){
Classes.update(instance.data.classId, {$set: {color: event.color}});
},
"tap #deleteButton": function(event, instance){
Classes.softRemoveNode(instance.data.classId);
GlobalUI.deletedToast(instance.data.classId, "Classes", "Class");

View File

@@ -1,12 +1,12 @@
<template name="experienceDialog">
{{#with experience}}
{{#baseDialog title=name class=colorClass hideColor="true" startEditing=../startEditing}}
{{#baseDialog title=name class=color hideColor="true" startEditing=../startEditing}}
<div horizontal layout center-justified class= "display2">
{{value}}
</div>
{{#if description}}
<hr class="vertMargin">
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{description}}</div>
{{/if}}
{{else}}
<div horizontal layout>

View File

@@ -1,6 +1,11 @@
Template.experienceDialog.helpers({
feature: function(){
return Features.findOne(this.featureId);
experience: function(){
Experiences.findOne(this.experienceId);
return Experiences.findOne(this.experienceId);
},
color: function() {
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
});
@@ -27,10 +32,3 @@ Template.experienceDialog.events({
Experiences.update(this._id, {$set: {description: value}});
},
});
Template.experienceDialog.helpers({
experience: function(){
Experiences.findOne(this.experienceId);
return Experiences.findOne(this.experienceId);
}
});

View File

@@ -1,7 +1,7 @@
<template name="noteDialog">
{{#with note}}
{{#baseDialog title=name class=colorClass startEditing=../startEditing}}
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{description}}</div>
{{else}}
{{> noteDialogEdit}}
{{/baseDialog}}

View File

@@ -1,5 +1,5 @@
<template name="raceDialog">
{{#baseDialog title="Race" class=colorClass hideColor="true" hideDelete="true" startEditing=startEditing}}
{{#baseDialog title="Race" class=color hideColor="true" hideDelete="true" startEditing=startEditing}}
<div horizontal layout center-justified class= "display2">
{{race}}
</div>

View File

@@ -13,5 +13,9 @@ Template.raceDialog.helpers({
race: function(){
var char = Characters.findOne(this.charId, {fields: {race: 1}});
return char && char.race;
}
},
color: function() {
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
});

View File

@@ -27,7 +27,7 @@
</template>
<template name="containerCard">
{{#containerCardHelper this}}{{body}}{{/containerCardHelper}}
{{#containerCardHelper this}}{{evaluateString _id body}}{{/containerCardHelper}}
</template>
<template name="containerCardHelper">

View File

@@ -1,6 +1,6 @@
<template name="textDialog">
{{#baseDialog title=title class=colorClass hideColor="true" hideDelete="true" startEditing=startEditing}}
<div class="prewrap">{{value}}</div>
<div class="pre-wrap">{{evaluateString charId value}}</div>
{{else}}
{{> textDialogEdit}}
{{/baseDialog}}

View File

@@ -26,7 +26,7 @@
<span class="body2">Duration: </span><span>{{duration}}</span>
</div>
</div>
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
</template>
<template name="spellEdit">

View File

@@ -20,7 +20,7 @@
{{/if}}
</div>
<hr class="vertMargin">
<div class="prewrap">{{description}}</div>
<div class="pre-wrap">{{evaluateString charId description}}</div>
</div>
{{else}}
<!--Name-->

View File

@@ -23,7 +23,7 @@
{{#each baseEffects}}
<tr>
<td>{{sourceName}}</td>
<td>{{signedString statValue}}</td>
<td>Base: {{statValue}}</td>
</tr>
{{/each}}
{{#each addEffects}}
@@ -35,7 +35,7 @@
{{#each mulEffects}}
<tr>
<td>{{sourceName}}</td>
<td>&times;{{statValue}}</td>
<td>&times; {{statValue}}</td>
</tr>
{{/each}}
{{#each minEffects}}

View File

@@ -0,0 +1,39 @@
<template name="strengthDialog">
{{#baseDialog title=name class=color hideEdit=true}}
{{> attributeDialogView}}
<hr class="vertMargin">
<div>
<div class="title padded">Carrying</div>
{{> carryCapacityTable}}
<div class="title padded">Jumping</div>
<table class="strengthTable">
<tr>
<td>Running long jump</td>
<td>{{evaluate charId "strength"}} feet</td>
</tr>
<tr>
<td>Standing long jump</td>
<td>{{evaluate charId "floor(strength/2)"}} feet</td>
</tr>
<tr>
<td>Running high jump</td>
<td>{{evaluate charId "3 + strengthMod"}} feet</td>
<td class="caption">
Can reach a ledge as high as
{{evaluate charId "3 + strengthMod"}} feet
+ 1.5&times; your height
</td>
</tr>
<tr>
<td>Standing high jump</td>
<td>{{evaluate charId "floor((3 + strengthMod)/2)"}} feet</td>
<td class="caption">
Can reach a ledge as high as
{{evaluate charId "floor((3 + strengthMod)/2)"}} feet
+ 1.5&times; your height
</td>
</tr>
</table>
</div>
{{/baseDialog}}
</template>

View File

@@ -0,0 +1,7 @@
Template.strengthDialog.helpers({
color: function(){
if (this.color) return this.color + " white-text";
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
});

View File

@@ -0,0 +1,28 @@
<template name="carryCapacityTable">
<table class="carryCapacityTable strengthTable">
<tr>
<td>Encumbered</td>
<td>&gt;{{evaluate charId "strength * 5"}}lbs</td>
<td class="caption">Variant rule, encumbered characters move 10 feet slower</td>
</tr>
<tr>
<td>Heavily encumbered</td>
<td>&gt;{{evaluate charId "strength * 10"}}lbs</td>
<td class="caption">
Variant rule, heavily encumbered characters move 20 feet slower and have disadvantage on ability checks, attack rolls, and saving thows that use Strength, Dexterity, or Constitution
</td>
</tr>
<tr>
<td>Over Encumbered</td>
<td>&gt;{{evaluate charId "strength * 15"}}lbs</td>
<td class="caption">
Characters that can only just lift, push or drag their current load can only move at 5 feet.
</td>
</tr>
<tr>
<td>Push, drag or lift maximum</td>
<td>{{evaluate charId "strength * 30"}}lbs</td>
<td class="caption"></td>
</tr>
</table>
</template>

View File

@@ -27,8 +27,10 @@ Template.stats.events({
},
"tap .abilityMiniCard": function(event, instance){
var charId = Template.parentData()._id;
var template = "attributeDialog";
if (this.ability === "strength") template = "strengthDialog";
GlobalUI.setDetail({
template: "attributeDialog",
template: template,
data: {
name: this.title,
statName: this.ability,

View File

@@ -12,4 +12,7 @@ Template.fabMenu.events({
"tap .expand-menu": function(event, instance) {
instance.active.set(!instance.active.get());
},
});
"tap .mini-holder paper-fab": function(event, instance) {
instance.active.set(false);
},
});

21
rpg-docs/lib/dice/roll.js Normal file
View File

@@ -0,0 +1,21 @@
roll = function(n, d){
var result = [];
if (!isNaN(n)){
//if only provided 1 argument, it is the dice to roll
if (d === undefined){
d = n;
n = 1;
}
//hard limit the number of dice rolled
if (n > 500){
console.warn(n + " > 500, cannot lift that many dice to roll them");
return;
}
for (var i = 0; i < n; i++){
var roll = Math.floor(Random.fraction() * d + 1);
result.push(roll);
}
return result;
}
return result;
};

View File

@@ -1,44 +0,0 @@
roll = function(n, d){
if (!isNaN(n)){
//first digit is a number
if (d === undefined){
d = n;
n = 1;
}
if (n > 500){
console.log(n + " > 500, cannot lift that many dice to roll them");
return;
}
var result = {sum: 0, rolls: []};
for (var i = 0; i < n; i++){
var roll = Math.floor(Random.fraction() * d + 1);
result.sum += roll;
result.rolls.push(roll);
}
return result;
}
console.log("rolling dice failed for inputs: ", n, d);
return {sum: 0, rolls: []};
};
rollDropLow = function(n, d, drop){
var r = roll(n, d);
r.rolls.sort(function(a, b){return a - b;}); //sort ascending
r.rolls.splice(0, drop); //remove the lowest elements
r.sum = 0;
for (var i = 0, l = r.rolls.length; i , l ; i++){
sum += r.rolls[i];
}
return r;
};
rollDropHigh = function(n, d, drop){
var r = roll(n, d);
r.rolls.sort(function(a, b){return b - a;}); //sort descending
r.rolls.splice(0, drop); //remove the highest elements
r.sum = 0;
for (var i = 0, l = r.rolls.length; i , l ; i++){
sum += r.rolls[i];
}
return r;
};

View File

@@ -0,0 +1,445 @@
var checkWritePermission = function(charId) {
if (!Meteor.call("canWriteCharacter", charId)){
throw new Meteor.Error(
"Access denied",
"You do not have permission to edit the assets of this character"
);
}
};
var getCondition = function(conditionName) {
//get condition from constant
var condition = CONDITIONS[conditionName];
//check that condition exists
if (!condition) {
throw new Meteor.Error(
"Invalid condition",
conditionName + " is not a known condition"
);
}
return condition;
};
Meteor.methods({
giveCondition: function(charId, conditionName) {
checkWritePermission(charId);
var condition = getCondition(conditionName);
//create the buff
var buff = _.extend(
{charId: charId, type: "inate"}, condition.buff
);
//make sure the character doesn't already have the buff
var existingBuffs = Buffs.find(_.clone(buff)).count();
if (existingBuffs) return;
//remove exclusive conditions
_.each(condition.exclusiveConditions, function(exCond) {
Meteor.call("removeCondition", charId, exCond);
});
//insert the buff
var buffId = Buffs.insert(buff);
//extend and insert each effect
_.each(condition.effects, function(effect) {
var newEffect = {
stat: effect.stat,
operation: effect.operation,
value: effect.value,
charId: charId,
parent: {
id: buffId,
collection: "Buffs",
},
enabled: true,
};
//we know these effects are right,
//skip after hooks, skip validation
Effects.direct.insert(
newEffect,
{
validate: false,
filter: false,
autoConvert: false,
removeEmptyStrings: false,
}
);
});
//recurse for subConditions
_.each(condition.subConditions, function(subCondition) {
Meteor.call("giveCondition", charId, subCondition);
});
},
removeCondition: function(charId, conditionName) {
checkWritePermission(charId);
var condition = getCondition(conditionName);
//remove the buff
var buff = _.extend(
{charId: charId, type: "inate"}, condition.buff
);
Buffs.remove(buff);
//dont remove the effects, they get removed automatically through parenting
},
});
trackEncumbranceConditions = function(charId, templateInstance) {
templateInstance.autorun(function() {
//get weight
var weight = 0;
Containers.find(
{charId: charId, isCarried: true},
{fields: {weight: 1}}
).forEach(function(container){
weight += container.totalWeight();
});
Items.find(
{charId: charId, "parent.id": charId},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
var character = Characters.findOne(
charId,
{fields: {strength: 1, "settings": 1}}
);
var strength = character.attributeValue("strength");
var give = function(condition) {
Meteor.call("giveCondition", charId, condition);
};
var remove = function(condition) {
Meteor.call("removeCondition", charId, condition);
};
//variant encumbrance rules
if (weight > strength * 10 &&
character.settings.useVariantEncumbrance) {
give("encumbered2");
remove("encumbered");
} else if (weight > strength * 5 &&
character.settings.useVariantEncumbrance){
give("encumbered");
remove("encumbered2");
} else {
remove("encumbered");
remove("encumbered2");
}
//normal encumbrance rules
if (weight > strength * 30 &&
character.settings.useStandardEncumbrance){
give("encumbered4");
remove("encumbered3");
} else if (weight > strength * 15 &&
character.settings.useStandardEncumbrance) {
give("encumbered3");
remove("encumbered4");
} else {
remove("encumbered3");
remove("encumbered4");
}
});
};
CONDITIONS = {
//Conditions
blind: {
buff: {
name: "Blind",
description: "A blinded creature cant see and automatically fails any ability check that requires sight.\n\nAttack rolls against the creature have advantage, and the creatures attack rolls have disadvantage.",
},
effects: [
{
stat: "perception",
operation: "conditional",
calculation: "You fail your perception check if it requires sight",
}
],
},
deaf: {
buff: {
name: "Deaf",
description: "A deafened creature cant hear and automatically fails any ability check that requires hearing.",
},
effects: [
{
stat: "perception",
operation: "conditional",
calculation: "You fail your perception check if it requires hearing",
}
],
},
frightened: {
buff: {
name: "Frightened",
description: "A frightened creature has disadvantage on ability checks and attack rolls while the source of its fear is within line of sight.\n\nThe creature cant willingly move closer to the source of its fear.",
}
},
grappled: {
buff:{
name: "Grappled",
description: "A grappled creatures speed becomes 0, and it cant benefit from any bonus to its speed.\n\nThe condition ends if the grappler is incapacitated.\n\nThe condition also ends if an effect removes the grappled creature from the reach of the grappler or grappling effect, such as when a creature is hurled away by the thunder wave spell.",
},
effects: [
{
stat: "speed",
operation: "max",
value: 0,
},
],
},
incapacitated: {
buff: {
name: "Incapacitated",
description: "An incapacitated creature cant take actions or reactions.",
}
},
invisible: {
buff: {
name: "Invisible",
description: "An invisible creature is impossible to see without the aid of magic or a special sense. For the purpose of hiding, the creature is heavily obscured. The creatures location can be detected by any noise it makes or any tracks it leaves.\n\nAttack rolls against the creature have disadvantage, and the creatures attack rolls have advantage.",
}
},
paralyzed: {
buff: {
name: "Paralyzed",
description: "A paralyzed creature is incapacitated and cant move or speak.\n\nAttack rolls against the creature have advantage.\n\nAny attack that hits the creature is a critical hit if the attacker is within 5 feet of the creature.",
},
effects: [
{
stat: "speed",
operation: "mul",
value: 0,
},
{
stat: "strengthSave",
operation: "fail",
},
{
stat: "dexteritySave",
operation: "fail",
},
],
subConditions: [
"incapacitated",
],
},
petrified: {
buff: {
name: "Petrified",
description: "A petrified creature is transformed, along with any nonmagical object it is wearing or carrying, into a solid inanimate substance (usually stone). Its weight increases by a factor of ten, and it ceases aging.\n\nA petrified creature is incapacitated and cant move or speak, and is unaware of its surroundings.\n\nAttack rolls against the creature have advantage.\n\nThe creature is immune to poison and disease, although a poison or disease already in its system is suspended, not neutralized.",
},
effects: (function() {
var effects = [
{stat: "speed", operation: "max", value: 0},
{stat: "strengthSave", operation: "fail"},
{stat: "dexteritySave", operation: "fail"},
];
_.each(
_.without(DAMAGE_MULTIPLIERS, "poisonMultiplier"),
function(multiplier){
effects.push({stat: multiplier, operation: "mul", value: 0.5});
}
);
effects.push({stat: "poisonMultiplier", operation: "mul", value: 0});
})(),
subConditions: [
"incapacitated",
],
},
poisoned: {
buff: {
name: "Poisoned",
description: "A poisoned creature has disadvantage on attack rolls and ability checks.",
},
effects: (function() {
return _.map(SKILLS, function(skill) {
return {stat: skill, operation: "disadvantage", value: 1};
});
})(),
},
prone: {
buff: {
name: "Prone",
description: "A prone creatures only movement option is to crawl, unless it stands up and thereby ends the condition.\n\nThe creature has disadvantage on attack rolls.\n\nAn attack roll against the creature has advantage if the attacker is within 5 feet of the creature. Otherwise, the attack roll has disadvantage.",
}
},
restrained: {
buff: {
name: "Restrained",
description: "A restrained creatures speed becomes 0, and it cant benefit from any bonus to its speed.\n\nAttack rolls against the creature have advantage, and the creatures attack rolls have disadvantage.\n\nThe creature has disadvantage on Dexterity saving throws.",
},
effects: [
{
stat: "speed",
operation: "max",
value: 0,
},
{
stat: "dexteritySave",
operation: "disadvantage",
value: 1,
},
],
},
stunned: {
buff: {
name: "Stunned",
description: "A stunned creature is incapacitated, cant move, and can speak only falteringly\n\nThe creature automatically fails Strength and Dexterity saving throws.\n\nAttack rolls against the creature have advantage.",
},
effects: [
{
stat: "speed",
operation: "max",
value: 0,
},
{
stat: "strengthSave",
operation: "fail",
},
{
stat: "dexteritySave",
operation: "fail",
},
],
subConditions: ["incapacitated"],
},
unconscious: {
buff: {
name: "Unconscious",
description: "An unconscious creature is incapacitated, cant move or speak, and is unaware of its surroundings.\n\nThe creature drops whatever its holding and falls prone.\n\nThe creature automatically fails Strength and Dexterity saving throws.\n\nAttack rolls against the creature have advantage.\n\nAny attack that hits the creature is a critical hit if the attacker is within 5 feet of the creature.",
},
subConditions: ["incapacitated", "prone"],
},
exhaustion1: {
buff: {
name: "Exhaustion - 1",
description: "Disadvantage on ability checks\n\nFinishing a long rest reduces a creatures exhaustion level by 1, provided that the creature has also ingested some food and drink.",
},
effects: (function() {
return _.map(SKILLS, function(skill) {
return {stat: skill, operation: "disadvantage", value: 1};
});
})(),
},
exhaustion2: {
buff: {
name: "Exhaustion - 2",
description: "Speed halved",
},
effects: [
{
stat: "speed",
operation: "mul",
value: 0.5,
}
],
subConditions: ["exhaustion1"],
},
exhaustion3: {
buff: {
name: "Exhaustion - 3",
description: "Disadvantage on attack rolls and saving throws",
},
effects: (function() {
return _.map(SAVES, function(skill) {
return {stat: skill, operation: "disadvantage", value: 1};
});
})(),
subConditions: ["exhaustion2"],
},
exhaustion4: {
buff: {
name: "Exhaustion - 4",
description: "Hit point maximum halved",
},
effects: [
{
stat: "hitPoints",
operation: "mul",
value: 0.5,
}
],
subConditions: ["exhaustion3"],
},
exhaustion5: {
buff: {
name: "Exhaustion - 5",
description: "Speed reduced to 0",
},
effects: [
{
stat: "speed",
operation: "max",
value: 0,
}
],
subConditions: ["exhaustion4"],
},
exhaustion6: {
buff: {
name: "Exhaustion - 6",
description: "You have died of exhaustion",
},
effects: [
{
stat: "hitPoints",
operation: "max",
value: 0,
}
],
subConditions: ["exhaustion5"],
},
encumbered: {
buff: {
name: "Encumbered",
description: "Encumbered characters move 10 feet slower.",
},
effects: [
{stat: "speed", operation: "add", value: -10}
],
},
encumbered2: {
buff: {
name: "Heavily encumbered",
description: "Heavily encumbered characters move 20 feet slower and have disadvantage on ability checks, attack rolls, and saving thows that use Strength, Dexterity, or Constitution.",
},
effects: [
{stat: "speed", operation: "add", value: -20},
{stat: "strengthSave", operation: "disadvantage", value: 1},
{stat: "dexteritySave", operation: "disadvantage", value: 1},
{stat: "constitutionSave", operation: "disadvantage", value: 1},
{stat: "athletics", operation: "disadvantage", value: 1},
{stat: "acrobatics", operation: "disadvantage", value: 1},
{stat: "sleightOfHand", operation: "disadvantage", value: 1},
{stat: "stealth", operation: "disadvantage", value: 1},
{stat: "initiative", operation: "disadvantage", value: 1},
],
},
encumbered3: {
buff: {
name: "Over encumbered",
description: "Characters that can only just lift, push or drag their current load move at 5 feet.",
},
effects: [
{stat: "speed", operation: "max", value: 5},
],
},
encumbered4: {
buff: {
name: "Can't move load",
description: "Characters attempting to carry more than what they can lift, push, or drag can't move.",
},
effects: [
{stat: "speed", operation: "max", value: 0},
],
},
};

View File

@@ -76,3 +76,46 @@ ChangeLogs.insert({
"Removed a lot of unneeded effects and webcomponents, should result in significantly improved performance on low-powered devices.",
],
});
ChangeLogs.insert({
version: "0.3.1",
changes: [
"Re-implemented floating action button menu component to move away from the broken third party implementation.",
],
});
ChangeLogs.insert({
version: "0.4.0",
changes: [
"Changed attacks to use arbitrary strings with inline calculations",
"Added item increment and decrement buttons",
"fixed incorrect line breaks and formatting in dialogs",
"Added calculated values for jumping and carrying to the strength detail box",
],
});
ChangeLogs.insert({
version: "0.4.1",
changes: [
"Fixed strength jumping calculations not rounding down correctly",
],
});
ChangeLogs.insert({
version: "0.4.2",
changes: [
"Fixed attack migrations from 0.3 -> 0.4",
],
});
ChangeLogs.insert({
version: "0.5",
changes: [
"Fixed a bug that caused multiple resistances or vulnerabilities to combine incorrectly",
"Added encumbrance effects that automatically apply when carrying too much load",
"Added a bunch of UI elements to make your character's current load clear",
"Character data is now chached, swapping between two characters should be faster",
"Floating button menus now close as expected when you click a sub-button",
"Base values in attribute summaries no longer look like added values"
],
});

View File

@@ -6,7 +6,7 @@ Meteor.methods({
var user = Meteor.users.findOne(this.userId);
if (!user){
throw new Meteor.Error(
"logged-out",
"logged-out",
"The user must be logged in to migrate the database"
);
}
@@ -18,7 +18,7 @@ Meteor.methods({
"The user must be an administrator to migrate the database"
);
}
}
},
});
Migrations.add({
@@ -58,3 +58,53 @@ Migrations.add({
);
},
});
Migrations.add({
version: 2,
name: "Converts attacks from damage dice and damage bonus to a string with curly bracket calculations, adds settings.showIncrement to items",
up: function() {
//update attacks
Attacks.find({}).forEach(function(attack) {
if (!attack.damage && attack.damageDice && attack.damageBonus){
var newDamage = attack.damageDice +
" + {" + attack.damageBonus + "}";
Attacks.update(
attack._id,
{
$unset: {
damageBonus: "",
damageDice: "",
},
$set: {
damage: newDamage
},
},
{validate: false});
}
});
//update Items
Items.update(
{settings: undefined},
{$set: {"settings.showIncrement" : false}},
{validate: false, multi: true}
);
},
});
Migrations.add({
version: 3,
name: "Converts attacks from damage dice and damage bonus to a string with curly bracket calculations, adds settings.showIncrement to items",
up: function() {
//update characters
Characters.update(
{"settings.useVariantEncumbrance": undefined},
{$set: {"settings.useVariantEncumbrance" : false}},
{validate: false, multi: true}
);
Characters.update(
{"settings.useStandardEncumbrance": undefined},
{$set: {"settings.useStandardEncumbrance" : true}},
{validate: false, multi: true}
);
},
});

View File

@@ -15,6 +15,7 @@ Meteor.publish("singleCharacter", function(characterId){
//get all the assets for this character including soft deleted ones
Actions.find ({charId: characterId}, {removed: true}),
Attacks.find ({charId: characterId}, {removed: true}),
Buffs.find ({charId: characterId}, {removed: true}),
Classes.find ({charId: characterId}, {removed: true}),
Containers.find ({charId: characterId}, {removed: true}),
Effects.find ({charId: characterId}, {removed: true}),