Moved views out of private folder

This commit is contained in:
Stefan Zermatten
2017-01-12 15:28:59 +02:00
parent 37268495ae
commit 38ea89995a
162 changed files with 6 additions and 3 deletions

View File

@@ -0,0 +1,16 @@
<template name="abilityMiniCard">
<div>
<paper-material class="card abilityMiniCard clickable"
hero-id="main" {{detailHero ability ../_id}}
layout horizontal>
<div class="left white-text {{color}}"
hero-id="toolbar" {{detailHero ability ../_id}}>
<div class="display1">{{characterCalculate "attributeValue" ../_id ability}}</div>
<div class="title">{{abilityMod}}</div>
</div>
<div class="right subhead" layout horizontal center>
{{title}}
</div>
</paper-material>
</div>
</template>

View File

@@ -0,0 +1,9 @@
Template.abilityMiniCard.helpers({
abilityMod: function() {
return signedString(
Characters.calculate.abilityMod(
Template.parentData()._id, this.ability
)
);
}
});

View File

@@ -0,0 +1,14 @@
<!-- data just needs charId -->
<template name="addTHPDialog">
<div style="width: 200px; height: 150px;">
<paper-input id="nameInput" label="Label"></paper-input>
<paper-input-decorator label="Quantity" floatinglabel>
<input autoFocus id="quantityInput" type="number" value="10">
</paper-input-decorator>
<div layout horizontal justify-center>
Delete when zero <paper-checkbox id="deleteWhenZeroCheckbox" checked style="margin-left: 8px;"></paper-checkbox>
</div>
</div>
<paper-button id="cancelButton" affirmative> Cancel </paper-button>
<paper-button id="addButton" affirmative> Add </paper-button>
</template>

View File

@@ -0,0 +1,12 @@
Template.addTHPDialog.events({
"tap #addButton": function(event, instance){
var max = +instance.find("#quantityInput").value;
if (!max || max < 0) max = 0;
TemporaryHitPoints.insert({
charId: this.charId,
name: instance.find("#nameInput").value,
maximum: max,
deleteOnZero: !!instance.find("#deleteWhenZeroCheckbox").checked,
});
}
});

View File

@@ -0,0 +1,68 @@
<!-- needs name, char, and statName -->
<template name="attributeDialog">
{{#baseDialog title=name class=color hideEdit=true}}
{{> attributeDialogView}}
{{/baseDialog}}
</template>
<template name="attributeDialogView">
<div layout horizontal center-justified end>
<div class="display2">
{{attributeValue}}
</div>
{{#if adjustment}}
<div class="display1">
/{{attributeBase}}
</div>
{{/if}}
</div>
<hr class="vertMargin">
<table class="summaryTable">
{{#each baseEffects}}
<tr>
<td>{{sourceName}}</td>
<td>Base: {{statValue}}</td>
</tr>
{{/each}}
{{#each addEffects}}
<tr>
<td>{{sourceName}}</td>
<td>{{signedString statValue}}</td>
</tr>
{{/each}}
{{#each mulEffects}}
<tr>
<td>{{sourceName}}</td>
<td>&times; {{statValue}}</td>
</tr>
{{/each}}
{{#each minEffects}}
<tr>
<td>{{sourceName}}</td>
<td>Min: {{statValue}}</td>
</tr>
{{/each}}
{{#each maxEffects}}
<tr>
<td>{{sourceName}}</td>
<td>Max: {{statValue}}</td>
</tr>
{{/each}}
{{#if adjustment}}
<tr class="body2">
<td>Base Value</td>
<td>{{attributeBase}}</td>
</tr>
<tr>
<td>Adjustment</td>
<td>{{signedString adjustment}}</td>
</tr>
{{/if}}
<tr class="body2">
<td>Total</td>
<td>{{attributeValue}}</td>
</tr>
</table>
</template>

View File

@@ -0,0 +1,160 @@
//TODO add dexterity armor
var stats = {
"strength":{"name":"Strength"},
"dexterity":{"name":"Dexterity"},
"constitution":{"name":"Constitution"},
"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"},
"hitPoints":{"name":"Hit Points"},
"armor":{"name":"Armor"},
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
"speed":{"name":"Speed"},
"proficiencyBonus":{"name":"Proficiency Bonus"},
"ki":{"name":"Ki Points"},
"sorceryPoints":{"name":"Sorcery Points"},
"rages":{"name":"Rages"},
"rageDamage":{"name":"Rage Damage"},
"expertiseDice":{"name":"Expertise Dice"},
"superiorityDice":{"name":"Superiority Dice"},
"level1SpellSlots":{"name":"level 1 Spell Slots"},
"level2SpellSlots":{"name":"level 2 Spell Slots"},
"level3SpellSlots":{"name":"level 3 Spell Slots"},
"level4SpellSlots":{"name":"level 4 Spell Slots"},
"level5SpellSlots":{"name":"level 5 Spell Slots"},
"level6SpellSlots":{"name":"level 6 Spell Slots"},
"level7SpellSlots":{"name":"level 7 Spell Slots"},
"level8SpellSlots":{"name":"level 8 Spell Slots"},
"level9SpellSlots":{"name":"level 9 Spell Slots"},
"d6HitDice":{"name":"d6 Hit Dice"},
"d8HitDice":{"name":"d8 Hit Dice"},
"d10HitDice":{"name":"d10 Hit Dice"},
"d12HitDice":{"name":"d12 Hit Dice"},
"acidMultiplier":{"name":"Acid", "group": "Weakness/Resistance"},
"bludgeoningMultiplier":{"name":"Bludgeoning", "group": "Weakness/Resistance"},
"coldMultiplier":{"name":"Cold", "group": "Weakness/Resistance"},
"fireMultiplier":{"name":"Fire", "group": "Weakness/Resistance"},
"forceMultiplier":{"name":"Force", "group": "Weakness/Resistance"},
"lightningMultiplier":{"name":"Lightning", "group": "Weakness/Resistance"},
"necroticMultiplier":{"name":"Necrotic", "group": "Weakness/Resistance"},
"piercingMultiplier":{"name":"Piercing", "group": "Weakness/Resistance"},
"poisonMultiplier":{"name":"Poison", "group": "Weakness/Resistance"},
"psychicMultiplier":{"name":"Psychic", "group": "Weakness/Resistance"},
"radiantMultiplier":{"name":"Radiant", "group": "Weakness/Resistance"},
"slashingMultiplier":{"name":"Slashing", "group": "Weakness/Resistance"},
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"},
};
var operations = {
base: {name: "Base Value"},
proficiency: {name: "Proficiency"},
add: {name: "&plus;"},
mul: {name: "&times;"},
min: {name: "Min"},
max: {name: "Max"},
advantage: {name: "Advantage"},
disadvantage: {name: "Disadvantage"},
passiveAdd: {name: "Passive Bonus"},
fail: {name: "Automatically Fail"},
conditional: {name: "Conditional Benefit"},
};
var abilities = {
strength: {name: "Strength"},
dexterity: {name: "Dexterity"},
constitution: {name: "Constitution"},
intelligence: {name: "Intelligence"},
wisdom: {name: "Wisdom"},
charisma: {name: "Charisma"},
};
Template.attributeDialog.helpers({
color: function(){
if (this.color) return this.color + " white-text";
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
});
Template.attributeDialogView.helpers({
or: function(a, b, c){
return a || b || c;
},
adjustment: function(){
var value = Characters.calculate.attributeValue(this.charId, this.statName);
var base = Characters.calculate.attributeBase(this.charId, this.statName);
return value - base;
},
baseEffects: function(){
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "base", enabled: true}
);
},
addEffects: function(){
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "add", enabled: true}
);
},
mulEffects: function(){
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "mul", enabled: true}
);
},
minEffects: function(){
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "min", enabled: true}
);
},
maxEffects: function(){
return Effects.find(
{charId: this.charId, stat: this.statName, operation: "max", enabled: true}
);
},
attributeBase: function(){
return Characters.calculate.attributeBase(this.charId, this.statName);
},
attributeValue: function() {
return Characters.calculate.attributeValue(this.charId, this.statName);
},
sourceName: function(){
if (this.parent.group === "racial"){
return this.getParent().race;
}
if (this.parent.collection === "Characters"){
return this.name;
}
return this.getParent().name;
},
operationName: function(){
var op = operations[this.operation];
return op && op.name || "No Operation";
},
statValue: function(){
return evaluateEffect(this.charId, this);
},
});

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
.healthCard paper-diff-slider{
width: 100%;
margin-right: 8px;
}
/*Slider knob color*/
#hitPointSlider::shadow #sliderKnobInner {
background-color: #0f9d58;
}
/*Slider pin*/
#hitPointSlider::shadow #sliderKnobInner::before {
background-color: #0f9d58;
height: 32px;
width: 32px;
}
/*Slider pin text*/
#hitPointSlider::shadow #sliderKnob > #sliderKnobInner::after {
font-size: 16px;
}
/*Slider bar*/
#hitPointSlider::shadow #sliderBar::shadow #activeProgress {
background-color: #0f9d58;
}

View File

@@ -0,0 +1,99 @@
<template name="healthCard">
<paper-material class="card container healthCard"
hero-id="main" {{detailHero "hitPoints" _id}}
layout horizontal wrap>
<div class="green white-text subhead left"
hero-id="toolbar" {{detailHero "hitPoints" _id}}
layout vertical center center-justified>
<div class="hitPointTitle clickable">Hit Points</div>
<paper-icon-button class="white54"
id="addTempHP"
icon="add"
disabled={{#unless canEditCharacter _id}}true{{/unless}}>
</paper-icon-button>
</div>
<div class="right" flex layout vertical center-justified style="min-width: 180px;">
<div layout horizontal>
<paper-diff-slider id="hitPointSlider"
value={{characterCalculate "attributeValue" _id "hitPoints"}}
max={{characterCalculate "attributeBase" _id "hitPoints"}}
editable pin
disabled={{#unless canEditCharacter _id}}true{{/unless}}
role="slider">
</paper-diff-slider>
</div>
{{#each tempHitPoints}}
<div>
{{name}}
<div layout horizontal>
<paper-diff-slider class="tempHitPointSlider"
value={{left}}
max={{maximum}}
editable pin
role="slider"
flex
></paper-diff-slider>
{{#unless left}}
<paper-icon-button class="deleteTHP" icon="delete"></paper-icon-button>
{{/unless}}
</div>
</div>
{{/each}}
<div class="caption">
{{#if multipliers.immunities.length}}
<div>
Immune: {{#each multipliers.immunities}} {{name}} {{/each}}
</div>
{{/if}}
{{#if multipliers.resistances.length}}
<div>
Resistance: {{#each multipliers.resistances}} {{name}} {{/each}}
</div>
{{/if}}
{{#if multipliers.weaknesses.length}}
<div>
Weakness: {{#each multipliers.weaknesses}} {{name}} {{/each}}
</div>
{{/if}}
</div>
{{#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-material>
</template>

View File

@@ -0,0 +1,111 @@
Template.healthCard.helpers({
tempHitPoints: function(){
return TemporaryHitPoints.find({charId: this._id});
},
showDeathSave: function(){
return Characters.calculate.attributeValue(this._id, "hitPoints") <= 0;
},
deathSaveObject: function(){
var char = Characters.findOne(this._id, {fields: {deathSave: 1}});
return char && char.deathSave;
},
failIcon: function(num){
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(){
return this.fail >= 3;
},
multipliers: function(){
var multipliers = [
{name: "Acid", value: Characters.calculate.attributeValue(this._id, "acidMultiplier")},
{name: "Bludgeoning", value: Characters.calculate.attributeValue(this._id, "bludgeoningMultiplier")},
{name: "Cold", value: Characters.calculate.attributeValue(this._id, "coldMultiplier")},
{name: "Fire", value: Characters.calculate.attributeValue(this._id, "fireMultiplier")},
{name: "Force", value: Characters.calculate.attributeValue(this._id, "forceMultiplier")},
{name: "Lightning", value: Characters.calculate.attributeValue(this._id, "lightningMultiplier")},
{name: "Necrotic", value: Characters.calculate.attributeValue(this._id, "necroticMultiplier")},
{name: "Piercing", value: Characters.calculate.attributeValue(this._id, "piercingMultiplier")},
{name: "Poison", value: Characters.calculate.attributeValue(this._id, "poisonMultiplier")},
{name: "Psychic", value: Characters.calculate.attributeValue(this._id, "psychicMultiplier")},
{name: "Radiant", value: Characters.calculate.attributeValue(this._id, "radiantMultiplier")},
{name: "Slashing", value: Characters.calculate.attributeValue(this._id, "slashingMultiplier")},
{name: "Thunder", value: Characters.calculate.attributeValue(this._id, "thunderMultiplier")},
];
multipliers = _.groupBy(multipliers, "value");
return {
"immunities": multipliers["0"] || [],
"resistances": multipliers["0.5"] || [],
"weaknesses": multipliers["2"] || [],
};
},
});
Template.healthCard.events({
"change #hitPointSlider": function(event){
var value = event.currentTarget.value;
var base = Characters.calculate.attributeBase(this._id, "hitPoints")
var adjustment = value - base;
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,
}}
);
},
"change .tempHitPointSlider": function(event){
var value = event.currentTarget.value;
var used = this.maximum - value;
TemporaryHitPoints.update(this._id, {$set: {"used": used}});
},
"tap .deleteTHP": function(event){
TemporaryHitPoints.remove(this._id);
},
"tap #addTempHP": function(event){
GlobalUI.showDialog({
template: "addTHPDialog",
data: {charId: this._id},
});
},
"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}});
},
});

View File

@@ -0,0 +1,35 @@
<template name="hitDice">
{{#if characterCalculate "attributeBase" ../_id name}}
<div>
<paper-material class="card hit-dice" hero-id="main"
{{detailHero name ../_id}}
layout horizontal>
<div class="left green display1 white-text"
hero-id="toolbar" {{detailHero name ../_id}}
layout horizontal>
<div>
<paper-icon-button class="resourceUp"
icon="arrow-drop-up"
disabled={{cantIncrement}}>
</paper-icon-button>
<paper-icon-button class="resourceDown"
icon="arrow-drop-down"
disabled={{cantDecrement}}>
</paper-icon-button>
</div>
<div class="resourceValue" layout vertical center>
<div>
{{characterCalculate "attributeValue" ../_id name}}
</div>
<div class="title white-text">
d{{diceNum}} {{conMod}}
</div>
</div>
</div>
<div class="right clickable" flex relative horizontal layout center>
Hit Dice
</div>
</paper-material>
</div>
{{/if}}
</template>

View File

@@ -0,0 +1,50 @@
Template.hitDice.helpers({
cantIncrement: function(){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
return value >= base || !canEditCharacter(this.char._id);
},
cantDecrement: function(){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
return value <= 0 || !canEditCharacter(this.char._id);
},
conMod: function(){
return signedString(
Characters.calculate.abilityMod(this.char._id, "constitution")
);
},
});
Template.hitDice.events({
"tap .resourceUp": function(event){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
var base = Characters.calculate.attributeBase(this.char._id, this.name);
if (value < base){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = 1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .resourceDown": function(event){
var value = Characters.calculate.attributeValue(this.char._id, this.name);
if (value > 0){
var modifier = {$inc: {}};
modifier.$inc[this.name + ".adjustment"] = -1;
Characters.update(this.char._id, modifier, {validate: false});
}
},
"tap .right": function() {
var charId = Template.parentData()._id;
var title = "d" + this.diceNum + " Hit Dice";
GlobalUI.setDetail({
template: "attributeDialog",
data: {
name: title,
statName: this.name,
charId: charId,
color: "green",
},
heroId: charId + this.name,
});
},
});

View File

@@ -0,0 +1,3 @@
.summaryNumber{
width: 50px;
}

View File

@@ -0,0 +1,101 @@
<!-- needs name, charId, and skillName -->
<template name="skillDialog">
{{#baseDialog title=name class=color hideEdit=true}}
{{> skillDialogView}}
{{/baseDialog}}
</template>
<template name="skillDialogView">
<div layout vertical center>
<div class="display2">
{{characterCalculate "skillMod" charId skillName}}
</div>
<div class="subhead">
<iron-icon icon="{{profIcon}}" class="black54"></iron-icon>
{{#if profSource}}
{{proficiencyValue}} - {{#with profSource}}{{sourceName}}{{/with}}
{{else}}
Not Proficient
{{/if}}
</div>
</div>
<hr class="vertMargin">
<table class="summaryTable">
<tr>
<td>{{abilityName}}</td>
<td>{{characterCalculate "abilityMod" charId ability}}</td>
</tr>
{{#if characterCalculate "proficiency" charId skillName}}
<tr>
<td>{{proficiencyValue}}</td>
<td>{{signedString profBonus}}</td>
</tr>
{{/if}}
{{#each addEffects}}
<tr>
<td>{{sourceName}}</td>
<td>{{signedString statValue}}</td>
</tr>
{{/each}}
{{#each mulEffects}}
<tr>
<td>{{sourceName}}</td>
<td>&times;{{statValue}}</td>
</tr>
{{/each}}
{{#each minEffects}}
<tr>
<td>{{sourceName}}</td>
<td>Min: {{statValue}}</td>
</tr>
{{/each}}
{{#each maxEffects}}
<tr>
<td>{{sourceName}}</td>
<td>Max: {{statValue}}</td>
</tr>
{{/each}}
<tr class="body2">
<td>Total</td>
<td>{{characterCalculate "skillMod" charId skillName}}</td>
</tr>
</table>
{{#if or advEffects.count dadvEffects.count conditionalEffects.count}}
<hr class="vertMargin">
{{/if}}
<div class="spaceAfter" horizontal center layout>
{{#if advEffects.count}}
<div class="body2" style="width: 100px;">
Advantage
</div>
<div flex>
{{#each advEffects}}
<div>{{sourceName}}</div>
{{/each}}
</div>
{{/if}}
</div>
<div class="spaceAfter" horizontal center layout>
{{#if dadvEffects.count}}
<div class="body2" style="width: 100px;">
Disadvantage
</div>
<div flex>
{{#each dadvEffects}}
<div>{{sourceName}}</div>
{{/each}}
</div>
{{/if}}
</div>
<!--Conditional Benefits-->
{{#each conditionalEffects}}
<div class="spaceAfter">
<div class="body2">{{sourceName}}</div>
<div>*{{statValue}}</div>
</div>
{{/each}}
</template>

View File

@@ -0,0 +1,239 @@
//TODO add dexterity armor
var stats = {
"strength":{"name":"Strength"},
"dexterity":{"name":"Dexterity"},
"constitution":{"name":"Constitution"},
"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"},
"hitPoints":{"name":"Hit Points"},
"armor":{"name":"Armor"},
"dexterityArmor":{"name":"Dexterity Armor Bonus"},
"speed":{"name":"Speed"},
"proficiencyBonus":{"name":"Proficiency Bonus"},
"ki":{"name":"Ki Points"},
"sorceryPoints":{"name":"Sorcery Points"},
"rages":{"name":"Rages"},
"rageDamage":{"name":"Rage Damage"},
"expertiseDice":{"name":"Expertise Dice"},
"superiorityDice":{"name":"Superiority Dice"},
"level1SpellSlots":{"name":"level 1 Spell Slots"},
"level2SpellSlots":{"name":"level 2 Spell Slots"},
"level3SpellSlots":{"name":"level 3 Spell Slots"},
"level4SpellSlots":{"name":"level 4 Spell Slots"},
"level5SpellSlots":{"name":"level 5 Spell Slots"},
"level6SpellSlots":{"name":"level 6 Spell Slots"},
"level7SpellSlots":{"name":"level 7 Spell Slots"},
"level8SpellSlots":{"name":"level 8 Spell Slots"},
"level9SpellSlots":{"name":"level 9 Spell Slots"},
"d6HitDice":{"name":"d6 Hit Dice"},
"d8HitDice":{"name":"d8 Hit Dice"},
"d10HitDice":{"name":"d10 Hit Dice"},
"d12HitDice":{"name":"d12 Hit Dice"},
"acidMultiplier":{"name":"Acid", "group": "Weakness/Resistance"},
"bludgeoningMultiplier":{"name":"Bludgeoning", "group": "Weakness/Resistance"},
"coldMultiplier":{"name":"Cold", "group": "Weakness/Resistance"},
"fireMultiplier":{"name":"Fire", "group": "Weakness/Resistance"},
"forceMultiplier":{"name":"Force", "group": "Weakness/Resistance"},
"lightningMultiplier":{"name":"Lightning", "group": "Weakness/Resistance"},
"necroticMultiplier":{"name":"Necrotic", "group": "Weakness/Resistance"},
"piercingMultiplier":{"name":"Piercing", "group": "Weakness/Resistance"},
"poisonMultiplier":{"name":"Poison", "group": "Weakness/Resistance"},
"psychicMultiplier":{"name":"Psychic", "group": "Weakness/Resistance"},
"radiantMultiplier":{"name":"Radiant", "group": "Weakness/Resistance"},
"slashingMultiplier":{"name":"Slashing", "group": "Weakness/Resistance"},
"thunderMultiplier":{"name":"Thunder", "group": "Weakness/Resistance"},
};
var operations = {
base: {name: "Base Value"},
proficiency: {name: "Proficiency"},
add: {name: "&plus;"},
mul: {name: "&times;"},
min: {name: "Min"},
max: {name: "Max"},
advantage: {name: "Advantage"},
disadvantage: {name: "Disadvantage"},
passiveAdd: {name: "Passive Bonus"},
fail: {name: "Automatically Fail"},
conditional: {name: "Conditional Benefit"},
};
var abilities = {
strength: {name: "Strength"},
dexterity: {name: "Dexterity"},
constitution: {name: "Constitution"},
intelligence: {name: "Intelligence"},
wisdom: {name: "Wisdom"},
charisma: {name: "Charisma"},
};
Template.skillDialog.helpers({
color: function(){
if (this.color) return this.color + " white-text";
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
});
Template.skillDialogView.helpers({
or: function(a, b, c){
return a || b || c;
},
profIcon: function(){
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
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}}
);
},
profBonus: function(){
var char = Characters.findOne(this.charId);
if (!char) return;
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
var proficiencyBonus =
Characters.calculate.attributeValue(this.charId, "proficiencyBonus");
return prof * proficiencyBonus;
},
proficiencyValue: function(){
var prof = Characters.calculate.proficiency(this.charId, this.skillName);
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",
enabled: true,
});
},
mulEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "mul",
enabled: true,
});
},
minEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "min",
enabled: true,
});
},
maxEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "max",
enabled: true,
});
},
advEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "advantage",
enabled: true,
});
},
dadvEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "disadvantage",
enabled: true,
});
},
conditionalEffects: function(){
return Effects.find({
charId: this.charId,
stat: this.skillName,
operation: "conditional",
enabled: true,
});
},
ability: function(){
var opts = {fields: {}};
opts.fields[this.skillName] = 1;
var char = Characters.findOne(this.charId, opts);
var skill = char && char[this.skillName];
return skill.ability;
},
abilityName: function(){
var skill = Characters.calculate.getField(this.charId, this.skillName);
if (!skill) return;
var ability = skill.ability;
return abilities[ability] && abilities[ability].name;
},
sourceName: function(){
if (this.parent.collection === "Characters"){
if (this.parent.group === "racial"){
return Characters.calculate.getField(this.charId, "race") || "Race";
}
if (this.parent.group === "background"){
return "Background";
}
return "Innate";
}
return this.getParent().name;
},
operationName: function(){
if (stats[this.stat].group === "Weakness/Resistance") return null;
return operations[this.operation] &&
operations[this.operation].name ||
"No Operation";
},
statValue: function(){
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;
}
return evaluate(this.charId, this.calculation) || this.value;
},
});

View File

@@ -0,0 +1,26 @@
<template name="skillRow">
<div class="item-slot">
<div class="skill-row item small"
hero-id="main"
{{detailHero skill ../_id}}
layout horizontal center>
<iron-icon icon="{{profIcon}}"></iron-icon>
{{#if failSkill}}
<div class="fail skill-mod">fail</div>
{{else}}
<div class="{{advantage}} skill-mod">
{{skillMod}}
</div>
{{/if}}
<div flex>
{{name}}
{{#if conditionalCount}}
*
{{/if}}
{{#if showPassive}}
({{characterCalculate "passiveSkill" ../_id skill}})
{{/if}}
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,41 @@
Template.skillRow.helpers({
skillMod: function() {
return signedString(
Characters.calculate.skillMod(
Template.parentData()._id, this.skill
)
);
},
profIcon: function(){
var charId = Template.parentData()._id;
var prof = Characters.calculate.proficiency(charId, this.skill);
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()._id;
return Effects.find({
charId: charId,
stat: this.skill,
enabled: true,
operation: "fail",
}).count();
},
advantage: function(){
var charId = Template.parentData()._id;
var advantage = Characters.calculate.advantage(charId, this.skill);
if (advantage > 0) return "advantage";
if (advantage < 0) return "disadvantage";
},
conditionalCount: function(){
var charId = Template.parentData()._id;
return Effects.find({
charId: charId,
stat: this.skill,
enabled: true,
operation: "conditional",
}).count();
},
});

View File

@@ -0,0 +1,21 @@
.skill-row {
.skill-mod{
width: 45px;
text-align: center;
&.fail {
color: #D50000;
}
&.advantage{
background-image: url(/png/advantage/greenUp.png);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
&.disadvantage{
background-image: url(/png/advantage/redDown.png);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
}
}

View File

@@ -0,0 +1,51 @@
.card-top {
flex-grow: 1;
padding: 16px;
border-radius: 2px 2px 0 0;
display: flex;
align-items: center;
justify-content: center;
}
.editEffect > * {
vertical-align: bottom;
}
.detailCard {
background: white;
border-radius: 2px;
padding: 16px;
}
#armorHeading {
background: url(/jpg/rusted-metal-armor.jpg) no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#detailContainer {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
#detailContainer > *{
pointer-events: auto;
}
#darkOverlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0,0,0,0.6);
}
section:not(.core-selected):not([animate]) paper-material[hero] {
visibility: hidden;
}

View File

@@ -0,0 +1,93 @@
<template name="stats">
<div class="scroll-y" fit>
<div style="padding: 8px 8px 0 8px">
{{> healthCard}}
</div>
<div class="column-container thin-columns" >
<!--Ability Scores-->
{{> abilityMiniCard ability="strength" title="Strength" color="red"}}
{{> abilityMiniCard ability="dexterity" title="Dexterity" color="indigo"}}
{{> abilityMiniCard ability="constitution" title="Constitution" color="green"}}
{{> abilityMiniCard ability="intelligence" title="Intelligence" color="deep-orange"}}
{{> abilityMiniCard ability="wisdom" title="Wisdom" color="purple"}}
{{> abilityMiniCard ability="charisma" title="Charisma" color="pink"}}
<!--Armor-->
{{> statCard stat="armor" name="Armor Class" color="teal"}}
<!--Speed-->
{{> statCard stat="speed" name="Speed" color="teal"}}
<!--Initiative-->
{{> statCard stat="initiative" name="Initiative" color="indigo" isSkill="true"}}
<!--Proficiency Bonus-->
{{> statCard stat="proficiencyBonus" name="Proficiency Bonus" color="blue" prefix="+"}}
<!--Hit Dice-->
{{>hitDice name="d6HitDice" diceNum="6" char=this}}
{{>hitDice name="d8HitDice" diceNum="8" char=this}}
{{>hitDice name="d10HitDice" diceNum="10" char=this}}
{{>hitDice name="d12HitDice" diceNum="12" char=this}}
<!--Saving Throws-->
<div>
<paper-material class="card">
<div class="top white subhead">
Saving Throws
</div>
<div flex class="bottom list">
{{> skillRow name="Strength" skill="strengthSave"}}
{{> skillRow name="Dexterity" skill="dexteritySave"}}
{{> skillRow name="Constitution" skill="constitutionSave"}}
{{> skillRow name="Intelligence" skill="intelligenceSave"}}
{{> skillRow name="Wisdom" skill="wisdomSave"}}
{{> skillRow name="Charisma" skill="charismaSave"}}
</div>
</paper-material>
</div>
<!--Skills-->
<div>
<paper-material class="card">
<div class="top white subhead">
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"}}
</div>
</paper-material>
</div>
</div>
</div>
</template>
<template name="statCard">
<div>
<paper-material class="card statCard clickable" hero-id="main" {{detailHero stat ../_id}} layout horizontal>
<div class="left display1 white-text {{color}}"
hero-id="toolbar" {{detailHero stat ../_id}}>
{{#if isSkill}}
{{prefix}}{{skillMod}}
{{else}}
{{prefix}}{{characterCalculate "attributeValue" ../_id stat}}
{{/if}}
</div>
<div class="right subhead" flex horizontal layout center>
{{name}}
</div>
</paper-material>
</div>
</template>

View File

@@ -0,0 +1,78 @@
Template.stats.events({
"tap .statCard": function(event, instance){
var charId = instance.data._id;
if (this.isSkill){
GlobalUI.setDetail({
template: "skillDialog",
data: {
name: this.name,
skillName: this.stat,
charId: charId,
color: this.color,
},
heroId: charId + this.stat,
});
} else {
GlobalUI.setDetail({
template: "attributeDialog",
data: {
name: this.name,
statName: this.stat,
charId: charId,
color: this.color,
},
heroId: charId + this.stat,
});
}
},
"tap .abilityMiniCard": function(event, instance){
var charId = Template.parentData()._id;
var template = "attributeDialog";
if (this.ability === "strength") template = "strengthDialog";
GlobalUI.setDetail({
template: template,
data: {
name: this.title,
statName: this.ability,
charId: charId,
color: this.color,
},
heroId: charId + this.ability,
});
},
"tap .skill-row": function(event, instance){
var skill = this.skill;
var charId = instance.data._id;
GlobalUI.setDetail({
template: "skillDialog",
data: {
name: this.name,
skillName: skill,
charId: charId,
},
heroId: charId + skill,
});
},
"tap .hitPointTitle": function(event, instance) {
GlobalUI.setDetail({
template: "attributeDialog",
data: {
name: "Hit Points",
statName: "hitPoints",
charId: this._id,
color: "green",
},
heroId: this._id + "hitPoints",
});
},
});
Template.statCard.helpers({
skillMod: function() {
return signedString(
Characters.calculate.skillMod(
Template.parentData()._id, this.stat
)
);
},
});