Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac23afac5d | ||
|
|
a411fb2b43 | ||
|
|
35b6fe20ae | ||
|
|
54f055d3ef | ||
|
|
2bacb296ba | ||
|
|
8b061f7aa9 | ||
|
|
6a84c83644 | ||
|
|
3227cd0934 | ||
|
|
089feae26f | ||
|
|
99c72d1e10 | ||
|
|
1e67afbe6f | ||
|
|
1cfec1ca45 | ||
|
|
09d1ac9ba3 | ||
|
|
834b9cf384 | ||
|
|
37291b347a | ||
|
|
efdfbeb59e | ||
|
|
a165f9b253 | ||
|
|
4a6fca98bc | ||
|
|
35464128a0 | ||
|
|
398f8a8a2a | ||
|
|
812a1784b2 | ||
|
|
8fa9cd0148 | ||
|
|
0e0662cc9a | ||
|
|
ad4e3f5b20 | ||
|
|
4cd058e1fe |
@@ -48,3 +48,4 @@ es5-shim@4.6.15
|
||||
differential:vulcanize
|
||||
reactive-dict
|
||||
percolate:synced-cron
|
||||
ongoworks:speakingurl
|
||||
|
||||
@@ -85,6 +85,7 @@ npm-mongo@2.2.16_1
|
||||
oauth@1.1.12
|
||||
oauth2@1.1.11
|
||||
observe-sequence@1.0.14
|
||||
ongoworks:speakingurl@9.0.0
|
||||
ordered-dict@1.0.9
|
||||
percolate:migrations@0.9.8
|
||||
percolate:synced-cron@1.3.2
|
||||
|
||||
@@ -11,10 +11,12 @@ Schemas.Action = new SimpleSchema({
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
optional: true,
|
||||
trim: false,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
optional: true,
|
||||
trim: false,
|
||||
},
|
||||
type: {
|
||||
|
||||
@@ -12,6 +12,7 @@ Schemas.Attack = new SimpleSchema({
|
||||
name: {
|
||||
type: String,
|
||||
defaultValue: "New Attack",
|
||||
optional: true,
|
||||
trim: false,
|
||||
},
|
||||
details: {
|
||||
|
||||
@@ -8,6 +8,7 @@ Schemas.Buff = new SimpleSchema({
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
optional: true,
|
||||
trim: false,
|
||||
},
|
||||
description: {
|
||||
|
||||
@@ -4,6 +4,7 @@ Characters = new Mongo.Collection("characters");
|
||||
Schemas.Character = new SimpleSchema({
|
||||
//strings
|
||||
name: {type: String, defaultValue: "", trim: false, optional: true},
|
||||
urlName: {type: String, defaultValue: "-", trim: false, optional: true},
|
||||
alignment: {type: String, defaultValue: "", trim: false, optional: true},
|
||||
gender: {type: String, defaultValue: "", trim: false, optional: true},
|
||||
race: {type: String, defaultValue: "", trim: false, optional: true},
|
||||
@@ -184,6 +185,9 @@ Schemas.Character = new SimpleSchema({
|
||||
defaultValue: "whitelist",
|
||||
allowedValues: ["whitelist", "public"],
|
||||
},
|
||||
"settings.exportFeatures": {type: Boolean, defaultValue: true},
|
||||
"settings.exportAttacks": {type: Boolean, defaultValue: true},
|
||||
"settings.exportDescription": {type: Boolean, defaultValue: true},
|
||||
});
|
||||
|
||||
Characters.attachSchema(Schemas.Character);
|
||||
@@ -254,7 +258,10 @@ var attributeBase = preventLoop(function(charId, statName){
|
||||
var result = (base + add) * mul;
|
||||
if (result < min) result = min;
|
||||
if (result > max) result = max;
|
||||
|
||||
// Don't round carry multiplier
|
||||
if (statName === "carryMultiplier"){
|
||||
return result;
|
||||
}
|
||||
return Math.floor(result);
|
||||
});
|
||||
|
||||
@@ -534,6 +541,15 @@ if (Meteor.isServer){
|
||||
Items .remove({charId: character._id});
|
||||
Containers .remove({charId: character._id});
|
||||
});
|
||||
Characters.after.update(function(userId, doc, fieldNames, modifier, options) {
|
||||
if (_.contains(fieldNames, "name")){
|
||||
var urlName = getSlug(doc.name, {maintainCase: true}) || "-";
|
||||
Characters.update(doc._id, {$set: {urlName}});
|
||||
}
|
||||
});
|
||||
Characters.before.insert(function(userId, doc) {
|
||||
doc.urlName = getSlug(doc.name, {maintainCase: true}) || "-";
|
||||
});
|
||||
}
|
||||
|
||||
Characters.allow({
|
||||
|
||||
@@ -2,7 +2,7 @@ Classes = new Mongo.Collection("classes");
|
||||
|
||||
Schemas.Class = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
name: {type: String, trim: false},
|
||||
name: {type: String, optional: true, trim: false},
|
||||
level: {type: Number},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
|
||||
@@ -2,7 +2,7 @@ Experiences = new Mongo.Collection("experience");
|
||||
|
||||
Schemas.Experience = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
name: {type: String, defaultValue: "New Experience", trim: false},
|
||||
name: {type: String, optional: true, trim: false, defaultValue: "New Experience"},
|
||||
description: {type: String, optional: true, trim: false},
|
||||
value: {type: Number, defaultValue: 0},
|
||||
dateAdded: {
|
||||
|
||||
@@ -2,7 +2,7 @@ Features = new Mongo.Collection("features");
|
||||
|
||||
Schemas.Feature = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
name: {type: String, trim: false},
|
||||
name: {type: String, optional: true, trim: false},
|
||||
description: {type: String, optional: true, trim: false},
|
||||
uses: {type: String, optional: true, trim: false},
|
||||
used: {type: Number, defaultValue: 0},
|
||||
|
||||
@@ -2,7 +2,7 @@ Notes = new Mongo.Collection("notes");
|
||||
|
||||
Schemas.Note = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
name: {type: String, trim: false},
|
||||
name: {type: String, optional: true, trim: false},
|
||||
description: {type: String, optional: true, trim: false},
|
||||
color: {
|
||||
type: String,
|
||||
|
||||
@@ -2,7 +2,7 @@ SpellLists = new Mongo.Collection("spellLists");
|
||||
|
||||
Schemas.SpellLists = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
name: {type: String, trim: false},
|
||||
name: {type: String, optional: true, trim: false},
|
||||
description: {type: String, optional: true, trim: false},
|
||||
saveDC: {type: String, optional: true, trim: false},
|
||||
attackBonus: {type: String, optional: true, trim: false},
|
||||
|
||||
@@ -9,6 +9,7 @@ Schemas.Spell = new SimpleSchema({
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
optional: true,
|
||||
trim: false,
|
||||
defaultValue: "New Spell",
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Containers = new Mongo.Collection("containers");
|
||||
|
||||
Schemas.Container = new SimpleSchema({
|
||||
name: {type: String, trim: false},
|
||||
name: {type: String, optional: true, trim: false},
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||
isCarried: {type: Boolean},
|
||||
weight: {type: Number, min: 0, defaultValue: 0, decimal: true},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Items = new Mongo.Collection("items");
|
||||
|
||||
Schemas.Item = new SimpleSchema({
|
||||
name: {type: String, defaultValue: "New Item", trim: false},
|
||||
name: {type: String, optional: true, trim: false, defaultValue: "New Item"},
|
||||
plural: {type: String, optional: true, trim: false},
|
||||
description:{type: String, optional: true, trim: false},
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, //id of owner
|
||||
|
||||
@@ -24,7 +24,7 @@ Router.map(function() {
|
||||
this.route("characterList", {
|
||||
path: "/characterList",
|
||||
waitOn: function(){
|
||||
return subsManager.subscribe("characterList", Meteor.userId());
|
||||
return subsManager.subscribe("characterList");
|
||||
},
|
||||
onAfterAction: function() {
|
||||
document.title = appName + " - Characters";
|
||||
@@ -32,11 +32,27 @@ Router.map(function() {
|
||||
fastRender: true,
|
||||
});
|
||||
|
||||
this.route("characterSheet", {
|
||||
path: "/character/:_id",
|
||||
this.route("characterSheetNaked", {
|
||||
path: "/character/:_id/",
|
||||
waitOn: function(){
|
||||
return [
|
||||
subsManager.subscribe("singleCharacter", this.params._id, Meteor.userId()),
|
||||
subsManager.subscribe("singleCharacter", this.params._id),
|
||||
];
|
||||
},
|
||||
action: function(){
|
||||
var _id = this.params._id
|
||||
var character = Characters.findOne(_id);
|
||||
var urlName = character && character.urlName;
|
||||
var path = `\/character\/${_id}\/${urlName || "-"}`;
|
||||
Router.go(path,{},{replaceState:true});
|
||||
},
|
||||
});
|
||||
|
||||
this.route("characterSheet", {
|
||||
path: "/character/:_id/:urlName",
|
||||
waitOn: function(){
|
||||
return [
|
||||
subsManager.subscribe("singleCharacter", this.params._id),
|
||||
];
|
||||
},
|
||||
data: function() {
|
||||
|
||||
3
rpg-docs/client/globalHelpers/characterPath.js
Normal file
3
rpg-docs/client/globalHelpers/characterPath.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Template.registerHelper("characterPath", function(char) {
|
||||
return `\/character\/${char._id}\/${char.urlName || "-"}`;
|
||||
});
|
||||
@@ -24,6 +24,10 @@ Template.registerHelper("evaluateString", function(charId, string) {
|
||||
return evaluateString(charId, string);
|
||||
});
|
||||
|
||||
Template.registerHelper("evaluateSpellString", function(charId, spellListId, string) {
|
||||
return evaluateSpellString(charId, spellListId, string);
|
||||
});
|
||||
|
||||
Template.registerHelper("evaluateShortString", function(charId, string) {
|
||||
if (_.isString(string)){
|
||||
return evaluateString(
|
||||
|
||||
195
rpg-docs/client/lib/improvedInitiativeJson.js
Normal file
195
rpg-docs/client/lib/improvedInitiativeJson.js
Normal file
@@ -0,0 +1,195 @@
|
||||
improvedInitiativeJson = function(charId, options){
|
||||
options = options || {
|
||||
features: true,
|
||||
attacks: true,
|
||||
description: true,
|
||||
};
|
||||
var char = Characters.findOne(charId);
|
||||
if (!char) return;
|
||||
var baseValue = function(attributeName){
|
||||
return Characters.calculate.attributeBase(charId, attributeName);
|
||||
};
|
||||
var skillMod = function(skillName){
|
||||
return Characters.calculate.skillMod(charId, skillName);
|
||||
};
|
||||
var damageMods = getDamageMods(charId);
|
||||
return JSON.stringify({
|
||||
"Id": char._id,
|
||||
"Name": char.name,
|
||||
"Source": "DiceCloud",
|
||||
"Type": char.race,
|
||||
"HP": {
|
||||
"Value": baseValue("hitPoints"),
|
||||
"Notes": getHitDiceString(charId) || "",
|
||||
},
|
||||
"AC": {
|
||||
"Value": baseValue("armor"),
|
||||
"Notes": getArmorString(charId) || "",
|
||||
},
|
||||
"InitiativeModifier": skillMod("initiative"),
|
||||
"Speed": ["" + baseValue("speed")],
|
||||
"Abilities": {
|
||||
"Str": baseValue("strength"),
|
||||
"Dex": baseValue("dexterity"),
|
||||
"Con": baseValue("constitution"),
|
||||
"Cha": baseValue("charisma"),
|
||||
"Int": baseValue("intelligence"),
|
||||
"Wis": baseValue("wisdom"),
|
||||
},
|
||||
"DamageVulnerabilities": damageMods.vulnerabilities,
|
||||
"DamageResistances": damageMods.resistances,
|
||||
"DamageImmunities": damageMods.immunities,
|
||||
"ConditionImmunities": [],
|
||||
"Saves": [
|
||||
{"Name": "Str", "Modifier": skillMod("strengthSave")},
|
||||
{"Name": "Dex", "Modifier": skillMod("dexteritySave")},
|
||||
{"Name": "Con", "Modifier": skillMod("constitutionSave")},
|
||||
{"Name": "Int", "Modifier": skillMod("intelligenceSave")},
|
||||
{"Name": "Wis", "Modifier": skillMod("wisdomSave")},
|
||||
{"Name": "Cha", "Modifier": skillMod("charismaSave")},
|
||||
],
|
||||
"Skills": getSkills(charId),
|
||||
"Senses": [
|
||||
"passive Perception " +
|
||||
Characters.calculate.passiveSkill(charId, "perception")
|
||||
],
|
||||
"Languages": getLanguages(charId),
|
||||
"Challenge": "",
|
||||
"Traits": options.features ? getTraits(charId) : [],
|
||||
"Actions": options.attacks ? getActions(charId) : [],
|
||||
"Reactions": [],
|
||||
"LegendaryActions": [],
|
||||
"Description": options.description ? char.description : "",
|
||||
"Player": Meteor.user().username,
|
||||
}, null, 2);
|
||||
}
|
||||
|
||||
var getHitDiceString = function(charId){
|
||||
var d6 = Characters.calculate.attributeBase(charId, "d6HitDice");
|
||||
var d8 = Characters.calculate.attributeBase(charId, "d8HitDice");
|
||||
var d10 = Characters.calculate.attributeBase(charId, "d10HitDice");
|
||||
var d12 = Characters.calculate.attributeBase(charId, "d12HitDice");
|
||||
var con = Characters.calculate.abilityMod(charId,"constitution");
|
||||
var string = "" +
|
||||
(d6 ? `${d6}d6 + ` : "") +
|
||||
(d8 ? `${d8}d8 + ` : "") +
|
||||
(d10 ? `${d10}d10 + ` : "") +
|
||||
(d12 ? `${d12}d12 + ` : "") +
|
||||
con;
|
||||
}
|
||||
|
||||
var getArmorString = function(charId){
|
||||
var bases = Effects.find({
|
||||
charId: charId,
|
||||
stat: "armor",
|
||||
operation: "base",
|
||||
enabled: true,
|
||||
}).map(e => ({
|
||||
ame: e.name,
|
||||
value: evaluateEffect(charId, e),
|
||||
}));
|
||||
var base = bases.length && _.max(bases, b => b.value).name || "";
|
||||
var effects = Effects.find({
|
||||
charId: charId,
|
||||
stat: "armor",
|
||||
operation: {$ne: "base"},
|
||||
enabled: true,
|
||||
}).map(e => e.name);
|
||||
var strings = base ? [base] : [];
|
||||
strings = strings.concat(effects);
|
||||
return strings.join(", ");
|
||||
}
|
||||
|
||||
var getDamageMods = function(charId){
|
||||
// jscs:disable maximumLineLength
|
||||
var multipliers = [
|
||||
{name: "Acid", value: Characters.calculate.attributeValue(charId, "acidMultiplier")},
|
||||
{name: "Bludgeoning", value: Characters.calculate.attributeValue(charId, "bludgeoningMultiplier")},
|
||||
{name: "Cold", value: Characters.calculate.attributeValue(charId, "coldMultiplier")},
|
||||
{name: "Fire", value: Characters.calculate.attributeValue(charId, "fireMultiplier")},
|
||||
{name: "Force", value: Characters.calculate.attributeValue(charId, "forceMultiplier")},
|
||||
{name: "Lightning", value: Characters.calculate.attributeValue(charId, "lightningMultiplier")},
|
||||
{name: "Necrotic", value: Characters.calculate.attributeValue(charId, "necroticMultiplier")},
|
||||
{name: "Piercing", value: Characters.calculate.attributeValue(charId, "piercingMultiplier")},
|
||||
{name: "Poison", value: Characters.calculate.attributeValue(charId, "poisonMultiplier")},
|
||||
{name: "Psychic", value: Characters.calculate.attributeValue(charId, "psychicMultiplier")},
|
||||
{name: "Radiant", value: Characters.calculate.attributeValue(charId, "radiantMultiplier")},
|
||||
{name: "Slashing", value: Characters.calculate.attributeValue(charId, "slashingMultiplier")},
|
||||
{name: "Thunder", value: Characters.calculate.attributeValue(charId, "thunderMultiplier")},
|
||||
];
|
||||
// jscs:enable maximumLineLength
|
||||
multipliers = _.groupBy(multipliers, "value");
|
||||
var names = o => o.name;
|
||||
return {
|
||||
"immunities": _.map(multipliers["0"], names),
|
||||
"resistances": _.map(multipliers["0.5"], names),
|
||||
"vulnerabilities": _.map(multipliers["2"], names),
|
||||
};
|
||||
}
|
||||
|
||||
var getSkills = function(charId){
|
||||
var allSkills = [
|
||||
{name: "acrobatics", attribute: "dexterity"},
|
||||
{name: "animalHandling", attribute: "wisdom"},
|
||||
{name: "arcana", attribute: "intelligence"},
|
||||
{name: "athletics", attribute: "strength"},
|
||||
{name: "deception", attribute: "charisma"},
|
||||
{name: "history", attribute: "intelligence"},
|
||||
{name: "insight", attribute: "wisdom"},
|
||||
{name: "intimidation", attribute: "charisma"},
|
||||
{name: "investigation", attribute: "intelligence"},
|
||||
{name: "medicine", attribute: "wisdom"},
|
||||
{name: "nature", attribute: "intelligence"},
|
||||
{name: "perception", attribute: "wisdom"},
|
||||
{name: "performance", attribute: "charisma"},
|
||||
{name: "persuasion", attribute: "charisma"},
|
||||
{name: "religion", attribute: "intelligence"},
|
||||
{name: "sleightOfHand", attribute: "dexterity"},
|
||||
{name: "stealth", attribute: "dexterity"},
|
||||
{name: "survival", attribute: "wisdom"},
|
||||
];
|
||||
var skills = [];
|
||||
_.each(allSkills, skill => {
|
||||
var value = Characters.calculate.skillMod(charId, skill.name);
|
||||
var mod = Characters.calculate.abilityMod(charId, skill.attribute);
|
||||
if (value !== mod){
|
||||
skills.push({Name: skill.name, Modifier: value});
|
||||
}
|
||||
});
|
||||
return skills;
|
||||
};
|
||||
|
||||
var getLanguages = function(charId){
|
||||
return Proficiencies.find({
|
||||
charId,
|
||||
enabled: true,
|
||||
type: "language",
|
||||
}).map(l => l.name);
|
||||
};
|
||||
|
||||
var getTraits = function(charId){
|
||||
return Features.find(
|
||||
{charId: charId},
|
||||
{sort: {color: 1, name: 1}}
|
||||
).map(f => ({
|
||||
Name: f.name,
|
||||
// evaluateShortString helper
|
||||
Content: evaluateString(
|
||||
charId, f.description && f.description.split(/^( *[-*_]){3,} *(?:\n+|$)/m)[0]
|
||||
) || "",
|
||||
Usage: "",
|
||||
}));
|
||||
}
|
||||
|
||||
var getActions = function(charId){
|
||||
return Attacks.find(
|
||||
{charId, enabled: true},
|
||||
{sort: {color: 1, name: 1}}
|
||||
).map(a => ({
|
||||
Name: a.name,
|
||||
Content: `+${evaluate(charId, a.attackBonus)} to hit, ` +
|
||||
`${evaluateString(charId, a.damage)} ${a.damageType} damage, ` +
|
||||
`${a.details}`,
|
||||
Usage: "",
|
||||
}));
|
||||
}
|
||||
28
rpg-docs/client/lib/requestAnimationFramePolyfill.js
Normal file
28
rpg-docs/client/lib/requestAnimationFramePolyfill.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
||||
|
||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||||
|
||||
// MIT license
|
||||
var lastTime = 0;
|
||||
var vendors = ["ms", "moz", "webkit", "o"];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"];
|
||||
window.cancelAnimationFrame = window[vendors[x] + "CancelAnimationFrame"] ||
|
||||
window[vendors[x] + "CancelRequestAnimationFrame"];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
@@ -23,6 +23,7 @@
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
position: initial;
|
||||
}
|
||||
|
||||
.card .top {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
body .paper-font-display4, body .paper-font-display3, body .paper-font-title, body .paper-font-caption{
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.white-text {
|
||||
color: #dedede;
|
||||
color: rgba(255,255,255,0.87);
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
<iron-icon icon="settings" item-icon></iron-icon>
|
||||
Settings
|
||||
</paper-icon-item>
|
||||
<paper-icon-item id="characterExport">
|
||||
<iron-icon icon="content-copy" item-icon></iron-icon>
|
||||
Export to Improved Initiative
|
||||
</paper-icon-item>
|
||||
</paper-menu>
|
||||
</paper-menu-button>
|
||||
{{/if}}
|
||||
|
||||
@@ -203,4 +203,11 @@ Template.characterSheet.events({
|
||||
element: event.currentTarget.parentElement.parentElement,
|
||||
});
|
||||
},
|
||||
"click #characterExport": function(event, instance){
|
||||
pushDialogStack({
|
||||
data: this,
|
||||
template: "exportDialog",
|
||||
element: event.currentTarget.parentElement.parentElement,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -20,26 +20,28 @@
|
||||
<div class="effectEdit layout horizontal flex">
|
||||
<dicecloud-selector class="statMenu flex" selected={{stat}} selectable="paper-item" style="height: 100%; overflow-y: auto;">
|
||||
{{#each statGroups}}
|
||||
<div style="font-weight: bold; margin-top: 16px; padding-left: 8px;">
|
||||
<div class="statGroupTitle clickable" style="font-weight: bold; margin-top: 16px; padding-left: 8px;">
|
||||
{{this}}
|
||||
</div>
|
||||
{{#each stats}}
|
||||
<paper-item name={{stat}}>{{name}}</paper-item>
|
||||
{{/each}}
|
||||
<iron-collapse opened={{isGroupSelected this ../stat}}>
|
||||
{{#each stats}}
|
||||
<paper-item name={{stat}} class="clickable">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</iron-collapse>
|
||||
{{/each}}
|
||||
</dicecloud-selector>
|
||||
{{#if operations}}
|
||||
<dicecloud-selector class="operationMenu flex" selected={{operation}} style="height: 100%; overflow-y: auto;">
|
||||
{{#each operations}}
|
||||
<paper-item name={{operation}}>{{name}}</paper-item>
|
||||
<paper-item name={{operation}} class="clickable">{{name}}</paper-item>
|
||||
{{/each}}
|
||||
</dicecloud-selector>
|
||||
{{else}} {{#if showMultiplierOperations}}
|
||||
<dicecloud-selector class="multiplierMenu flex"
|
||||
selected={{value}}>
|
||||
<paper-item name="0.5">Resistance</paper-item>
|
||||
<paper-item name="2">Vulnerability</paper-item>
|
||||
<paper-item name="0">Immunity</paper-item>
|
||||
<paper-item name="0.5" class="clickable">Resistance</paper-item>
|
||||
<paper-item name="2" class="clickable">Vulnerability</paper-item>
|
||||
<paper-item name="0" class="clickable">Immunity</paper-item>
|
||||
</dicecloud-selector>
|
||||
{{else}}
|
||||
<div class="flex" style="height: 100%;"></div>
|
||||
|
||||
@@ -149,47 +149,71 @@ Template.effectEdit.helpers({
|
||||
effectValue: function(){
|
||||
return this.calculation || this.value;
|
||||
},
|
||||
isGroupSelected: function(groupName, statName){
|
||||
var stat = statsDict[statName]
|
||||
return stat && (stat.group === groupName);
|
||||
},
|
||||
});
|
||||
|
||||
var setStat = function(statName, effectId){
|
||||
var setter = {stat: statName};
|
||||
var effect = Effects.findOne(this._id);
|
||||
var group = statsDict[statName].group;
|
||||
if (group === "Saving Throws" || group === "Skills"){
|
||||
// Skills must have a valid skill operation
|
||||
if (!_.contains(
|
||||
_.map(skillOperations, ao => ao.operation),
|
||||
effect.operation
|
||||
)){
|
||||
setter.operation = "add";
|
||||
}
|
||||
} else if (group !== "Weakness/Resistance"){
|
||||
// Attributes must have a valid attribute operation
|
||||
if (!_.contains(
|
||||
_.map(attributeOperations, ao => ao.operation),
|
||||
effect.operation
|
||||
)){
|
||||
setter.operation = "base";
|
||||
}
|
||||
} else {
|
||||
// Weakness/Resistance must have a mul operation and value
|
||||
if (effect.operation !== "mul"){
|
||||
setter.operation = "mul";
|
||||
}
|
||||
if (!_.contains([0, 0.5, 2], effect.value)){
|
||||
setter.value = 0.5;
|
||||
}
|
||||
}
|
||||
Effects.update(effectId, {$set: setter});
|
||||
};
|
||||
|
||||
var scrollAnimationId;
|
||||
var scrollElementToView = element => {
|
||||
var scrollFunction = function(){
|
||||
element.scrollIntoView();
|
||||
scrollAnimationId = requestAnimationFrame(scrollFunction);
|
||||
};
|
||||
return scrollFunction;
|
||||
}
|
||||
|
||||
Template.effectEdit.events({
|
||||
"click #deleteButton": function(event, instance){
|
||||
Effects.softRemoveNode(instance.data.id);
|
||||
GlobalUI.deletedToast(instance.data.id, "Effects", "Effect");
|
||||
popDialogStack();
|
||||
},
|
||||
"click .statGroupTitle": function(event, instance){
|
||||
var groupName = this.toString();
|
||||
var firstStat = statGroups[groupName][0].stat;
|
||||
setStat(firstStat, instance.data.id);
|
||||
scrollAnimationId = requestAnimationFrame(scrollElementToView(event.target));
|
||||
_.delay(() => cancelAnimationFrame(scrollAnimationId), 300);
|
||||
},
|
||||
"iron-select .statMenu": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
var statName = detail.item.getAttribute("name");
|
||||
if (statName == this.stat) return;
|
||||
var setter = {stat: statName};
|
||||
var group = Blaze.getData(detail.item).group;
|
||||
var effect = Effects.findOne(this._id);
|
||||
if (group === "Saving Throws" || group === "Skills"){
|
||||
// Skills must have a valid skill operation
|
||||
if (!_.contains(
|
||||
_.map(skillOperations, ao => ao.operation),
|
||||
effect.operation
|
||||
)){
|
||||
setter.operation = "add";
|
||||
}
|
||||
} else if (group !== "Weakness/Resistance"){
|
||||
// Attributes must have a valid attribute operation
|
||||
if (!_.contains(
|
||||
_.map(attributeOperations, ao => ao.operation),
|
||||
effect.operation
|
||||
)){
|
||||
setter.operation = "base";
|
||||
}
|
||||
} else {
|
||||
// Weakness/Resistance must have a mul operation and value
|
||||
if (effect.operation !== "mul"){
|
||||
setter.operation = "mul";
|
||||
}
|
||||
if (!_.contains([0, 0.5, 2], effect.value)){
|
||||
setter.value = 0.5;
|
||||
}
|
||||
}
|
||||
Effects.update(this._id, {$set: setter});
|
||||
setStat(statName, this._id);
|
||||
},
|
||||
"iron-select .operationMenu": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
|
||||
@@ -33,7 +33,7 @@ Template.effectsEditList.events({
|
||||
template: "effectEdit",
|
||||
data: {id: effectId},
|
||||
element: event.currentTarget,
|
||||
returnElement: instance.find(`tr.effect[data-id='${effectId}']`),
|
||||
returnElement: () => instance.find(`tr.effect[data-id='${effectId}']`),
|
||||
});
|
||||
},
|
||||
"tap .edit-effect": function(event, template){
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.exportDialog .iiexport {
|
||||
overflow-y: auto;
|
||||
width: 100% !important;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<template name="exportDialog">
|
||||
<div class="exportDialog fit layout vertical">
|
||||
{{#with character}}
|
||||
<app-header fixed effects="waterfall">
|
||||
<app-toolbar>
|
||||
<div main-title>Export Character to Improved Initiative</div>
|
||||
</app-toolbar>
|
||||
</app-header>
|
||||
<div class="form flex layout vertical">
|
||||
<paper-toggle-button id="exportFeatures" checked={{settings.exportFeatures}}>
|
||||
Features
|
||||
</paper-toggle-button>
|
||||
<paper-toggle-button id="exportAttacks" checked={{settings.exportAttacks}}>
|
||||
Attacks
|
||||
</paper-toggle-button>
|
||||
<paper-toggle-button id="exportDescription" checked={{settings.exportDescription}}>
|
||||
Description
|
||||
</paper-toggle-button>
|
||||
<div class="paper-font-title padded">JSON</div>
|
||||
<textarea class="flex iiexport">{{improvedInitiativeJson}}</textarea>
|
||||
<paper-button id="copyExportButton" class="red-button" raised>
|
||||
<iron-icon icon="content-copy"></iron-icon>
|
||||
Copy to Clipboard
|
||||
</paper-button>
|
||||
</div>
|
||||
<div class="buttons layout horizontal end-justified">
|
||||
<paper-button class="doneButton"> Done </paper-button>
|
||||
</div>
|
||||
{{/with}}
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,60 @@
|
||||
Template.exportDialog.helpers({
|
||||
character: function(){
|
||||
return Characters.findOne(this._id);
|
||||
},
|
||||
improvedInitiativeJson: function(){
|
||||
var options = {
|
||||
features: this.settings.exportFeatures,
|
||||
attacks: this.settings.exportAttacks,
|
||||
description: this.settings.exportDescription,
|
||||
}
|
||||
return improvedInitiativeJson(this._id, options);
|
||||
},
|
||||
});
|
||||
|
||||
Template.exportDialog.events({
|
||||
"change #exportFeatures": function(event, template){
|
||||
Characters.update(this._id, {$set: {
|
||||
"settings.exportFeatures": event.target.checked,
|
||||
}});
|
||||
},
|
||||
"change #exportAttacks": function(event, template){
|
||||
Characters.update(this._id, {$set: {
|
||||
"settings.exportAttacks": event.target.checked,
|
||||
}});
|
||||
},
|
||||
"change #exportDescription": function(event, template){
|
||||
Characters.update(this._id, {$set: {
|
||||
"settings.exportDescription": event.target.checked,
|
||||
}});
|
||||
},
|
||||
"click #copyExportButton": function(event, template){
|
||||
var copyTextarea = template.find(".iiexport");
|
||||
copyTextarea.select();
|
||||
var msg;
|
||||
try {
|
||||
var successful = document.execCommand("copy");
|
||||
var msg = successful ? "JSON copied to clipboard" : "Unable to copy JSON";
|
||||
} catch (err) {
|
||||
msg = "Unable to copy JSON";
|
||||
} finally {
|
||||
clearSelection();
|
||||
GlobalUI.toast(msg);
|
||||
}
|
||||
},
|
||||
"click .doneButton": function(event, instance){
|
||||
popDialogStack();
|
||||
},
|
||||
});
|
||||
|
||||
var clearSelection = function(){
|
||||
if (window.getSelection) {
|
||||
if (window.getSelection().empty) { // Chrome
|
||||
window.getSelection().empty();
|
||||
} else if (window.getSelection().removeAllRanges) { // Firefox
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
} else if (document.selection) { // IE?
|
||||
document.selection.empty();
|
||||
}
|
||||
};
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div>{{#markdown}}{{evaluateString charId description}}{{/markdown}}</div>
|
||||
<div>{{#markdown}}{{evaluateSpellString charId parent.id description}}{{/markdown}}</div>
|
||||
{{> attacksViewList charId=charId parentId=_id}}
|
||||
</template>
|
||||
|
||||
|
||||
@@ -78,6 +78,20 @@
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.spell.item > div > div {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.spell.item > div {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.spell.item iron-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.spellLevel {
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transform: translateX(0);
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
{{/unless}}
|
||||
</div>
|
||||
<paper-diff-slider class="tempHitPointSlider flex"
|
||||
value={{left}}
|
||||
max={{maximum}}
|
||||
value={{left}}
|
||||
editable pin
|
||||
></paper-diff-slider>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +61,18 @@
|
||||
<td>Total</td>
|
||||
<td>{{characterCalculate "skillMod" charId skillName}}</td>
|
||||
</tr>
|
||||
{{#each passiveEffects}}
|
||||
<tr>
|
||||
<td>{{sourceName}}</td>
|
||||
<td>Passive Bonus: {{statValue}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#if showPassiveTotal}}
|
||||
<tr class="paper-font-body2">
|
||||
<td>Passive Score</td>
|
||||
<td>{{characterCalculate "passiveSkill" charId skillName}}</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ Template.skillDialogView.helpers({
|
||||
var char = Characters.findOne(this.charId);
|
||||
if (!char) return;
|
||||
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
|
||||
var proficiencyBonus =
|
||||
var proficiencyBonus =
|
||||
Characters.calculate.attributeValue(this.charId, "proficiencyBonus");
|
||||
return prof * proficiencyBonus;
|
||||
},
|
||||
@@ -189,6 +189,23 @@ Template.skillDialogView.helpers({
|
||||
enabled: true,
|
||||
});
|
||||
},
|
||||
passiveEffects: function(){
|
||||
return Effects.find({
|
||||
charId: this.charId,
|
||||
stat: this.skillName,
|
||||
operation: "passiveAdd",
|
||||
enabled: true,
|
||||
});
|
||||
},
|
||||
showPassiveTotal: function(){
|
||||
if (this.skillName === "perception") return true;
|
||||
return Effects.find({
|
||||
charId: this.charId,
|
||||
stat: this.skillName,
|
||||
operation: "passiveAdd",
|
||||
enabled: true,
|
||||
}).count();
|
||||
},
|
||||
ability: function(){
|
||||
var opts = {fields: {}};
|
||||
opts.fields[this.skillName] = 1;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{{#if conditionalCount}}
|
||||
*
|
||||
{{/if}}
|
||||
{{#if showPassive}}
|
||||
{{#if isPassiveShown}}
|
||||
({{characterCalculate "passiveSkill" ../_id skill}})
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
@@ -38,4 +38,16 @@ Template.skillRow.helpers({
|
||||
operation: "conditional",
|
||||
}).count();
|
||||
},
|
||||
isPassiveShown: function(){
|
||||
if (this.showPassive === "forced") return true;
|
||||
if (this.showPassive === "ifNeeded"){
|
||||
var charId = Template.parentData()._id;
|
||||
return Effects.find({
|
||||
charId,
|
||||
stat: this.skill,
|
||||
operation: "passiveAdd",
|
||||
enabled: true,
|
||||
}).count();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -49,24 +49,24 @@
|
||||
Skills
|
||||
</div>
|
||||
<div flex class="bottom list">
|
||||
{{> skillRow name="Acrobatics" skill="acrobatics"}}
|
||||
{{> skillRow name="Animal Handling" skill="animalHandling"}}
|
||||
{{> skillRow name="Arcana" skill="arcana"}}
|
||||
{{> skillRow name="Athletics" skill="athletics"}}
|
||||
{{> skillRow name="Deception" skill="deception"}}
|
||||
{{> skillRow name="History" skill="history"}}
|
||||
{{> skillRow name="Insight" skill="insight"}}
|
||||
{{> skillRow name="Intimidation" skill="intimidation"}}
|
||||
{{> skillRow name="Investigation" skill="investigation"}}
|
||||
{{> skillRow name="Medicine" skill="medicine"}}
|
||||
{{> skillRow name="Nature" skill="nature"}}
|
||||
{{> skillRow name="Perception" skill="perception" showPassive="true"}}
|
||||
{{> skillRow name="Performance" skill="performance"}}
|
||||
{{> skillRow name="Persuasion" skill="persuasion"}}
|
||||
{{> skillRow name="Religion" skill="religion"}}
|
||||
{{> skillRow name="Sleight of Hand" skill="sleightOfHand"}}
|
||||
{{> skillRow name="Stealth" skill="stealth"}}
|
||||
{{> skillRow name="Survival" skill="survival"}}
|
||||
{{> skillRow name="Acrobatics" skill="acrobatics" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Animal Handling" skill="animalHandling" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Arcana" skill="arcana" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Athletics" skill="athletics" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Deception" skill="deception" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="History" skill="history" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Insight" skill="insight" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Intimidation" skill="intimidation" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Investigation" skill="investigation" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Medicine" skill="medicine" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Nature" skill="nature" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Perception" skill="perception" showPassive="forced"}}
|
||||
{{> skillRow name="Performance" skill="performance" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Persuasion" skill="persuasion" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Religion" skill="religion" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Sleight of Hand" skill="sleightOfHand" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Stealth" skill="stealth" showPassive="ifNeeded"}}
|
||||
{{> skillRow name="Survival" skill="survival" showPassive="ifNeeded"}}
|
||||
</div>
|
||||
</paper-material>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{{#if characters.count}}
|
||||
<div class="character-list layout horizontal wrap">
|
||||
{{# each characters}}
|
||||
<a class="character-card flex layout vertical end-justified" href="/character/{{_id}}">
|
||||
<a class="character-card flex layout vertical end-justified" href="{{characterPath this}}">
|
||||
<iron-image class="fit {{colorClass}}"
|
||||
sizing="cover" preload fade src={{picture}}>
|
||||
</iron-image>
|
||||
|
||||
@@ -10,7 +10,15 @@ Template.characterList.helpers({
|
||||
]
|
||||
},
|
||||
{
|
||||
fields: {name: 1, picture: 1, color: 1, race: 1, alignment: 1, gender: 1},
|
||||
fields: {
|
||||
name: 1,
|
||||
urlName: 1,
|
||||
picture: 1,
|
||||
color: 1,
|
||||
race: 1,
|
||||
alignment: 1,
|
||||
gender: 1,
|
||||
},
|
||||
sort: {name: 1},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{{#if characters.count}}
|
||||
<div class="side-list">
|
||||
{{#each characters}}
|
||||
<a href={{pathFor route="characterSheet" data=this}} tabindex="-1" class="side-list-character characterRepresentative">
|
||||
<a href={{characterPath this}} tabindex="-1" class="side-list-character characterRepresentative">
|
||||
<paper-item class="short">
|
||||
<div class="character-name">
|
||||
{{name}}
|
||||
|
||||
@@ -14,7 +14,7 @@ Template.characterSideList.helpers({
|
||||
]
|
||||
},
|
||||
{
|
||||
fields: {name: 1},
|
||||
fields: {name: 1, urlName: 1},
|
||||
sort: {name: 1},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -21,10 +21,15 @@
|
||||
max-width: 300px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.intro .section .columns {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.intro paper-button {
|
||||
min-width: 200px;
|
||||
flex-basis: 200px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</div>
|
||||
<div class="section white-text" style="background: #282828">
|
||||
<div class="columns layout horizontal around-justified wrap">
|
||||
<div>
|
||||
<div class="layout vertical center">
|
||||
<div class="paper-font-headline">
|
||||
Guide
|
||||
</div>
|
||||
@@ -78,7 +78,7 @@
|
||||
</paper-button>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<div class="layout vertical center">
|
||||
<div class="paper-font-headline">
|
||||
Discuss
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
</paper-button>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<div class="layout vertical center">
|
||||
<div class="paper-font-headline">
|
||||
Get involved
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
})();
|
||||
|
||||
//evaluates a calculation string
|
||||
evaluate = function(charId, string){
|
||||
evaluate = function(charId, string, opts){
|
||||
var spellListId = opts && opts.spellListId;
|
||||
if (!string) return string;
|
||||
string = string.replace(/\b[a-z]+\b/gi, function(sub){
|
||||
string = string.replace(/\b[a-z,1-9]+\b/gi, function(sub){
|
||||
//fields
|
||||
if (Schemas.Character.schema(sub)){
|
||||
return Characters.calculate.fieldValue(charId, sub);
|
||||
@@ -43,6 +44,12 @@ evaluate = function(charId, string){
|
||||
if (sub.toUpperCase() === "LEVEL"){
|
||||
return Characters.calculate.level(charId);
|
||||
}
|
||||
if (spellListId && sub.toUpperCase() === "DC") {
|
||||
var list = SpellLists.findOne(spellListId);
|
||||
if (list && list.saveDC){
|
||||
return evaluate(charId, list.saveDC);
|
||||
}
|
||||
}
|
||||
return sub;
|
||||
});
|
||||
try {
|
||||
@@ -66,6 +73,17 @@ evaluateString = function(charId, string){
|
||||
return result;
|
||||
};
|
||||
|
||||
evaluateSpellString = function (charId, spellListId, string) {
|
||||
//define brackets as curly brackets around anything that isn't a curly bracket
|
||||
if (!string) return string;
|
||||
var brackets = /\{[^\{\}]*\}/g;
|
||||
var result = string.replace(brackets, function(exp){
|
||||
exp = exp.replace(/(\{|\})/g, ""); //remove curly brackets
|
||||
return evaluate(charId, exp, {spellListId});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
//returns the value of the effect if it exists,
|
||||
//otherwise returns the result of the calculation if it exists,
|
||||
//otherwise returns 0
|
||||
|
||||
@@ -249,7 +249,9 @@
|
||||
},
|
||||
|
||||
_updateItems: function() {
|
||||
var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
|
||||
var nodes = this.selectable
|
||||
? Polymer.dom(this).querySelectorAll(this.selectable)
|
||||
: Polymer.dom(this).queryDistributedElements('*');
|
||||
nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
|
||||
this._setItems(nodes);
|
||||
},
|
||||
|
||||
@@ -23,127 +23,13 @@ Meteor.methods({
|
||||
|
||||
Migrations.add({
|
||||
version: 1,
|
||||
name: "converts effect proficiencies to proficiency objects, removes types from assets",
|
||||
up: function() {
|
||||
//convert proficiency effects to proficiency objects
|
||||
Effects.find({operation: "proficiency"}).forEach(function(effect){
|
||||
var type = "skill";
|
||||
if (_.contains(SAVES, effect.stat)) type = "save";
|
||||
Proficiencies.insert({
|
||||
charId: effect.charId,
|
||||
name: effect.stat,
|
||||
value: effect.value,
|
||||
parent: _.clone(effect.parent),
|
||||
type: type,
|
||||
enabled: effect.enabled,
|
||||
}, function(err){
|
||||
if (!err) Effects.remove(effect._id);
|
||||
});
|
||||
});
|
||||
//store type as a parent group if it's needed
|
||||
Effects.find({"parent.collection": "Characters"}).forEach(function(e){
|
||||
Effects.update(e._id, {$set: {"parent.group": e.type}});
|
||||
});
|
||||
Attacks.find({"parent.collection": "Characters"}).forEach(function(a){
|
||||
Attacks.update(a._id, {$set: {"parent.group": a.type}});
|
||||
});
|
||||
//remove type
|
||||
Effects.update({}, {$unset: {type: ""}}, {validate: false, multi: true});
|
||||
Attacks.update({}, {$unset: {type: ""}}, {validate: false, multi: true});
|
||||
//remove languages and proficiencies
|
||||
Characters.update(
|
||||
{},
|
||||
{$unset: {languages: "", proficiencies: ""}},
|
||||
{validate: false, multi: true}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Migrations.add({
|
||||
version: 2,
|
||||
name: "Converts attacks from damage dice and damage bonus to a string with curly bracket calculations, adds settings.showIncrement to items",
|
||||
up: function() {
|
||||
//update attacks
|
||||
Attacks.find({}).forEach(function(attack) {
|
||||
if (!attack.damage && attack.damageDice && attack.damageBonus){
|
||||
var newDamage = attack.damageDice +
|
||||
" + {" + attack.damageBonus + "}";
|
||||
Attacks.update(
|
||||
attack._id,
|
||||
{
|
||||
$unset: {
|
||||
damageBonus: "",
|
||||
damageDice: "",
|
||||
},
|
||||
$set: {
|
||||
damage: newDamage
|
||||
},
|
||||
},
|
||||
{validate: false});
|
||||
}
|
||||
});
|
||||
//update Items
|
||||
Items.update(
|
||||
{settings: undefined},
|
||||
{$set: {"settings.showIncrement" : false}},
|
||||
{validate: false, multi: true}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Migrations.add({
|
||||
version: 3,
|
||||
name: "Converts attacks from damage dice and damage bonus to a string with curly bracket calculations, adds settings.showIncrement to items",
|
||||
name: "Gives all characters a URL name",
|
||||
up: function() {
|
||||
//update characters
|
||||
Characters.update(
|
||||
{"settings.useVariantEncumbrance": undefined},
|
||||
{$set: {"settings.useVariantEncumbrance" : false}},
|
||||
{validate: false, multi: true}
|
||||
);
|
||||
Characters.update(
|
||||
{"settings.useStandardEncumbrance": undefined},
|
||||
{$set: {"settings.useStandardEncumbrance" : true}},
|
||||
{validate: false, multi: true}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Migrations.add({
|
||||
version: 4,
|
||||
name: "Adds an effect to give characters a base carry capacity",
|
||||
up: function() {
|
||||
//update characters
|
||||
|
||||
Characters.find({}).forEach(function(char){
|
||||
Characters.update(char._id, {
|
||||
$set: {
|
||||
carryMultiplier: {
|
||||
adjustment: 0,
|
||||
reset: "longRest",
|
||||
}
|
||||
}
|
||||
});
|
||||
var effect = Effects.findOne({
|
||||
charId: char._id, name: "Natural Carrying Capacity"
|
||||
});
|
||||
if (effect) return;
|
||||
Effects.insert({
|
||||
charId: char._id,
|
||||
name: "Natural Carrying Capacity",
|
||||
stat: "carryMultiplier",
|
||||
operation: "base",
|
||||
value: "1",
|
||||
parent: {
|
||||
id: char._id,
|
||||
collection: "Characters",
|
||||
group: "Inate",
|
||||
},
|
||||
});
|
||||
effect = Effects.findOne({
|
||||
charId: char._id, name: "Natural Carrying Capacity"
|
||||
});
|
||||
if (!effect) throw "Carry capacity effect should be set by now."
|
||||
if (char.urlName) return;
|
||||
var urlName = getSlug(char.name, {maintainCase: true}) || "-";
|
||||
Characters.update(char._id, {$set: {urlName}});
|
||||
});
|
||||
},
|
||||
down: function(){
|
||||
|
||||
@@ -15,6 +15,7 @@ Meteor.publish("characterList", function(){
|
||||
{
|
||||
fields: {
|
||||
name: 1,
|
||||
urlName: 1,
|
||||
race: 1,
|
||||
alignment: 1,
|
||||
gender: 1,
|
||||
|
||||
Reference in New Issue
Block a user