Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89f03c7601 | ||
|
|
9d2eb14c0c | ||
|
|
7b3cb54983 | ||
|
|
a09bad2fed | ||
|
|
afd897edfe | ||
|
|
efc79cb6e7 | ||
|
|
35efe39ea7 | ||
|
|
4f1376a666 | ||
|
|
78b1d71b9d | ||
|
|
1323d8006c | ||
|
|
87d722adaf | ||
|
|
90e511eb00 | ||
|
|
5b8c25f5de | ||
|
|
2fbc54fee8 | ||
|
|
a064ae3fe8 | ||
|
|
ba9b518d7e | ||
|
|
2f729070b2 | ||
|
|
7aedb9451c | ||
|
|
c6886dd49e | ||
|
|
038ce490e4 | ||
|
|
52bef57637 | ||
|
|
29e9f8c8dc | ||
|
|
fea02811ff | ||
|
|
73cee52fff | ||
|
|
b58c006ed4 | ||
|
|
ef44f6c1a5 | ||
|
|
f455cea43f |
@@ -25,3 +25,5 @@ splendido:accounts-meld
|
|||||||
email
|
email
|
||||||
fourseven:scss@2.1.1
|
fourseven:scss@2.1.1
|
||||||
wolves:bourbon
|
wolves:bourbon
|
||||||
|
meteorhacks:subs-manager
|
||||||
|
meteorhacks:kadira
|
||||||
|
|||||||
@@ -50,11 +50,15 @@ logging@1.0.7
|
|||||||
matb33:collection-hooks@0.7.13
|
matb33:collection-hooks@0.7.13
|
||||||
meteor@1.1.6
|
meteor@1.1.6
|
||||||
meteor-platform@1.2.2
|
meteor-platform@1.2.2
|
||||||
|
meteorhacks:kadira@2.21.0
|
||||||
|
meteorhacks:meteorx@1.3.1
|
||||||
|
meteorhacks:subs-manager@1.3.0
|
||||||
minifiers@1.1.5
|
minifiers@1.1.5
|
||||||
minimongo@1.0.8
|
minimongo@1.0.8
|
||||||
mobile-status-bar@1.0.3
|
mobile-status-bar@1.0.3
|
||||||
momentjs:moment@2.10.3
|
momentjs:moment@2.10.3
|
||||||
mongo@1.1.0
|
mongo@1.1.0
|
||||||
|
mongo-livedata@1.0.8
|
||||||
npm-bcrypt@0.7.8_2
|
npm-bcrypt@0.7.8_2
|
||||||
oauth@1.1.4
|
oauth@1.1.4
|
||||||
oauth2@1.1.3
|
oauth2@1.1.3
|
||||||
|
|||||||
@@ -1,28 +1,51 @@
|
|||||||
Buffs = new Mongo.Collection("buffs");
|
Buffs = new Mongo.Collection("buffs");
|
||||||
|
|
||||||
//buffs are temporary once applied and store things which expire and their expiry time
|
|
||||||
Schemas.Buff = new SimpleSchema({
|
Schemas.Buff = new SimpleSchema({
|
||||||
//buff id
|
|
||||||
_id: {
|
|
||||||
type: String,
|
|
||||||
regEx: SimpleSchema.RegEx.Id,
|
|
||||||
autoValue: function(){
|
|
||||||
if (!this.isSet) return Random.id();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
charId: {
|
charId: {
|
||||||
type: String,
|
type: String,
|
||||||
regEx: SimpleSchema.RegEx.Id,
|
regEx: SimpleSchema.RegEx.Id,
|
||||||
},
|
},
|
||||||
//expiry time
|
name: {
|
||||||
expiry: {type: Number, optional: true},
|
type: String,
|
||||||
duration: {type: Number},
|
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.attachSchema(Schemas.Buff);
|
||||||
|
|
||||||
Buffs.attachBehaviour("softRemovable");
|
Buffs.attachBehaviour("softRemovable");
|
||||||
makeParent(Buffs, "name"); //parents of effects and attacks
|
makeParent(Buffs, ["name", "enabled"]); //parents of effects
|
||||||
|
|
||||||
Buffs.allow(CHARACTER_SUBSCHEMA_ALLOW);
|
Buffs.allow(CHARACTER_SUBSCHEMA_ALLOW);
|
||||||
Buffs.deny(CHARACTER_SUBSCHEMA_DENY);
|
Buffs.deny(CHARACTER_SUBSCHEMA_DENY);
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ Schemas.Character = new SimpleSchema({
|
|||||||
deathSave: {type: Schemas.DeathSave},
|
deathSave: {type: Schemas.DeathSave},
|
||||||
|
|
||||||
//permissions
|
//permissions
|
||||||
|
party: {type: String, regEx: SimpleSchema.RegEx.Id, optional: true},
|
||||||
owner: {type: String, regEx: SimpleSchema.RegEx.Id},
|
owner: {type: String, regEx: SimpleSchema.RegEx.Id},
|
||||||
readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
|
readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
|
||||||
writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
|
writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
|
||||||
@@ -168,21 +169,58 @@ Schemas.Character = new SimpleSchema({
|
|||||||
defaultValue: "q",
|
defaultValue: "q",
|
||||||
},
|
},
|
||||||
//TODO add per-character settings
|
//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},
|
||||||
|
//hide spellcasting
|
||||||
|
"settings.hideSpellcasting": {type: Boolean, defaultValue: false},
|
||||||
});
|
});
|
||||||
|
|
||||||
Characters.attachSchema(Schemas.Character);
|
Characters.attachSchema(Schemas.Character);
|
||||||
|
|
||||||
var attributeBase = function(charId, statName){
|
var attributeBase = function(charId, statName){
|
||||||
check(statName, String);
|
check(statName, String);
|
||||||
var effects = Effects.find(
|
//if it's a damage multiplier, we treat it specially
|
||||||
{charId: charId, stat: statName, enabled: true}
|
if (_.contains(DAMAGE_MULTIPLIERS, statName)){
|
||||||
).fetch();
|
var effects = Effects.find(
|
||||||
effects = _.groupBy(effects, "operation");
|
{charId: charId, stat: statName, enabled: true, operation: "mul"}
|
||||||
var value = _.contains(DAMAGE_MULTIPLIERS, statName) ? 1 : 0;
|
).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
|
//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);
|
var efv = evaluateEffect(charId, effect);
|
||||||
if (efv > value){
|
if (efv > value){
|
||||||
value = efv;
|
value = efv;
|
||||||
@@ -190,23 +228,31 @@ var attributeBase = function(charId, statName){
|
|||||||
});
|
});
|
||||||
|
|
||||||
//add all the add values
|
//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);
|
value += evaluateEffect(charId, effect);
|
||||||
});
|
});
|
||||||
|
|
||||||
//multiply all the mul values
|
//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);
|
value *= evaluateEffect(charId, effect);
|
||||||
});
|
});
|
||||||
|
|
||||||
//ensure value is >= all mins
|
//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);
|
var min = evaluateEffect(charId, effect);
|
||||||
value = value > min ? value : min;
|
value = value > min ? value : min;
|
||||||
});
|
});
|
||||||
|
|
||||||
//ensure value is <= all maxes
|
//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);
|
var max = evaluateEffect(charId, effect);
|
||||||
value = value < max ? value : max;
|
value = value < max ? value : max;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,7 +45,26 @@ Meteor.methods({
|
|||||||
metaData: Object,
|
metaData: Object,
|
||||||
});
|
});
|
||||||
report.owner = this.userId;
|
report.owner = this.userId;
|
||||||
Reports.insert(report);
|
var id = Reports.insert(report);
|
||||||
|
var user = Meteor.users.findOne(this.userId);
|
||||||
|
var sender = user &&
|
||||||
|
user.emails &&
|
||||||
|
user.emails[0] &&
|
||||||
|
user.emails[0].address ||
|
||||||
|
user.services &&
|
||||||
|
user.services.google &&
|
||||||
|
user.services.google.email ||
|
||||||
|
"reports@dicecloud.com";
|
||||||
|
var bodyText = "Report ID: " + id +
|
||||||
|
"\nSeverity: " + report.severity +
|
||||||
|
"\nType: " + report.type +
|
||||||
|
"\n\n" + report.description;
|
||||||
|
Email.send({
|
||||||
|
from: sender,
|
||||||
|
to: "stefan.zermatten@gmail.com",
|
||||||
|
subject: "DiceCloud feedback - " + report.title,
|
||||||
|
text: bodyText,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
deleteReport: function(id) {
|
deleteReport: function(id) {
|
||||||
var user = Meteor.users.findOne(this.userId);
|
var user = Meteor.users.findOne(this.userId);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Router.map(function() {
|
|||||||
this.route("characterList", {
|
this.route("characterList", {
|
||||||
path: "/characterList",
|
path: "/characterList",
|
||||||
waitOn: function(){
|
waitOn: function(){
|
||||||
return Meteor.subscribe("characterList", Meteor.userId());
|
return subsManager.subscribe("characterList", Meteor.userId());
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
characters: function(){
|
characters: function(){
|
||||||
@@ -47,7 +47,7 @@ Router.map(function() {
|
|||||||
path: "/character/:_id",
|
path: "/character/:_id",
|
||||||
waitOn: function(){
|
waitOn: function(){
|
||||||
return [
|
return [
|
||||||
Meteor.subscribe("singleCharacter", this.params._id, Meteor.userId()),
|
subsManager.subscribe("singleCharacter", this.params._id, Meteor.userId()),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
@@ -81,7 +81,7 @@ Router.map(function() {
|
|||||||
name: "changeLog",
|
name: "changeLog",
|
||||||
waitOn: function() {
|
waitOn: function() {
|
||||||
return [
|
return [
|
||||||
Meteor.subscribe("changeLog"),
|
subsManager.subscribe("changeLog"),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
Template.registerHelper("valueString", function(value) {
|
Template.registerHelper("valueString", function(value) {
|
||||||
|
var intValue = Math.round(value * 100);
|
||||||
|
var cp = intValue % 10;
|
||||||
|
intValue -= cp;
|
||||||
|
cp = Math.round(cp);
|
||||||
|
sp = intValue % 100;
|
||||||
|
intValue -= sp;
|
||||||
|
sp = Math.round(sp / 10)
|
||||||
|
gp = Math.floor(value);
|
||||||
|
|
||||||
var resultArray = [];
|
var resultArray = [];
|
||||||
//sp
|
|
||||||
var gp = Math.floor(value);
|
|
||||||
if (gp > 0) {
|
if (gp > 0) {
|
||||||
resultArray.push(gp + "gp");
|
resultArray.push(gp + "gp");
|
||||||
}
|
}
|
||||||
//sp
|
|
||||||
var sp = Math.floor(10 * (value % 1));
|
|
||||||
if (sp > 0) {
|
if (sp > 0) {
|
||||||
resultArray.push(sp + "sp");
|
resultArray.push(sp + "sp");
|
||||||
}
|
}
|
||||||
//cp
|
|
||||||
var cp = 10 * ((value * 10) % 1);
|
|
||||||
cp = Math.round(cp * 1000) / 1000;
|
|
||||||
if (cp > 0) {
|
if (cp > 0) {
|
||||||
resultArray.push(cp + "cp");
|
resultArray.push(cp + "cp");
|
||||||
}
|
}
|
||||||
|
|
||||||
//build string with correct spacing
|
//build string with correct spacing
|
||||||
var result = "";
|
var result = "";
|
||||||
for (var i = 0; i < resultArray.length; i++) {
|
for (var i = 0, l = resultArray.length; i < l; i++) {
|
||||||
//add a space between values
|
//add a space between values
|
||||||
if (i !== 0) {
|
if (i !== 0) {
|
||||||
result += " ";
|
result += " ";
|
||||||
|
|||||||
@@ -89,3 +89,8 @@ $thinColumnWidth: 240px;
|
|||||||
border-radius: 0 2px 2px 0;
|
border-radius: 0 2px 2px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* undo pointer cursor on detail box heading */
|
||||||
|
#globalDetail .card .top {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
Template.buffDialog.helpers({
|
||||||
|
buff: function(){
|
||||||
|
return Buffs.findOne(this.buffId);
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,3 +1,26 @@
|
|||||||
<template name="characterSettings">
|
<template name="characterSettings">
|
||||||
|
{{#with character}}
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Hide Spells tab</td>
|
||||||
|
<td>
|
||||||
|
<paper-toggle-button id="hideSpellcasting"
|
||||||
|
checked={{settings.hideSpellcasting}}
|
||||||
|
touch-action="pan-y">
|
||||||
|
</paper-toggle-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Use variant encumbrance</td>
|
||||||
|
<td>
|
||||||
|
<paper-toggle-button id="variantEncumbrance"
|
||||||
|
checked={{settings.useVariantEncumbrance}}
|
||||||
|
touch-action="pan-y">
|
||||||
|
</paper-toggle-button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{/with}}
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,3 +1,26 @@
|
|||||||
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}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"change #hideSpellcasting": function(event, instance){
|
||||||
|
var value = instance.find("#hideSpellcasting").checked;
|
||||||
|
if (this.settings.hideSpellcasting !== value){
|
||||||
|
Characters.update(
|
||||||
|
this._id,
|
||||||
|
{$set: {"settings.hideSpellcasting": value}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
<paper-item id="shareCharacter">
|
<paper-item id="shareCharacter">
|
||||||
<core-icon icon="social:share"></core-icon>Share
|
<core-icon icon="social:share"></core-icon>Share
|
||||||
</paper-item>
|
</paper-item>
|
||||||
|
<paper-item id="characterSettings">
|
||||||
|
<core-icon icon="settings"></core-icon>Settings
|
||||||
|
</paper-item>
|
||||||
</core-menu>
|
</core-menu>
|
||||||
</paper-dropdown>
|
</paper-dropdown>
|
||||||
</paper-menu-button>
|
</paper-menu-button>
|
||||||
@@ -28,7 +31,9 @@
|
|||||||
<paper-tab name="stats">Stats</paper-tab>
|
<paper-tab name="stats">Stats</paper-tab>
|
||||||
<paper-tab name="features">Features</paper-tab>
|
<paper-tab name="features">Features</paper-tab>
|
||||||
<paper-tab name="inventory">Inventory</paper-tab>
|
<paper-tab name="inventory">Inventory</paper-tab>
|
||||||
|
{{#unless hideSpellcasting}}
|
||||||
<paper-tab name="spells">Spells</paper-tab>
|
<paper-tab name="spells">Spells</paper-tab>
|
||||||
|
{{/unless}}
|
||||||
<paper-tab name="persona">Persona</paper-tab>
|
<paper-tab name="persona">Persona</paper-tab>
|
||||||
<paper-tab name="journal">Journal</paper-tab>
|
<paper-tab name="journal">Journal</paper-tab>
|
||||||
</paper-tabs>
|
</paper-tabs>
|
||||||
@@ -39,7 +44,9 @@
|
|||||||
<section flex name="stats">{{> stats}}</section>
|
<section flex name="stats">{{> stats}}</section>
|
||||||
<section flex name="features">{{> features}}</section>
|
<section flex name="features">{{> features}}</section>
|
||||||
<section flex name="inventory">{{> inventory}}</section>
|
<section flex name="inventory">{{> inventory}}</section>
|
||||||
|
{{#unless hideSpellcasting}}
|
||||||
<section flex name="spells">{{> spells}}</section>
|
<section flex name="spells">{{> spells}}</section>
|
||||||
|
{{/unless}}
|
||||||
<section flex name="persona">{{> persona}}</section>
|
<section flex name="persona">{{> persona}}</section>
|
||||||
<section flex name="journal">{{> journal}}</section>
|
<section flex name="journal">{{> journal}}</section>
|
||||||
</core-animated-pages>
|
</core-animated-pages>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
Template.characterSheet.created = function(){
|
Template.characterSheet.onCreated(function() {
|
||||||
|
//default to the first tab
|
||||||
Session.setDefault(this.data._id + ".selectedTab", "stats");
|
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){
|
var setTab = function(charId, tab){
|
||||||
return Session.set(charId + ".selectedTab", tab);
|
return Session.set(charId + ".selectedTab", tab);
|
||||||
@@ -14,6 +17,10 @@ Template.characterSheet.helpers({
|
|||||||
selectedTab: function(){
|
selectedTab: function(){
|
||||||
return getTab(this._id);
|
return getTab(this._id);
|
||||||
},
|
},
|
||||||
|
hideSpellcasting: function() {
|
||||||
|
var char = Characters.findOne(this._id);
|
||||||
|
return char && char.settings.hideSpellcasting;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.characterSheet.events({
|
Template.characterSheet.events({
|
||||||
@@ -40,4 +47,11 @@ Template.characterSheet.events({
|
|||||||
template: "shareDialog",
|
template: "shareDialog",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
"tap #characterSettings": function(event, instance){
|
||||||
|
GlobalUI.showDialog({
|
||||||
|
heading: this.name + " Settings",
|
||||||
|
data: this,
|
||||||
|
template: "characterSettings",
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,21 +1,13 @@
|
|||||||
body /deep/ #statGroupDropDown {
|
html /deep/ .operationDropDown {
|
||||||
width: 120px;
|
width: 152px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body /deep/ #statDropDown {
|
html /deep/ .statDropDown {
|
||||||
width: 120px;
|
width: 152px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body /deep/ #operationDropDown {
|
html /deep/ .damageMultiplierDropDown {
|
||||||
width: 100px;
|
width: 152px;
|
||||||
}
|
|
||||||
|
|
||||||
body /deep/ #damageMultiplierDropDown {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body /deep/ #proficiencyDropDown {
|
|
||||||
width: 120px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html /deep/ .effectEdit paper-input {
|
html /deep/ .effectEdit paper-input {
|
||||||
@@ -24,6 +16,7 @@ html /deep/ .effectEdit paper-input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html /deep/ .effectEdit {
|
html /deep/ .effectEdit {
|
||||||
|
height: 64px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
<template name="effectEdit">
|
<template name="effectEdit">
|
||||||
<div class="effectEdit" layout horizontal center>
|
<div class="effectEdit" layout horizontal center>
|
||||||
<paper-dropdown-menu class="statGroupDropDown" label="Stat Group" flex>
|
<paper-dropdown-menu class="statDropDown"
|
||||||
<paper-dropdown layered class="dropdown">
|
label="Stat">
|
||||||
<core-menu class="menu statGroupMenu" selected={{selectedStatGroup}}>
|
<paper-dropdown layered
|
||||||
{{#each statGroups}}
|
class="dropdown">
|
||||||
<paper-item class="statGroupSelect" name={{this}}>{{this}}</paper-item>
|
<core-menu class="menu statMenu" selected={{stat}}>
|
||||||
{{/each}}
|
{{#each statGroups}}
|
||||||
</core-menu>
|
<div style="font-weight: bold;
|
||||||
</paper-dropdown>
|
margin-top: 16px;">{{this}}</div>
|
||||||
</paper-dropdown-menu>
|
{{#each stats}}
|
||||||
{{#if stats}}
|
<paper-item name={{stat}}>{{name}}</paper-item>
|
||||||
<paper-dropdown-menu class="statDropDown" label="Stat" flex>
|
{{/each}}
|
||||||
<paper-dropdown layered class="dropdown">
|
|
||||||
<core-menu class="menu statMenu" selected={{stat}} on-tap="onStatMenuTap">
|
|
||||||
{{#each stats}}
|
|
||||||
<paper-item name={{stat}}>{{name}}</paper-item>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</core-menu>
|
</core-menu>
|
||||||
</paper-dropdown>
|
</paper-dropdown>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
{{/if}}
|
|
||||||
{{#if operations}}
|
{{#if operations}}
|
||||||
<paper-dropdown-menu class="operationDropDown" label="Operation" flex>
|
<paper-dropdown-menu class="operationDropDown"
|
||||||
|
label="Operation">
|
||||||
<paper-dropdown layered class="dropdown">
|
<paper-dropdown layered class="dropdown">
|
||||||
<core-menu class="menu operationMenu" selected={{operation}}>
|
<core-menu class="menu operationMenu" selected={{operation}}>
|
||||||
{{#each operations}}
|
{{#each operations}}
|
||||||
@@ -31,24 +27,39 @@
|
|||||||
</paper-dropdown>
|
</paper-dropdown>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{> Template.dynamic template=effectValueTemplate}}
|
{{#if effectValueTemplate}}
|
||||||
<paper-icon-button class="deleteEffect" role="button" tabindex="0" icon="delete" aria-label="Delete"></paper-icon-button>
|
{{> Template.dynamic template=effectValueTemplate}}
|
||||||
|
{{else}}
|
||||||
|
<div flex></div>
|
||||||
|
{{/if}}
|
||||||
|
<paper-icon-button class="deleteEffect"
|
||||||
|
icon="delete">
|
||||||
|
</paper-icon-button>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="regularEffectValue">
|
<template name="regularEffectValue">
|
||||||
<paper-input class="effectValueInput" label="Value" floatinglabel value={{effectValue}} flex></paper-input>
|
<paper-input class="effectValueInput"
|
||||||
|
label="Value"
|
||||||
|
floatinglabel
|
||||||
|
value={{effectValue}}
|
||||||
|
flex>
|
||||||
|
</paper-input>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="multiplierEffectValue">
|
<template name="multiplierEffectValue">
|
||||||
<paper-dropdown-menu class="damageMultiplierDropDown" label="Damage Multiplier" flex>
|
<paper-dropdown-menu class="damageMultiplierDropDown"
|
||||||
<paper-dropdown layered class="dropdown">
|
label="Damage Multiplier">
|
||||||
<core-menu class="menu multiplierMenu" selected={{value}}>
|
<paper-dropdown layered
|
||||||
|
class="dropdown">
|
||||||
|
<core-menu class="menu multiplierMenu"
|
||||||
|
selected={{value}}>
|
||||||
<paper-item name="0.5">Resistance</paper-item>
|
<paper-item name="0.5">Resistance</paper-item>
|
||||||
<paper-item name="2">Vulnerability</paper-item>
|
<paper-item name="2">Vulnerability</paper-item>
|
||||||
<paper-item name="0">Immunity</paper-item>
|
<paper-item name="0">Immunity</paper-item>
|
||||||
</core-menu>
|
</core-menu>
|
||||||
</paper-dropdown>
|
</paper-dropdown>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
|
<div flex></div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -93,24 +93,17 @@ var skillOperations = [
|
|||||||
{name: "Conditional Benefit", operation: "conditional"}
|
{name: "Conditional Benefit", operation: "conditional"}
|
||||||
];
|
];
|
||||||
|
|
||||||
Template.effectEdit.created = function(){
|
|
||||||
var statGroup = statsDict[this.data.stat] && statsDict[this.data.stat].group;
|
|
||||||
this.selectedStatGroup = new ReactiveVar(statGroup);
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.effectEdit.helpers({
|
Template.effectEdit.helpers({
|
||||||
selectedStatGroup: function(){
|
|
||||||
return Template.instance().selectedStatGroup.get();
|
|
||||||
},
|
|
||||||
statGroups: function(){
|
statGroups: function(){
|
||||||
return statGroupNames;
|
return statGroupNames;
|
||||||
},
|
},
|
||||||
stats: function(){
|
stats: function(){
|
||||||
var group = Template.instance().selectedStatGroup.get();
|
var group = this;
|
||||||
return statGroups[group];
|
return statGroups[group];
|
||||||
},
|
},
|
||||||
operations: function(){
|
operations: function(){
|
||||||
var group = Template.instance().selectedStatGroup.get();
|
var stat = statsDict[this.stat];
|
||||||
|
var group = stat && stat.group;
|
||||||
if (group === "Weakness/Resistance") return null;
|
if (group === "Weakness/Resistance") return null;
|
||||||
if (group === "Saving Throws" || group === "Skills"){
|
if (group === "Saving Throws" || group === "Skills"){
|
||||||
return skillOperations;
|
return skillOperations;
|
||||||
@@ -120,7 +113,8 @@ Template.effectEdit.helpers({
|
|||||||
},
|
},
|
||||||
effectValueTemplate: function(){
|
effectValueTemplate: function(){
|
||||||
//resistance/vulnerability template
|
//resistance/vulnerability template
|
||||||
var group = Template.instance().selectedStatGroup.get();
|
var stat = statsDict[this.stat];
|
||||||
|
var group = stat && stat.group;
|
||||||
if (group === "Weakness/Resistance") return "multiplierEffectValue";
|
if (group === "Weakness/Resistance") return "multiplierEffectValue";
|
||||||
|
|
||||||
var op = this.operation;
|
var op = this.operation;
|
||||||
@@ -144,25 +138,6 @@ Template.effectEdit.events({
|
|||||||
Effects.softRemoveNode(this._id);
|
Effects.softRemoveNode(this._id);
|
||||||
GlobalUI.deletedToast(this._id, "Effects", "Effect");
|
GlobalUI.deletedToast(this._id, "Effects", "Effect");
|
||||||
},
|
},
|
||||||
"core-select .statGroupDropDown": function(event, instance){
|
|
||||||
var detail = event.originalEvent.detail;
|
|
||||||
if (!detail.isSelected) return;
|
|
||||||
var groupName = detail.item.getAttribute("name");
|
|
||||||
var oldName = Template.instance().selectedStatGroup.get();
|
|
||||||
if (oldName != groupName){
|
|
||||||
instance.selectedStatGroup.set(groupName);
|
|
||||||
if (groupName === "Weakness/Resistance"){
|
|
||||||
Effects.update(this._id, {$set: {
|
|
||||||
value: 0.5,
|
|
||||||
calculation: "",
|
|
||||||
operation: "mul"}, $unset: {stat: ""}});
|
|
||||||
} else {
|
|
||||||
Effects.update(this._id,
|
|
||||||
{$set: {operation: "add"},
|
|
||||||
$unset: {stat: "", value: "", calculation: ""}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"core-select .statDropDown": function(event){
|
"core-select .statDropDown": function(event){
|
||||||
var detail = event.originalEvent.detail;
|
var detail = event.originalEvent.detail;
|
||||||
if (!detail.isSelected) return;
|
if (!detail.isSelected) return;
|
||||||
|
|||||||
@@ -57,40 +57,40 @@ var stats = {
|
|||||||
"d12HitDice":{"name":"d12 Hit Dice"},
|
"d12HitDice":{"name":"d12 Hit Dice"},
|
||||||
"acidMultiplier":{"name":"Acid damage", "group": "Weakness/Resistance"},
|
"acidMultiplier":{"name":"Acid damage", "group": "Weakness/Resistance"},
|
||||||
"bludgeoningMultiplier":{
|
"bludgeoningMultiplier":{
|
||||||
"name":"Bludgeoning damage", "group": "Weakness/Resistance"
|
"name":"Bludgeoning damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"coldMultiplier":{
|
"coldMultiplier":{
|
||||||
"name":"Cold damage", "group": "Weakness/Resistance"
|
"name":"Cold damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"fireMultiplier":{
|
"fireMultiplier":{
|
||||||
"name":"Fire damage", "group": "Weakness/Resistance"
|
"name":"Fire damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"forceMultiplier":{
|
"forceMultiplier":{
|
||||||
"name":"Force damage", "group": "Weakness/Resistance"
|
"name":"Force damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"lightningMultiplier":{
|
"lightningMultiplier":{
|
||||||
"name":"Lightning damage", "group": "Weakness/Resistance"
|
"name":"Lightning damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"necroticMultiplier":{
|
"necroticMultiplier":{
|
||||||
"name":"Necrotic damage", "group": "Weakness/Resistance"
|
"name":"Necrotic damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"piercingMultiplier":{
|
"piercingMultiplier":{
|
||||||
"name":"Piercing damage", "group": "Weakness/Resistance"
|
"name":"Piercing damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"poisonMultiplier":{
|
"poisonMultiplier":{
|
||||||
"name":"Poison damage", "group": "Weakness/Resistance"
|
"name":"Poison damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"psychicMultiplier":{
|
"psychicMultiplier":{
|
||||||
"name":"Psychic damage", "group": "Weakness/Resistance"
|
"name":"Psychic damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"radiantMultiplier":{
|
"radiantMultiplier":{
|
||||||
"name":"Radiant damage", "group": "Weakness/Resistance"
|
"name":"Radiant damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"slashingMultiplier":{
|
"slashingMultiplier":{
|
||||||
"name":"Slashing damage", "group": "Weakness/Resistance"
|
"name":"Slashing damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
"thunderMultiplier":{
|
"thunderMultiplier":{
|
||||||
"name":"Thunder damage", "group": "Weakness/Resistance"
|
"name":"Thunder damage", "group": "Weakness/Resistance",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,8 +110,8 @@ var operations = {
|
|||||||
Template.effectView.helpers({
|
Template.effectView.helpers({
|
||||||
sourceName: function(){
|
sourceName: function(){
|
||||||
var id = this.parent.id;
|
var id = this.parent.id;
|
||||||
if(!id) return;
|
if (!id) return;
|
||||||
switch(this.parent.collection){
|
switch (this.parent.collection){
|
||||||
case "Features":
|
case "Features":
|
||||||
return "Feature - " + Features.findOne(id, {fields: {name: 1}}).name;
|
return "Feature - " + Features.findOne(id, {fields: {name: 1}}).name;
|
||||||
case "Classes":
|
case "Classes":
|
||||||
@@ -130,33 +130,39 @@ Template.effectView.helpers({
|
|||||||
return stats[this.stat] && stats[this.stat].name || "No Stat";
|
return stats[this.stat] && stats[this.stat].name || "No Stat";
|
||||||
},
|
},
|
||||||
operationName: function(){
|
operationName: function(){
|
||||||
if(this.operation === "proficiency" ||
|
if (this.operation === "proficiency" ||
|
||||||
this.operation === "conditional") return null;
|
this.operation === "conditional") return null;
|
||||||
if(stats[this.stat].group === "Weakness/Resistance") return null;
|
if (stats[this.stat] && stats[this.stat].group === "Weakness/Resistance")
|
||||||
if(this.operation === "add" && evaluateEffect(this.charId, this) < 0) return null;
|
return null;
|
||||||
return operations[this.operation] && operations[this.operation].name || "No Operation";
|
if (this.operation === "add" && evaluateEffect(this.charId, this) < 0)
|
||||||
|
return null;
|
||||||
|
return operations[this.operation] &&
|
||||||
|
operations[this.operation].name || "No Operation";
|
||||||
},
|
},
|
||||||
statValue: function(){
|
statValue: function(){
|
||||||
if(this.operation === "advantage" ||
|
if (this.operation === "advantage" ||
|
||||||
this.operation === "disadvantage" ||
|
this.operation === "disadvantage" ||
|
||||||
this.operation === "fail"){
|
this.operation === "fail"){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(this.operation === "proficiency"){
|
if (this.operation === "proficiency"){
|
||||||
if(this.value == 0.5 || this.calculation == 0.5) return "Half Proficiency";
|
if (this.value == 0.5 || this.calculation == 0.5)
|
||||||
if(this.value == 1 || this.calculation == 1) return "Proficiency";
|
return "Half Proficiency";
|
||||||
if(this.value == 2 || this.calculation == 2) return "Double Proficiency";
|
if (this.value == 1 || this.calculation == 1)
|
||||||
|
return "Proficiency";
|
||||||
|
if (this.value == 2 || this.calculation == 2)
|
||||||
|
return "Double Proficiency";
|
||||||
}
|
}
|
||||||
if(this.operation === "conditional"){
|
if (this.operation === "conditional"){
|
||||||
return this.calculation || this.value;
|
return this.calculation || this.value;
|
||||||
}
|
}
|
||||||
if(stats[this.stat].group === "Weakness/Resistance"){
|
if (stats[this.stat] && stats[this.stat].group === "Weakness/Resistance"){
|
||||||
if(this.value === 0.5) return "Resistance";
|
if (this.value === 0.5) return "Resistance";
|
||||||
if(this.value === 2) return "Vulnerability";
|
if (this.value === 2) return "Vulnerability";
|
||||||
if(this.value === 0) return "Immunity";
|
if (this.value === 0) return "Immunity";
|
||||||
}
|
}
|
||||||
var value = evaluateEffect(this.charId, this);
|
var value = evaluateEffect(this.charId, this);
|
||||||
if(_.isNumber(value)) return value;
|
if (_.isNumber(value)) return value;
|
||||||
return this.calculation || this.value;
|
return this.calculation || this.value;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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";
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -3,22 +3,51 @@
|
|||||||
<div id="inventory" class="scroll-y" fit>
|
<div id="inventory" class="scroll-y" fit>
|
||||||
<div class="column-container">
|
<div class="column-container">
|
||||||
<!--Net Worth-->
|
<!--Net Worth-->
|
||||||
<paper-shadow class="card" layout horizontal>
|
<paper-shadow class="card">
|
||||||
<div class="indigo white-text subhead left">
|
<div class="white top" layout horizontal center>
|
||||||
Net Worth
|
<div class="subhead" flex>
|
||||||
</div>
|
Net Worth
|
||||||
<div class="right" flex>
|
</div>
|
||||||
{{valueString netWorth}}
|
<div>
|
||||||
|
{{valueString netWorth}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</paper-shadow>
|
</paper-shadow>
|
||||||
<!--Weight Carried-->
|
<!--Weight Carried-->
|
||||||
<paper-shadow class="card" layout horizontal>
|
<paper-shadow class="card"
|
||||||
<div class="green white-text subhead left">
|
hero-id="main" {{detailHero "weightCarried" _id}}>
|
||||||
Weight Carried
|
<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>
|
||||||
<div class="right" flex>
|
<div class="bottom green" style="padding: 0;">
|
||||||
{{round weightCarried}}lbs
|
{{> carryCapacityBar}}
|
||||||
</div>
|
</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>
|
</paper-shadow>
|
||||||
<!--Equipment-->
|
<!--Equipment-->
|
||||||
<paper-shadow class="card equipmentContainer">
|
<paper-shadow class="card equipmentContainer">
|
||||||
@@ -51,7 +80,7 @@
|
|||||||
<!--Carried Items-->
|
<!--Carried Items-->
|
||||||
<paper-shadow class="card carriedContainer">
|
<paper-shadow class="card carriedContainer">
|
||||||
<div class="white top" layout horizontal center>
|
<div class="white top" layout horizontal center>
|
||||||
<div class="subhead">
|
<div class="subhead" flex>
|
||||||
Carried
|
Carried
|
||||||
</div>
|
</div>
|
||||||
<div class="caption" style="margin-right: 8px">
|
<div class="caption" style="margin-right: 8px">
|
||||||
|
|||||||
@@ -61,6 +61,18 @@ Template.inventory.helpers({
|
|||||||
});
|
});
|
||||||
return weight;
|
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(){
|
equipmentValue: function(){
|
||||||
var value = 0;
|
var value = 0;
|
||||||
Items.find(
|
Items.find(
|
||||||
@@ -136,6 +148,23 @@ Template.inventory.events({
|
|||||||
heroId: containerId,
|
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){
|
"tap .inventoryItem": function(event){
|
||||||
var itemId = this._id;
|
var itemId = this._id;
|
||||||
var charId = Template.parentData()._id;
|
var charId = Template.parentData()._id;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{{#each baseEffects}}
|
{{#each baseEffects}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{sourceName}}</td>
|
<td>{{sourceName}}</td>
|
||||||
<td>{{signedString statValue}}</td>
|
<td>Base: {{statValue}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each addEffects}}
|
{{#each addEffects}}
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
{{#each mulEffects}}
|
{{#each mulEffects}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{sourceName}}</td>
|
<td>{{sourceName}}</td>
|
||||||
<td>×{{statValue}}</td>
|
<td>× {{statValue}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each minEffects}}
|
{{#each minEffects}}
|
||||||
|
|||||||
@@ -4,32 +4,7 @@
|
|||||||
<hr class="vertMargin">
|
<hr class="vertMargin">
|
||||||
<div>
|
<div>
|
||||||
<div class="title padded">Carrying</div>
|
<div class="title padded">Carrying</div>
|
||||||
<table class="strengthTable">
|
{{> carryCapacityTable}}
|
||||||
<tr>
|
|
||||||
<td>Encumbered</td>
|
|
||||||
<td>{{evaluate charId "strength * 5"}}lbs</td>
|
|
||||||
<td class="caption">Speed drops by 10 feet</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Heavily encumbered</td>
|
|
||||||
<td>{{evaluate charId "strength * 10"}}lbs</td>
|
|
||||||
<td class="caption">
|
|
||||||
Speed drops by 20 feet, disadvantage on strength,
|
|
||||||
dexterity and constitution ability checks, attack
|
|
||||||
rolls and saving throws
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Maximum carrying capacity</td>
|
|
||||||
<td>{{evaluate charId "strength * 15"}}lbs</td>
|
|
||||||
<td class="caption">Speed drops to 5 feet</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Push, drag or lift maximum</td>
|
|
||||||
<td>{{evaluate charId "strength * 30"}}lbs</td>
|
|
||||||
<td class="caption">You can't move more than this weight</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="title padded">Jumping</div>
|
<div class="title padded">Jumping</div>
|
||||||
<table class="strengthTable">
|
<table class="strengthTable">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -38,7 +13,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Standing long jump</td>
|
<td>Standing long jump</td>
|
||||||
<td>{{evaluate charId "round(strength/2)"}} feet</td>
|
<td>{{evaluate charId "floor(strength/2)"}} feet</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Running high jump</td>
|
<td>Running high jump</td>
|
||||||
@@ -51,10 +26,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Standing high jump</td>
|
<td>Standing high jump</td>
|
||||||
<td>{{evaluate charId "round((3 + strengthMod)/2)"}} feet</td>
|
<td>{{evaluate charId "floor((3 + strengthMod)/2)"}} feet</td>
|
||||||
<td class="caption">
|
<td class="caption">
|
||||||
Can reach a ledge as high as
|
Can reach a ledge as high as
|
||||||
{{evaluate charId "round((3 + strengthMod)/2)"}} feet
|
{{evaluate charId "floor((3 + strengthMod)/2)"}} feet
|
||||||
+ 1.5× your height
|
+ 1.5× your height
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<template name="carryCapacityTable">
|
||||||
|
<table class="carryCapacityTable strengthTable">
|
||||||
|
<tr>
|
||||||
|
<td>Encumbered</td>
|
||||||
|
<td>>{{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>>{{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>>{{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>
|
||||||
@@ -25,6 +25,13 @@
|
|||||||
</paper-autogrow-textarea>
|
</paper-autogrow-textarea>
|
||||||
</paper-input-decorator>
|
</paper-input-decorator>
|
||||||
</div>
|
</div>
|
||||||
<paper-button id="cancelButton" affirmative>Cancel</paper-button>
|
<paper-button id="cancelButton"
|
||||||
<paper-button id="sendButton" affirmative>Send </paper-button>
|
affirmative>
|
||||||
|
Cancel
|
||||||
|
</paper-button>
|
||||||
|
<paper-button id="sendButton"
|
||||||
|
affirmative
|
||||||
|
disabled={{invalid}}>
|
||||||
|
Send
|
||||||
|
</paper-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,4 +1,23 @@
|
|||||||
|
Template.feedback.onCreated(function() {
|
||||||
|
this.title = new ReactiveVar("");
|
||||||
|
this.description = new ReactiveVar("");
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.feedback.helpers({
|
||||||
|
invalid: function() {
|
||||||
|
var inst = Template.instance();
|
||||||
|
return !inst.title.get() ||
|
||||||
|
!inst.description.get();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Template.feedback.events({
|
Template.feedback.events({
|
||||||
|
"input #feedbackTitle": function(event, instance) {
|
||||||
|
instance.title.set(instance.find("#feedbackTitle").value);
|
||||||
|
},
|
||||||
|
"input #feedbackDescription": function(event, instance) {
|
||||||
|
instance.description.set(instance.find("#feedbackDescription").value);
|
||||||
|
},
|
||||||
"tap #sendButton": function(event, instance) {
|
"tap #sendButton": function(event, instance) {
|
||||||
var report = {};
|
var report = {};
|
||||||
report.title = instance.find("#feedbackTitle").value;
|
report.title = instance.find("#feedbackTitle").value;
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
<div layout vertical center>
|
<div layout vertical center>
|
||||||
<paper-shadow class="wallOfText card" style="padding: 32px; max-width: 800px;">
|
<paper-shadow class="wallOfText card" style="padding: 32px; max-width: 800px;">
|
||||||
<h1>Dicecloud Beta</h1>
|
<h1>Dicecloud Beta</h1>
|
||||||
<p>Welcome to the Dicecloud beta. Please don't share the link with people you don't actively play with, since the beta is intended to be small, and your experience will probably get laggy if it gets more traffic than I'm expecting.</p>
|
<p>Welcome to the Dicecloud beta.</p>
|
||||||
<p>The beta is going to start with just the character sheet. You can play D&D without minis and maps, without a pre-written adventure, you can play without a lot of things, but the character sheet is necessary. So I'm starting here and working my way outwards.</p>
|
<p>The beta is going to start with just the character sheet. You can play D&D without minis and maps, without a pre-written adventure, you can play without a lot of things, but the character sheet is necessary. So I'm starting here and working my way outwards.</p>
|
||||||
<p>I will eventually have public bug tracking and feature requests going, but for now I'm going to track comments, feedback and suggestions on <a href="http://reddit.com/r/dicecloud">this subreddit</a>. If you've never used reddit before, all you need is a username and password to sign up. So it should be pretty accessible.</p>
|
<p>Leave any comments, feedback and suggestions on <a href="http://reddit.com/r/dicecloud">this subreddit</a>. If you've never used reddit before, all you need is a username and password to sign up. So it should be pretty accessible.</p>
|
||||||
|
<p>If you'd like to see a list of known issues and upcoming features, check out the <a href="https://trello.com/b/94M0SCnq/dicecloud-roadmap">DiceCloud Roadmap</a>.</p>
|
||||||
<h2>Character Sheet Philosophy</h2>
|
<h2>Character Sheet Philosophy</h2>
|
||||||
<p>Setting up your character on Dicecloud is going to take you a little longer than just filling it in on a paper character sheet would have. The goal of using an online sheet is to make actually playing the game more streamlined, and ultimately more fun. So putting a little extra effort into setting up your character now will pay off over and over again once you're playing.</p>
|
<p>Setting up your character on Dicecloud is going to take you a little longer than just filling it in on a paper character sheet would have. The goal of using an online sheet is to make actually playing the game more streamlined, and ultimately more fun. So putting a little extra effort into setting up your character now will pay off over and over again once you're playing.</p>
|
||||||
<p>The idea is to track where each number comes from, and allow you to easily make changes on the fly.</p>
|
<p>The idea is to track where each number comes from, and allow you to easily make changes on the fly.</p>
|
||||||
|
|||||||
@@ -12,4 +12,7 @@ Template.fabMenu.events({
|
|||||||
"tap .expand-menu": function(event, instance) {
|
"tap .expand-menu": function(event, instance) {
|
||||||
instance.active.set(!instance.active.get());
|
instance.active.set(!instance.active.get());
|
||||||
},
|
},
|
||||||
});
|
"tap .mini-holder paper-fab": function(event, instance) {
|
||||||
|
instance.active.set(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
1
rpg-docs/lib/constants/subsManager.js
Normal file
1
rpg-docs/lib/constants/subsManager.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
subsManager = new SubsManager();
|
||||||
445
rpg-docs/lib/methods/conditions.js
Normal file
445
rpg-docs/lib/methods/conditions.js
Normal 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 can’t see and automatically fails any ability check that requires sight.\n\nAttack rolls against the creature have advantage, and the creature’s 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 can’t 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 can’t willingly move closer to the source of its fear.",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
grappled: {
|
||||||
|
buff:{
|
||||||
|
name: "Grappled",
|
||||||
|
description: "A grappled creature’s speed becomes 0, and it can’t 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 can’t 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 creature’s location can be detected by any noise it makes or any tracks it leaves.\n\nAttack rolls against the creature have disadvantage, and the creature’s attack rolls have advantage.",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
paralyzed: {
|
||||||
|
buff: {
|
||||||
|
name: "Paralyzed",
|
||||||
|
description: "A paralyzed creature is incapacitated and can’t 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 can’t 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 creature’s 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 creature’s speed becomes 0, and it can’t benefit from any bonus to its speed.\n\nAttack rolls against the creature have advantage, and the creature’s 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, can’t 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, can’t move or speak, and is unaware of its surroundings.\n\nThe creature drops whatever it’s 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 creature’s 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},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -93,3 +93,68 @@ ChangeLogs.insert({
|
|||||||
"Added calculated values for jumping and carrying to the strength detail box",
|
"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",
|
||||||
|
"Floating button menus now close as expected when you click a sub-button",
|
||||||
|
"Base values in attribute summaries no longer look like added values"
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChangeLogs.insert({
|
||||||
|
version: "0.5.1",
|
||||||
|
changes: [
|
||||||
|
"Characters are now cached and should take much faster to load when swapping between them",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChangeLogs.insert({
|
||||||
|
version: "0.5.2",
|
||||||
|
changes: [
|
||||||
|
"Opened the beta up to the general public",
|
||||||
|
"Added performance monitoring",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChangeLogs.insert({
|
||||||
|
version: "0.5.3",
|
||||||
|
changes: [
|
||||||
|
"Prevented a harmless error caused by effects which have no stat set",
|
||||||
|
"Added the ability to hide the spells tab",
|
||||||
|
"Feedback forms now give me push notifications",
|
||||||
|
"Feedback forms now won't send unless properly filled out",
|
||||||
|
"Overhauled how effects' stats are chosen",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChangeLogs.insert({
|
||||||
|
version: "0.5.4",
|
||||||
|
changes: [
|
||||||
|
"Fixed rounding error on net worth calculation",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChangeLogs.insert({
|
||||||
|
version: "0.5.5",
|
||||||
|
changes: [
|
||||||
|
"Fixed reports from google users not correctly storing the reply-to email address",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|||||||
1
rpg-docs/server/kadira.js
Normal file
1
rpg-docs/server/kadira.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Kadira.connect("erzTBaxBGjsd28SDt", "1c100582-dfce-4378-884f-e133e347b7b3");
|
||||||
@@ -65,20 +65,22 @@ Migrations.add({
|
|||||||
up: function() {
|
up: function() {
|
||||||
//update attacks
|
//update attacks
|
||||||
Attacks.find({}).forEach(function(attack) {
|
Attacks.find({}).forEach(function(attack) {
|
||||||
var newDamage = attack.damageDice +
|
if (!attack.damage && attack.damageDice && attack.damageBonus){
|
||||||
" + {" + attack.damageBonus + "}";
|
var newDamage = attack.damageDice +
|
||||||
Attacks.update(
|
" + {" + attack.damageBonus + "}";
|
||||||
attack._id,
|
Attacks.update(
|
||||||
{
|
attack._id,
|
||||||
$unset: {
|
{
|
||||||
damageBonus: "",
|
$unset: {
|
||||||
damageDice: "",
|
damageBonus: "",
|
||||||
|
damageDice: "",
|
||||||
|
},
|
||||||
|
$set: {
|
||||||
|
damage: newDamage
|
||||||
|
},
|
||||||
},
|
},
|
||||||
$set: {
|
{validate: false});
|
||||||
damage: newDamage
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
{validate: false});
|
|
||||||
});
|
});
|
||||||
//update Items
|
//update Items
|
||||||
Items.update(
|
Items.update(
|
||||||
@@ -88,3 +90,21 @@ Migrations.add({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Meteor.publish("singleCharacter", function(characterId){
|
|||||||
//get all the assets for this character including soft deleted ones
|
//get all the assets for this character including soft deleted ones
|
||||||
Actions.find ({charId: characterId}, {removed: true}),
|
Actions.find ({charId: characterId}, {removed: true}),
|
||||||
Attacks.find ({charId: characterId}, {removed: true}),
|
Attacks.find ({charId: characterId}, {removed: true}),
|
||||||
|
Buffs.find ({charId: characterId}, {removed: true}),
|
||||||
Classes.find ({charId: characterId}, {removed: true}),
|
Classes.find ({charId: characterId}, {removed: true}),
|
||||||
Containers.find ({charId: characterId}, {removed: true}),
|
Containers.find ({charId: characterId}, {removed: true}),
|
||||||
Effects.find ({charId: characterId}, {removed: true}),
|
Effects.find ({charId: characterId}, {removed: true}),
|
||||||
|
|||||||
Reference in New Issue
Block a user