Implemented a javascript code style

This commit is contained in:
Stefan Zermatten
2015-04-22 12:44:25 +02:00
parent dce20375b5
commit fada0f5136
113 changed files with 1614 additions and 1650 deletions

56
.jscsrc Normal file
View File

@@ -0,0 +1,56 @@
{
"requireOperatorBeforeLineBreak": true,
"requireCamelCaseOrUpperCaseIdentifiers": true,
"maximumLineLength": {
"value": 80,
"allowComments": true,
"allowRegex": true
},
"validateIndentation": "\t",
"validateQuoteMarks": "\"",
"disallowMultipleLineStrings": true,
"disallowMixedSpacesAndTabs": "smart",
"disallowTrailingWhitespace": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowMultipleVarDecl": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowKeywordsOnNewLine": ["else"],
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"return",
"try",
"catch"
],
"requireSpaceBeforeBinaryOperators": [
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
"&=", "|=", "^=", "+=",
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
"|", "^", "&&", "||", "===", "==", ">=",
"<=", "<", ">", "!=", "!=="
],
"requireSpaceAfterBinaryOperators": true,
"requireSpacesInConditionalExpression": true,
"requireSpacesInForStatement": true,
"requireTrailingComma": {
"ignoreSingleValue": true,
"ignoreSingleLine": true
},
"requireLineFeedAtFileEnd": true,
"disallowSpacesInAnonymousFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideObjectBrackets": "all",
"disallowSpacesInsideArrayBrackets": "all",
"disallowSpacesInsideParentheses": true,
"disallowMultipleLineBreaks": true,
"disallowNewlineBeforeBlockStatements": true
}

3
.jshintrc Normal file
View File

@@ -0,0 +1,3 @@
{
"undef": false
}

View File

@@ -4,4 +4,4 @@ Schemas.Instance = new SimpleSchema({
//an instance is a single flow of time all parties in an instance are in-sync time wise
});
Instances.attachSchema(Schemas.Instance);
Instances.attachSchema(Schemas.Instance);

View File

@@ -5,4 +5,4 @@ Schemas.Party = new SimpleSchema({
//each party can only be in a single instance at a time
});
Parties.attachSchema(Schemas.Party);
Parties.attachSchema(Schemas.Party);

View File

@@ -5,29 +5,32 @@ Actions = new Mongo.Collection("actions");
*/
Schemas.Action = new SimpleSchema({
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id
type: String,
regEx: SimpleSchema.RegEx.Id,
},
name: {
type: String, trim: false
type: String,
trim: false,
},
description: {
type: String, trim: false
type: String,
trim: false,
},
type: {
type: String,
allowedValues: ["action, bonus, reaction, free"],
defaultValue: "action"
defaultValue: "action",
},
//the immediate impact of doing this action (eg. -1 rages)
adjustments: {
type: [Schemas.Adjustment], defaultValue: []
}
type: [Schemas.Adjustment],
defaultValue: [],
},
});
Actions.attachSchema(Schemas.Action);
Actions.attachBehaviour('softRemovable');
Actions.attachBehaviour("softRemovable");
makeChild(Actions);
Actions.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -5,62 +5,75 @@ Attacks = new Mongo.Collection("attacks");
*/
Schemas.Attack = new SimpleSchema({
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id
type: String,
regEx: SimpleSchema.RegEx.Id,
},
name: {
type: String,
defaultValue: "New Attack",
trim: false
defaultValue: "New Attack",
trim: false,
},
details: {
type: String,
optional: true,
trim: false
optional: true,
trim: false,
},
attackBonus: {
type: String,
defaultValue: "strengthMod + proficiencyBonus",
optional: true,
trim: false
optional: true,
trim: false,
},
damageBonus: {
type: String,
defaultValue: "strengthMod",
optional: true,
trim: false
optional: true,
trim: false,
},
damageDice: {
type: String,
optional: true,
defaultValue: "1d8",
allowedValues: DAMAGE_DICE
allowedValues: DAMAGE_DICE,
},
damageType: {
type: String,
allowedValues: ["bludgeoning", "piercing", "slashing", "acid", "cold", "fire", "force", "lightning", "necrotic",
"poison", "psychic", "radiant", "thunder"],
defaultValue: "slashing"
allowedValues: [
"bludgeoning",
"piercing",
"slashing",
"acid",
"cold",
"fire",
"force",
"lightning",
"necrotic",
"poison",
"psychic",
"radiant",
"thunder",
],
defaultValue: "slashing",
},
//the id of the feature, buff or item that created this effect
parent: {
type: Schemas.Parent
},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q"
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
enabled: {
type: Boolean,
defaultValue: true
}
defaultValue: true,
},
});
Attacks.attachSchema(Schemas.Attack);
Attacks.attachBehaviour('softRemovable');
makeChild(Attacks, ['name', 'enabled']); //children of lots of things
Attacks.attachBehaviour("softRemovable");
makeChild(Attacks, ["name", "enabled"]); //children of lots of things
Attacks.allow(CHARACTER_SUBSCHEMA_ALLOW);
Attacks.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -7,21 +7,22 @@ Schemas.Buff = new SimpleSchema({
type: String,
regEx: SimpleSchema.RegEx.Id,
autoValue: function(){
if(!this.isSet) return Random.id();
}},
if (!this.isSet) return Random.id();
},
},
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id
type: String,
regEx: SimpleSchema.RegEx.Id,
},
//expiry time
expiry: { type: Number, optional: true},
duration: { type: Number }
expiry: {type: Number, optional: true},
duration: {type: Number},
});
Buffs.attachSchema(Schemas.Buff);
Buffs.attachBehaviour('softRemovable');
makeParent(Buffs, 'name'); //parents of effects and attacks
Buffs.attachBehaviour("softRemovable");
makeParent(Buffs, "name"); //parents of effects and attacks
Buffs.allow(CHARACTER_SUBSCHEMA_ALLOW);
Buffs.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -3,16 +3,16 @@ Characters = new Mongo.Collection("characters");
Schemas.Character = new SimpleSchema({
//strings
name: { type: String, defaultValue: "", trim: false},
alignment: { type: String, defaultValue: "", trim: false},
gender: { type: String, defaultValue: "", trim: false},
race: { type: String, defaultValue: "", trim: false},
description: { type: String, defaultValue: "", trim: false},
personality: { type: String, defaultValue: "", trim: false},
ideals: { type: String, defaultValue: "", trim: false},
bonds: { type: String, defaultValue: "", trim: false},
flaws: { type: String, defaultValue: "", trim: false},
backstory: { type: String, defaultValue: "", trim: false},
name: {type: String, defaultValue: "", trim: false},
alignment: {type: String, defaultValue: "", trim: false},
gender: {type: String, defaultValue: "", trim: false},
race: {type: String, defaultValue: "", trim: false},
description: {type: String, defaultValue: "", trim: false},
personality: {type: String, defaultValue: "", trim: false},
ideals: {type: String, defaultValue: "", trim: false},
bonds: {type: String, defaultValue: "", trim: false},
flaws: {type: String, defaultValue: "", trim: false},
backstory: {type: String, defaultValue: "", trim: false},
//attributes
//ability scores
@@ -73,99 +73,100 @@ Schemas.Character = new SimpleSchema({
slashingMultiplier: {type: Schemas.Attribute},
thunderMultiplier: {type: Schemas.Attribute},
//skills
//saves
strengthSave: {type: Schemas.Skill},
"strengthSave.ability": { type: String, defaultValue: "strength" },
"strengthSave.ability": {type: String, defaultValue: "strength"},
dexteritySave: {type: Schemas.Skill},
"dexteritySave.ability": { type: String, defaultValue: "dexterity" },
"dexteritySave.ability": {type: String, defaultValue: "dexterity"},
constitutionSave:{type: Schemas.Skill},
"constitutionSave.ability": { type: String, defaultValue: "constitution" },
"constitutionSave.ability": {type: String, defaultValue: "constitution"},
intelligenceSave:{type: Schemas.Skill},
"intelligenceSave.ability": { type: String, defaultValue: "intelligence" },
"intelligenceSave.ability": {type: String, defaultValue: "intelligence"},
wisdomSave: {type: Schemas.Skill},
"wisdomSave.ability": { type: String, defaultValue: "wisdom" },
"wisdomSave.ability": {type: String, defaultValue: "wisdom"},
charismaSave: {type: Schemas.Skill},
"charismaSave.ability": { type: String, defaultValue: "charisma" },
"charismaSave.ability": {type: String, defaultValue: "charisma"},
//skill skills
acrobatics: {type: Schemas.Skill},
"acrobatics.ability": { type: String, defaultValue: "dexterity" },
acrobatics: {type: Schemas.Skill},
"acrobatics.ability": {type: String, defaultValue: "dexterity"},
animalHandling: {type: Schemas.Skill},
"animalHandling.ability": { type: String, defaultValue: "wisdom" },
animalHandling: {type: Schemas.Skill},
"animalHandling.ability": {type: String, defaultValue: "wisdom"},
arcana: {type: Schemas.Skill},
"arcana.ability": { type: String, defaultValue: "intelligence" },
arcana: {type: Schemas.Skill},
"arcana.ability": {type: String, defaultValue: "intelligence"},
athletics: {type: Schemas.Skill},
"athletics.ability": { type: String, defaultValue: "strength" },
athletics: {type: Schemas.Skill},
"athletics.ability": {type: String, defaultValue: "strength"},
deception: {type: Schemas.Skill},
"deception.ability": { type: String, defaultValue: "charisma" },
deception: {type: Schemas.Skill},
"deception.ability": {type: String, defaultValue: "charisma"},
history: {type: Schemas.Skill},
"history.ability": { type: String, defaultValue: "intelligence" },
history: {type: Schemas.Skill},
"history.ability": {type: String, defaultValue: "intelligence"},
insight: {type: Schemas.Skill},
"insight.ability": { type: String, defaultValue: "wisdom" },
insight: {type: Schemas.Skill},
"insight.ability": {type: String, defaultValue: "wisdom"},
intimidation: {type: Schemas.Skill},
"intimidation.ability": { type: String, defaultValue: "charisma" },
intimidation: {type: Schemas.Skill},
"intimidation.ability": {type: String, defaultValue: "charisma"},
investigation: {type: Schemas.Skill},
"investigation.ability": { type: String, defaultValue: "intelligence" },
"investigation.ability": {type: String, defaultValue: "intelligence"},
medicine: {type: Schemas.Skill},
"medicine.ability": { type: String, defaultValue: "wisdom" },
"medicine.ability": {type: String, defaultValue: "wisdom"},
nature: {type: Schemas.Skill},
"nature.ability": { type: String, defaultValue: "intelligence" },
"nature.ability": {type: String, defaultValue: "intelligence"},
perception: {type: Schemas.Skill},
"perception.ability": { type: String, defaultValue: "wisdom" },
"perception.ability": {type: String, defaultValue: "wisdom"},
performance: {type: Schemas.Skill},
"performance.ability": { type: String, defaultValue: "charisma" },
"performance.ability": {type: String, defaultValue: "charisma"},
persuasion: {type: Schemas.Skill},
"persuasion.ability": { type: String, defaultValue: "charisma" },
persuasion: {type: Schemas.Skill},
"persuasion.ability": {type: String, defaultValue: "charisma"},
religion: {type: Schemas.Skill},
"religion.ability": { type: String, defaultValue: "intelligence" },
religion: {type: Schemas.Skill},
"religion.ability": {type: String, defaultValue: "intelligence"},
sleightOfHand: {type: Schemas.Skill},
"sleightOfHand.ability": { type: String, defaultValue: "dexterity" },
"sleightOfHand.ability": {type: String, defaultValue: "dexterity"},
stealth: {type: Schemas.Skill},
"stealth.ability": { type: String, defaultValue: "dexterity" },
"stealth.ability": {type: String, defaultValue: "dexterity"},
survival: {type: Schemas.Skill},
"survival.ability": { type: String, defaultValue: "wisdom" },
"survival.ability": {type: String, defaultValue: "wisdom"},
//Mechanical Skills
initiative: {type: Schemas.Skill},
"initiative.ability": { type: String, defaultValue: "dexterity" },
initiative: {type: Schemas.Skill},
"initiative.ability": {type: String, defaultValue: "dexterity"},
dexterityArmor: {type: Schemas.Skill},
"dexterityArmor.ability": { type: String, defaultValue: "dexterity" },
"dexterityArmor.ability": {type: String, defaultValue: "dexterity"},
//mechanics
deathSave: { type: Schemas.DeathSave },
deathSave: {type: Schemas.DeathSave},
//permissions
owner: { type: String, regEx: SimpleSchema.RegEx.Id },
readers: { type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [] },
writers: { type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [] },
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"},
owner: {type: String, regEx: SimpleSchema.RegEx.Id},
readers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: []},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
//TODO add per-character settings
"settings.experiencesInc": {type: Number, defaultValue: 20}, //how many experiences to load at a time in XP table
});
@@ -174,9 +175,11 @@ Characters.attachSchema(Schemas.Character);
var attributeBase = function(charId, statName){
check(statName, String);
var effects = Effects.find({charId: charId, stat: statName, enabled: true}).fetch();
var effects = Effects.find(
{charId: charId, stat: statName, enabled: true}
).fetch();
effects = _.groupBy(effects, "operation");
var value = _.contains(DAMAGE_MULTIPLIERS, statName)? 1 : 0;
var value = _.contains(DAMAGE_MULTIPLIERS, statName) ? 1 : 0;
//start with the highest base value
_.each(effects.base, function(effect){
@@ -199,13 +202,13 @@ var attributeBase = function(charId, statName){
//ensure value is >= all mins
_.each(effects.min, function(effect){
var min = evaluateEffect(charId, effect);
value = value > min? value : min;
value = value > min ? value : min;
});
//ensure value is <= all maxes
_.each(effects.max, function(effect){
var max = evaluateEffect(charId, effect);
value = value < max? value : max;
value = value < max ? value : max;
});
return value;
};
@@ -221,16 +224,24 @@ Characters.helpers({
fieldSelector[fieldName] = 1;
var char = Characters.findOne(this._id, {fields: fieldSelector});
var field = char[fieldName];
if(field === undefined){
throw new Meteor.Error("getField failed",
"getField could not find field " + fieldName + " in character "+ char._id);
if (field === undefined){
throw new Meteor.Error(
"getField failed",
"getField could not find field " +
fieldName +
" in character " +
char._id
);
}
return field;
},
//returns the value of a field
fieldValue : function(fieldName){
if(!Schemas.Character.schema(fieldName)){
throw new Meteor.Error("Field not found", "Character's schema does not contain a field called: " + fieldName);
if (!Schemas.Character.schema(fieldName)){
throw new Meteor.Error(
"Field not found",
"Character's schema does not contain a field called: " + fieldName
);
}
//duck typing to get the right value function
//.ability implies skill
@@ -277,7 +288,9 @@ Characters.helpers({
mod += prof * this.attributeValue("proficiencyBonus");
//apply all effects
var rawEffects = Effects.find({charId: charId, stat: skillName, enabled: true}).fetch();
var rawEffects = Effects.find(
{charId: charId, stat: skillName, enabled: true}
).fetch();
var effects = _.groupBy(rawEffects, "operation");
_.forEach(effects.add, function(effect){
mod += evaluateEffect(charId, effect);
@@ -287,11 +300,11 @@ Characters.helpers({
});
_.forEach(effects.min, function(effect){
var min = evaluateEffect(charId, effect);
mod = mod > min? mod : min;
mod = mod > min ? mod : min;
});
_.forEach(effects.max, function(effect){
var max = evaluateEffect(charId, effect);
mod = mod < max? mod : max;
mod = mod < max ? mod : max;
});
return signedString(mod);
}),
@@ -300,7 +313,9 @@ Characters.helpers({
var charId = this._id;
//return largest value in proficiency array
var prof = 0;
Proficiencies.find({charId: charId, name: skillName, enabled: true}).forEach(function(proficiency){
Proficiencies.find(
{charId: charId, name: skillName, enabled: true}
).forEach(function(proficiency){
var newProf = proficiency.value;
if (newProf > prof){
prof = newProf;
@@ -316,7 +331,9 @@ Characters.helpers({
var charId = this._id;
var mod = +this.skillMod(skillName);
var value = 10 + mod;
Effects.find({charId: charId, stat: skillName, enabled: true, operation: "passiveAdd"}).forEach(function(effect){
Effects.find(
{charId: charId, stat: skillName, enabled: true, operation: "passiveAdd"}
).forEach(function(effect){
value += evaluateEffect(charId, effect);
});
return value;
@@ -325,10 +342,14 @@ Characters.helpers({
advantage: function(skillName){
var charId = this._id;
var advantage = Effects.find({charId: charId, stat: skillName, enabled: true, operation: "advantage"}).count();
var disadvantage = Effects.find({charId: charId, stat: skillName, enabled: true, operation: "disadvantage"}).count();
if(advantage && !disadvantage) return 1;
if(disadvantage && !advantage) return -1;
var advantage = Effects.find(
{charId: charId, stat: skillName, enabled: true, operation: "advantage"}
).count();
var disadvantage = Effects.find(
{charId: charId, stat: skillName, enabled: true, operation: "disadvantage"}
).count();
if (advantage && !disadvantage) return 1;
if (disadvantage && !advantage) return -1;
return 0;
},
@@ -343,15 +364,12 @@ Characters.helpers({
xpLevel: function(){
var xp = this.experience();
var xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000,
85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000,
305000, 355000];
for(var i = 0; i < 19; i++){
if(xp < xpTable[i]){
for (var i = 0; i < 19; i++){
if (xp < XP_TABLE[i]){
return i;
}
};
if(xp > 355000) return 20;
}
if (xp > 355000) return 20;
return 0;
},
@@ -359,22 +377,25 @@ Characters.helpers({
var level = 0;
Classes.find({charId: this._id}).forEach(function(cls){
level += cls.level;
})
});
return level;
},
experience: function(){
var xp = 0;
Experiences.find({charId: this._id}, {fields: {value: 1}}).forEach(function(e){
Experiences.find(
{charId: this._id},
{fields: {value: 1}}
).forEach(function(e){
xp += e.value;
})
});
return xp;
}
},
});
//clean up all data related to that character before removing it
Characters.after.remove(function (userId, character) {
if(Meteor.isServer){
Characters.after.remove(function(userId, character) {
if (Meteor.isServer){
Actions .remove({charId: character._id});
Attacks .remove({charId: character._id});
Buffs .remove({charId: character._id});
@@ -391,25 +412,25 @@ Characters.after.remove(function (userId, character) {
});
Characters.allow({
insert: function (userId, doc) {
insert: function(userId, doc) {
// the user must be logged in, and the document must be owned by the user
return (userId && doc.owner === userId);
},
update: function (userId, doc, fields, modifier) {
update: function(userId, doc, fields, modifier) {
// can only change documents you have write access to
return doc.owner === userId ||
_.contains(doc.writers, userId);
},
remove: function (userId, doc) {
remove: function(userId, doc) {
// can only remove your own documents
return doc.owner === userId;
},
fetch: ["owner", "writers"]
fetch: ["owner", "writers"],
});
Characters.deny({
update: function (userId, docs, fields, modifier) {
update: function(userId, docs, fields, modifier) {
// can't change owners
return _.contains(fields, 'owner');
return _.contains(fields, "owner");
}
});

View File

@@ -8,21 +8,25 @@ Schemas.Class = new SimpleSchema({
type: Date,
autoValue: function() {
if (this.isInsert) {
return new Date;
return new Date();
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
return {$setOnInsert: new Date()};
} else {
this.unset();
}
}
},
},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
});
Classes.attachSchema(Schemas.Class);
Classes.attachBehaviour('softRemovable');
makeParent(Classes, 'name'); //parents of effects and attacks
Classes.attachBehaviour("softRemovable");
makeParent(Classes, "name"); //parents of effects and attacks
Classes.allow(CHARACTER_SUBSCHEMA_ALLOW);
Classes.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -7,27 +7,39 @@ Effects = new Mongo.Collection("effects");
Schemas.Effect = new SimpleSchema({
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id
regEx: SimpleSchema.RegEx.Id,
},
name: {
type: String,
optional: true, //TODO make necessary if there is no owner
trim: false
trim: false,
},
operation: {
type: String,
defaultValue: "add",
allowedValues: ["base", "proficiency","add","mul","min","max","advantage","disadvantage","passiveAdd","fail","conditional"]
allowedValues: [
"base",
"proficiency",
"add",
"mul",
"min",
"max",
"advantage",
"disadvantage",
"passiveAdd",
"fail",
"conditional",
],
},
value: {
type: Number,
decimal: true,
optional: true
optional: true,
},
calculation: {
type: String,
optional: true,
trim: false
trim: false,
},
//the thing that created this effect
parent: {
@@ -36,17 +48,17 @@ Schemas.Effect = new SimpleSchema({
//which stat the effect is applied to
stat: {
type: String,
optional: true
optional: true,
},
enabled: {
type: Boolean,
defaultValue: true
}
defaultValue: true,
},
});
Effects.attachSchema(Schemas.Effect);
if(Meteor.isServer) Characters.after.insert(function (userId, char) {
if (Meteor.isServer) Characters.after.insert(function(userId, char) {
Effects.insert({
charId: char._id,
type: "inate",
@@ -56,8 +68,8 @@ if(Meteor.isServer) Characters.after.insert(function (userId, char) {
calculation: "level * constitutionMod",
parent: {
id: char._id,
collection: "Characters"
}
collection: "Characters",
},
});
Effects.insert({
charId: char._id,
@@ -68,8 +80,8 @@ if(Meteor.isServer) Characters.after.insert(function (userId, char) {
calculation: "floor(level / 4 + 1.75)",
parent: {
id: char._id,
collection: "Characters"
}
collection: "Characters",
},
});
Effects.insert({
charId: char._id,
@@ -80,8 +92,8 @@ if(Meteor.isServer) Characters.after.insert(function (userId, char) {
calculation: "dexterityArmor",
parent: {
id: char._id,
collection: "Characters"
}
collection: "Characters",
},
});
Effects.insert({
charId: char._id,
@@ -92,12 +104,12 @@ if(Meteor.isServer) Characters.after.insert(function (userId, char) {
value: 10,
parent: {
id: char._id,
collection: "Characters"
}
collection: "Characters",
},
});
});
Effects.attachBehaviour('softRemovable');
Effects.attachBehaviour("softRemovable");
makeChild(Effects, ["enabled"]); //children of lots of things
Effects.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -9,19 +9,19 @@ Schemas.Experience = new SimpleSchema({
type: Date,
autoValue: function() {
if (this.isInsert) {
return new Date;
return new Date();
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
return {$setOnInsert: new Date()};
} else {
this.unset();
}
}
},
},
});
Experiences.attachSchema(Schemas.Experience);
Experiences.attachBehaviour('softRemovable');
Experiences.attachBehaviour("softRemovable");
Experiences.allow(CHARACTER_SUBSCHEMA_ALLOW);
Experiences.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -6,10 +6,17 @@ Schemas.Feature = new SimpleSchema({
description: {type: String, optional: true, trim: false},
uses: {type: String, optional: true, trim: false},
used: {type: Number, defaultValue: 0},
reset: {type: String, allowedValues: ["manual", "longRest", "shortRest"], defaultValue: "manual"},
reset: {
type: String,
allowedValues: ["manual", "longRest", "shortRest"],
defaultValue: "manual",
},
enabled: {type: Boolean, defaultValue: true},
alwaysEnabled:{type: Boolean, defaultValue: true},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
color: {type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Features.attachSchema(Schemas.Feature);
@@ -20,11 +27,11 @@ Features.helpers({
},
usesValue: function(){
return evaluate(this.charId, this.uses);
}
},
});
Features.attachBehaviour('softRemovable');
makeParent(Features, ['name', 'enabled']); //parents of effects and attacks
Features.attachBehaviour("softRemovable");
makeParent(Features, ["name", "enabled"]); //parents of effects and attacks
Features.allow(CHARACTER_SUBSCHEMA_ALLOW);
Features.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -4,12 +4,16 @@ Schemas.Note = new SimpleSchema({
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
name: {type: String, trim: false},
description: {type: String, optional: true, trim: false},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
color: {
type: String,
allowedValues:_.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Notes.attachSchema(Schemas.Note);
Notes.attachBehaviour('softRemovable');
Notes.attachBehaviour("softRemovable");
Notes.allow(CHARACTER_SUBSCHEMA_ALLOW);
Notes.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -3,7 +3,7 @@ Proficiencies = new Mongo.Collection("proficiencies");
Schemas.Proficiency = new SimpleSchema({
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id
regEx: SimpleSchema.RegEx.Id,
},
name: {
type: String,
@@ -24,12 +24,12 @@ Schemas.Proficiency = new SimpleSchema({
enabled: {
type: Boolean,
defaultValue: true,
}
},
});
Proficiencies.attachSchema(Schemas.Proficiency);
Proficiencies.attachBehaviour('softRemovable');
Proficiencies.attachBehaviour("softRemovable");
makeChild(Proficiencies);
Proficiencies.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -7,7 +7,11 @@ Schemas.SpellLists = new SimpleSchema({
saveDC: {type: String, optional: true, trim: false},
attackBonus: {type: String, optional: true, trim: false},
maxPrepared: {type: String, optional: true, trim: false},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
"settings.showUnprepared": {type: Boolean, defaultValue: true},
});
@@ -16,14 +20,17 @@ SpellLists.attachSchema(Schemas.SpellLists);
SpellLists.helpers({
numPrepared: function(){
var num = 0;
Spells.find({charId: this.charId, listId: this._id, prepared: 1}, {fields: {prepareCost: 1}}).forEach(function(spell){
Spells.find(
{charId: this.charId, listId: this._id, prepared: 1},
{fields: {prepareCost: 1}}
).forEach(function(spell){
num += spell.prepareCost;
});
return num;
}
});
SpellLists.attachBehaviour('softRemovable');
SpellLists.attachBehaviour("softRemovable");
makeParent(SpellLists); //parents of spells
SpellLists.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -2,25 +2,65 @@ Spells = new Mongo.Collection("spells");
Schemas.Spell = new SimpleSchema({
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
prepared: {type: String, defaultValue: "prepared", allowedValues: ["prepared","unprepared","always"]},
name: {type: String, trim: false, defaultValue: "New Spell"},
description: {type: String, optional: true, trim: false},
castingTime: {type: String, optional: true, defaultValue: "action", trim: false},
range: {type: String, optional: true, trim: false},
duration: {type: String, optional: true, trim: false, defaultValue: "Instantaneous"},
"components.verbal": {type: Boolean, defaultValue: false},
"components.somatic": {type: Boolean, defaultValue: false},
"components.material": {type: String, optional: true},
prepared: {
type: String,
defaultValue: "prepared",
allowedValues: ["prepared", "unprepared", "always"],
},
name: {
type: String,
trim: false,
defaultValue: "New Spell",
},
description: {
type: String,
optional: true,
trim: false,
},
castingTime: {
type: String,
optional: true,
defaultValue: "action",
trim: false,
},
range: {
type: String,
optional: true,
trim: false,
},
duration: {
type: String,
optional: true,
trim: false,
defaultValue: "Instantaneous",
},
"components.verbal": {type: Boolean, defaultValue: false},
"components.somatic": {type: Boolean, defaultValue: false},
"components.concentration": {type: Boolean, defaultValue: false},
ritual: {type: Boolean, defaultValue: false},
level: {type: Number, defaultValue: 1},
school: {type: String, defaultValue: "Abjuration", allowedValues: magicSchools},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
"components.material": {type: String, optional: true},
ritual: {
type: Boolean,
defaultValue: false,
},
level: {
type: Number,
defaultValue: 1,
},
school: {
type: String,
defaultValue: "Abjuration",
allowedValues: magicSchools,
},
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Spells.attachSchema(Schemas.Spell);
Spells.attachBehaviour('softRemovable');
Spells.attachBehaviour("softRemovable");
makeChild(Spells); //children of spell lists
Spells.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -5,21 +5,21 @@
Schemas.Adjustment = new SimpleSchema({
name: {
type: String,
optional: true
optional: true,
},
//which stat the adjustment is applied to
stat: {
type: String,
optional: true
optional: true,
},
//the value added to the stat
value: {
type: Number,
decimal: true,
optional: true
optional: true,
},
calculation: {
type: String,
optional: true
}
optional: true,
},
});

View File

@@ -3,11 +3,11 @@ Schemas.Attribute = new SimpleSchema({
//should be zero after reset
adjustment: {
type: Number,
defaultValue: 0
defaultValue: 0,
},
reset: {
type: String,
defaultValue: "longRest",
allowedValues: ["longRest", "shortRest"]
}
allowedValues: ["longRest", "shortRest"],
},
});

View File

@@ -3,20 +3,20 @@ Schemas.DeathSave = new SimpleSchema({
type: Number,
min: 0,
max: 3,
defaultValue: 0
defaultValue: 0,
},
fail: {
type: Number,
min: 0,
max: 3,
defaultValue: 0
defaultValue: 0,
},
canDeathSave: {
type: Boolean,
defaultValue: true
defaultValue: true,
},
stable: {
type: Boolean,
defaultValue: false
}
defaultValue: false,
},
});

View File

@@ -1,4 +1,4 @@
Schemas.Skill = new SimpleSchema({
//attribute name that this skill used as base mod for roll
ability: { type: String, defaultValue: "" },
ability: {type: String, defaultValue: ""},
});

View File

@@ -16,7 +16,7 @@ Schemas.TemporaryHitPoints = new SimpleSchema({
} else {
this.unset();
}
}
},
},
});
@@ -29,11 +29,13 @@ TemporaryHitPoints.helpers({
});
//remove the temporary hit points when they hit zero
TemporaryHitPoints.after.update(function (userId, thp, fieldNames, modifier, options) {
if(thp.used >= thp.maximum && thp.deleteOnZero){
TemporaryHitPoints.remove(thp._id);
}
}, {fetchPrevious: false});
TemporaryHitPoints.after.update(
function(userId, thp, fieldNames, modifier, options){
if (thp.used >= thp.maximum && thp.deleteOnZero){
TemporaryHitPoints.remove(thp._id);
}
}, {fetchPrevious: false}
);
TemporaryHitPoints.allow(CHARACTER_SUBSCHEMA_ALLOW);
TemporaryHitPoints.deny(CHARACTER_SUBSCHEMA_DENY);

View File

@@ -2,13 +2,17 @@
Containers = new Mongo.Collection("containers");
Schemas.Container = new SimpleSchema({
name: { type: String, trim: false },
charId: { type: String, regEx: SimpleSchema.RegEx.Id},
isCarried: { type: Boolean },
name: {type: String, trim: false},
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
isCarried: {type: Boolean},
weight: {type: Number, min: 0, defaultValue: 0, decimal: true},
value: {type: Number, min: 0, defaultValue: 0, decimal: true},
description:{type: String, optional: true, trim: false},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Containers.attachSchema(Schemas.Container);
@@ -16,7 +20,10 @@ Containers.attachSchema(Schemas.Container);
Containers.helpers({
contentsValue: function(){
var value = 0;
Items.find({"parent.id": this._id}, {fields: {quantity: 1, value: 1}}).forEach(function(item){
Items.find(
{"parent.id": this._id},
{fields: {quantity: 1, value: 1}}
).forEach(function(item){
value += item.totalValue();
});
return value;
@@ -26,7 +33,10 @@ Containers.helpers({
},
contentsWeight: function(){
var weight = 0;
Items.find({"parent.id": this._id}, {fields: {quantity: 1, weight: 1}}).forEach(function(item){
Items.find(
{"parent.id": this._id},
{fields: {quantity: 1, weight: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
return weight;
@@ -35,12 +45,12 @@ Containers.helpers({
return this.contentsWeight() + this.weight;
},
moveToCharacter: function(characterId){
if(this.charId === characterId) return;
if (this.charId === characterId) return;
Items.update(this._id, {$set: {charId: characterId}});
}
},
});
Containers.attachBehaviour('softRemovable');
Containers.attachBehaviour("softRemovable");
makeParent(Containers); //parents of items
Containers.allow(CHARACTER_SUBSCHEMA_ALLOW);

View File

@@ -1,4 +1,4 @@
Items = new Mongo.Collection('items');
Items = new Mongo.Collection("items");
Schemas.Item = new SimpleSchema({
name: {type: String, defaultValue: "New Item", trim: false},
@@ -10,7 +10,11 @@ Schemas.Item = new SimpleSchema({
value: {type: Number, min: 0, defaultValue: 0, decimal: true},
enabled: {type: Boolean, defaultValue: false},
requiresAttunement: {type: Boolean, defaultValue: false},
color: {type: String, allowedValues: _.pluck(colorOptions, "key"), defaultValue: "q"}
color: {
type: String,
allowedValues: _.pluck(colorOptions, "key"),
defaultValue: "q",
},
});
Items.attachSchema(Schemas.Item);
@@ -23,40 +27,77 @@ Items.helpers({
return this.weight * this.quantity;
},
pluralName: function(){
if(this.plural && this.quantity !== 1){
if (this.plural && this.quantity !== 1){
return this.plural;
} else{
} else {
return this.name;
}
},
equip: function(characterId){
var charId = characterId || this.charId;
if(!charId || ! Characters.findOne(charId)) throw "Invalid character";
if(this.parent.collection === "Characters" && this.parent.id === charId && this.enabled) return;
Items.update(this._id, {$set: {"parent.collection": "Characters", "parent.id": charId, enabled: true}});
if (!charId || !Characters.findOne(charId)) throw "Invalid character";
if (this.parent.collection === "Characters" &&
this.parent.id === charId &&
this.enabled) {
return;
}
Items.update(
this._id,
{$set: {
"parent.collection": "Characters",
"parent.id": charId,
enabled: true,
}}
);
},
unequip: function(){
if(!this.enabled) return;
if (!this.enabled) return;
Items.update(this._id, {$set: {enabled: false}});
},
moveToContainer: function(containerId){
if( !containerId || !Containers.findOne(containerId) ) throw "Invalid container";
if(this.parent.collection === "Containers" && this.parent.id === containerId && !this.enabled) return;
Items.update(this._id, {$set: {"parent.collection": "Containers", "parent.id": containerId, enabled: false}});
if (!containerId || !Containers.findOne(containerId)){
throw "Invalid container";
}
if (this.parent.collection === "Containers" &&
this.parent.id === containerId &&
!this.enabled) return;
Items.update(
this._id,
{$set: {
"parent.collection": "Containers",
"parent.id": containerId,
enabled: false,
}}
);
},
moveToCharacter: function(characterId){
if(!characterId || ! Characters.findOne(characterId)) throw "Invalid character";
if(this.parent.collection === "Characters" && this.parent.id === characterId && !this.enabled) return;
Items.update(this._id, {$set: {"parent.collection": "Characters", "parent.id": characterId, charId: characterId, enabled: false}});
if (!characterId || !Characters.findOne(characterId)) {
throw "Invalid character";
}
if (this.parent.collection === "Characters" &&
this.parent.id === characterId &&
!this.enabled) return;
Items.update(
this._id,
{$set: {
"parent.collection": "Characters",
"parent.id": characterId,
charId: characterId,
enabled: false,
}}
);
},
splitToParent: function(parent, moveQuantity){
check(parent, {id: String, collection: String});
check(moveQuantity, Number);
var parentCollection = Meteor.isClient? window[parent.collection] : global[parent.collection];
if(!parent.id || !parentCollection.findOne(parent.id)) throw "Invalid parent";
var parentCollection = Meteor.isClient ?
window[parent.collection] : global[parent.collection];
if (!parent.id || !parentCollection.findOne(parent.id)){
throw "Invalid parent";
}
var oldStack = this;
//we can only move as much as we have, leaving 0 behind at worst
if(oldStack.quantity < moveQuantity) moveQuantity = oldStack.quantity;
if (oldStack.quantity < moveQuantity) moveQuantity = oldStack.quantity;
var oldQuantity = oldStack.quantity - moveQuantity;
var newStack = _.pick(oldStack, Schemas.Item.objectKeys());
@@ -65,31 +106,39 @@ Items.helpers({
var existingStack = Items.findOne(_.omit(newStack, "quantity"));
var updateStackSize = function(){
if(oldQuantity > 0){
if (oldQuantity > 0){
Items.update(oldStack._id, {$set: {quantity: oldQuantity}});
} else {
Items.remove(oldStack._id);
}
};
if(existingStack){
Items.update(existingStack._id, {$inc: {quantity: moveQuantity}}, {}, function(){
updateStackSize();
});
}else{
if (existingStack){
Items.update(
existingStack._id,
{$inc: {quantity: moveQuantity}},
{},
function(){
updateStackSize();
}
);
} else {
Items.insert(newStack, function(err, id){
if(err) throw err;
if (err) throw err;
updateStackSize();
//copy the children also
Meteor.call("cloneChildren", oldStack._id, {collection: "Items", id: id});
});
}
}
},
});
Items.before.update(function(userId, doc, fieldNames, modifier, options){
if(
if (
modifier && modifier.$set && modifier.$set.enabled && //we are equipping this item
!(modifier.$set["parent.collection"] === "Characters" && modifier.$set["parent.id"]) //and we haven't specified a character to equip to
!(
modifier.$set["parent.collection"] === "Characters" &&
modifier.$set["parent.id"]
) //and we haven"t specified a character to equip to
){
//equip it to the current character
modifier.$set["parent.collection"] = "Characters";
@@ -97,21 +146,21 @@ Items.before.update(function(userId, doc, fieldNames, modifier, options){
}
});
Items.attachBehaviour('softRemovable');
Items.attachBehaviour("softRemovable");
makeChild(Items); //children of containers
makeParent(Items, ['name', 'enabled']); //parents of effects and attacks
makeParent(Items, ["name", "enabled"]); //parents of effects and attacks
Items.allow(CHARACTER_SUBSCHEMA_ALLOW);
//give characters default items
Characters.after.insert(function (userId, char) {
if(Meteor.isServer){
Characters.after.insert(function(userId, char) {
if (Meteor.isServer){
var containerId = Containers.insert({
name: "Coin Pouch",
charId: char._id,
isCarried: true,
description: "A sturdy pouch for coins",
color: "d"
color: "d",
});
Items.insert({
name: "Gold piece",
@@ -123,8 +172,8 @@ Characters.after.insert(function (userId, char) {
color: "n",
parent: {
id: containerId,
collection: "Containers"
}
collection: "Containers",
},
});
Items.insert({
name: "Silver piece",
@@ -136,8 +185,8 @@ Characters.after.insert(function (userId, char) {
color: "q",
parent: {
id: containerId,
collection: "Containers"
}
collection: "Containers",
},
});
Items.insert({
name: "Copper piece",
@@ -149,8 +198,8 @@ Characters.after.insert(function (userId, char) {
color: "s",
parent: {
id: containerId,
collection: "Containers"
}
collection: "Containers",
},
});
}
});

View File

@@ -4,17 +4,17 @@ Schema.User = new SimpleSchema({
username: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/,
optional: true
optional: true,
},
emails: {
type: [Object],
// this must be optional if you also use other login services like facebook,
// but if you use only accounts-password, then it can be required
optional: true
optional: true,
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
regEx: SimpleSchema.RegEx.Email,
},
"emails.$.verified": {
type: Boolean
@@ -25,20 +25,20 @@ Schema.User = new SimpleSchema({
services: {
type: Object,
optional: true,
blackbox: true
blackbox: true,
},
roles: {
type: [String],
optional: true
}
optional: true,
},
});
Meteor.users.attachSchema(Schema.User);
Meteor.users.allow({
update: function (userId, doc, fields, modifier) {
update: function(userId, doc, fields, modifier) {
return userId === doc._id &&
fields.length === 1 &&
fields[0] === 'username';
fields[0] === "username";
}
});

View File

@@ -1,12 +1,12 @@
Router.configure({
loadingTemplate: 'loading',
layoutTemplate: 'layout'
loadingTemplate: "loading",
layoutTemplate: "layout",
});
Router.map( function () {
Router.map(function() {
/*
this.route('home', {
path: '/',
this.route("home", {
path: "/",
waitOn: function(){
return Meteor.subscribe("characterList", Meteor.userId());
},
@@ -17,8 +17,8 @@ Router.map( function () {
}
});*/ //add a home route and change characterList route
this.route('characterList', {
path: '/',
this.route("characterList", {
path: "/",
waitOn: function(){
return Meteor.subscribe("characterList", Meteor.userId());
},
@@ -29,37 +29,40 @@ Router.map( function () {
},
onAfterAction: function() {
document.title = appName;
}
},
});
this.route('characterSheet', {
path: '/character/:_id',
this.route("characterSheet", {
path: "/character/:_id",
waitOn: function(){
return [
Meteor.subscribe("singleCharacter", this.params._id, Meteor.userId()),
];
},
data: function() {
var data = Characters.findOne({_id: this.params._id}, {fields: {_id: 1, name: 1, color: 1}});
var data = Characters.findOne(
{_id: this.params._id},
{fields: {_id: 1, name: 1, color: 1}}
);
return data;
},
onAfterAction: function() {
var char = Characters.findOne({_id: this.params._id}, {fields: {name: 1}});
var name = char && char.name;
if(name){
if (name){
document.title = name;
}
}
},
});
this.route('loading', {
path: '/loading'
this.route("loading", {
path: "/loading"
});
this.route('profile', {
path: '/account',
this.route("profile", {
path: "/account",
onAfterAction: function() {
document.title = appName + " Account";
}
},
});
});
});

View File

@@ -12,10 +12,10 @@ this.GlobalUI = (function() {
return toast.show();
};
GlobalUI.deletedToast = function(id, collection, itemName){
GlobalUI.deletedToast = function(id, collection, itemName) {
GlobalUI.toast({
text: itemName? itemName + " deleted" : "Deleted item from" + collection,
template: "undoToast",
text: itemName ? itemName + " deleted" : "Deleted item from" + collection,
template: "undoToast",
data: {
id: id,
collection: collection
@@ -23,7 +23,7 @@ this.GlobalUI = (function() {
});
};
GlobalUI.setDialog = function(opts){
GlobalUI.setDialog = function(opts) {
this.dialog = $("[global-dialog]")[0];
Session.set("global.ui.dialogHeader", opts.heading);
Session.set("global.ui.dialogData", opts.data);
@@ -58,7 +58,7 @@ this.GlobalUI = (function() {
Session.set("global.ui.detailShow", true);
};
//if setting the detail rather than showing it,
//if setting the detail rather than showing it,
//the template should contain the following in template.rendered
//
//if (!this.alreadyRendered){
@@ -69,30 +69,30 @@ this.GlobalUI = (function() {
Session.set("global.ui.detailData", opts.data);
Session.set("global.ui.detailTemplate", opts.template);
Session.set("global.ui.detailHeroId", opts.heroId);
if(!!(window.history && window.history.pushState)){
if (window.history && window.history.pushState) {
history.replaceState({detail: "closed", opts: opts}, "Detail Dialog");
history.pushState({detail: "opened", opts: opts}, "Detail Dialog");
}
};
var throttleBack = _.throttle(function(){
var throttleBack = _.throttle(function() {
history.back();
}, 800, {trailing: false});
GlobalUI.closeDetail = function(){
if(!!(window.history && window.history.pushState)){
GlobalUI.closeDetail = function() {
if (!!(window.history && window.history.pushState)) {
throttleBack();
} else{
} else {
Session.set("global.ui.detailShow", false);
}
};
GlobalUI.popStateHandler = function(e){
GlobalUI.popStateHandler = function(e) {
var state = e.originalEvent.state;
if(state) {
if(state.detail === "closed"){
if (state) {
if (state.detail === "closed") {
Session.set("global.ui.detailShow", false);
} else if(state.detail === "opened"){
} else if (state.detail === "opened") {
var opts = state.opts;
Session.set("global.ui.detailData", opts.data);
Session.set("global.ui.detailTemplate", opts.template);
@@ -115,22 +115,22 @@ Template.layout.helpers({
globalDialogFullOnMobile: function() {
return Session.get("global.ui.dialogFullOnMobile");
},
globalDialogHeader: function(){
globalDialogHeader: function() {
return Session.get("global.ui.dialogHeader");
},
globalDetailSelected: function(){
globalDetailSelected: function() {
return Session.get("global.ui.detailShow") ? 1 : 0;
},
globalDetailTemplate: function(){
globalDetailTemplate: function() {
return Session.get("global.ui.detailTemplate");
},
globalDetailData: function(){
globalDetailData: function() {
return Session.get("global.ui.detailData");
},
globalToastTemplate: function(){
globalToastTemplate: function() {
return Session.get("global.ui.toastTemplate");
},
globalToastData: function(){
globalToastData: function() {
return Session.get("global.ui.toastData");
}
});
@@ -143,7 +143,7 @@ Template.layout.events({
},
"core-animated-pages-transition-end [detail-pages]": function(e) {
var detailOpened = Session.get("global.ui.detailShow");
if(!detailOpened){
if (!detailOpened) {
Session.set("global.ui.detailData", null);
Session.set("global.ui.detailTemplate", null);
Session.set("global.ui.detailHeroId", null);
@@ -151,14 +151,14 @@ Template.layout.events({
},
"core-animated-pages-transition-prepare": function(e) {
var detailOpened = Session.get("global.ui.detailShow");
if(detailOpened) {
if (detailOpened) {
//set up the transition
} else {
//undo hack
$("#mainContentSection").removeClass("fake-selected");
}
},
"tap #screenDim": function(e){
"tap #screenDim": function(e) {
GlobalUI.closeDetail();
}
});

View File

@@ -1,3 +1,3 @@
Template.registerHelper("canCast", function(){
Template.registerHelper("canCast", function() {
return Characters.find({_id: this._id, spells: {$size: 0}}).count() === 0;
});
});

View File

@@ -1,8 +1,11 @@
Template.registerHelper("colorClass", function(color){
if(color) return getColorClass(color);
else if(this.color) return getColorClass(this.color);
Template.registerHelper("colorClass", function(color) {
if (color) {
return getColorClass(color);
} else if (this.color) {
return getColorClass(this.color);
}
});
Template.registerHelper("hexColor", function(color){
Template.registerHelper("hexColor", function(color) {
return getHexColor(color);
});

View File

@@ -1,7 +1,9 @@
Template.registerHelper("detailHero", function(suffix, givenId){
Template.registerHelper("detailHero", function(suffix, givenId) {
var id = givenId || this._id;
if(suffix) id += suffix;
if ( Session.equals("global.ui.detailHeroId", id) ) {
if (suffix) {
id += suffix;
}
if (Session.equals("global.ui.detailHeroId", id)) {
return "hero";
}
});
});

View File

@@ -1,124 +0,0 @@
/*Template.registerHelper(function("effectList", */var disabled = function(charId, fieldName){
var obj = Characters.findOne(charId, {fields: {_id: 1}}).getField(fieldName);
var result = $("<div>");
if(_.has(obj, "conditional") && obj.conditional.length > 0){
_.each(obj.conditional, function(cond){
var c = $("<div>")
.append("* ")
.append(evaluateString(charId, cond.name));
result.append(c);
});
}
if(obj.base > 0){
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(obj.base))
.append("Base");
result.append(c);
}
if(_.has(obj, "proficiency") && obj.proficiency.length > 0){
var highestProf = {};
_.each(obj.proficiency, function(prof, i){
var value = evaluateEffect(charId, prof)
if(i === 0 || value > highestProf.value){
highestProf.value = value;
highestProf.name = prof.name;
highestProf.calculation = prof.calculation;
}
});
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(highestProf.value).append(" x Proficiency Bonus"))
.append(highestProf.name);
result.append(c);
}
if(_.has(obj, "add") && obj.add.length > 0){
_.each(obj.add, function(a){
var value = signedString(evaluateEffect(charId, a));
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(value))
.append(a.name);
result.append(c);
});
}
if(_.has(obj, "mul") && obj.mul.length > 0){
_.each(obj.mul, function(a){
var value = signedString(evaluateEffect(charId, a));
var c = $("<div>")
.append($("<span>").addClass("auditValue").append("&times;").append(value))
.append(a.name);
result.append(c);
});
}
if(_.has(obj, "min") && obj.min.length > 0){
var highestMin = {};
_.each(obj.min, function(m, i){
var value = evaluateEffect(charId, m)
if(i === 0 || value > highestMin.value){
highestMin.value = value;
highestMin.name = m.name;
highestMin.calculation = m.calculation;
}
});
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(highestMin.value).append(" Minimum"))
.append(highestMin.name);
result.append(c);
}
if(_.has(obj, "max") && obj.max.length > 0){
var lowestMax = {};
_.each(obj.max, function(m, i){
var value = evaluateEffect(charId, m)
if(i === 0 || value < lowestMax.value){
lowestMax.value = value;
lowestMax.name = m.name;
lowestMax.calculation = m.calculation;
}
});
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(lowestMax.value).append(" Maximum"))
.append(lowestMax.name);
result.append(c);
}
if(obj.base < 0){
var c = $("<div>")
.append($("<span>").addClass("auditValue").append(obj.base))
.append("Damage");
result.append(c);
}
if(_.has(obj, "advantage") && obj.advantage.length > 0){
_.each(obj.advantage, function(adv){
var c = $("<div>")
.append($("<span>").addClass("auditValue").append("Advantage"))
.append(adv.name);
result.append(c);
})
}
if(_.has(obj, "disadvantage") && obj.disadvantage.length > 0){
_.each(obj.disadvantage, function(disadv){
var c = $("<div>")
.append($("<span>").addClass("auditValue").append("Disadvantage"))
.append(disadv.name);
result.append(c);
})
}
if(_.has(obj, "fail") && obj.fail.length > 0){
_.each(obj.fail, function(f){
var c = $("<div>")
.append($("<span>").addClass("auditValue").append("Fail"))
.append(f.name);
result.append(c);
})
}
var string = result.html()
if (_.isString(string)) return Spacebars.SafeString(string);
return string;
};

View File

@@ -1,25 +1,25 @@
Template.registerHelper("evaluate", function(charId, string){
Template.registerHelper("evaluate", function(charId, string) {
return evaluate(charId, string);
});
Template.registerHelper("evaluateSigned", function(charId, string){
Template.registerHelper("evaluateSigned", function(charId, string) {
var number = evaluate(charId, string);
if(_.isFinite(number)){
return number > 0? "+" + number : "" + number;
} else{
if (_.isFinite(number)) {
return number > 0 ? "+" + number : "" + number;
} else {
return number;
}
});
Template.registerHelper("evaluateSignedSpaced", function(charId, string){
Template.registerHelper("evaluateSignedSpaced", function(charId, string) {
var number = evaluate(charId, string);
if(_.isFinite(number)){
return number > 0? "+ " + number : "- " + (-1 * number);
} else{
if (_.isFinite(number)) {
return number > 0 ? "+ " + number : "- " + (-1 * number);
} else {
return number;
}
});
Template.registerHelper("evaluateString", function(charId, string){
Template.registerHelper("evaluateString", function(charId, string) {
return evaluateString(charId, string);
});

View File

@@ -1,21 +1,21 @@
openParentDialog = function(parent, charId, heroId){
openParentDialog = function(parent, charId, heroId) {
var detail;
if(parent.collection === "Characters" && parent.group === "racial"){
if (parent.collection === "Characters" && parent.group === "racial") {
detail = {
template: "raceDialog",
data: {charId: parent.id},
};
} else if( parent.collection === "Features" ){
} else if (parent.collection === "Features") {
detail = {
template: "featureDialog",
data: {featureId: parent.id},
};
} else if( parent.collection === "Classes" ){
} else if (parent.collection === "Classes") {
detail = {
template: "classDialog",
data: {classId: parent.id},
};
} else if( parent.collection === "Items" ){
} else if (parent.collection === "Items") {
detail = {
template: "itemDialog",
data: {itemId: parent.id},

View File

@@ -1,6 +1,6 @@
Template.registerHelper("round", function(value, decimalPlaces){
Template.registerHelper("round", function(value, decimalPlaces) {
decimalPlaces = +decimalPlaces || 2;
var num = +value;
var tens = Math.pow(10, decimalPlaces)
var tens = Math.pow(10, decimalPlaces);
return Math.round(num * tens) / tens;
});
});

View File

@@ -1,3 +1,3 @@
Template.registerHelper("session", function(key){
Template.registerHelper("session", function(key) {
return Session.get(key);
});
});

View File

@@ -1,3 +1,3 @@
Template.registerHelper("signedString", function(number){
return number >= 0? "+" + number : "" + number;
});
Template.registerHelper("signedString", function(number) {
return number >= 0 ? "+" + number : "" + number;
});

View File

@@ -1,21 +1,27 @@
Template.registerHelper("valueString", function(value){
Template.registerHelper("valueString", function(value) {
var resultArray = [];
//sp
var gp = Math.floor(value);
if(gp > 0) resultArray.push(gp + "gp");
if (gp > 0) {
resultArray.push(gp + "gp");
}
//sp
var sp = Math.floor(10 * (value % 1));
if(sp > 0) resultArray.push(sp + "sp");
if (sp > 0) {
resultArray.push(sp + "sp");
}
//cp
var cp = 10 * ((value * 10) % 1);
cp = Math.round(cp * 1000) / 1000;
if(cp > 0) resultArray.push(cp + "cp");
if (cp > 0) {
resultArray.push(cp + "cp");
}
//build string with correct spacing
var result = "";
for(var i = 0; i < resultArray.length; i++){
for (var i = 0; i < resultArray.length; i++) {
//add a space between values
if(i !== 0){
if (i !== 0) {
result += " ";
}
result += resultArray[i];
@@ -23,24 +29,30 @@ Template.registerHelper("valueString", function(value){
return result;
});
Template.registerHelper("longValueString", function(value){
Template.registerHelper("longValueString", function(value) {
var resultArray = [];
//sp
var gp = Math.floor(value);
if(gp > 0) resultArray.push(gp + "gp");
if (gp > 0) {
resultArray.push(gp + "gp");
}
//sp
var sp = Math.floor(10 * (value % 1));
if(sp > 0 || resultArray.length) resultArray.push(sp + "sp");
if (sp > 0 || resultArray.length) {
resultArray.push(sp + "sp");
}
//cp
var cp = 10 * ((value * 10) % 1);
cp = Math.round(cp * 1000) / 1000;
if(cp > 0 || resultArray.length) resultArray.push(cp + "cp");
if (cp > 0 || resultArray.length) {
resultArray.push(cp + "cp");
}
//build string with correct spacing
var result = "";
for(var i = 0; i < resultArray.length; i++){
for (var i = 0; i < resultArray.length; i++) {
//add a space between values
if(i !== 0){
if (i !== 0) {
result += " ";
}
result += resultArray[i];

View File

@@ -1,44 +1,45 @@
var damageTypes = ["bludgeoning", "piercing", "slashing", "acid", "cold", "fire", "force", "lightning", "necrotic",
var damageTypes = ["bludgeoning", "piercing", "slashing",
"acid", "cold", "fire", "force", "lightning", "necrotic",
"poison", "psychic", "radiant", "thunder"];
Template.attackEdit.events({
"tap #deleteAttack": function(event, instance){
"tap #deleteAttack": function(event, instance) {
Attacks.softRemoveNode(this._id);
GlobalUI.deletedToast(this._id, "Attacks", "Attack");
},
"change #attackBonusInput": function(event){
"change #attackBonusInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {attackBonus: value}});
},
"change #damageInput": function(event){
"change #damageInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {damageBonus: value}});
},
"change #detailInput": function(event){
"change #detailInput": function(event) {
var value = event.currentTarget.value;
Attacks.update(this._id, {$set: {details: value}});
},
"core-select #damageTypeDropdown": function(event){
"core-select #damageTypeDropdown": function(event) {
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if(value == this.damageType) return;
if (value == this.damageType) return;
Attacks.update(this._id, {$set: {damageType: value}});
},
"core-select #damageDiceDropdown": function(event){
"core-select #damageDiceDropdown": function(event) {
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if(value == this.damageDice) return;
if (value == this.damageDice) return;
Attacks.update(this._id, {$set: {damageDice: value}});
}
});
Template.attackEdit.helpers({
damageTypes: function(){
damageTypes: function() {
return damageTypes;
},
DAMAGE_DICE: function(){
DAMAGE_DICE: function() {
return DAMAGE_DICE;
}
});
});

View File

@@ -1,12 +1,12 @@
Template.attackEditList.helpers({
attacks: function(){
attacks: function() {
var cursor = Attacks.find({"parent.id": this.parentId, charId: this.charId});
return cursor;
}
});
Template.attackEditList.events({
"tap #addAttackButton": function(){
"tap #addAttackButton": function() {
Attacks.insert({
charId: this.charId,
parent: {

View File

@@ -1,5 +1,5 @@
Template.attacksViewList.helpers({
attacks: function(){
attacks: function() {
return Attacks.find({"parent.id": this.parentId, charId: this.charId});
}
});

View File

@@ -1,3 +1,3 @@
Template.characterSettings.events({
});

View File

@@ -1,23 +1,25 @@
Template.deleteCharacterConfirmation.onCreated(function(){
Template.deleteCharacterConfirmation.onCreated(function() {
this.canDelete = new ReactiveVar(false);
});
Template.deleteCharacterConfirmation.helpers({
cantDelete: function(){
cantDelete: function() {
return !Template.instance().canDelete.get();
},
getStyle: function(){
if(Template.instance().canDelete.get()) return "background: #d23f31; color: white;";
getStyle: function() {
if (Template.instance().canDelete.get()) {
return "background: #d23f31; color: white;";
}
}
});
Template.deleteCharacterConfirmation.events({
"change #nameInput, input #nameInput": function(event, instance){
"change #nameInput, input #nameInput": function(event, instance) {
var canDel = instance.find("#nameInput").value === this.name;
instance.canDelete.set(canDel);
},
"tap #deleteButton": function(event, instance){
if(instance.find("#nameInput").value === this.name){
"tap #deleteButton": function(event, instance) {
if (instance.find("#nameInput").value === this.name) {
GlobalUI.closeDialog();
Router.go("/");
Characters.remove(this._id);

View File

@@ -22,13 +22,14 @@ Template.shareDialog.helpers({
});
Template.shareDialog.events({
"input #userNameOrEmailInput, change #userNameOrEmailInput": function(event, instance){
"input #userNameOrEmailInput, change #userNameOrEmailInput":
function(event, instance){
var userName = instance.find("#userNameOrEmailInput").value;
instance.userId.set(undefined);
Meteor.call("getUserId", userName, function (err, result) {
if(err){
Meteor.call("getUserId", userName, function(err, result) {
if (err){
console.error(err);
} else{
} else {
console.log(result);
instance.userId.set(result);
}
@@ -37,10 +38,10 @@ Template.shareDialog.events({
"tap #shareButton": function(event, instance){
var self = this;
var permission = instance.find("#accessLevelMenu").selected;
if(!permission) throw "no permission set";
if (!permission) throw "no permission set";
var userId = instance.userId.get();
if(!userId) return;
if(permission === "write"){
if (!userId) return;
if (permission === "write"){
Characters.update(self._id, {
$addToSet: {writers: userId},
$pull: {readers: userId}

View File

@@ -112,8 +112,8 @@ Template.effectEdit.helpers({
},
operations: function(){
var group = Template.instance().selectedStatGroup.get();
if(group === "Weakness/Resistance") return null;
if(group === "Saving Throws" || group === "Skills"){
if (group === "Weakness/Resistance") return null;
if (group === "Saving Throws" || group === "Skills"){
return skillOperations;
} else {
return attributeOperations;
@@ -122,14 +122,14 @@ Template.effectEdit.helpers({
effectValueTemplate: function(){
//resistance/vulnerability template
var group = Template.instance().selectedStatGroup.get();
if(group === "Weakness/Resistance") return "multiplierEffectValue";
if (group === "Weakness/Resistance") return "multiplierEffectValue";
var op = this.operation;
if(!op) return null;
if (!op) return null;
//operations that don't need templates
if(op === "advantage" || op === "disadvantage" || op === "fail") return null;
if (op === "advantage" || op === "disadvantage" || op === "fail") return null;
//proficiency template
if(op === "proficiency") return "proficiencyEffectValue";
if (op === "proficiency") return "proficiencyEffectValue";
//default template
return "regularEffectValue";
@@ -149,44 +149,57 @@ Template.effectEdit.events({
},
"core-select .statGroupDropDown": function(event, instance){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var groupName = detail.item.getAttribute("name");
var oldName = Template.instance().selectedStatGroup.get();
if(oldName != groupName){
if (oldName != groupName){
instance.selectedStatGroup.set(groupName);
if(groupName === "Skills" || groupName === "Saving Throws"){
Effects.update(this._id, {$set: {operation: "proficiency", value: 1, calculation: ""}, $unset: {stat: ""} });
} else if(groupName === "Weakness/Resistance"){
Effects.update(this._id, {$set: {value: 0.5, calculation: "", operation: "mul"}, $unset: {stat: ""} });
if (groupName === "Skills" || groupName === "Saving Throws"){
Effects.update(this._id, {$set: {
operation: "proficiency",
value: 1,
calculation: ""
}, $unset: {stat: ""}});
} else 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: ""} });
Effects.update(this._id,
{$set: {operation: "add"},
$unset: {stat: "", value: "", calculation: ""}});
}
}
},
"core-select .statDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var statName = detail.item.getAttribute("name");
if (statName == this.stat) return;
Effects.update(this._id, {$set: {stat: statName}});
},
"core-select .operationDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var opName = detail.item.getAttribute("name");
if (opName == this.operation) return;
Effects.update(this._id, {$set: {operation: opName}});
},
"core-select .damageMultiplierDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = +detail.item.getAttribute("name");
if (value == this.value) return;
Effects.update(this._id, {$set: {value: value, calculation: "", operation: "mul"}});
Effects.update(this._id, {$set: {
value: value,
calculation: "",
operation: "mul"
}});
},
"core-select .proficiencyDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = +detail.item.getAttribute("name");
if (value == this.value) return;
Effects.update(this._id, {$set: {value: value, calculation: ""}});
@@ -194,7 +207,7 @@ Template.effectEdit.events({
"change .effectValueInput": function(event){
var value = event.currentTarget.value;
var numValue = +value;
if(_.isFinite(numValue)){
if (_.isFinite(numValue)){
if (this.value === numValue) return;
Effects.update(this._id, {$set: {value: numValue, calculation: ""}});
} else if (_.isString(value)){

View File

@@ -6,31 +6,31 @@ var stats = {
"intelligence":{"name":"Intelligence"},
"wisdom":{"name":"Wisdom"},
"charisma":{"name":"Charisma"},
"strengthSave":{"name":"Strength Save",},
"dexteritySave":{"name":"Dexterity Save",},
"constitutionSave":{"name":"Constitution Save",},
"intelligenceSave":{"name":"Intelligence Save",},
"wisdomSave":{"name":"Wisdom Save",},
"charismaSave":{"name":"Charisma Save",},
"acrobatics":{"name":"Acrobatics",},
"animalHandling":{"name":"Animal Handling",},
"arcana":{"name":"Arcana",},
"athletics":{"name":"Athletics",},
"deception":{"name":"Deception",},
"history":{"name":"History",},
"insight":{"name":"Insight",},
"intimidation":{"name":"Intimidation",},
"investigation":{"name":"Investigation",},
"medicine":{"name":"Medicine",},
"nature":{"name":"Nature",},
"perception":{"name":"Perception",},
"performance":{"name":"Performance",},
"persuasion":{"name":"Persuasion",},
"religion":{"name":"Religion",},
"sleightOfHand":{"name":"Sleight of Hand",},
"stealth":{"name":"Stealth",},
"survival":{"name":"Survival",},
"initiative":{"name":"Initiative",},
"strengthSave":{"name":"Strength Save"},
"dexteritySave":{"name":"Dexterity Save"},
"constitutionSave":{"name":"Constitution Save"},
"intelligenceSave":{"name":"Intelligence Save"},
"wisdomSave":{"name":"Wisdom Save"},
"charismaSave":{"name":"Charisma Save"},
"acrobatics":{"name":"Acrobatics"},
"animalHandling":{"name":"Animal Handling"},
"arcana":{"name":"Arcana"},
"athletics":{"name":"Athletics"},
"deception":{"name":"Deception"},
"history":{"name":"History"},
"insight":{"name":"Insight"},
"intimidation":{"name":"Intimidation"},
"investigation":{"name":"Investigation"},
"medicine":{"name":"Medicine"},
"nature":{"name":"Nature"},
"perception":{"name":"Perception"},
"performance":{"name":"Performance"},
"persuasion":{"name":"Persuasion"},
"religion":{"name":"Religion"},
"sleightOfHand":{"name":"Sleight of Hand"},
"stealth":{"name":"Stealth"},
"survival":{"name":"Survival"},
"initiative":{"name":"Initiative"},
"hitPoints":{"name":"Hit Points"},
"armor":{"name":"Armor"},
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
@@ -56,18 +56,42 @@ var stats = {
"d10HitDice":{"name":"d10 Hit Dice"},
"d12HitDice":{"name":"d12 Hit Dice"},
"acidMultiplier":{"name":"Acid damage", "group": "Weakness/Resistance"},
"bludgeoningMultiplier":{"name":"Bludgeoning damage", "group": "Weakness/Resistance"},
"coldMultiplier":{"name":"Cold damage", "group": "Weakness/Resistance"},
"fireMultiplier":{"name":"Fire damage", "group": "Weakness/Resistance"},
"forceMultiplier":{"name":"Force damage", "group": "Weakness/Resistance"},
"lightningMultiplier":{"name":"Lightning damage", "group": "Weakness/Resistance"},
"necroticMultiplier":{"name":"Necrotic damage", "group": "Weakness/Resistance"},
"piercingMultiplier":{"name":"Piercing damage", "group": "Weakness/Resistance"},
"poisonMultiplier":{"name":"Poison damage", "group": "Weakness/Resistance"},
"psychicMultiplier":{"name":"Psychic damage", "group": "Weakness/Resistance"},
"radiantMultiplier":{"name":"Radiant damage", "group": "Weakness/Resistance"},
"slashingMultiplier":{"name":"Slashing damage", "group": "Weakness/Resistance"},
"thunderMultiplier":{"name":"Thunder damage", "group": "Weakness/Resistance"}
"bludgeoningMultiplier":{
"name":"Bludgeoning damage", "group": "Weakness/Resistance"
},
"coldMultiplier":{
"name":"Cold damage", "group": "Weakness/Resistance"
},
"fireMultiplier":{
"name":"Fire damage", "group": "Weakness/Resistance"
},
"forceMultiplier":{
"name":"Force damage", "group": "Weakness/Resistance"
},
"lightningMultiplier":{
"name":"Lightning damage", "group": "Weakness/Resistance"
},
"necroticMultiplier":{
"name":"Necrotic damage", "group": "Weakness/Resistance"
},
"piercingMultiplier":{
"name":"Piercing damage", "group": "Weakness/Resistance"
},
"poisonMultiplier":{
"name":"Poison damage", "group": "Weakness/Resistance"
},
"psychicMultiplier":{
"name":"Psychic damage", "group": "Weakness/Resistance"
},
"radiantMultiplier":{
"name":"Radiant damage", "group": "Weakness/Resistance"
},
"slashingMultiplier":{
"name":"Slashing damage", "group": "Weakness/Resistance"
},
"thunderMultiplier":{
"name":"Thunder damage", "group": "Weakness/Resistance"
},
};
var operations = {
@@ -107,7 +131,7 @@ Template.effectView.helpers({
},
operationName: function(){
if(this.operation === "proficiency" ||
this.operation === "conditional") return null;
this.operation === "conditional") return null;
if(stats[this.stat].group === "Weakness/Resistance") return null;
if(this.operation === "add" && evaluateEffect(this.charId, this) < 0) return null;
return operations[this.operation] && operations[this.operation].name || "No Operation";
@@ -127,9 +151,9 @@ Template.effectView.helpers({
return this.calculation || this.value;
}
if(stats[this.stat].group === "Weakness/Resistance"){
if(this.value == 0.5 || this.calculation == 0.5) return "Resistance";
if(this.value == 2 || this.calculation == 2) return "Vulnerability";
if(this.value == 0 || this.calculation == 0) return "Immunity";
if(this.value === 0.5) return "Resistance";
if(this.value === 2) return "Vulnerability";
if(this.value === 0) return "Immunity";
}
var value = evaluateEffect(this.charId, this);
if(_.isNumber(value)) return value;

View File

@@ -5,7 +5,7 @@ Template.effectsEditList.helpers({
"parent.collection": this.parentCollection,
"charId": this.charId
};
if(this.parentGroup){
if (this.parentGroup){
selector["parent.group"] = this.parentGroup;
}
var cursor = Effects.find(selector);
@@ -15,7 +15,7 @@ Template.effectsEditList.helpers({
Template.effectsEditList.events({
"tap #addEffectButton": function(){
if ( !_.isBoolean(this.enabled) ) {
if (!_.isBoolean(this.enabled)) {
this.enabled = true;
}
Effects.insert({
@@ -29,4 +29,4 @@ Template.effectsEditList.events({
enabled: this.enabled
});
},
});
});

View File

@@ -4,7 +4,7 @@ Template.effectsViewList.helpers({
"parent.id": this.parentId,
"charId": this.charId
};
if(this.parentGroup){
if (this.parentGroup){
selector["parent.group"] = this.parentGroup;
}
return Effects.find(selector, {fields: {parent: 0}});

View File

@@ -17,7 +17,7 @@ Template.featureDialog.events({
Template.featureDetails.helpers({
or: function(a, b){
return a ||b;
return a || b;
},
hasUses: function(){
return this.usesValue() > 0;
@@ -43,7 +43,7 @@ Template.featureDetails.events({
"change .enabledCheckbox": function(event){
var enabled = !this.enabled;
Features.update(this._id, {$set: {enabled: enabled}});
}
},
});
Template.featureEdit.onRendered(function(){
@@ -55,10 +55,10 @@ Template.featureEdit.helpers({
return _.isString(this.uses);
},
enabledSelection: function(){
if(!this.enabled) return "disabled";
if(this.alwaysEnabled) return "alwaysEnabled";
if (!this.enabled) return "disabled";
if (this.alwaysEnabled) return "alwaysEnabled";
return "enabled";
}
},
});
Template.featureEdit.events({
@@ -73,7 +73,7 @@ Template.featureEdit.events({
"change #limitUseCheck": function(event){
var currentUses = this.uses;
var featureId = this._id;
if( event.target.checked && !_.isString(currentUses) ){
if (event.target.checked && !_.isString(currentUses)){
Features.update(featureId, {$set: {uses: ""}}, {removeEmptyStrings: false});
} else if (!event.target.checked && _.isString(currentUses)){
Features.update(featureId, {$unset: {uses: ""}});
@@ -86,17 +86,18 @@ Template.featureEdit.events({
},
"core-select #enabledDropdown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
var setter;
if(value === "enabled"){
if (value === "enabled"){
setter = {enabled: true, alwaysEnabled: false};
} else if (value === "disabled"){
setter = {enabled: false, alwaysEnabled: false};
} else{
} else {
setter = {enabled: true, alwaysEnabled: true};
}
if (setter.enabled === this.enabled && setter.alwaysEnabled === this.alwaysEnabled) return;
if (setter.enabled === this.enabled &&
setter.alwaysEnabled === this.alwaysEnabled) return;
Features.update(this._id, {$set: setter});
},
});

View File

@@ -19,7 +19,9 @@ Template.features.helpers({
return _.indexOf(_.keys(colorOptions), this.color);
},
attacks: function(){
return Attacks.find({charId: this._id, enabled: true}, {sort: {color: 1, name: 1}});
return Attacks.find(
{charId: this._id, enabled: true},
{sort: {color: 1, name: 1}});
},
canEnable: function(){
return !this.alwaysEnabled;
@@ -41,7 +43,7 @@ Template.features.events({
GlobalUI.setDetail({
template: "featureDialog",
data: {featureId: featureId, charId: this._id, startEditing: true},
heroId: featureId
heroId: featureId,
});
},
"tap #addAttackButton": function(event){
@@ -49,11 +51,11 @@ Template.features.events({
Attacks.insert({
charId: charId
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "attackDialog",
data: {attackId: id, charId: charId},
heroId: id
heroId: id,
});
}
});
@@ -64,7 +66,7 @@ Template.features.events({
GlobalUI.setDetail({
template: "featureDialog",
data: {featureId: featureId, charId: charId},
heroId: featureId
heroId: featureId,
});
},
"tap .attack": function(event){
@@ -82,8 +84,13 @@ Template.features.events({
var charId = this._id;
GlobalUI.setDetail({
template: "textDialog",
data: {charId: charId, field: "proficiencies", title: "Proficiencies", color: "q"},
heroId: this._id + "proficiencies"
data: {
charId: charId,
field: "proficiencies",
title: "Proficiencies",
color: "q",
},
heroId: this._id + "proficiencies",
});
},
"tap .enabledCheckbox": function(event){
@@ -92,45 +99,48 @@ Template.features.events({
"change .enabledCheckbox": function(event){
var enabled = !this.enabled;
Features.update(this._id, {$set: {enabled: enabled}});
}
},
});
Template.resource.helpers({
cantIncrement: function(){
return !(this.char.attributeValue(this.name) < this.char.attributeBase(this.name));
var baseBigger = this.char.attributeValue(this.name) <
this.char.attributeBase(this.name);
return !baseBigger;
},
cantDecrement: function(){
return !(this.char.attributeValue(this.name) > 0);
var valuePositive = this.char.attributeValue(this.name) > 0;
return !valuePositive;
},
getColor: function(){
if(this.char.attributeValue(this.name) > 0){
if (this.char.attributeValue(this.name) > 0){
return this.color;
} else {
return "grey";
}
}
},
});
Template.resource.events({
"tap .resourceUp": function(event){
if(this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
if (this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = 1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .resourceDown": function(event){
if(this.char.attributeValue(this.name) > 0){
if (this.char.attributeValue(this.name) > 0){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = -1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .containerRight": function (event, instance) {
"tap .containerRight": function(event, instance) {
GlobalUI.setDetail({
template: "attributeDialog",
data: {name: this.title, statName: this.name, charId: this.char._id},
heroId: this.char._id + this.name
heroId: this.char._id + this.name,
});
}
},
});

View File

@@ -14,7 +14,10 @@ Template.containerEdit.events({
},
"tap #deleteButton": function(event, instance){
Containers.softRemoveNode(instance.data.containerId);
GlobalUI.deletedToast(instance.data.containerId, "Containers", "Container and contents");
GlobalUI.deletedToast(
instance.data.containerId,
"Containers", "Container and contents"
);
GlobalUI.closeDetail();
},
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
@@ -30,8 +33,8 @@ Template.containerEdit.events({
var value = +Template.instance().find("#valueInput").value;
Containers.update(this._id, {$set: {value: value}});
},
"change #containerDescriptionInput": function(event){
var description = Template.instance().find("#containerDescriptionInput").value;
"change #containerDescriptionInput": function(event, instance){
var description = instance.find("#containerDescriptionInput").value;
Containers.update(this._id, {$set: {description: description}});
}
},
});

View File

@@ -7,16 +7,28 @@ Template.inventory.helpers({
return Containers.find({charId: this._id}, {sort: {color: 1, name: 1}});
},
items: function(charId, containerId){
return Items.find({charId: charId, "parent.id": containerId }, {sort: {color: 1, name: 1}});
return Items.find(
{charId: charId, "parent.id": containerId},
{sort: {color: 1, name: 1}}
);
},
attuned: function(){
return Items.find({ charId: this._id, enabled: true, requiresAttunement: true }, {sort: {color: 1, name: 1}});
return Items.find(
{charId: this._id, enabled: true, requiresAttunement: true},
{sort: {color: 1, name: 1}}
);
},
equipment: function(){
return Items.find({ charId: this._id, enabled: true, requiresAttunement: false }, {sort: {color: 1, name: 1}});
return Items.find(
{charId: this._id, enabled: true, requiresAttunement: false},
{sort: {color: 1, name: 1}}
);
},
carriedItems: function(){
return Items.find({charId: this._id, enabled: false, "parent.id": this._id}, {sort: {color: 1, name: 1}});
return Items.find(
{charId: this._id, enabled: false, "parent.id": this._id},
{sort: {color: 1, name: 1}}
);
},
showAddButtons: function(){
return Template.instance().showAddButtons.get();
@@ -26,45 +38,64 @@ Template.inventory.helpers({
},
netWorth: function(){
var worth = 0;
Items.find({charId: this._id}, {fields: {value : 1, quantity: 1}}).forEach(function(item){
Items.find(
{charId: this._id},
{fields: {value : 1, quantity: 1}}
).forEach(function(item){
worth += item.totalValue();
});
return worth;
},
weightCarried: function(){
var weight = 0;
Containers.find({charId: this._id, isCarried: true}).forEach(function(container){
Containers.find(
{charId: this._id, isCarried: true}
).forEach(function(container){
weight += container.totalWeight();
});
Items.find({charId: this._id, "parent.id": this._id}, {fields: {weight : 1, quantity: 1}}).forEach(function(item){
Items.find(
{charId: this._id, "parent.id": this._id},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
return weight;
},
equipmentValue: function(){
var value = 0;
Items.find({charId: this._id, enabled: true}, {fields: {value : 1, quantity: 1}}).forEach(function(item){
Items.find(
{charId: this._id, enabled: true},
{fields: {value : 1, quantity: 1}}
).forEach(function(item){
value += item.totalValue();
});
return value;
},
equipmentWeight: function(){
var weight = 0;
Items.find({charId: this._id, enabled: true}, {fields: {weight : 1, quantity: 1}}).forEach(function(item){
Items.find({charId: this._id, enabled: true},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
return weight;
},
carriedValue: function(){
var value = 0;
Items.find({charId: this._id, enabled: false, "parent.id": this._id}, {fields: {value : 1, quantity: 1}}).forEach(function(item){
Items.find(
{charId: this._id, enabled: false, "parent.id": this._id},
{fields: {value : 1, quantity: 1}}
).forEach(function(item){
value += item.totalValue();
});
return value;
},
carriedWeight: function(){
var weight = 0;
Items.find({charId: this._id, enabled: false, "parent.id": this._id}, {fields: {weight : 1, quantity: 1}}).forEach(function(item){
Items.find(
{charId: this._id, enabled: false, "parent.id": this._id},
{fields: {weight : 1, quantity: 1}}
).forEach(function(item){
weight += item.totalWeight();
});
return weight;
@@ -78,23 +109,31 @@ Template.inventory.events({
charId: charId,
parent:{
id: charId,
collection: "Characters"
}
collection: "Characters",
},
}, function(err, itemId){
if(err) throw err;
if (err) throw err;
GlobalUI.setDetail({
template: "itemDialog",
data: {itemId: itemId, charId: charId, startEditing: true},
heroId: itemId
heroId: itemId,
});
});
},
"tap #addContainer": function(event){
var containerId = Containers.insert({name: "New Container", isCarried: true, charId: this._id});
var containerId = Containers.insert({
name: "New Container",
isCarried: true,
charId: this._id,
});
GlobalUI.setDetail({
template: "containerDialog",
data: {containerId: containerId, charId: this.charId, startEditing: true},
heroId: containerId
data: {
containerId: containerId,
charId: this.charId,
startEditing: true,
},
heroId: containerId,
});
},
"tap .inventoryItem": function(event){
@@ -103,14 +142,14 @@ Template.inventory.events({
GlobalUI.setDetail({
template: "itemDialog",
data: {itemId: itemId, charId: charId},
heroId: itemId
heroId: itemId,
});
},
"tap .containerTop": function(event){
GlobalUI.setDetail({
template: "containerDialog",
data: {containerId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap .carriedCheckbox": function(event){
@@ -118,10 +157,10 @@ Template.inventory.events({
},
"change .carriedCheckbox": function(event){
var carried;
if(this.isCarried) carried = false;
if (this.isCarried) carried = false;
else carried = true;
Containers.update(this._id, {$set: {isCarried: carried}});
}
},
});
Template.inventoryItem.helpers({
@@ -129,8 +168,8 @@ Template.inventoryItem.helpers({
return num !== 1;
},
hidden: function(){
return Session.equals("inventory.dragItemId", this._id)? "hidden" : null;
}
return Session.equals("inventory.dragItemId", this._id) ? "hidden" : null;
},
});
Template.layout.events({
@@ -153,17 +192,17 @@ Template.layout.events({
},
"drop .itemContainer": function(event, instacne){
var item = Items.findOne(Session.get("inventory.dragItemId"));
if(event.ctrlKey){
if (event.ctrlKey){
//split the stack to the container
GlobalUI.showDialog({
template: "splitStackDialog",
data: {
id: item._id,
parentCollection: "Containers",
parentId: this._id
}
parentId: this._id,
},
});
} else{
} else {
//move item to the container
item.moveToContainer(this._id);
}
@@ -178,22 +217,22 @@ Template.layout.events({
"drop .carriedContainer": function(event, instance){
var charId = Session.get("inventory.dragItemOriginalCharacter");
var item = Items.findOne(Session.get("inventory.dragItemId"));
if(event.ctrlKey){
if (event.ctrlKey){
//split the stack to the container
GlobalUI.showDialog({
template: "splitStackDialog",
data: {
id: item._id,
parentCollection: "Characters",
parentId: this._id
}
parentId: this._id,
},
});
} else{
} else {
//move item to the character
item.moveToCharacter(this._id);
}
resetInvetorySession();
}
},
});
var resetInvetorySession = function(){

View File

@@ -1,5 +1,8 @@
var getContainers = function(charId){
return Containers.find({charId: charId}, {sort: {name: 1, _id: 1}, fields: {name: 1}});
return Containers.find(
{charId: charId},
{sort: {name: 1, _id: 1}, fields: {name: 1}}
);
};
Template.itemDialog.onCreated(function(){
@@ -14,13 +17,13 @@ Template.itemDialog.helpers({
return Template.instance().editing.get();
},
itemHeading: function(){
if(this.quantity === 1){
if (this.quantity === 1){
return this.name;
} else{
} else {
var pName = this.plural || this.name;
return this.quantity + " " + pName;
}
}
},
});
Template.itemDialog.events({
@@ -79,8 +82,8 @@ Template.itemEdit.events({
"change #equippedInput": function(event){
var equipped = Template.instance().find("#equippedInput").checked;
var item = Items.findOne(this._id);
if(item){
if(equipped){
if (item){
if (equipped){
item.equip();
} else {
item.unequip();
@@ -90,7 +93,7 @@ Template.itemEdit.events({
"change #attunementCheckbox": function(event){
var value = event.currentTarget.checked;
Items.update(this._id, {$set: {requiresAttunement: value}});
}
},
});
Template.containerDropdown.helpers({
@@ -102,7 +105,7 @@ Template.containerDropdown.helpers({
Template.containerDropdown.events({
"core-select #containerDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var containerId = detail.item.getAttribute("name");
var item = Items.findOne(Template.currentData()._id);
item.moveToContainer(containerId);

View File

@@ -1,27 +1,28 @@
Template.splitStackDialog.helpers({
quantity: function(){
var item = Items.findOne(this.id);
if(item) return Math.round(item.quantity/2);
if (item) return Math.round(item.quantity / 2);
}
});
Template.splitStackDialog.events({
'tap #moveButton': function(event, instance){
"tap #moveButton": function(event, instance){
var item = Items.findOne(this.id);
if(item){
if (item){
item.splitToParent(
{collection: this.parentCollection , id: this.parentId},
+instance.find('#quantityInput').value
{collection: this.parentCollection , id: this.parentId},
+instance.find("#quantityInput").value
);
}
},
'tap #oneButton':function(event, instance){
instance.find('#quantityInput').value = 1;
"tap #oneButton":function(event, instance){
instance.find("#quantityInput").value = 1;
},
'tap #halfButton':function(event, instance){
instance.find('#quantityInput').value = Math.round(Items.findOne(this.id).quantity/2);
"tap #halfButton":function(event, instance){
var val = Math.round(Items.findOne(this.id).quantity / 2);
instance.find("#quantityInput").value = val;
},
"tap #allButton":function(event, instance){
instance.find("#quantityInput").value = Items.findOne(this.id).quantity;
},
'tap #allButton':function(event, instance){
instance.find('#quantityInput').value = Items.findOne(this.id).quantity;
}
});

View File

@@ -15,11 +15,11 @@ Template.classDialog.events({
"change #levelValueInput": function(event){
var value = event.currentTarget.value;
Classes.update(this._id, {$set: {level: value}});
}
},
});
Template.classDialog.helpers({
class: function(){
return Classes.findOne(this.classId);
}
});
});

View File

@@ -7,7 +7,10 @@ Template.experienceDialog.helpers({
Template.experienceDialog.events({
"tap #deleteButton": function(event, instance){
Experiences.softRemove(instance.data.experienceId);
GlobalUI.deletedToast(instance.data.experienceId, "Experiences", "Experience");
GlobalUI.deletedToast(
instance.data.experienceId,
"Experiences", "Experience"
);
GlobalUI.closeDetail();
},
//TODO validate input (integer, non-negative, etc) for these inputs and give validation errors
@@ -22,7 +25,7 @@ Template.experienceDialog.events({
"change #experienceDescriptionInput": function(event){
var value = event.currentTarget.value;
Experiences.update(this._id, {$set: {description: value}});
}
},
});
Template.experienceDialog.helpers({

View File

@@ -1,6 +1,8 @@
Template.journal.created = function(){
var self = this;
self.experiencesLimit = new ReactiveVar(self.data.settings && self.data.settings.experiencesInc || 10);
self.experiencesLimit = new ReactiveVar(
self.data.settings && self.data.settings.experiencesInc || 10
);
};
Template.journal.helpers({
@@ -8,17 +10,29 @@ Template.journal.helpers({
return Notes.find({charId: this._id}, {sort: {color: 1, name: 1}});
},
experiences: function(){
return Experiences.find({charId: this._id}, {sort: {dateAdded: -1}, limit: Template.instance().experiencesLimit.get()});
return Experiences.find(
{charId: this._id},
{
sort: {dateAdded: -1},
limit: Template.instance().experiencesLimit.get(),
}
);
},
notMoreExperiences: function(){
return Experiences.find({charId: this._id}).count() < Template.instance().experiencesLimit.get();
return Experiences.find(
{charId: this._id}
).count() < Template.instance().experiencesLimit.get();
},
cantCollapse: function(){
return Template.instance().experiencesLimit.get() <= (this.settings && this.settings.experiencesInc || 10);
return Template.instance().experiencesLimit.get() <=
(this.settings && this.settings.experiencesInc || 10);
},
moreExperiencesOrCollapse: function(){
return (!(Experiences.find({charId: this._id}).count() < Template.instance().experiencesLimit.get())) ||
Template.instance().experiencesLimit.get() > (this.settings && this.settings.experiencesInc || 10);
var allShown = Experiences.find({charId: this._id}).count() <
Template.instance().experiencesLimit.get();
var canCollapse = Template.instance().experiencesLimit.get() >
(this.settings && this.settings.experiencesInc || 10);
return !allShown || canCollapse;
},
classes: function(){
return Classes.find({charId: this._id}, {sort: {createdAt: 1}});
@@ -29,13 +43,13 @@ Template.journal.helpers({
nextLevelXP: function(){
var currentLevel = this.level();
if (currentLevel < 20){
return xpTable[currentLevel];
return XP_TABLE[currentLevel];
}
},
race: function(){
var char = Characters.findOne(this._id, {fields: {race: 1}});
return char && char.race;
}
},
});
Template.journal.events({
@@ -43,41 +57,41 @@ Template.journal.events({
GlobalUI.setDetail({
template: "noteDialog",
data: {noteId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap .experience": function(event){
GlobalUI.setDetail({
template: "experienceDialog",
data: {experienceId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap .class": function(event){
GlobalUI.setDetail({
template: "classDialog",
data: {classId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap .race": function(event){
GlobalUI.setDetail({
template: "raceDialog",
data: {charId: this._id},
heroId: this._id + "race"
heroId: this._id + "race",
});
},
"tap #addNote": function(event){
var charId = this._id;
Notes.insert({
name: "New Note",
charId: charId
name: "New Note",
charId: charId,
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "noteDialog",
data: {noteId: id, charId: charId, startEditing: true},
heroId: id
heroId: id,
});
}
});
@@ -87,11 +101,11 @@ Template.journal.events({
Experiences.insert({
charId: charId
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "experienceDialog",
data: {experienceId: id, charId: charId, startEditing: true},
heroId: id
heroId: id,
});
}
});
@@ -101,30 +115,39 @@ Template.journal.events({
Classes.insert({
charId: charId,
name: "new Class",
level: 1
level: 1,
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "classDialog",
data: {classId: id, charId: charId, startEditing: true},
heroId: id
heroId: id,
});
}
});
},
"tap #moreExperiences": function(event){
var inst = Template.instance();
inst.experiencesLimit.set(inst.experiencesLimit.get() + (this.settings && this.settings.experiencesInc || 10));
inst.experiencesLimit.set(
inst.experiencesLimit.get() +
(this.settings && this.settings.experiencesInc || 10)
);
},
"tap #lessExperiences": function(event){
var inst = Template.instance();
inst.experiencesLimit.set(this.settings && this.settings.experiencesInc || 10);
inst.experiencesLimit.set(
this.settings && this.settings.experiencesInc || 10
);
//scroll to the top of the div
inst.$(".scroll-y").animate({
scrollTop: inst.$(".scroll-y").scrollTop() + inst.$(".experiencesCard").position().top - 8
scrollTop: (
inst.$(".scroll-y").scrollTop() +
inst.$(".experiencesCard").position().top -
8
)
}, 300);
//HACK giggle the columns :( to workaround chrome bug that stops .containers height from updating
var cs = inst.$(".containers").removeClass("containers");
_.defer(function(){cs.addClass("containers");});
}
},
});

View File

@@ -18,11 +18,11 @@ Template.noteDialog.events({
"change #noteDescriptionInput": function(event){
var value = event.currentTarget.value;
Notes.update(this._id, {$set: {description: value}});
}
},
});
Template.noteDialog.helpers({
note: function(){
return Notes.findOne(this.noteId);
}
});
});

View File

@@ -14,4 +14,4 @@ Template.raceDialog.helpers({
var char = Characters.findOne(this.charId, {fields: {race: 1}});
return char && char.race;
}
});
});

View File

@@ -4,9 +4,9 @@ Template.newCharacterDialog.events({
name: instance.find("#nameInput").value,
gender: instance.find("#genderInput").value,
race: instance.find("#raceInput").value,
owner: Meteor.userId()
owner: Meteor.userId(),
}, function(err, id){
if(err) throw err;
if (err) throw err;
Router.go("characterSheet", {_id: id});
});
}

View File

@@ -5,18 +5,18 @@ Template.personaDetailsDialog.onRendered(function(){
Template.personaDetailsDialog.events({
"change #nameInput": function(event){
var input = event.currentTarget.value;
Characters.update( this.charId, {$set: {name: input}} );
Characters.update(this.charId, {$set: {name: input}});
},
"change #alignmentInput": function(event){
var input = event.currentTarget.value;
Characters.update( this.charId, {$set: {alignment: input}} );
Characters.update(this.charId, {$set: {alignment: input}});
},
"change #genderInput": function(event){
var input = event.currentTarget.value;
Characters.update( this.charId, {$set: {gender: input}} );
Characters.update(this.charId, {$set: {gender: input}});
},
"change #raceInput": function(event){
var input = event.currentTarget.value;
Characters.update( this.charId, {$set: {race: input}} );
}
Characters.update(this.charId, {$set: {race: input}});
},
});

View File

@@ -4,12 +4,15 @@ var colorMap = {
ideals: "g",
bonds: "h",
flaws: "i",
backstory: "j"
backstory: "j",
};
Template.persona.helpers({
characterDetails: function(){
var char = Characters.findOne(this._id, {fields: {name: 1, gender: 1, alignment: 1, race:1}});
var char = Characters.findOne(
this._id,
{fields: {name: 1, gender: 1, alignment: 1, race:1}}
);
char.field = "details";
char.title = char.name;
char.color = "d";
@@ -26,7 +29,7 @@ Template.persona.helpers({
field: field,
color: color,
body: char[field],
topClass: "characterField"
topClass: "characterField",
};
},
languages: function(){
@@ -36,20 +39,25 @@ Template.persona.helpers({
Template.persona.events({
"tap .characterField": function(event){
if(this.field !== "details"){
if (this.field !== "details"){
var charId = Template.parentData()._id;
GlobalUI.setDetail({
template: "textDialog",
data: {charId: charId, field: this.field, title: this.title, color: this.color},
heroId: this._id + this.field
data: {
charId: charId,
field: this.field,
title: this.title,
color: this.color,
},
heroId: this._id + this.field,
});
} else{
} else {
this.charId = Template.parentData()._id;
GlobalUI.setDetail({
template: "personaDetailsDialog",
data: this,
heroId: this._id + "details"
heroId: this._id + "details",
});
}
}
});
});

View File

@@ -18,4 +18,4 @@ Template.textDialog.events({
setter.$set[this.field] = input;
Characters.update(this.charId, setter);
}
});
});

View File

@@ -4,7 +4,7 @@ var profTypes = [
{type: "weapon", name: "Weapon"},
{type: "armor", name: "Armor"},
{type: "tool", name: "Tool"},
{type: "language", name: "Language"}
{type: "language", name: "Language"},
];
var saves = [
@@ -43,11 +43,11 @@ Template.proficiencyEdit.helpers({
return profTypes;
},
nameInputTemplate: function(){
if(!this.type) return null;
if(this.type === "skill"||
if (!this.type) return null;
if (this.type === "skill" ||
this.type === "save") return "nameDropdown";
return "nameInput";
}
},
});
Template.proficiencyEdit.events({
@@ -57,21 +57,21 @@ Template.proficiencyEdit.events({
},
"core-select .typeDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var type = detail.item.getAttribute("name");
if (type == this.type) return;
Proficiencies.update(this._id, {$set: {type: type}});
},
"core-select .valueDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = +detail.item.getAttribute("name");
if (value == this.value) return;
Proficiencies.update(this._id, {$set: {value: value}});
},
"core-select .nameDropDown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var name = detail.item.getAttribute("name");
if (name == this.name) return;
Proficiencies.update(this._id, {$set: {name: name}});
@@ -79,7 +79,7 @@ Template.proficiencyEdit.events({
"change .nameInput": function(event){
var name = event.currentTarget.value;
Proficiencies.update(this._id, {$set: {name: name}});
}
},
});
Template.nameDropdown.helpers({
@@ -87,4 +87,4 @@ Template.nameDropdown.helpers({
if (this.type === "skill") return skills;
if (this.type === "save") return saves;
}
});
});

View File

@@ -2,9 +2,9 @@ Template.proficiencyEditList.helpers({
proficiencies: function(){
var selector = {
"parent.id": this.parentId,
"charId": this.charId
"charId": this.charId,
};
if(this.parentGroup){
if (this.parentGroup){
selector["parent.group"] = this.parentGroup;
}
return Proficiencies.find(selector);
@@ -13,14 +13,14 @@ Template.proficiencyEditList.helpers({
Template.proficiencyEditList.events({
"tap #addProficiencyButton": function(){
if ( !_.isBoolean(this.enabled) ) {
if (!_.isBoolean(this.enabled)) {
this.enabled = true;
}
Proficiencies.insert({
charId: this.charId,
parent: {
id: this.parentId,
collection: this.parentCollection
collection: this.parentCollection,
},
enabled: this.enabled,
value: 1,

View File

@@ -1,16 +1,16 @@
Template.proficiencyListItem.helpers({
profIcon: function(){
var prof = this.value;
if(prof > 0 && prof < 1) return "image:brightness-2";
if(prof === 1) return "image:brightness-1";
if(prof > 1) return "av:album";
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
return "radio-button-off";
},
getName: function(){
if(this.type === "skill") return skills[this.name];
if(this.type === "save") return saves[this.name];
if (this.type === "skill") return skills[this.name];
if (this.type === "save") return saves[this.name];
return this.name;
}
},
});
Template.proficiencyListItem.events({

View File

@@ -32,14 +32,14 @@ var skills = {
Template.proficiencyView.helpers({
profIcon: function(){
var prof = this.value;
if(prof > 0 && prof < 1) return "image:brightness-2";
if(prof === 1) return "image:brightness-1";
if(prof > 1) return "av:album";
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
return "radio-button-off";
},
getName: function(){
if(this.type === "skill") return skills[this.name];
if(this.type === "save") return saves[this.name];
if (this.type === "skill") return skills[this.name];
if (this.type === "save") return saves[this.name];
return this.name;
}
},
});

View File

@@ -2,9 +2,9 @@ Template.proficiencyViewList.helpers({
proficiencies: function(){
var selector = {
"parent.id": this.parentId,
"charId": this.charId
"charId": this.charId,
};
if(this.parentGroup){
if (this.parentGroup){
selector["parent.group"] = this.parentGroup;
}
return Proficiencies.find(selector);

View File

@@ -1,14 +1,14 @@
var spellLevels = [
{ name: "Cantrip", level: 0 },
{ name: "Level 1", level: 1 },
{ name: "Level 2", level: 2 },
{ name: "Level 3", level: 3 },
{ name: "Level 4", level: 4 },
{ name: "Level 5", level: 5 },
{ name: "Level 6", level: 6 },
{ name: "Level 7", level: 7 },
{ name: "Level 8", level: 8 },
{ name: "Level 9", level: 9 },
{name: "Cantrip", level: 0},
{name: "Level 1", level: 1},
{name: "Level 2", level: 2},
{name: "Level 3", level: 3},
{name: "Level 4", level: 4},
{name: "Level 5", level: 5},
{name: "Level 6", level: 6},
{name: "Level 7", level: 7},
{name: "Level 8", level: 8},
{name: "Level 9", level: 9},
];
Template.spellDialog.helpers({
@@ -31,19 +31,19 @@ Template.spellDialog.events({
Template.spellDetails.helpers({
getComponents: function(){
var components = "";
if(this.components.concentration) components += "C";
if(this.components.verbal) components += components.length? ", V" : "V";
if(this.components.somatic) components += components.length? ", S" : "S";
if(this.components.material) {
components += components.length? ", M" : "M";
if (this.components.concentration) components += "C";
if (this.components.verbal) components += components.length ? ", V" : "V";
if (this.components.somatic) components += components.length ? ", S" : "S";
if (this.components.material) {
components += components.length ? ", M" : "M";
components += " (" + this.components.material + ")";
}
return components;
},
preparedString: function(){
if(this.prepared === "prepared") return "prepared";
if(this.prepared === "unprepared") return "unprepared";
if(this.prepared === "always") return "always prepared";
if (this.prepared === "prepared") return "prepared";
if (this.prepared === "unprepared") return "unprepared";
if (this.prepared === "always") return "always prepared";
},
});
@@ -65,9 +65,9 @@ Template.spellEdit.helpers({
return [
{name: "Prepared", value: "prepared"},
{name: "Unprepared", value: "unprepared"},
{name: "Always Prepared", value: "always"}
{name: "Always Prepared", value: "always"},
];
}
},
});
Template.spellEdit.events({
@@ -97,30 +97,30 @@ Template.spellEdit.events({
},
"core-select #listDropdown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if (value == this.parent.id) return;
Spells.update(this._id, {$set: {"parent.id": value}});
},
"core-select #levelDropdown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if(value == this.level) return;
if (value == this.level) return;
Spells.update(this._id, {$set: {level: value}});
},
"core-select #schoolDropdown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if(value == this.school) return;
if (value == this.school) return;
Spells.update(this._id, {$set: {school: value}});
},
"core-select #preparedDropdown": function(event){
var detail = event.originalEvent.detail;
if(!detail.isSelected) return;
if (!detail.isSelected) return;
var value = detail.item.getAttribute("name");
if(value == this.school) return;
if (value == this.school) return;
Spells.update(this._id, {$set: {prepared: value}});
},
"change #verbalCheckbox": function(event){

View File

@@ -8,7 +8,11 @@ Template.spellListDialog.events({
},
"tap #deleteButton": function(event, instance){
SpellLists.softRemoveNode(instance.data.spellListId);
GlobalUI.deletedToast(instance.data.spellListId, "SpellLists", "Spell list and contents");
GlobalUI.deletedToast(
instance.data.spellListId,
"SpellLists",
"Spell list and contents"
);
GlobalUI.closeDetail();
},
//TODO clean up String -> num here so they don't need casting by Schema.clean
@@ -21,11 +25,13 @@ Template.spellListDialog.events({
var value = event.currentTarget.value;
SpellLists.update(this._id, {$set: {saveDC: value}});
},
"change #spellListAttackBonusInput, input #spellListAttackBonusInput": function(event){
"change #spellListAttackBonusInput, input #spellListAttackBonusInput":
function(event){
var value = event.currentTarget.value;
SpellLists.update(this._id, {$set: {attackBonus: value}});
},
"change #spellListMaxPreparedInput, input #spellListMaxPreparedInput": function(event){
"change #spellListMaxPreparedInput, input #spellListMaxPreparedInput":
function(event){
var value = event.currentTarget.value;
SpellLists.update(this._id, {$set: {maxPrepared: value}});
},
@@ -39,4 +45,4 @@ Template.spellListDialog.helpers({
spellList: function(){
return SpellLists.findOne(this.spellListId);
}
});
});

View File

@@ -1,14 +1,14 @@
var spellLevels = [
{ name: "Cantrips", level: 0 },
{ name: "Level 1", level: 1 },
{ name: "Level 2", level: 2 },
{ name: "Level 3", level: 3 },
{ name: "Level 4", level: 4 },
{ name: "Level 5", level: 5 },
{ name: "Level 6", level: 6 },
{ name: "Level 7", level: 7 },
{ name: "Level 8", level: 8 },
{ name: "Level 9", level: 9 },
{name: "Cantrips", level: 0},
{name: "Level 1", level: 1},
{name: "Level 2", level: 2},
{name: "Level 3", level: 3},
{name: "Level 4", level: 4},
{name: "Level 5", level: 5},
{name: "Level 6", level: 6},
{name: "Level 7", level: 7},
{name: "Level 8", level: 8},
{name: "Level 9", level: 9},
];
Template.spells.helpers({
@@ -16,40 +16,56 @@ Template.spells.helpers({
return SpellLists.find({charId: this._id}, {sort: {color: 1, name: 1}});
},
spellCount: function(list, charId){
if(!list || !list.settings) return;
if(list.settings.showUnprepared){
return Spells.find( {charId: charId, "parent.id": list._id, level: this.level},
{fields: {_id: 1, level: 1}} ).count() > 0;
} else{
return Spells.find( {charId: charId, "parent.id": list._id, level: this.level, prepared: {$in: ["prepared", "always"]} },
{fields: {_id: 1, level: 1}} ).count() > 0;
if (!list || !list.settings) return;
if (list.settings.showUnprepared){
return Spells.find(
{charId: charId, "parent.id": list._id, level: this.level},
{fields: {_id: 1, level: 1}}
).count() > 0;
} else {
return Spells.find(
{
charId: charId,
"parent.id": list._id,
level: this.level,
prepared: {$in: ["prepared", "always"]},
},
{fields: {_id: 1, level: 1}}
).count() > 0;
}
},
spells: function(listId, charId){
return Spells.find( {charId: charId, "parent.id": listId, level: this.level}, {sort: {color: 1, name: 1}} );
return Spells.find(
{charId: charId, "parent.id": listId, level: this.level},
{sort: {color: 1, name: 1}}
);
},
levels: function(){
return spellLevels;
},
numPrepared: function(){
return Spells.find({charId: Template.parentData()._id, "parent.id": this._id, prepared: "prepared"}).count();
return Spells.find({
charId: Template.parentData()._id,
"parent.id": this._id,
prepared: "prepared",
}).count();
},
order: function(){
return _.indexOf(_.keys(colorOptions), this.color);
},
spellComponents: function(){
var components = "";
if(this.components.verbal){
components += "V"
if (this.components.verbal){
components += "V";
}
if(this.components.somatic){
components += components? ", S" : "S";
if (this.components.somatic){
components += components ? ", S" : "S";
}
if(this.components.material){
components += components? ", M" : "M";
if (this.components.material){
components += components ? ", M" : "M";
}
if(this.components.concentration){
components += components? ", C" : "C";
if (this.components.concentration){
components += components ? ", C" : "C";
}
return components;
},
@@ -57,7 +73,7 @@ Template.spells.helpers({
return this.prepared === "prepared" || this.prepared === "always";
},
showSpell: function(listShowPrepped){
if(listShowPrepped) {
if (listShowPrepped) {
return true;
} else {
return this.prepared === "prepared" || this.prepared === "always";
@@ -67,71 +83,76 @@ Template.spells.helpers({
return this.prepared === "always";
},
cantCast: function(level, char){
for(var i = level; i <= 9; i++){
if (char.attributeValue("level"+i+"SpellSlots") > 0){
for (var i = level; i <= 9; i++){
if (char.attributeValue("level" + i + "SpellSlots") > 0){
return false;
}
}
return true;
},
baseSlots: function(char){
return char.attributeBase("level" + this.level +"SpellSlots");
return char.attributeBase("level" + this.level + "SpellSlots");
},
slots: function(char){
return char.attributeValue("level" + this.level +"SpellSlots");
return char.attributeValue("level" + this.level + "SpellSlots");
},
showSlots: function(char){
return this.level && char.attributeBase("level" + this.level +"SpellSlots");
return this.level && char.attributeBase("level" + this.level + "SpellSlots");
},
hasSlots: function(){
for(var i = 1; i <= 9; i += 1){
if(this.attributeBase("level"+i+"SpellSlots")){
for (var i = 1; i <= 9; i += 1){
if (this.attributeBase("level" + i + "SpellSlots")){
return true;
}
}
return false;
},
slotBubbles: function(char){
var baseSlots = char.attributeBase("level" + this.level +"SpellSlots"),
currentSlots = char.attributeValue("level" + this.level +"SpellSlots"),
slotsUsed = baseSlots - currentSlots,
bubbles = [], i;
for(i = 0; i < currentSlots; i++){
var baseSlots = char.attributeBase("level" + this.level + "SpellSlots");
var currentSlots = char.attributeValue("level" + this.level + "SpellSlots");
var slotsUsed = baseSlots - currentSlots;
var bubbles = [];
var i;
for (i = 0; i < currentSlots; i++){
bubbles.push({
icon: "radio-button-on",
disabled: i !== currentSlots -1, //last full slot not disabled
attribute: "level" + this.level +"SpellSlots",
charId: char._id
icon: "radio-button-on",
disabled: i !== currentSlots - 1, //last full slot not disabled
attribute: "level" + this.level + "SpellSlots",
charId: char._id,
});
}
for(i = 0; i < slotsUsed; i++){
for (i = 0; i < slotsUsed; i++){
bubbles.push({
icon: "radio-button-off",
icon: "radio-button-off",
disabled: i !== 0, //first empty slot not disabled
attribute: "level" + this.level +"SpellSlots",
charId: char._id
attribute: "level" + this.level + "SpellSlots",
charId: char._id,
});
}
return bubbles;
},
slotStatName: function () {
return "level" + this.level +"SpellSlots";
}
},
slotStatName: function() {
return "level" + this.level + "SpellSlots";
},
});
Template.spells.events({
"tap .slotBubble": function(event){
if(!event.currentTarget.disabled){
var modifier;
if (!event.currentTarget.disabled){
var char = Characters.findOne(this.charId);
if(event.currentTarget.icon === "radio-button-off"){
if(char.attributeValue(this.attribute) < char.attributeBase(this.attribute)){
var modifier = {$inc: {}};
if (event.currentTarget.icon === "radio-button-off"){
if (
char.attributeValue(this.attribute) <
char.attributeBase(this.attribute)
){
modifier = {$inc: {}};
modifier.$inc[this.attribute + ".adjustment"] = 1;
Characters.update(this.charId, modifier, {validate: false});
}
} else {
if(char.attributeValue(this.attribute) > 0){
var modifier = {$inc: {}};
if (char.attributeValue(this.attribute) > 0){
modifier = {$inc: {}};
modifier.$inc[this.attribute + ".adjustment"] = -1;
Characters.update(this.charId, modifier, {validate: false});
}
@@ -139,43 +160,43 @@ Template.spells.events({
}
event.stopPropagation();
},
"tap .spellSlot": function (event, instance) {
var name = "Level " + this.level +" Spell Slots";
var stat = "level" + this.level +"SpellSlots";
"tap .spellSlot": function(event, instance) {
var name = "Level " + this.level + " Spell Slots";
var stat = "level" + this.level + "SpellSlots";
var charId = instance.data._id;
GlobalUI.setDetail({
template: "attributeDialog",
data: {name: name, statName: stat, charId: charId},
heroId: charId + stat
heroId: charId + stat,
});
},
"tap .containerTop": function(event){
GlobalUI.setDetail({
template: "spellListDialog",
data: {spellListId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap .spell": function(event){
GlobalUI.setDetail({
template: "spellDialog",
data: {spellId: this._id, charId: this.charId},
heroId: this._id
heroId: this._id,
});
},
"tap #addSpellList": function(event){
var charId = this.charId;
SpellLists.insert({
name: "New SpellList",
name: "New SpellList",
charId: this._id,
saveDC: "8 + intelligenceMod + proficiencyBonus",
attackBonus: "intelligenceMod + proficiencyBonus"
attackBonus: "intelligenceMod + proficiencyBonus",
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "spellListDialog",
data: {spellListId: id, charId: charId, startEditing: true},
heroId: id
heroId: id,
});
}
});
@@ -184,19 +205,19 @@ Template.spells.events({
var charId = this.charId;
var listId = SpellLists.findOne({charId: this._id})._id;
Spells.insert({
name: "New Spell",
name: "New Spell",
charId: this._id,
parent: {
id: listId,
collection: "SpellLists"
collection: "SpellLists",
},
prepared: "prepared"
prepared: "prepared",
}, function(error, id){
if(!error){
if (!error){
GlobalUI.setDetail({
template: "spellDialog",
data: {spellId: id, charId: charId, startEditing: true},
heroId: id
heroId: id,
});
}
});
@@ -206,9 +227,9 @@ Template.spells.events({
},
"change .preparedCheckbox": function(event){
var value = event.currentTarget.checked;
if(this.prepared === "unprepared" && value)
if (this.prepared === "unprepared" && value)
Spells.update(this._id, {$set: {prepared: "prepared"}});
else if(this.prepared === "prepared" && !value)
else if (this.prepared === "prepared" && !value)
Spells.update(this._id, {$set: {prepared: "unprepared"}});
},
"tap .prepSpells": function(event){

View File

@@ -1,11 +1,10 @@
Template.addTHPDialog.events({
'tap #addButton': function(event, instance){
"tap #addButton": function(event, instance){
TemporaryHitPoints.insert({
charId: this.charId,
name: instance.find('#nameInput').value,
maximum: +instance.find('#quantityInput').value,
deleteOnZero: !!instance.find('#deleteWhenZeroCheckbox').checked
name: instance.find("#nameInput").value,
maximum: +instance.find("#quantityInput").value,
deleteOnZero: !!instance.find("#deleteWhenZeroCheckbox").checked,
});
}
});

View File

@@ -6,31 +6,31 @@ var stats = {
"intelligence":{"name":"Intelligence"},
"wisdom":{"name":"Wisdom"},
"charisma":{"name":"Charisma"},
"strengthSave":{"name":"Strength Save",},
"dexteritySave":{"name":"Dexterity Save",},
"constitutionSave":{"name":"Constitution Save",},
"intelligenceSave":{"name":"Intelligence Save",},
"wisdomSave":{"name":"Wisdom Save",},
"charismaSave":{"name":"Charisma Save",},
"acrobatics":{"name":"Acrobatics",},
"animalHandling":{"name":"Animal Handling",},
"arcana":{"name":"Arcana",},
"athletics":{"name":"Athletics",},
"deception":{"name":"Deception",},
"history":{"name":"History",},
"insight":{"name":"Insight",},
"intimidation":{"name":"Intimidation",},
"investigation":{"name":"Investigation",},
"medicine":{"name":"Medicine",},
"nature":{"name":"Nature",},
"perception":{"name":"Perception",},
"performance":{"name":"Performance",},
"persuasion":{"name":"Persuasion",},
"religion":{"name":"Religion",},
"sleightOfHand":{"name":"Sleight of Hand",},
"stealth":{"name":"Stealth",},
"survival":{"name":"Survival",},
"initiative":{"name":"Initiative",},
"strengthSave":{"name":"Strength Save"},
"dexteritySave":{"name":"Dexterity Save"},
"constitutionSave":{"name":"Constitution Save"},
"intelligenceSave":{"name":"Intelligence Save"},
"wisdomSave":{"name":"Wisdom Save"},
"charismaSave":{"name":"Charisma Save"},
"acrobatics":{"name":"Acrobatics"},
"animalHandling":{"name":"Animal Handling"},
"arcana":{"name":"Arcana"},
"athletics":{"name":"Athletics"},
"deception":{"name":"Deception"},
"history":{"name":"History"},
"insight":{"name":"Insight"},
"intimidation":{"name":"Intimidation"},
"investigation":{"name":"Investigation"},
"medicine":{"name":"Medicine"},
"nature":{"name":"Nature"},
"perception":{"name":"Perception"},
"performance":{"name":"Performance"},
"persuasion":{"name":"Persuasion"},
"religion":{"name":"Religion"},
"sleightOfHand":{"name":"Sleight of Hand"},
"stealth":{"name":"Stealth"},
"survival":{"name":"Survival"},
"initiative":{"name":"Initiative"},
"hitPoints":{"name":"Hit Points"},
"armor":{"name":"Armor"},
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
@@ -67,7 +67,7 @@ var stats = {
"psychicMultiplier":{"name":"Psychic", "group": "Weakness/Resistance"},
"radiantMultiplier":{"name":"Radiant", "group": "Weakness/Resistance"},
"slashingMultiplier":{"name":"Slashing", "group": "Weakness/Resistance"},
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"}
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"},
};
var operations = {
@@ -81,7 +81,7 @@ var operations = {
disadvantage: {name: "Disadvantage"},
passiveAdd: {name: "Passive Bonus"},
fail: {name: "Automatically Fail"},
conditional: {name: "Conditional Benefit"}
conditional: {name: "Conditional Benefit"},
};
var abilities = {
@@ -99,34 +99,44 @@ Template.attributeDialogView.helpers({
},
adjustment: function(){
var char = Characters.findOne(this.charId);
if(!char) return;
if (!char) return;
var value = char.attributeValue(this.statName);
var base = char.attributeBase(this.statName);
return value - base;
},
baseEffects: function(){
return Effects.find({charId: this.charId, stat: this.statName, operation: "base"});
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "base"}
);
},
addEffects: function(){
return Effects.find({charId: this.charId, stat: this.statName, operation: "add"});
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "add"}
);
},
mulEffects: function(){
return Effects.find({charId: this.charId, stat: this.statName, operation: "mul"});
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "mul"}
);
},
minEffects: function(){
return Effects.find({charId: this.charId, stat: this.statName, operation: "min"});
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "min"}
);
},
maxEffects: function(){
return Effects.find({charId: this.charId, stat: this.statName, operation: "max"});
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "max"}
);
},
attributeBase: function(){
var char = Characters.findOne(this.charId);
if(!char) throw "character is " + char;
if (!char) throw "character is " + char;
return char.attributeBase(this.statName);
},
attributeValue: function () {
attributeValue: function() {
var char = Characters.findOne(this.charId);
if(!char) throw "character is " + char;
if (!char) throw "character is " + char;
return char.attributeValue(this.statName);
},
sourceName: function(){
@@ -135,10 +145,9 @@ Template.attributeDialogView.helpers({
},
operationName: function(){
var op = operations[this.operation];
return op && op.name || "No Operation";
return op && op.name || "No Operation";
},
statValue: function(){
return evaluateEffect(this.charId, this);
},
});

View File

@@ -10,11 +10,11 @@ Template.healthCard.helpers({
return char && char.deathSave;
},
failIcon: function(num){
if(num <= this.fail) return "radio-button-on";
if (num <= this.fail) return "radio-button-on";
else return "radio-button-off";
},
passIcon: function(num){
if(num <= this.pass) return "radio-button-on";
if (num <= this.pass) return "radio-button-on";
else return "radio-button-off";
},
failDisabled: function(num){
@@ -27,7 +27,7 @@ Template.healthCard.helpers({
return this.fail >= 3;
},
multipliers: function(){
var char = Characters.findOne(this._id, {fields: {_id: 1} });
var char = Characters.findOne(this._id, {fields: {_id: 1}});
var multipliers = [
{name: "Acid", value: char.attributeValue("acidMultiplier", 1)},
{name: "Bludgeoning", value: char.attributeValue("bludgeoningMultiplier", 1)},
@@ -41,15 +41,15 @@ Template.healthCard.helpers({
{name: "Psychic", value: char.attributeValue("psychicMultiplier", 1)},
{name: "Radiant", value: char.attributeValue("radiantMultiplier", 1)},
{name: "Slashing", value: char.attributeValue("slashingMultiplier", 1)},
{name: "Thunder", value: char.attributeValue("thunderMultiplier", 1)}
{name: "Thunder", value: char.attributeValue("thunderMultiplier", 1)},
];
multipliers = _.groupBy(multipliers, "value");
return {
"immunities": multipliers["0"] || [],
"resistances": multipliers["0.5"] || [],
"weaknesses": multipliers["2"] || []
"weaknesses": multipliers["2"] || [],
};
}
},
});
Template.healthCard.events({
@@ -58,12 +58,15 @@ Template.healthCard.events({
var adjustment = value - this.attributeBase("hitPoints");
Characters.update(this._id, {$set: {"hitPoints.adjustment": adjustment}});
//reset the death saves if we are gaining HP
if(value > 0)
Characters.update(this._id, { $set: {
"deathSave.pass": 0,
"deathSave.fail": 0,
"deathSave.stable": false
} });
if (value > 0)
Characters.update(
this._id,
{$set: {
"deathSave.pass": 0,
"deathSave.fail": 0,
"deathSave.stable": false,
}}
);
},
"change .tempHitPointSlider": function(event){
var value = event.currentTarget.value;
@@ -76,24 +79,24 @@ Template.healthCard.events({
"tap #addTempHP": function(event){
GlobalUI.showDialog({
template: "addTHPDialog",
data: {charId: this._id}
data: {charId: this._id},
});
},
"tap .failBubble": function(event){
if(event.currentTarget.disabled) return;
if (event.currentTarget.disabled) return;
var char = Template.parentData();
if(event.currentTarget.icon === "radio-button-off"){
if (event.currentTarget.icon === "radio-button-off"){
Characters.update(char._id, {$set: {"deathSave.fail": this.fail + 1}});
} else{
} else {
Characters.update(char._id, {$set: {"deathSave.fail": this.fail - 1}});
}
},
"tap .passBubble": function(event){
if(event.currentTarget.disabled) return;
if (event.currentTarget.disabled) return;
var char = Template.parentData();
if(event.currentTarget.icon === "radio-button-off"){
if (event.currentTarget.icon === "radio-button-off"){
Characters.update(char._id, {$set: {"deathSave.pass": this.pass + 1}});
} else{
} else {
Characters.update(char._id, {$set: {"deathSave.pass": this.pass - 1}});
}
},
@@ -104,5 +107,5 @@ Template.healthCard.events({
"tap #unstableButton": function(event){
var char = Template.parentData();
Characters.update(char._id, {$set: {"deathSave.stable": true}});
}
},
});

View File

@@ -1,25 +1,28 @@
Template.hitDice.helpers({
cantIncrement: function(){
return !(this.char.attributeValue(this.name) < this.char.attributeBase(this.name));
var valueSmallerThanBase = this.char.attributeValue(this.name) <
this.char.attributeBase(this.name);
return !valueSmallerThanBase;
},
cantDecrement: function(){
return !(this.char.attributeValue(this.name) > 0);
}
var valuePositive = this.char.attributeValue(this.name) > 0;
return !valuePositive;
},
});
Template.hitDice.events({
"tap .resourceUp": function(event){
if(this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
if (this.char.attributeValue(this.name) < this.char.attributeBase(this.name)){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = 1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .resourceDown": function(event){
if(this.char.attributeValue(this.name) > 0){
if (this.char.attributeValue(this.name) > 0){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = -1;
Characters.update(this.char._id, modifier, {validate: false});
}
}
},
});

View File

@@ -6,31 +6,31 @@ var stats = {
"intelligence":{"name":"Intelligence"},
"wisdom":{"name":"Wisdom"},
"charisma":{"name":"Charisma"},
"strengthSave":{"name":"Strength Save",},
"dexteritySave":{"name":"Dexterity Save",},
"constitutionSave":{"name":"Constitution Save",},
"intelligenceSave":{"name":"Intelligence Save",},
"wisdomSave":{"name":"Wisdom Save",},
"charismaSave":{"name":"Charisma Save",},
"acrobatics":{"name":"Acrobatics",},
"animalHandling":{"name":"Animal Handling",},
"arcana":{"name":"Arcana",},
"athletics":{"name":"Athletics",},
"deception":{"name":"Deception",},
"history":{"name":"History",},
"insight":{"name":"Insight",},
"intimidation":{"name":"Intimidation",},
"investigation":{"name":"Investigation",},
"medicine":{"name":"Medicine",},
"nature":{"name":"Nature",},
"perception":{"name":"Perception",},
"performance":{"name":"Performance",},
"persuasion":{"name":"Persuasion",},
"religion":{"name":"Religion",},
"sleightOfHand":{"name":"Sleight of Hand",},
"stealth":{"name":"Stealth",},
"survival":{"name":"Survival",},
"initiative":{"name":"Initiative",},
"strengthSave":{"name":"Strength Save"},
"dexteritySave":{"name":"Dexterity Save"},
"constitutionSave":{"name":"Constitution Save"},
"intelligenceSave":{"name":"Intelligence Save"},
"wisdomSave":{"name":"Wisdom Save"},
"charismaSave":{"name":"Charisma Save"},
"acrobatics":{"name":"Acrobatics"},
"animalHandling":{"name":"Animal Handling"},
"arcana":{"name":"Arcana"},
"athletics":{"name":"Athletics"},
"deception":{"name":"Deception"},
"history":{"name":"History"},
"insight":{"name":"Insight"},
"intimidation":{"name":"Intimidation"},
"investigation":{"name":"Investigation"},
"medicine":{"name":"Medicine"},
"nature":{"name":"Nature"},
"perception":{"name":"Perception"},
"performance":{"name":"Performance"},
"persuasion":{"name":"Persuasion"},
"religion":{"name":"Religion"},
"sleightOfHand":{"name":"Sleight of Hand"},
"stealth":{"name":"Stealth"},
"survival":{"name":"Survival"},
"initiative":{"name":"Initiative"},
"hitPoints":{"name":"Hit Points"},
"armor":{"name":"Armor"},
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
@@ -67,11 +67,11 @@ var stats = {
"psychicMultiplier":{"name":"Psychic", "group": "Weakness/Resistance"},
"radiantMultiplier":{"name":"Radiant", "group": "Weakness/Resistance"},
"slashingMultiplier":{"name":"Slashing", "group": "Weakness/Resistance"},
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"}
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"},
};
var operations = {
base: {name: "Base Value"},
base: {name: "Base Value"},
proficiency: {name: "Proficiency"},
add: {name: "&plus;"},
mul: {name: "&times;"},
@@ -81,7 +81,7 @@ var operations = {
disadvantage: {name: "Disadvantage"},
passiveAdd: {name: "Passive Bonus"},
fail: {name: "Automatically Fail"},
conditional: {name: "Conditional Benefit"}
conditional: {name: "Conditional Benefit"},
};
var abilities = {
@@ -99,50 +99,82 @@ Template.skillDialogView.helpers({
},
profIcon: function(){
var char = Characters.findOne(this.charId);
if(!char) return;
if (!char) return;
var prof = char.proficiency(this.skillName);
if(prof > 0 && prof < 1) return "image:brightness-2";
if(prof === 1) return "image:brightness-1";
if(prof > 1) return "av:album";
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
return "radio-button-off";
},
profSource: function(){
return Proficiencies.findOne({charId: this.charId, name: this.skillName}, {sort: {value: -1}});
return Proficiencies.findOne(
{charId: this.charId, name: this.skillName},
{sort: {value: -1}}
);
},
profBonus: function(){
var char = Characters.findOne(this.charId);
if(!char) return;
return char.proficiency(this.skillName) * char.attributeValue("proficiencyBonus");
if (!char) return;
return char.proficiency(this.skillName) *
char.attributeValue("proficiencyBonus");
},
proficiencyValue: function(){
var char = Characters.findOne(this.charId);
if(!char) return;
if (!char) return;
var prof = char.proficiency(this.skillName);
if(prof == 0.5) return "Half Proficiency";
if(prof == 1) return "Proficient";
if(prof == 2) return "Double Proficiency";
if (prof == 0.5) return "Half Proficiency";
if (prof == 1) return "Proficient";
if (prof == 2) return "Double Proficiency";
return prof + "x Proficiency";
},
addEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "add"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "add",
});
},
mulEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "mul"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "mul",
});
},
minEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "min"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "min",
});
},
maxEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "max"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "max",
});
},
advEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "advantage"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "advantage",
});
},
dadvEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "disadvantage"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "disadvantage",
});
},
conditionalEffects: function(){
return Effects.find({charId: this.charId, stat: this.skillName, operation: "conditional"});
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "conditional",
});
},
ability: function(){
var opts = {fields: {}};
@@ -155,9 +187,9 @@ Template.skillDialogView.helpers({
var opts = {fields: {}};
opts.fields[this.skillName] = 1;
var char = Characters.findOne(this.charId, opts);
if(!char) return;
if (!char) return;
var skill = char[this.skillName];
if(!skill) return;
if (!skill) return;
var ability = skill.ability;
return abilities[ability] && abilities[ability].name;
},
@@ -169,24 +201,24 @@ Template.skillDialogView.helpers({
return this.getParent().name;
},
operationName: function(){
if(stats[this.stat].group === "Weakness/Resistance") return null;
if (stats[this.stat].group === "Weakness/Resistance") return null;
return operations[this.operation] &&
operations[this.operation].name ||
"No Operation";
},
statValue: function(){
if(
if (
this.operation === "advantage" ||
this.operation === "disadvantage" ||
this.operation === "fail"
){
return null;
}
if(stats[this.stat].group === "Weakness/Resistance"){
if(this.value === 0.5) return "Resistance";
if(this.value === 2) return "Vulnerability";
if(this.value === 0) return "Immunity";
return " Damage x"+ this.value;
if (stats[this.stat].group === "Weakness/Resistance"){
if (this.value === 0.5) return "Resistance";
if (this.value === 2) return "Vulnerability";
if (this.value === 0) return "Immunity";
return " Damage x" + this.value;
}
return evaluate(this.charId, this.calculation) || this.value;
},

View File

@@ -1,22 +1,32 @@
Template.skillRow.helpers({
profIcon: function(){
var prof = Template.parentData(1).proficiency(this.skill);
if(prof > 0 && prof < 1) return "image:brightness-2";
if(prof === 1) return "image:brightness-1";
if(prof > 1) return "av:album";
if (prof > 0 && prof < 1) return "image:brightness-2";
if (prof === 1) return "image:brightness-1";
if (prof > 1) return "av:album";
return "radio-button-off";
},
failSkill: function(){
var charId = Template.parentData(1)._id;
return Effects.find({charId: charId, stat: this.skill, enabled: true, operation: "fail"}).count();
return Effects.find({
charId: charId,
stat: this.skill,
enabled: true,
operation: "fail",
}).count();
},
advantage: function(){
var advantage = Template.parentData(1).advantage(this.skill);
if(advantage > 0) return "advantage";
if(advantage < 0) return "disadvantage";
if (advantage > 0) return "advantage";
if (advantage < 0) return "disadvantage";
},
conditionalCount: function(){
var charId = Template.parentData(1)._id;
return Effects.find({charId: charId, stat: this.skill, enabled: true, operation: "conditional"}).count();
}
});
return Effects.find({
charId: charId,
stat: this.skill,
enabled: true,
operation: "conditional",
}).count();
},
});

View File

@@ -1,17 +1,17 @@
Template.stats.events({
"tap .statCard": function(event, instance){
var charId = instance.data._id;
if(this.isSkill){
if (this.isSkill){
GlobalUI.setDetail({
template: "skillDialog",
data: {name: this.name, skillName: this.stat, charId: charId},
heroId: charId + this.stat
heroId: charId + this.stat,
});
} else {
GlobalUI.setDetail({
template: "attributeDialog",
data: {name: this.name, statName: this.stat, charId: charId},
heroId: charId + this.stat
heroId: charId + this.stat,
});
}
},
@@ -20,7 +20,7 @@ Template.stats.events({
GlobalUI.setDetail({
template: "attributeDialog",
data: {name: this.title, statName: this.ability, charId: charId},
heroId: charId + this.ability
heroId: charId + this.ability,
});
},
"tap .skillRow": function(event, instance){
@@ -29,16 +29,16 @@ Template.stats.events({
GlobalUI.setDetail({
template: "skillDialog",
data: {name: this.name, skillName: skill, charId: charId},
heroId: charId + skill
heroId: charId + skill,
});
},
"tap .hitPointTitle": function (event, instance) {
"tap .hitPointTitle": function(event, instance) {
GlobalUI.setDetail({
template: "attributeDialog",
data: {name: "Hit Points", statName: "hitPoints", charId: this._id},
heroId: this._id + "hitPoints"
heroId: this._id + "hitPoints",
});
}
},
});
Template.stats.helpers({

View File

@@ -1,6 +1,9 @@
Template.characterList.helpers({
characterDetails: function(){
var char = Characters.findOne(this._id, {fields: {name: 1, gender: 1, alignment: 1, race:1, color: 1}});
var char = Characters.findOne(
this._id,
{fields: {name: 1, gender: 1, alignment: 1, race:1, color: 1}}
);
char.title = char.name;
char.field = "base";
char.class = "characterCard";
@@ -12,7 +15,10 @@ Template.characterList.events({
"tap .characterCard": function(event, instance){
Router.go("characterSheet", {_id: this._id});
},
"tap .addCharacter": function (event, template) {
GlobalUI.showDialog({heading: "New Character", template: "newCharacterDialog"});
"tap .addCharacter": function(event, template) {
GlobalUI.showDialog({
heading: "New Character",
template: "newCharacterDialog",
});
},
});

View File

@@ -1,10 +1,13 @@
Template.home.helpers({
characterDetails: function(){
var char = Characters.findOne(this._id, {fields: {name: 1, gender: 1, alignment: 1, race:1}})
var char = Characters.findOne(
this._id,
{fields: {name: 1, gender: 1, alignment: 1, race:1}}
);
char.title = char.name;
char.field = "base"
char.field = "base";
char.color = "d";
char.class = "characterCard"
char.class = "characterCard";
return char;
}
});
@@ -13,10 +16,10 @@ Template.home.events({
"tap .characterCard": function(event, instance){
Router.go("characterSheet", {_id: this._id});
},
"tap #addCharacter": function (event, template) {
"tap #addCharacter": function(event, template) {
Characters.insert({owner: Meteor.userId()});
},
"tap #deleteChar": function(event, template){
Characters.remove(this._id);
}
},
});

View File

@@ -1,14 +1,14 @@
Template.layout.rendered = function() {
$(window).on('popstate', GlobalUI.popStateHandler);
$(window).on("popstate", GlobalUI.popStateHandler);
};
Template.layout.destroyed = function() {
$(window).off('popstate', GlobalUI.popStateHandler);
$(window).off("popstate", GlobalUI.popStateHandler);
};
Template.layout.helpers({
notSelected: function(){
return Session.get("global.ui.detailShow")? "not-selected" : null;
return Session.get("global.ui.detailShow") ? "not-selected" : null;
}
});
@@ -18,5 +18,5 @@ Template.layout.events({
},
"tap #profileLink": function(event, instance){
Router.go("profile");
}
},
});

View File

@@ -8,4 +8,4 @@ Template.loading.helpers({
randomHint: function(){
return Random.choice(hints);
}
});
});

View File

@@ -9,7 +9,7 @@ Template.colorDropdown.events({
var color = event.currentTarget.getAttribute("name");
instance.$("#colorDropdown").trigger({
type: "color-change",
color: color
color: color,
});
}
})
});

View File

@@ -3,4 +3,4 @@ Template.gridPadding.helpers({
list: function(){
return _.range(1, this.num);
}
})
});

View File

@@ -1,8 +1,12 @@
Template.undoToast.events({
'tap #undoButton': function(event, instance){
"tap #undoButton": function(event, instance){
var collection = window[this.collection];
if(!collection){
console.warn("Collection with name ", this.collection, " could not be found");
if (!collection){
console.warn(
"Collection with name ",
this.collection,
" could not be found"
);
return;
}
collection.restoreNode(this.id);

View File

@@ -1,19 +1,19 @@
Template.profile.events({
"tap #username": function(){
if(this._id === Meteor.userId()){
if (this._id === Meteor.userId()){
GlobalUI.showDialog({
heading: "Change Username",
template: "usernameDialog"
template: "usernameDialog",
});
}
},
"tap #verifyEmail": function(event, instance){
if(!Meteor.user()) return;
if (!Meteor.user()) return;
Accounts.sendVerificationEmail(Meteor.userId(), this.address);
GlobalUI.toast({
text: "Email verification sent to " + this.address,
template: "",
data: {}
data: {},
});
}
},
});

View File

@@ -1,5 +1,8 @@
Template.usernameDialog.events({
"tap #changeButton": function(event, instance){
Meteor.users.update(Meteor.userId(), {$set: {username: instance.find("#usernameInput").value}});
Meteor.users.update(
Meteor.userId(),
{$set: {username: instance.find("#usernameInput").value}}
);
}
});

View File

@@ -4,7 +4,7 @@ Template.signIn.events({
var pass = instance.find("#passwordInput").value;
Meteor.loginWithPassword(email, pass);
},
"keypress #emailInput, keypress #passwordInput": function (event, instance) {
"keypress #emailInput, keypress #passwordInput": function(event, instance) {
if (event.which === 13) {
var email = instance.find("#emailInput").value;
var pass = instance.find("#passwordInput").value;

View File

@@ -1,118 +0,0 @@
DamageTypes = [
"acid", "bludgeoning", "cold", "fire", "force",
"lightning", "necrotic", "piercing", "poison", "psychic",
"radiant", "slashing", "thunder"
]
Conditions = {};
Conditions.Blinded = {
description: ["a blinded creature can't see and automatically fails any ability check that requires sight.",
"Attack rolls against the creature have advantage, and the creature's attack rolls have disadvantage."]
}
Conditions.Charmed = {
description: ["A charmed creature can't attack the charmer or target the charmer with harmful abilities or magical effects",
"The charmer has advantage on any ability check to interact socially with the creature."]
}
Conditions.Deafened = {
description: ["A deafened creature can't hear and automatically fails any ability check that requires hearing"]
}
Conditions.Frightened = {
description: []
}
Conditions.Grappled = {
description: [
"A grappled creature's speed becomes 0, and it can't benefit from any bonuses to its speed",
"The condition ends if the grappler is incapacitated",
"The conditions also ends if 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 thunderwave spell."
],
effects: [
{stat: "attributes.speed.max", value: 0}
]
}
Conditions.Incapacitated = {
effects: [
{stat: "attributes.actions.max", value: 0},
{stat: "attributes.reactions.max", value: 0},
{stat: "attributes.bonusActions.max", value: 0}
]
}
Conditions.Invisible = {
}
Conditions.Paralyzed = {
//implies incapacitated
effects: [
{stat: "skills.strengthSave.fail", value: 1},
{stat: "skills.dexteritySave.fail", value: 1},
{stat: "attributes.speed.max", value: 0}
]
}
_.extend(Conditions.Paralyzed, Conditions.Incapacitated);
Conditions.Petrified = {
effects: [
{stat: "attributes.weight.mul", value: 10},
{stat: "attributes.ageRate.max", value: 0},
{stat: "attributes.ageRate.min", value: 0},
{stat: "skills.strengthSave.fail", value: 1},
{stat: "skills.dexteritySave.fail", value: 1},
{stat: "attributes.speed.max", value: 0}
]
}
for(var i = 0, l = DamageTypes.length; i < l; i++){
var str = "vulnerability." + DamageTypes[i] + ".mul"
Conditions.Petrified.effects.push({stat: str, value: 0.5});
}
_.extend(Conditions.Petrified, Conditions.Incapacitated);
Conditions.Poisoned = {
description: []
}
Conditions.Prone = {
description: [],
effects: [
{stat: "skills.strengthAttack.disadvantage", value: 1},
{stat: "skills.dexterityAttack.disadvantage", value: 1},
{stat: "skills.rangedAttack.disadvantage", value: 1}
]
}
Conditions.Restrained = {
effects: [
{stat: "attributes.speed.max", value: 0}
]
}
Conditions.Stunned = {
//implies incapacitated
effects: [
{stat: "attributes.speed.max", value: 0},
{stat: "skills.strengthSave.fail", value: 1},
{stat: "skills.dexteritySave.fail", value: 1}
]
}
_.extend(Conditions.Stunned, Conditions.Incapacitated);
Conditions.Unconscious = {
//implies incapacitated
//implies prone
effects: [
{stat: "attributes.speed.max", value: 0},
{stat: "skills.strengthSave.fail", value: 1},
{stat: "skills.dexteritySave.fail", value: 1}
]
}
_.extend(Conditions.Unconscious, Conditions.Incapacitated);
_.extend(Conditions.Unconscious, Conditions.Prone);

View File

@@ -4,5 +4,5 @@ abilities = [
"constitution",
"intelligence",
"wisdom",
"charisma"
];
"charisma",
];

View File

@@ -1 +1 @@
appName = "Dice Cloud";
appName = "Dice Cloud";

View File

@@ -1,31 +1,50 @@
CHARACTER_SUBSCHEMA_ALLOW = {
// the user must be logged in, and the user must be a writer of the character
insert: function (userId, doc) {
var char = Characters.findOne( doc.charId, { fields: {owner: 1, writers: 1} } );
return ( userId && char.owner === userId || _.contains(char.writers, userId) );
insert: function(userId, doc) {
var char = Characters.findOne(
doc.charId,
{fields: {owner: 1, writers: 1}}
);
return (userId && char.owner === userId || _.contains(char.writers, userId));
},
update: function (userId, doc, fields, modifier) {
var char = Characters.findOne( doc.charId, { fields: {owner: 1, writers: 1} } );
return ( userId && char.owner === userId || _.contains(char.writers, userId) );
update: function(userId, doc, fields, modifier) {
var char = Characters.findOne(
doc.charId,
{fields: {owner: 1, writers: 1}}
);
return (userId && char.owner === userId || _.contains(char.writers, userId));
},
remove: function (userId, doc) {
var char = Characters.findOne( doc.charId, { fields: {owner: 1, writers: 1} } );
return ( userId && char.owner === userId || _.contains(char.writers, userId) );
remove: function(userId, doc) {
var char = Characters.findOne(
doc.charId,
{fields: {owner: 1, writers: 1}}
);
return userId && char.owner === userId || _.contains(char.writers, userId);
},
fetch: ["charId"]
fetch: ["charId"],
};
CHARACTER_SUBSCHEMA_DENY = {
update: function (userId, doc, fields, modifier) {
if(modifier && modifier.$set && modifier.$set.charId){
update: function(userId, doc, fields, modifier) {
if (modifier && modifier.$set && modifier.$set.charId){
var id1 = doc.charId;
var char1 = Characters.findOne( id1, { fields: {owner: 1, writers: 1} } ) || {};
var char1Allowed = ( userId && char1.owner === userId || _.contains(char1.writers, userId) );
var char1 = Characters.findOne(
id1,
{fields: {owner: 1, writers: 1}}
) || {};
var char1Allowed = (
userId && char1.owner === userId || _.contains(char1.writers, userId)
);
var id2 = modifier.$set.charId;
var char2 = Characters.findOne( id2, { fields: {owner: 1, writers: 1} } ) || {};
var char2Allowed = ( userId && char1.owner === userId || _.contains(char1.writers, userId) );
var char2 = Characters.findOne(
id2,
{fields: {owner: 1, writers: 1}}
) || {};
var char2Allowed = (
userId && char1.owner === userId || _.contains(char1.writers, userId)
);
return (!char1Allowed || !char2Allowed);
}
},
fetch: ["charId"]
fetch: ["charId"],
};

View File

@@ -24,28 +24,28 @@ colorOptions = [
var colorOptionMap = _.pluck(colorOptions, "key");
getColorClass = function(key){
if(!key){
if (!key){
return "grey white-text";
}
var index = _.indexOf(colorOptionMap, key);
if(index == -1){
if (index == -1){
return "grey white-text";
}
var option = colorOptions[index];
var colorClass = option.className;
if(option.whiteText){
if (option.whiteText){
colorClass += " white-text";
}
return colorClass;
}
};
getHexColor = function(key) {
if(!key){
if (!key){
return "#000";
}
var index = _.indexOf(colorOptionMap, key);
if(index === -1){
if (index === -1){
return "#000";
}
return colorOptions[index].color;
}
};

View File

@@ -1,9 +1,9 @@
DAMAGE_DICE = [
"1",
"1",
"1d4",
"1d6",
"1d8",
"1d10",
"1d12",
"2d6"
]
"2d6",
];

View File

@@ -11,7 +11,7 @@ DAMAGE_TYPES = {
"psychic": {name: "Psychic"},
"radiant": {name: "Radiant"},
"slashing": {name: "Slashing"},
"thunder": {name: "Thunder"}
"thunder": {name: "Thunder"},
};
DAMAGE_MULTIPLIERS = [
@@ -27,5 +27,5 @@ DAMAGE_MULTIPLIERS = [
"psychicMultiplier",
"radiantMultiplier",
"slashingMultiplier",
"thunderMultiplier"
"thunderMultiplier",
];

View File

@@ -18,4 +18,4 @@ SKILLS = [
"stealth",
"survival",
"initiative",
];
];

View File

@@ -1,291 +0,0 @@
standardItems = [
//armor
{
name: "Padded Armor",
plural: "Padded Armor",
description: "Padded armor consists of quilted layers of cloth and batting.",
equipmentSlot: "armor",
weight: 8,
value: 5,
effects: [
{
stat: "armor",
operation: "base",
value: 11,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Leather Armor",
plural: "Leather Armor",
description:
"The breastplate and shoulder protectors of this armor are made of leather that has been stiffened by being boiled in oil. The rest of the armor is made of softer and more flexible materials.",
equipmentSlot: "armor",
weight: 10,
value: 10,
effects: [
{
stat: "armor",
operation: "base",
value: 11,
}
]
},
{
name: "Studded leather Armor",
plural: "Studded leather Armor",
description:
"Made from tough but flexible leather, studded leather is reinforced with close-set rivets or spikes.",
equipmentSlot: "armor",
weight: 13,
value: 45,
effects: [
{
stat: "armor",
operation: "base",
value: 12,
}
]
},
{
name: "Hide Armor",
plural: "Hide Armor",
description:
"This crude armor consists of thick furs and pelts. It is commonly worn by barbarian tribes, evil humanoids, and other folk who lack access to the tools and materials needed to create better armor.",
equipmentSlot: "armor",
weight: 12,
value: 10,
effects: [
{
stat: "armor",
operation: "base",
value: 12,
},
{
stat: "dexterityArmor",
operation: "max",
value: 2,
}
]
},
{
name: "Chain Shirt",
plural: "Chain Shirts",
description:
"Made of interlocking metal rings, a chain shirt is worn between layers of clothing or leather. This armor offers modest protection to the wearers upper body and allows the sound of the rings rubbing against one another to be muffled by outer layers.",
equipmentSlot: "armor",
weight: 20,
value: 50,
effects: [
{
stat: "armor",
operation: "base",
value: 13,
},
{
stat: "dexterityArmor",
operation: "max",
value: 2,
}
]
},
{
name: "Scale Mail",
plural: "Scale Mail",
description:
"This armor consists of a coat and leggings (and perhaps a separate skirt) of leather covered with overlapping pieces of metal, much like the scales of a fish. The suit includes gauntlets.",
equipmentSlot: "armor",
weight: 45,
value: 50,
effects: [
{
stat: "armor",
operation: "base",
value: 14,
},
{
stat: "dexterityArmor",
operation: "max",
value: 2,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Breastplate",
plural: "Breastplates",
description:
"This armor consists of a fitted metal chest piece worn with supple leather. Although it leaves the legs and arms relatively unprotected, this armor provides good protection for the wearers vital organs while leaving the wearer relatively unencumbered.",
equipmentSlot: "armor",
weight: 20,
value: 400,
effects: [
{
stat: "armor",
operation: "base",
value: 14,
},
{
stat: "dexterityArmor",
operation: "max",
value: 2,
}
]
},
{
name: "Half Plate",
plural: "Half Plate",
description:
"Half plate consists of shaped metal plates that cover most of the wearers body. It does not include leg protection beyond simple greaves that are attached with leather straps.",
equipmentSlot: "armor",
weight: 40,
value: 750,
effects: [
{
stat: "armor",
operation: "base",
value: 15,
},
{
stat: "dexterityArmor",
operation: "max",
value: 2,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Ring Mail",
plural: "Ring Mail",
description:
"This armor is leather armor with heavy rings sewn into it. The rings help reinforce the armor against blows from swords and axes. Ring mail is inferior to chain mail, and its usually worn only by those who cant afford better armor.",
equipmentSlot: "armor",
weight: 40,
value: 30,
effects: [
{
stat: "armor",
operation: "base",
value: 14,
},
{
stat: "dexterityArmor",
operation: "max",
value: 0,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Chain Mail",
plural: "Chain Mail",
description:
"Made of interlocking metal rings, chain mail includes a layer of quilted fabric worn underneath the mail to prevent chafing and to cushion the impact of blows. The suit includes gauntlets.",
equipmentSlot: "armor",
weight: 55,
value: 75,
effects: [
{
stat: "armor",
operation: "base",
value: 16,
},
{
stat: "dexterityArmor",
operation: "max",
value: 0,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Splint Armor",
plural: "Splint Armor",
description:
"This armor is made of narrow vertical strips of metal riveted to a backing of leather that is worn over cloth padding. Flexible chain mail protects the joints.",
equipmentSlot: "armor",
weight: 60,
value: 200,
effects: [
{
stat: "armor",
operation: "base",
value: 17,
},
{
stat: "dexterityArmor",
operation: "max",
value: 0,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Plate Armor",
plural: "Plate Armor",
description:
"Plate consists of shaped, interlocking metal plates to cover the entire body. A suit of plate includes gauntlets, heavy leather boots, a visored helmet, and thick layers of padding underneath the armor. Buckles and straps distribute the weight over the body.",
equipmentSlot: "armor",
weight: 65,
value: 1500,
effects: [
{
stat: "armor",
operation: "base",
value: 18,
},
{
stat: "dexterityArmor",
operation: "max",
value: 0,
},
{
stat: "stealth",
operation: "disadvantage",
value: 1,
}
]
},
{
name: "Shield",
plural: "Shields",
description:
"A shield is made from wood or metal and is carried in one hand. Wielding a shield increases your Armor Class by 2. You can benefit from only one shield at a time.",
equipmentSlot: "held",
weight: 6,
value: 10,
effects: [
{
stat: "armor",
operation: "add",
value: 2,
}
]
},
]

View File

@@ -1,3 +1,21 @@
xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000,
85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000,
305000, 355000];
XP_TABLE = [0,
300,
900,
2700,
6500,
14000,
23000,
34000,
48000,
64000,
85000,
100000,
120000,
140000,
165000,
195000,
225000,
265000,
305000,
355000,
];

View File

@@ -1,7 +1,7 @@
getMod = function(score){
return Math.floor((score-10)/2);
}
return Math.floor((score - 10) / 2);
};
signedString = function(number){
return number >= 0? "+" + number : "" + number;
}
return number >= 0 ? "+" + number : "" + number;
};

View File

@@ -1,17 +1,17 @@
roll = function (n, d){
if(!isNaN(n)){
roll = function(n, d){
if (!isNaN(n)){
//first digit is a number
if(d === undefined){
if (d === undefined){
d = n;
n = 1;
}
if(n > 500){
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)
var roll = Math.floor(Random.fraction() * d + 1);
result.sum += roll;
result.rolls.push(roll);
}
@@ -19,26 +19,26 @@ roll = function (n, d){
}
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
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
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

@@ -1,62 +1,69 @@
//evaluates a calculation string
evaluate = function(charId, string){
if(!string) return string;
if (!string) return string;
var char = Characters.findOne(charId, {fields: {_id: 1}});
string = string.replace(/\b[a-z]+\b/gi, function(sub){
//fields
if(Schemas.Character.schema(sub)){
return char.fieldValue(sub)
if (Schemas.Character.schema(sub)){
return char.fieldValue(sub);
}
//ability modifiers
var abilityMods = ["STRENGTHMOD", "DEXTERITYMOD", "CONSTITUTIONMOD", "INTELLIGENCEMOD", "WISDOMMOD", "CHARISMAMOD"]
if( _.contains(abilityMods, sub.toUpperCase()) ){
var slice = sub.slice(0, - 3);
var abilityMods = [
"STRENGTHMOD",
"DEXTERITYMOD",
"CONSTITUTIONMOD",
"INTELLIGENCEMOD",
"WISDOMMOD",
"CHARISMAMOD",
];
if (_.contains(abilityMods, sub.toUpperCase())){
var slice = sub.slice(0, -3);
return char.abilityMod(slice);
}
//class levels
if(/\w+levels?\b/gi.test(sub)){
if (/\w+levels?\b/gi.test(sub)){
//strip out "level"
var className = sub.replace(/levels?\b/gi, "");
var cls = Classes.findOne({charId: charId, name: className});
return cls && cls.level;
}
//character level
if(sub.toUpperCase() === "LEVEL"){
if (sub.toUpperCase() === "LEVEL"){
return char.level();
}
return sub;
});
try{
try {
var result = math.eval(string);
return result;
} catch(e){
} catch (e){
console.log("Failed to evaluate ", string);
return string;
}
}
};
//takes a string with {calculations} and returns it with the results
//takes a string with {calculations} and returns it with the results
//of the calculations returned in place
evaluateString = function(charId, string){
//define brackets as curly brackets around anything that isn't a curly bracket
if(!string) return string;
if (!string) return string;
var brackets = /\{[^\{\}]*\}/g;
var result = string.replace(brackets, function(exp){
var exp = exp.replace(/(\{|\})/g, "") //remove curly brackets
exp = exp.replace(/(\{|\})/g, ""); //remove curly brackets
return evaluate(charId, exp);
});
return result;
}
};
//returns the value of the effect if it exists,
//returns the value of the effect if it exists,
//otherwise returns the result of the calculation if it exists,
//otherwise returns 0
evaluateEffect = function(charId, effect){
if(_.isFinite(effect.value)){
if (_.isFinite(effect.value)){
return effect.value;
} else if(_.isString(effect.calculation)){
} else if (_.isString(effect.calculation)){
return +evaluate(charId, effect.calculation);
} else {
return 0;
}
}
};

View File

@@ -1,31 +1,35 @@
var childSchema = new SimpleSchema({
parent: { type: Object },
'parent.collection': { type: String },
'parent.id': { type: String, regEx: SimpleSchema.RegEx.Id },
'parent.group': { type: String, optional: true},
'removedWith': { optional: true, type: String, regEx: SimpleSchema.RegEx.Id },
parent: {type: Object},
"parent.collection": {type: String},
"parent.id": {type: String, regEx: SimpleSchema.RegEx.Id},
"parent.group": {type: String, optional: true},
"removedWith": {
optional: true,
type: String,
regEx: SimpleSchema.RegEx.Id,
},
});
var joinWithDefaultKeys = function(keys){
var defaultKeys = [
'charId',
"charId",
];
return _.union(keys, defaultKeys);
};
var limitModifierToKeys = function(modifier, keys){
if(!modifier) return;
modifier = _.pick(modifier, ['$set', '$unset']);
if(modifier.$set) modifier.$set = _.pick(modifier.$set, keys);
if(modifier.$unset) modifier.$unset = _.pick(modifier.$unset, keys);
if(_.isEmpty(modifier.$set)) delete modifier.$set;
if(_.isEmpty(modifier.$unset)) delete modifier.$unset;
if (!modifier) return;
modifier = _.pick(modifier, ["$set", "$unset"]);
if (modifier.$set) modifier.$set = _.pick(modifier.$set, keys);
if (modifier.$unset) modifier.$unset = _.pick(modifier.$unset, keys);
if (_.isEmpty(modifier.$set)) delete modifier.$set;
if (_.isEmpty(modifier.$unset)) delete modifier.$unset;
return modifier;
};
var getParent = function(doc){
if(!doc || !doc.parent) return;
var parentCol = Meteor.isClient?
if (!doc || !doc.parent) return;
var parentCol = Meteor.isClient ?
window[doc.parent.collection] : global[doc.parent.collection];
if (parentCol)
return parentCol.findOne(doc.parent.id, {removed: true});
@@ -33,9 +37,12 @@ var getParent = function(doc){
var inheritParentProperties = function(doc, collection){
var parent = getParent(doc);
if(!parent) throw new Meteor.Error('Parenting Error', 'Document\'s parent does not exist');
if (!parent) throw new Meteor.Error(
"Parenting Error",
"Document's parent does not exist"
);
var handMeDowns = _.pick(parent, collection.inheritedKeys);
if(_.isEmpty(handMeDowns)) return;
if (_.isEmpty(handMeDowns)) return;
collection.update(doc._id, {$set: handMeDowns});
};
@@ -43,16 +50,18 @@ var childCollections = [];
makeChild = function(collection, inheritedKeys){
inheritedKeys = inheritedKeys || [];
if(inheritedKeys) collection.inheritedKeys = joinWithDefaultKeys(inheritedKeys);
if (inheritedKeys) {
collection.inheritedKeys = joinWithDefaultKeys(inheritedKeys);
}
collection.helpers({
//returns the parent even if it's removed
getParent: function(){
return getParent(this);
},
getParentCollection: function(){
return Meteor.isClient?
return Meteor.isClient ?
window[this.parent.collection] : global[this.parent.collection];
}
},
});
//when created, inherit parent properties
@@ -62,17 +71,19 @@ makeChild = function(collection, inheritedKeys){
collection.before.update(function(userId, doc, fieldNames, modifier, options){
//if we are restoring this asset, unmark that it was removed with its parent, we no longer care
if( modifier && modifier.$unset && modifier.$unset.removed){
if (modifier && modifier.$unset && modifier.$unset.removed) {
modifier.$unset.removedWith = "";
}
});
if(Meteor.isClient) collection.after.update(function (userId, doc, fieldNames, modifier, options) {
if(modifier && modifier.$set && modifier.$set.parent){
//when we change parents, inherit its properties
inheritParentProperties(doc, collection);
}
});
if (Meteor.isClient) {
collection.after.update(function(userId, doc, fieldNames, modifier, options) {
if (modifier && modifier.$set && modifier.$set.parent){
//when we change parents, inherit its properties
inheritParentProperties(doc, collection);
}
});
}
collection.softRemoveNode = collection.softRemoveNode || function(id){
collection.softRemove(id);
@@ -91,47 +102,55 @@ makeParent = function(collection, donatedKeys){
donatedKeys = joinWithDefaultKeys(donatedKeys);
var collectionName = collection._collection.name;
//after changing, push the changes to all children
if(Meteor.isClient) collection.after.update(function (userId, doc, fieldNames, modifier, options) {
modifier = limitModifierToKeys(modifier, donatedKeys);
doc = _.pick(doc, ['_id','charId']);
if(!modifier) return;
Meteor.call('updateChildren', doc, modifier, true);
});
if (Meteor.isClient) {
collection.after.update(function(userId, doc, fieldNames, modifier, options) {
modifier = limitModifierToKeys(modifier, donatedKeys);
doc = _.pick(doc, ["_id", "charId"]);
if (!modifier) return;
Meteor.call("updateChildren", doc, modifier, true);
});
}
collection.softRemoveNode = function(id){
Meteor.call('softRemoveNode', collectionName, id);
Meteor.call("softRemoveNode", collectionName, id);
};
collection.restoreNode = function(id){
Meteor.call('restoreNode', collectionName, id);
Meteor.call("restoreNode", collectionName, id);
};
if(Meteor.isServer) collection.after.remove(function (userId, doc) {
if (Meteor.isServer) collection.after.remove(function(userId, doc) {
_.each(childCollections, function(collection){
collection.remove(
{'parent.id': doc._id}
{"parent.id": doc._id}
);
});
});
};
var checkPermission = function(userId, charId){
var char = Characters.findOne( charId, { fields: {owner: 1, writers: 1} } );
if(!char)
throw new Meteor.Error('Access Denied, no charId',
'Character '+charId+' does not exist');
var char = Characters.findOne(charId, {fields: {owner: 1, writers: 1}});
if (!char)
throw new Meteor.Error("Access Denied, no charId",
"Character " + charId + " does not exist");
if (!userId)
throw new Meteor.Error('Access Denied, no userId',
'No UserId set when trying to update character asset.');
throw new Meteor.Error("Access Denied, no userId",
"No UserId set when trying to update character asset.");
if (char.owner !== userId && !_.contains(char.writers, userId))
throw new Meteor.Error('Access Denied, not permitted',
'Not permitted to update assets of this character.');
throw new Meteor.Error("Access Denied, not permitted",
"Not permitted to update assets of this character.");
return true;
};
var cascadeSoftRemove = function(id, removedWithId){
_.each(childCollections, function(treeCollection){
treeCollection.update({"parent.id": id}, {$set: {removed: true, removedWith: removedWithId}}, {multi: true});
treeCollection.update(
{"parent.id": id},
{$set: {
removed: true,
removedWith: removedWithId,
}},
{multi: true}
);
treeCollection.find({"parent.id": id}).forEach(function(doc){
cascadeSoftRemove(doc._id, removedWithId);
});
@@ -159,37 +178,40 @@ Meteor.methods({
var collection = Mongo.Collection.get(collectionName);
collection.restore(id);
_.each(childCollections, function(treeCollection){
treeCollection.update({removedWith: id, removed: true}, { $unset: {removed: true, removedWith: ""} }, {multi: true});
treeCollection.update(
{removedWith: id, removed: true},
{$unset: {removed: true, removedWith: ""}},
{multi: true}
);
});
},
updateChildren: function (parent, modifier, limitToInheritance) {
updateChildren: function(parent, modifier, limitToInheritance) {
check(parent, {_id: String, charId: String});
check(modifier, Object);
checkPermission(this.userId, parent.charId);
var selector = {'parent.id': parent._id};
var selector = {"parent.id": parent._id};
_.each(childCollections, function(collection){
var thisModifier;
if(limitToInheritance){
if (limitToInheritance){
thisModifier = limitModifierToKeys(modifier, collection.inheritedKeys);
} else{
} else {
thisModifier = _.clone(modifier);
}
if(_.isEmpty(thisModifier)) return;
collection.update( selector, thisModifier, {multi: true, removed: true});
if (_.isEmpty(thisModifier)) return;
collection.update(selector, thisModifier, {multi: true, removed: true});
});
},
cloneChildren: function (objectId, newParent){
cloneChildren: function(objectId, newParent){
check(objectId, String);
check(newParent, {id: String, collection: String});
_.each(childCollections, function(collection){
var keys = collection.simpleSchema().objectKeys();
collection.find({'parent.id': objectId}).forEach(function(doc){
var newDoc = _.pick( doc, keys);
collection.find({"parent.id": objectId}).forEach(function(doc){
var newDoc = _.pick(doc, keys);
newDoc.parent = newParent;
collection.insert(newDoc);
});
});
}
},
});

Some files were not shown because too many files have changed in this diff Show More