Implemented remaining core features
This commit is contained in:
@@ -9,7 +9,8 @@ Schemas.Attack = new SimpleSchema({
|
||||
regEx: SimpleSchema.RegEx.Id
|
||||
},
|
||||
name: {
|
||||
type: String
|
||||
type: String,
|
||||
defaultValue: "New Attack"
|
||||
},
|
||||
range: {
|
||||
type: String,
|
||||
@@ -17,15 +18,24 @@ Schemas.Attack = new SimpleSchema({
|
||||
},
|
||||
attackBonus: {
|
||||
type: String,
|
||||
optional: true
|
||||
optional: true,
|
||||
defaultValue: "strengthMod + proficiencyBonus"
|
||||
},
|
||||
damage: {
|
||||
type: String
|
||||
type: String,
|
||||
optional: true,
|
||||
defaultValue: "1d8 + {strengthMod}"
|
||||
},
|
||||
damageType: {
|
||||
type: String,
|
||||
allowedValues: ["acid", "bludgeoning", "cold", "fire", "force", "lightning", "necrotic",
|
||||
"piercing", "poison", "psychic", "radiant", "slashing", "thunder"]
|
||||
allowedValues: ["bludgeoning", "piercing", "slashing", "acid", "cold", "fire", "force", "lightning", "necrotic",
|
||||
"poison", "psychic", "radiant", "thunder"],
|
||||
defaultValue: "slashing"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
allowedValues: _.pluck(colorOptions, "key"),
|
||||
defaultValue: "q"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -3,16 +3,18 @@ Characters = new Meteor.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},
|
||||
proficiencies:{ type: String, defaultValue: "", trim: false},
|
||||
languages: { type: String, defaultValue: "", trim: false},
|
||||
|
||||
//attributes
|
||||
//ability scores
|
||||
|
||||
@@ -5,7 +5,7 @@ Effects = new Meteor.Collection("effects");
|
||||
* that modify their final value or presentation in some way
|
||||
*/
|
||||
Schemas.Effect = new SimpleSchema({
|
||||
charId: {
|
||||
charId: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id
|
||||
},
|
||||
@@ -31,7 +31,7 @@ Schemas.Effect = new SimpleSchema({
|
||||
type: {
|
||||
type: String,
|
||||
defaultValue: "editable",
|
||||
allowedValues: ["editable", "feature", "buff", "equipment", "inate"]
|
||||
allowedValues: ["editable", "feature", "level", "buff", "equipment", "racial", "inate"]
|
||||
},
|
||||
//the id of the feature, buff or item that created this effect
|
||||
sourceId: {
|
||||
|
||||
20
rpg-docs/Model/Character/Levels/Classes.js
Normal file
20
rpg-docs/Model/Character/Levels/Classes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
Classes = new Meteor.Collection("classes");
|
||||
|
||||
Schemas.Class = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
|
||||
name: {type: String},
|
||||
createdAt: {
|
||||
type: Date,
|
||||
autoValue: function() {
|
||||
if (this.isInsert) {
|
||||
return new Date;
|
||||
} else if (this.isUpsert) {
|
||||
return {$setOnInsert: new Date};
|
||||
} else {
|
||||
this.unset();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Classes.attachSchema(Schemas.Class);
|
||||
9
rpg-docs/Model/Character/Levels/Levels.js
Normal file
9
rpg-docs/Model/Character/Levels/Levels.js
Normal file
@@ -0,0 +1,9 @@
|
||||
Levels = new Meteor.Collection("levels");
|
||||
|
||||
Schemas.Level = new SimpleSchema({
|
||||
charId: {type: String, regEx: SimpleSchema.RegEx.Id},
|
||||
classId: {type: String, regEx: SimpleSchema.RegEx.Id},
|
||||
value: {type: Number}
|
||||
});
|
||||
|
||||
Levels.attachSchema(Schemas.Level);
|
||||
@@ -14,5 +14,9 @@ Schemas.DeathSave = new SimpleSchema({
|
||||
canDeathSave: {
|
||||
type: Boolean,
|
||||
defaultValue: true
|
||||
},
|
||||
stable: {
|
||||
type: Boolean,
|
||||
defaultValue: false
|
||||
}
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
//set up the collection for containers
|
||||
Containers = new Meteor.Collection("containers");
|
||||
|
||||
|
||||
Schemas.Container = new SimpleSchema({
|
||||
name: { type: String },
|
||||
charId: { type: String, regEx: SimpleSchema.RegEx.Id},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Template.registerHelper("detailHero", function(){
|
||||
if ( Session.equals("global.ui.detailHeroId", this._id) ) {
|
||||
Template.registerHelper("detailHero", function(suffix){
|
||||
var id = suffix? this._id + suffix : this._id;
|
||||
if ( Session.equals("global.ui.detailHeroId", id) ) {
|
||||
return "hero";
|
||||
}
|
||||
});
|
||||
@@ -4,5 +4,13 @@ Template.registerHelper("evaluate", function(charId, string){
|
||||
|
||||
Template.registerHelper("evaluateSigned", function(charId, string){
|
||||
var number = evaluate(charId, string);
|
||||
return number > 0? "+" + number : "" + number;
|
||||
if(_.isFinite(number)){
|
||||
return number > 0? "+" + number : "" + number;
|
||||
} else{
|
||||
return number;
|
||||
}
|
||||
});
|
||||
|
||||
Template.registerHelper("evaluateString", function(charId, string){
|
||||
return evaluateString(charId, string);
|
||||
});
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
Session.set("Mongol", {
|
||||
'collections': [
|
||||
"Characters",
|
||||
"Actions",
|
||||
"Attacks",
|
||||
"Classes",
|
||||
"Containers",
|
||||
"Items",
|
||||
"Features",
|
||||
"Effects",
|
||||
"Spells",
|
||||
"SpellLists",
|
||||
"Experiences",
|
||||
"Features",
|
||||
"Items",
|
||||
"Levels",
|
||||
"Notes",
|
||||
"Experiences"
|
||||
"Spells",
|
||||
"SpellLists"
|
||||
],
|
||||
'display': true,
|
||||
'opacity_normal': ".7",
|
||||
|
||||
@@ -161,6 +161,10 @@ paper-fab-menu /deep/ .container {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
paper-slider {
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.list-subhead {
|
||||
color: rgba(0,0,0,0.54);
|
||||
font-size: 14px;
|
||||
@@ -169,6 +173,18 @@ paper-fab-menu /deep/ .container {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.whiteTop {
|
||||
border-bottom: rgba(0,0,0,0.12) solid 1px;
|
||||
background: white;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.whiteTop paper-icon-button {
|
||||
margin: -8px;
|
||||
}
|
||||
|
||||
.fullwidth {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -177,6 +193,26 @@ paper-fab-menu /deep/ .container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.listPadded {
|
||||
padding: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.rightPadded {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.bottomPadded {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.s {
|
||||
padding: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.leftRound{
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
.preline {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
@@ -101,3 +101,8 @@ p, .body1, body {
|
||||
html /deep/ .white-text{
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.black54 {
|
||||
color: #444;
|
||||
color: rgba(0,0,0,0.54);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<template name="attackDialog">
|
||||
{{#with attack}}
|
||||
<core-header-panel fit>
|
||||
<core-toolbar class={{colorClass}} hero-id="toolbar" hero>
|
||||
<paper-icon-button id="backButton" role="button" tabindex="0" icon="arrow-back" aria-label="close"></paper-icon-button>
|
||||
<div flex>{{name}}</div>
|
||||
<paper-icon-button id="deleteAttack"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
icon="delete"
|
||||
aria-label="Delete Attack"
|
||||
noink></paper-icon-button>
|
||||
</core-toolbar>
|
||||
<div class="detailContent">
|
||||
<div layout horizontal>
|
||||
<!--Name-->
|
||||
<paper-input id="attackNameInput" label="Name" floatinglabel value={{name}}></paper-input>
|
||||
<!--color-->
|
||||
{{> colorDropdown}}
|
||||
</div>
|
||||
<!--attackBonus-->
|
||||
<paper-input id="attackBonusInput" label="Attack Bonus" floatinglabel value={{attackBonus}}></paper-input>
|
||||
<!--damage-->
|
||||
<paper-input id="damageInput" label="Damage" floatinglabel value={{damage}}></paper-input>
|
||||
<!--range-->
|
||||
<paper-input id="rangeInput" label="Range" floatinglabel value={{range}}></paper-input>
|
||||
<!--DamageType-->
|
||||
<paper-dropdown-menu id="damageTypeDropdown" label="DamageType">
|
||||
<paper-dropdown layered class="dropdown">
|
||||
<core-menu class="menu" selected={{damageType}}>
|
||||
{{#each damageTypes}}
|
||||
<paper-item name={{this}} class="containerMenuItem">{{this}}</paper-item>
|
||||
{{/each}}
|
||||
</core-menu>
|
||||
</paper-dropdown>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
</core-header-panel>
|
||||
{{/with}}
|
||||
</template>
|
||||
@@ -0,0 +1,78 @@
|
||||
var damageTypes = ["bludgeoning", "piercing", "slashing", "acid", "cold", "fire", "force", "lightning", "necrotic",
|
||||
"poison", "psychic", "radiant", "thunder"];
|
||||
|
||||
Template.attackDialog.rendered = function(){
|
||||
var self = this;
|
||||
//update all autogrows after they've been filled
|
||||
var pata = this.$("paper-autogrow-textarea");
|
||||
pata.each(function(index, el){
|
||||
el.update($(el).children().get(0));
|
||||
})
|
||||
//update all input fields as well
|
||||
var input = this.$("paper-input");
|
||||
input.each(function(index, el){
|
||||
el.valueChanged();
|
||||
})
|
||||
//after the dialog is built, open it
|
||||
if (!this.alreadyRendered){
|
||||
Session.set("global.ui.detailShow", true);
|
||||
this.alreadyRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
Template.attackDialog.events({
|
||||
"tap #backButton": function(){
|
||||
GlobalUI.closeDetail()
|
||||
},
|
||||
"tap #deleteAttack": function(){
|
||||
Attacks.remove(this._id);
|
||||
GlobalUI.closeDetail()
|
||||
},
|
||||
"tap #addEffectButton": function(){
|
||||
Effects.insert({
|
||||
charId: this.charId,
|
||||
sourceId: this._id,
|
||||
operation: "add",
|
||||
type: "attack"
|
||||
});
|
||||
},
|
||||
"change #attackNameInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #attackBonusInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {attackBonus: value}});
|
||||
},
|
||||
"change #damageInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {damage: value}});
|
||||
},
|
||||
"change #rangeInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Attacks.update(this._id, {$set: {range: value}});
|
||||
},
|
||||
"core-select #damageTypeDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if(!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if(value == this.damageType) return;
|
||||
Attacks.update(this._id, {$set: {damageType: value}});
|
||||
},
|
||||
"core-select .colorDropdown": function(event){
|
||||
var detail = event.originalEvent.detail;
|
||||
if(!detail.isSelected) return;
|
||||
var value = detail.item.getAttribute("name");
|
||||
if(value == this.color) return;
|
||||
Attacks.update(this._id, {$set: {color: value}});
|
||||
},
|
||||
});
|
||||
|
||||
Template.attackDialog.helpers({
|
||||
attack: function(){
|
||||
return Attacks.findOne(this.attackId);
|
||||
},
|
||||
damageTypes: function(){
|
||||
return damageTypes;
|
||||
}
|
||||
});
|
||||
@@ -20,5 +20,4 @@
|
||||
|
||||
.resourceCards paper-shadow.healthCard {
|
||||
width: 100%;
|
||||
padding: 0 16px 0 0;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,48 @@
|
||||
{{>resource name="sorceryPoints" title="Sorcery Points" color="teal" char=this}}
|
||||
<!--superiorityDice-->
|
||||
{{>resource name="superiorityDice" title="Superiority Dice" color="teal" char=this}}
|
||||
|
||||
<!--Attacks-->
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}}>
|
||||
<div class="whiteTop" hero-id="toolbar" layout horizontal center {{detailHero}}>
|
||||
<div flex>
|
||||
<div class="containerName subhead">Attacks</div>
|
||||
</div>
|
||||
<paper-icon-button class="black54" id="addAttackButton" icon="add"></paper-icon-button>
|
||||
</div>
|
||||
<div class="containerMain listPadded">
|
||||
{{#each attacks}}
|
||||
<div class="itemSlot">
|
||||
<paper-item class="white attack" hero-id="main" {{detailHero}}>
|
||||
<div layout horizontal class="fullwidth">
|
||||
<div class="headline rightPadded" layout horizontal center>
|
||||
{{evaluateSigned ../_id attackBonus}}
|
||||
</div>
|
||||
<div layout vertical flex>
|
||||
<div>{{name}}</div>
|
||||
<div class="caption">
|
||||
{{{evaluateString ../_id damage}}} {{damageType}} {{range}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</paper-item>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
|
||||
<!--Proficiencies-->
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero "proficiencies"}}>
|
||||
<div id="proficiencies"
|
||||
class="containerTop grey white-text"
|
||||
hero-id="toolbar"
|
||||
layout horizontal center
|
||||
{{detailHero "proficiencies"}}>
|
||||
<div class="containerName subhead">Proficiencies</div>
|
||||
</div>
|
||||
<div flex class="containerMain padded preline">{{characterProficiencies}}</div>
|
||||
</paper-shadow>
|
||||
|
||||
<!--features-->
|
||||
{{#each features}}
|
||||
<paper-shadow class="card container featureCard" hero-id="main" {{detailHero}}>
|
||||
|
||||
@@ -11,6 +11,13 @@ Template.features.helpers({
|
||||
},
|
||||
featureOrder: function(){
|
||||
return _.indexOf(_.keys(colorOptions), this.color);
|
||||
},
|
||||
attacks: function(){
|
||||
return Attacks.find({charId: this._id}, {sort: {color: 1, name: 1}});
|
||||
},
|
||||
characterProficiencies: function(){
|
||||
var char = Characters.findOne(this._id);
|
||||
return char && char.proficiencies;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,7 +30,21 @@ Template.features.events({
|
||||
heroId: featureId
|
||||
})
|
||||
},
|
||||
"tap .containerTop": function(event){
|
||||
"tap #addAttackButton": function(event){
|
||||
var charId = this._id;
|
||||
Attacks.insert({
|
||||
charId: charId
|
||||
}, function(error, id){
|
||||
if(!error){
|
||||
GlobalUI.setDetail({
|
||||
template: "attackDialog",
|
||||
data: {attackId: id, charId: charId},
|
||||
heroId: id
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
"tap .featureCard .containerTop": function(event){
|
||||
var featureId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
@@ -32,6 +53,15 @@ Template.features.events({
|
||||
heroId: featureId
|
||||
});
|
||||
},
|
||||
"tap .attack": function(event){
|
||||
var attackId = this._id;
|
||||
var charId = Template.parentData()._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "attackDialog",
|
||||
data: {attackId: attackId, charId: charId},
|
||||
heroId: attackId
|
||||
});
|
||||
},
|
||||
"tap .useFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$inc: {used: 1}});
|
||||
@@ -39,6 +69,14 @@ Template.features.events({
|
||||
"tap .resetFeature": function(event){
|
||||
var featureId = this._id;
|
||||
Features.update(featureId, {$set: {used: 0}});
|
||||
},
|
||||
"tap #proficiencies": function(event){
|
||||
var charId = this._id;
|
||||
GlobalUI.setDetail({
|
||||
template: "textDialog",
|
||||
data: {charId: charId, field: "proficiencies", title: "Proficiencies", color: "q"},
|
||||
heroId: this._id + "proficiencies"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<template name="healthCard">
|
||||
<paper-shadow class="card container healthCard" hero-id="main" {{detailHero}} layout horizontal>
|
||||
<div class="green white-text title padded leftRound" layout horizontal center>
|
||||
Hit Points
|
||||
</div>
|
||||
<div flex layout vertical around-justified>
|
||||
<paper-slider id="hitPointSlider"
|
||||
value={{attributeValue "hitPoints"}}
|
||||
max={{attributeBase "hitPoints"}}
|
||||
editable pin
|
||||
role="slider"
|
||||
></paper-slider>
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</template>
|
||||
@@ -1,7 +0,0 @@
|
||||
Template.healthCard.events({
|
||||
"change #hitPointSlider": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
var adjustment = value - this.attributeBase("hitPoints");
|
||||
Characters.update(this._id, {$set: {"hitPoints.adjustment": adjustment}});
|
||||
}
|
||||
});
|
||||
@@ -2,11 +2,32 @@
|
||||
<div fit>
|
||||
<div id="inventory" class="scroll-y" fit>
|
||||
<div class="containers">
|
||||
<!--Net Worth-->
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}} layout horizontal>
|
||||
<div class="indigo white-text subhead padded leftRound" layout horizontal center>
|
||||
Net Worth
|
||||
</div>
|
||||
<div class="padded" layout horizontal center>
|
||||
{{valueString netWorth}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
<!--Weight Carried-->
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}} layout horizontal>
|
||||
<div class="green white-text subhead padded leftRound" layout horizontal center>
|
||||
Weight Carried
|
||||
</div>
|
||||
<div class="padded" layout horizontal center>
|
||||
{{round weightCarried}}lbs
|
||||
</div>
|
||||
</paper-shadow>
|
||||
<!--Equipment-->
|
||||
<paper-shadow class="card container">
|
||||
<div class="equipmentTop" layout horizontal center>
|
||||
<div class="containerName subhead" flex>Equipment</div>
|
||||
<div class="caption" style="margin-right: 8px">(net Worth)</div>
|
||||
<div class="caption">(weightCarried)lbs</div>
|
||||
<div class="containerName subhead" flex>
|
||||
Equipment
|
||||
</div>
|
||||
<div class="caption" style="margin-right: 8px">{{valueString equipmentValue}}</div>
|
||||
<div class="caption">{{round equipmentWeight}}lbs</div>
|
||||
</div>
|
||||
<div flex class="equipmentMain">
|
||||
{{#if armor}}
|
||||
|
||||
@@ -24,8 +24,36 @@ Template.inventory.helpers({
|
||||
colorClass: function(){
|
||||
return getColorClass(this.color)
|
||||
},
|
||||
containerOrder: function(){
|
||||
return _.indexOf(_.keys(colorOptions), this.color);
|
||||
netWorth: function(){
|
||||
var worth = 0;
|
||||
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){
|
||||
weight += container.totalWeight();
|
||||
});
|
||||
Items.find({charId: this._id, equipped: false}, {fields: {weight : 1, quantity: 1}}).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
},
|
||||
equipmentValue: function(){
|
||||
var value = 0;
|
||||
Items.find({charId: this._id, equipped: true}, {fields: {value : 1, quantity: 1}}).forEach(function(item){
|
||||
value += item.totalValue();
|
||||
});
|
||||
return value;
|
||||
},
|
||||
equipmentWeight: function(){
|
||||
var weight = 0;
|
||||
Items.find({charId: this._id, equipped: true}, {fields: {weight : 1, quantity: 1}}).forEach(function(item){
|
||||
weight += item.totalWeight();
|
||||
});
|
||||
return weight;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<paper-shadow class="card container experiencesCard" hero-id="main" {{detailHero}}>
|
||||
<div class="containerTop {{colorClass}}" hero-id="toolbar" layout horizontal center {{detailHero}}>
|
||||
<div class="containerName subhead" flex>Experience</div>
|
||||
<div class="subhead">{{experience}}XP</div>
|
||||
<div class="subhead">{{experience}} XP</div>
|
||||
</div>
|
||||
<div class="containerMain experiences">
|
||||
{{#each experiences}}
|
||||
@@ -23,6 +23,35 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</paper-shadow>
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}}>
|
||||
<div class="containerTop {{colorClass}}" hero-id="toolbar" layout horizontal center {{detailHero}}>
|
||||
<div flex>
|
||||
<div class="containerName subhead">Levels</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="containerMain experiences">
|
||||
<div class="list-subhead" layout horizontal center>
|
||||
Race
|
||||
</div>
|
||||
<div class="itemSlot">
|
||||
<paper-item class="inventoryItem race" hero-id="main" {{detailHero "race"}} layout horizontal>
|
||||
{{race}}
|
||||
</paper-item>
|
||||
</div>
|
||||
{{#each classes}}
|
||||
<div class="list-subhead" layout horizontal center>
|
||||
{{name}}
|
||||
</div>
|
||||
{{#each levels ../_id}}
|
||||
<div class="itemSlot">
|
||||
<paper-item class="inventoryItem level" hero-id="main" {{detailHero}} layout horizontal>
|
||||
Level {{value}}
|
||||
</paper-item>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
{{#each notes}}
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}}>
|
||||
<div class="containerTop {{colorClass}} noteTop" hero-id="toolbar" layout horizontal center {{detailHero}}>
|
||||
@@ -30,9 +59,7 @@
|
||||
<div class="containerName subhead">{{name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="containerMain">
|
||||
{{description}}
|
||||
</div>
|
||||
<div class="containerMain preline">{{description}}</div>
|
||||
</paper-shadow>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,16 @@ Template.journal.helpers({
|
||||
moreExperiencesOrCollapse: function(){
|
||||
return (!(Experiences.find({charId: this._id}).count() < Template.instance().experiencesLimit.get())) ||
|
||||
Template.instance().experiencesLimit.get() > (this.settings && this.settings.experiencesInc || 10);
|
||||
},
|
||||
classes: function(){
|
||||
return Classes.find({charId: this._id}, {sort: {createdAt: 1}});
|
||||
},
|
||||
levels: function(charId){
|
||||
return Levels.find({charId: charId, classId: this._id}, {sort: {value: 1}});
|
||||
},
|
||||
race: function(){
|
||||
var char = Characters.findOne(this._id, {fields: {race: 1}});
|
||||
return char && char.race;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,6 +47,20 @@ Template.journal.events({
|
||||
heroId: this._id
|
||||
});
|
||||
},
|
||||
"tap .level": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "levelDialog",
|
||||
data: {levelId: this._id, charId: this.charId},
|
||||
heroId: this._id
|
||||
});
|
||||
},
|
||||
"tap .race": function(event){
|
||||
GlobalUI.setDetail({
|
||||
template: "raceDialog",
|
||||
data: {charId: this._id},
|
||||
heroId: this._id + "race"
|
||||
});
|
||||
},
|
||||
"tap #addNote": function(event){
|
||||
var charId = this._id;
|
||||
Notes.insert({
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<template name="levelDialog">
|
||||
{{#with level}}
|
||||
<core-header-panel fit>
|
||||
<core-toolbar class="grey white-text" hero-id="toolbar" hero>
|
||||
<paper-icon-button id="backButton" role="button" tabindex="0" icon="arrow-back" aria-label="close"></paper-icon-button>
|
||||
<div flex>{{name}}</div>
|
||||
<paper-icon-button id="deleteLevel"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
icon="delete"
|
||||
aria-label="Delete Level"
|
||||
noink></paper-icon-button>
|
||||
</core-toolbar>
|
||||
<div class="detailContent">
|
||||
<!--Level-->
|
||||
<paper-input id="levelValueInput" label="Level" floatinglabel value={{value}}></paper-input>
|
||||
{{#if effects}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div id="effects">
|
||||
<h2>Effects</h2>
|
||||
{{#each effects}}
|
||||
{{>effectEdit}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div layout horizontal end-justified>
|
||||
<paper-button id="addEffectButton" raised>Add Effect</paper-button>
|
||||
</div>
|
||||
</div>
|
||||
</core-header-panel>
|
||||
{{/with}}
|
||||
</template>
|
||||
@@ -0,0 +1,49 @@
|
||||
Template.levelDialog.rendered = function(){
|
||||
var self = this;
|
||||
//update all autogrows after they've been filled
|
||||
var pata = this.$("paper-autogrow-textarea");
|
||||
pata.each(function(index, el){
|
||||
el.update($(el).children().get(0));
|
||||
})
|
||||
//update all input fields as well
|
||||
var input = this.$("paper-input");
|
||||
input.each(function(index, el){
|
||||
el.valueChanged();
|
||||
})
|
||||
//after the dialog is built, open it
|
||||
if (!this.alreadyRendered){
|
||||
Session.set("global.ui.detailShow", true);
|
||||
this.alreadyRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
Template.levelDialog.events({
|
||||
"tap #backButton": function(){
|
||||
GlobalUI.closeDetail()
|
||||
},
|
||||
"tap #deleteLevel": function(){
|
||||
Levels.remove(this._id);
|
||||
GlobalUI.closeDetail()
|
||||
},
|
||||
"tap #addEffectButton": function(){
|
||||
Effects.insert({
|
||||
charId: this.charId,
|
||||
sourceId: this._id,
|
||||
operation: "add",
|
||||
type: "level"
|
||||
});
|
||||
},
|
||||
"change #levelValueInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Levels.update(this._id, {$set: {value: value}});
|
||||
}
|
||||
});
|
||||
|
||||
Template.levelDialog.helpers({
|
||||
level: function(){
|
||||
return Levels.findOne(this.levelId);
|
||||
},
|
||||
effects: function(){
|
||||
return Effects.find({sourceId: this._id, type: "level"});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
<template name="raceDialog">
|
||||
<core-header-panel fit>
|
||||
<core-toolbar class="grey white-text" hero-id="toolbar" hero>
|
||||
<paper-icon-button id="backButton" role="button" tabindex="0" icon="arrow-back" aria-label="close"></paper-icon-button>
|
||||
<div flex>{{race}}</div>
|
||||
</core-toolbar>
|
||||
<div class="detailContent">
|
||||
<paper-input id="raceInput" label="Race" floatinglabel value={{race}}></paper-input>
|
||||
{{#if effects}}
|
||||
<hr style="margin: 16px 0 16px 0;">
|
||||
<div id="effects">
|
||||
<h2>Effects</h2>
|
||||
{{#each effects}}
|
||||
{{>effectEdit}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div layout horizontal end-justified>
|
||||
<paper-button id="addEffectButton" raised>Add Effect</paper-button>
|
||||
</div>
|
||||
</div>
|
||||
</core-header-panel>
|
||||
</template>
|
||||
@@ -0,0 +1,45 @@
|
||||
Template.raceDialog.rendered = function(){
|
||||
var self = this;
|
||||
//update all autogrows after they've been filled
|
||||
var pata = this.$("paper-autogrow-textarea");
|
||||
pata.each(function(index, el){
|
||||
el.update($(el).children().get(0));
|
||||
})
|
||||
//update all input fields as well
|
||||
var input = this.$("paper-input");
|
||||
input.each(function(index, el){
|
||||
el.valueChanged();
|
||||
})
|
||||
//after the dialog is built, open it
|
||||
if (!this.alreadyRendered){
|
||||
Session.set("global.ui.detailShow", true);
|
||||
this.alreadyRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
Template.raceDialog.events({
|
||||
"tap #backButton": function(){
|
||||
GlobalUI.closeDetail()
|
||||
},
|
||||
"tap #addEffectButton": function(){
|
||||
Effects.insert({
|
||||
charId: this.charId,
|
||||
operation: "add",
|
||||
type: "racial"
|
||||
});
|
||||
},
|
||||
"change #raceInput": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
Characters.update(this.charId, {$set: {race: value}});
|
||||
}
|
||||
});
|
||||
|
||||
Template.raceDialog.helpers({
|
||||
effects: function(){
|
||||
return Effects.find({charId: this.charId, type: "racial"});
|
||||
},
|
||||
race: function(){
|
||||
var char = Characters.findOne(this.charId, {fields: {race: 1}});
|
||||
return char && char.race;
|
||||
}
|
||||
});
|
||||
@@ -11,6 +11,7 @@
|
||||
{{> containerCard characterField "bonds" "Bonds"}}
|
||||
{{> containerCard characterField "flaws" "Flaws"}}
|
||||
{{> containerCard characterField "backstory" "Background"}}
|
||||
{{> containerCard characterField "languages" "Languages"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,8 @@ var colorMap = {
|
||||
ideals: "g",
|
||||
bonds: "h",
|
||||
flaws: "i",
|
||||
backstory: "j"
|
||||
backstory: "j",
|
||||
languages: "k"
|
||||
}
|
||||
|
||||
Template.persona.helpers({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var spellLevels = [
|
||||
{ name: "Cantrips", level: 0 },
|
||||
{ name: "Cantrip", level: 0 },
|
||||
{ name: "Level 1", level: 1 },
|
||||
{ name: "Level 2", level: 2 },
|
||||
{ name: "Level 3", level: 3 },
|
||||
|
||||
@@ -31,15 +31,15 @@ Template.spellListDialog.events({
|
||||
var value = event.currentTarget.value
|
||||
SpellLists.update(this._id, {$set: {name: value}});
|
||||
},
|
||||
"change #spellListSaveDCInput, input #spellListNameInput": function(event){
|
||||
"change #spellListSaveDCInput, input #spellListSaveDCInput": function(event){
|
||||
var value = event.currentTarget.value
|
||||
SpellLists.update(this._id, {$set: {saveDC: value}});
|
||||
},
|
||||
"change #spellListAttackBonusInput, input #spellListNameInput": function(event){
|
||||
"change #spellListAttackBonusInput, input #spellListAttackBonusInput": function(event){
|
||||
var value = event.currentTarget.value
|
||||
SpellLists.update(this._id, {$set: {attackBonus: value}});
|
||||
},
|
||||
"change #spellListMaxPreparedInput, input #spellListNameInput": function(event){
|
||||
"change #spellListMaxPreparedInput, input #spellListMaxPreparedInput": function(event){
|
||||
var value = event.currentTarget.value
|
||||
SpellLists.update(this._id, {$set: {maxPrepared: value}});
|
||||
},
|
||||
|
||||
@@ -2,27 +2,29 @@
|
||||
<div fit>
|
||||
<div id="spells" class="scroll-y" fit>
|
||||
<div class="containers">
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}} style="order: {{containerOrder}};">
|
||||
<div class="containerTop {{colorClass}}" layout horizontal center>
|
||||
<div class="containerName subhead" hero-id="title" flex>Spell Slots</div>
|
||||
</div>
|
||||
<div flex class="containerMain">
|
||||
{{#each levels}}{{#if showSlots ..}}
|
||||
<div class="itemSlot">
|
||||
<paper-item class="inventoryItem spellSlot" hero-id="main" {{detailHero}} layout horizontal>
|
||||
<div class="slotName">
|
||||
{{name}}
|
||||
</div>
|
||||
<div flex layout horizontal center>
|
||||
{{#each slotBubbles ..}}
|
||||
<paper-icon-button class="slotBubble" icon={{icon}} disabled={{disabled}}></paper-icon-button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-item>
|
||||
</div>
|
||||
{{/if}}{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
{{#if hasSlots}}
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}} style="order: {{containerOrder}};">
|
||||
<div class="containerTop {{colorClass}}" layout horizontal center>
|
||||
<div class="containerName subhead" hero-id="title" flex>Spell Slots</div>
|
||||
</div>
|
||||
<div flex class="containerMain">
|
||||
{{#each levels}}{{#if showSlots ..}}
|
||||
<div class="itemSlot">
|
||||
<paper-item class="inventoryItem spellSlot" hero-id="main" {{detailHero}} layout horizontal>
|
||||
<div class="slotName">
|
||||
{{name}}
|
||||
</div>
|
||||
<div flex layout horizontal center>
|
||||
{{#each slotBubbles ..}}
|
||||
<paper-icon-button class="slotBubble" icon={{icon}} disabled={{disabled}}></paper-icon-button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</paper-item>
|
||||
</div>
|
||||
{{/if}}{{/each}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
{{/if}}
|
||||
{{#each spellLists}}
|
||||
<paper-shadow class="card container" hero-id="main" {{detailHero}} style="order: {{order}};">
|
||||
<div class="containerTop {{colorClass}}" hero-id="toolbar" layout horizontal center {{detailHero}}>
|
||||
|
||||
@@ -46,7 +46,7 @@ Template.spells.helpers({
|
||||
}
|
||||
if(this.components.material){
|
||||
components += components? ", M" : "M";
|
||||
components += "("+this.components.material+")";
|
||||
components += " ("+this.components.material+")";
|
||||
}
|
||||
if(this.components.concentration){
|
||||
components += " - Requires concentration"
|
||||
@@ -83,6 +83,14 @@ Template.spells.helpers({
|
||||
showSlots: function(char){
|
||||
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")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
slotBubbles: function(char){
|
||||
var baseSlots = char.attributeBase("level" + this.level +"SpellSlots"),
|
||||
currentSlots = char.attributeValue("level" + this.level +"SpellSlots"),
|
||||
@@ -165,7 +173,8 @@ Template.spells.events({
|
||||
Spells.insert({
|
||||
name: "New Spell",
|
||||
charId: this._id,
|
||||
listId: SpellLists.findOne({charId: this._id})._id
|
||||
listId: SpellLists.findOne({charId: this._id})._id,
|
||||
prepared: "prepared"
|
||||
}, function(error, id){
|
||||
if(!error){
|
||||
GlobalUI.setDetail({
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<template name="healthCard">
|
||||
<paper-shadow class="card container healthCard" hero-id="main" {{detailHero}} layout horizontal wrap>
|
||||
<div class="green white-text subhead padded leftRound" layout horizontal center>
|
||||
Hit Points
|
||||
</div>
|
||||
<div class="padded" flex layout vertical center-justified style="min-width: 180px;">
|
||||
<paper-slider id="hitPointSlider"
|
||||
value={{attributeValue "hitPoints"}}
|
||||
max={{attributeBase "hitPoints"}}
|
||||
editable pin
|
||||
role="slider"
|
||||
></paper-slider>
|
||||
{{#if showDeathSave}}
|
||||
{{#with deathSaveObject}}
|
||||
<div class="padded" layout vertical center>
|
||||
<div class="subhead">
|
||||
Death Saves
|
||||
</div>
|
||||
<div layout horizontal>
|
||||
<div layout vertical center>
|
||||
<div class="caption">Fail</div>
|
||||
<div layout horizontal center-justified wrap reverse>
|
||||
<paper-icon-button class="slotBubble failBubble" icon={{failIcon 1}} disabled={{failDisabled 1}}></paper-icon-button>
|
||||
<paper-icon-button class="slotBubble failBubble" icon={{failIcon 2}} disabled={{failDisabled 2}}></paper-icon-button>
|
||||
<paper-icon-button class="slotBubble failBubble" icon={{failIcon 3}} disabled={{failDisabled 3}}></paper-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
<div layout horizontal center center-justified style="min-width: 94px">
|
||||
{{#if dead}}
|
||||
DEAD
|
||||
{{else}}
|
||||
{{#if stable}}
|
||||
<paper-button id="stableButton">Stable</paper-button>
|
||||
{{else}}
|
||||
<paper-button id="unstableButton">Unstable</paper-button>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div layout vertical center>
|
||||
<div class="caption">Pass</div>
|
||||
<div layout horizontal center-justified wrap>
|
||||
<paper-icon-button class="slotBubble passBubble" icon={{passIcon 1}} disabled={{passDisabled 1}}></paper-icon-button>
|
||||
<paper-icon-button class="slotBubble passBubble" icon={{passIcon 2}} disabled={{passDisabled 2}}></paper-icon-button>
|
||||
<paper-icon-button class="slotBubble passBubble" icon={{passIcon 3}} disabled={{passDisabled 3}}></paper-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/with}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</paper-shadow>
|
||||
</template>
|
||||
@@ -0,0 +1,61 @@
|
||||
Template.healthCard.helpers({
|
||||
showDeathSave: function(){
|
||||
return this.attributeValue("hitPoints") <= 0;
|
||||
},
|
||||
deathSaveObject: function(){
|
||||
var char = Characters.findOne(this._id, {fields: {deathSave: 1}});
|
||||
return char && char.deathSave;
|
||||
},
|
||||
failIcon: function(num){
|
||||
console.log("checking ", num, " against fail", this)
|
||||
if(num <= this.fail) return "radio-button-on";
|
||||
else return "radio-button-off";
|
||||
},
|
||||
passIcon: function(num){
|
||||
if(num <= this.pass) return "radio-button-on";
|
||||
else return "radio-button-off";
|
||||
},
|
||||
failDisabled: function(num){
|
||||
return !(num === this.fail || num - 1 === this.fail)
|
||||
},
|
||||
passDisabled: function(num){
|
||||
return !(num === this.pass || num - 1 === this.pass)
|
||||
},
|
||||
dead: function(char){
|
||||
return this.fail >= 3;
|
||||
}
|
||||
})
|
||||
|
||||
Template.healthCard.events({
|
||||
"change #hitPointSlider": function(event){
|
||||
var value = event.currentTarget.value;
|
||||
var adjustment = value - this.attributeBase("hitPoints");
|
||||
Characters.update(this._id, {$set: {"hitPoints.adjustment": adjustment}});
|
||||
},
|
||||
"tap .failBubble": function(event){
|
||||
if(event.currentTarget.disabled) return;
|
||||
var char = Template.parentData();
|
||||
if(event.currentTarget.icon === "radio-button-off"){
|
||||
Characters.update(char._id, {$set: {"deathSave.fail": this.fail + 1}});
|
||||
} else{
|
||||
Characters.update(char._id, {$set: {"deathSave.fail": this.fail - 1}});
|
||||
}
|
||||
},
|
||||
"tap .passBubble": function(event){
|
||||
if(event.currentTarget.disabled) return;
|
||||
var char = Template.parentData();
|
||||
if(event.currentTarget.icon === "radio-button-off"){
|
||||
Characters.update(char._id, {$set: {"deathSave.pass": this.pass + 1}});
|
||||
} else{
|
||||
Characters.update(char._id, {$set: {"deathSave.pass": this.pass - 1}});
|
||||
}
|
||||
},
|
||||
"tap #stableButton": function(event){
|
||||
var char = Template.parentData();
|
||||
Characters.update(char._id, {$set: {"deathSave.stable": false}});
|
||||
},
|
||||
"tap #unstableButton": function(event){
|
||||
var char = Template.parentData();
|
||||
Characters.update(char._id, {$set: {"deathSave.stable": true}});
|
||||
}
|
||||
});
|
||||
@@ -34,15 +34,9 @@ evaluateString = function(charId, string){
|
||||
if(!string) return string;
|
||||
var brackets = /\{[^\{\}]*\}/g;
|
||||
var result = string.replace(brackets, function(exp){
|
||||
var exp = exp.replace(/(\{|\})/g, "") //remove brackets
|
||||
var span = jQuery('<span/>', {
|
||||
title: exp,
|
||||
text: evaluate(charId, exp),
|
||||
class: "calculatedValue"
|
||||
});
|
||||
return span.prop('outerHTML');
|
||||
var exp = exp.replace(/(\{|\})/g, "") //remove curly brackets
|
||||
return evaluate(charId, exp);
|
||||
});
|
||||
//this is going to return HTML, ensure it is santized!
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
Meteor.publish("singleCharacter", function(characterId, userId){
|
||||
//TODO check if this characer can be viewed by this user
|
||||
return [
|
||||
Characters.find({_id: characterId}),
|
||||
Characters.find({_id: characterId}),
|
||||
|
||||
Actions.find({charId: characterId}),
|
||||
Attacks.find({charId: characterId}),
|
||||
Classes.find({charId: characterId}),
|
||||
Containers.find({charId: characterId}),
|
||||
Items.find({charId: characterId}),
|
||||
Features.find({charId: characterId}),
|
||||
Effects.find({charId: characterId}),
|
||||
Experiences.find({charId: characterId}),
|
||||
Features.find({charId: characterId}),
|
||||
Items.find({charId: characterId}),
|
||||
Levels.find({charId: characterId}),
|
||||
Notes.find({charId: characterId}),
|
||||
Spells.find({charId: characterId}),
|
||||
SpellLists.find({charId: characterId}),
|
||||
Notes.find({charId: characterId}),
|
||||
Experiences.find({charId: characterId})
|
||||
];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user