Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac772531ee | ||
|
|
9a3edb07e4 | ||
|
|
fea45d2398 | ||
|
|
18aa1b2040 | ||
|
|
9afe38d043 | ||
|
|
5ddbecf97e | ||
|
|
7b573ca86e | ||
|
|
a9256fed05 | ||
|
|
8ec10e7a6a |
4739
dataSources/srd/spells.json
Normal file
4739
dataSources/srd/spells.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -10,3 +10,8 @@ _.each(items, (item) => {
|
|||||||
item.library = "SRDLibraryGA3XWsd"
|
item.library = "SRDLibraryGA3XWsd"
|
||||||
LibraryItems.insert(item)
|
LibraryItems.insert(item)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_.each(spells, (spell) => {
|
||||||
|
spell.library = "SRDLibraryGA3XWsd"
|
||||||
|
LibrarySpells.insert(spell)
|
||||||
|
});
|
||||||
|
|||||||
66
rpg-docs/Model/Library/LibrarySpells.js
Normal file
66
rpg-docs/Model/Library/LibrarySpells.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
LibrarySpells = new Mongo.Collection("librarySpells");
|
||||||
|
|
||||||
|
Schemas.LibrarySpells = new SimpleSchema({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
trim: false,
|
||||||
|
defaultValue: "New Spell",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
trim: false,
|
||||||
|
},
|
||||||
|
castingTime: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
defaultValue: "action",
|
||||||
|
trim: false,
|
||||||
|
},
|
||||||
|
range: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
trim: false,
|
||||||
|
},
|
||||||
|
duration: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
trim: false,
|
||||||
|
defaultValue: "Instantaneous",
|
||||||
|
},
|
||||||
|
"components.verbal": {type: Boolean, defaultValue: false},
|
||||||
|
"components.somatic": {type: Boolean, defaultValue: false},
|
||||||
|
"components.concentration": {type: Boolean, defaultValue: false},
|
||||||
|
"components.material": {type: String, optional: true},
|
||||||
|
ritual: {
|
||||||
|
type: Boolean,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
defaultValue: 1,
|
||||||
|
},
|
||||||
|
school: {
|
||||||
|
type: String,
|
||||||
|
defaultValue: "Abjuration",
|
||||||
|
allowedValues: magicSchools,
|
||||||
|
},
|
||||||
|
library: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1},
|
||||||
|
effects: {type: [Schemas.LibraryEffects], defaultValue: []},
|
||||||
|
attacks: {type: [Schemas.LibraryAttacks], defaultValue: []},
|
||||||
|
});
|
||||||
|
|
||||||
|
LibrarySpells.attachSchema(Schemas.LibrarySpells);
|
||||||
|
|
||||||
|
LibrarySpells.allow({
|
||||||
|
insert(userId, doc) {
|
||||||
|
return Libraries.canEdit(userId, doc.library);
|
||||||
|
},
|
||||||
|
update(userId, doc, fields, modifier) {
|
||||||
|
return Libraries.canEdit(userId, doc.library);
|
||||||
|
},
|
||||||
|
remove(userId, doc) {
|
||||||
|
return Libraries.canEdit(userId, doc.library);
|
||||||
|
},
|
||||||
|
fetch: ["library"],
|
||||||
|
});
|
||||||
@@ -29,7 +29,6 @@ Template.newCharacterDialog.helpers({
|
|||||||
|
|
||||||
changeFunction = function(field){
|
changeFunction = function(field){
|
||||||
return _.debounce(function(event, instance){
|
return _.debounce(function(event, instance){
|
||||||
console.log({field, event})
|
|
||||||
instance.character[field] = event.currentTarget.value;
|
instance.character[field] = event.currentTarget.value;
|
||||||
instance.schema.clean(instance.character);
|
instance.schema.clean(instance.character);
|
||||||
instance.context.validate(instance.character);
|
instance.context.validate(instance.character);
|
||||||
|
|||||||
@@ -131,6 +131,15 @@
|
|||||||
</paper-fab>
|
</paper-fab>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<paper-tooltip position="left">
|
||||||
|
Spell library
|
||||||
|
</paper-tooltip>
|
||||||
|
<paper-fab icon="av:library-books"
|
||||||
|
class="librarySpell"
|
||||||
|
mini>
|
||||||
|
</paper-fab>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<paper-tooltip position="left">
|
<paper-tooltip position="left">
|
||||||
New spell
|
New spell
|
||||||
|
|||||||
@@ -211,8 +211,17 @@ Template.spells.events({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
"click .addSpell": function(event, instance){
|
"click .addSpell": function(event, instance){
|
||||||
var charId = this.charId;
|
var charId = this._id;
|
||||||
var listId = SpellLists.findOne({charId: this._id})._id;
|
var list = SpellLists.findOne({charId});
|
||||||
|
var listId = list && list._id
|
||||||
|
if (!listId){
|
||||||
|
listId = SpellLists.insert({
|
||||||
|
name: "New SpellList",
|
||||||
|
charId: charId,
|
||||||
|
saveDC: "8 + intelligenceMod + proficiencyBonus",
|
||||||
|
attackBonus: "intelligenceMod + proficiencyBonus",
|
||||||
|
});
|
||||||
|
}
|
||||||
var id = Spells.insert({
|
var id = Spells.insert({
|
||||||
name: "New Spell",
|
name: "New Spell",
|
||||||
charId: this._id,
|
charId: this._id,
|
||||||
@@ -229,6 +238,49 @@ Template.spells.events({
|
|||||||
returnElement: () => instance.find(`.spell[data-id='${id}']`),
|
returnElement: () => instance.find(`.spell[data-id='${id}']`),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
"click .librarySpell": function(event, instance){
|
||||||
|
var charId = this._id;
|
||||||
|
var spellId = Random.id();
|
||||||
|
var list = SpellLists.findOne({charId});
|
||||||
|
var listId = list && list._id
|
||||||
|
pushDialogStack({
|
||||||
|
template: "spellLibraryDialog",
|
||||||
|
element: event.currentTarget,
|
||||||
|
callback: (result) => {
|
||||||
|
if (!result) return;
|
||||||
|
if (!listId){
|
||||||
|
listId = SpellLists.insert({
|
||||||
|
name: "New SpellList",
|
||||||
|
charId: charId,
|
||||||
|
saveDC: "8 + intelligenceMod + proficiencyBonus",
|
||||||
|
attackBonus: "intelligenceMod + proficiencyBonus",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Make the library spell into a regular spell
|
||||||
|
let spell = _.omit(result, "library", "attacks", "effects");
|
||||||
|
spell._id = spellId;
|
||||||
|
spell.charId = charId;
|
||||||
|
spell.parent = {
|
||||||
|
id: listId,
|
||||||
|
collection: "SpellLists",
|
||||||
|
};
|
||||||
|
spell.prepared = "prepared";
|
||||||
|
Spells.insert(spell);
|
||||||
|
// Copy over attacks and effects
|
||||||
|
_.each(result.attacks, (attack) => {
|
||||||
|
attack.charId = charId;
|
||||||
|
attack.parent = {id: spellId, collection: "Spells"};
|
||||||
|
Attacks.insert(attack);
|
||||||
|
});
|
||||||
|
_.each(result.effects, (effect) => {
|
||||||
|
effect.charId = charId;
|
||||||
|
effect.parent = {id: spellId, collection: "Spells"};
|
||||||
|
Effects.insert(effect);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
returnElement: () => $(`[data-id='${spellId}']`).get(0),
|
||||||
|
})
|
||||||
|
},
|
||||||
"click .preparedCheckbox": function(event){
|
"click .preparedCheckbox": function(event){
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.spell-library-dialog .spell.selected {
|
||||||
|
background-color: #e4e4e4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-library-dialog .category-header {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-library-dialog .category-header iron-icon {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-library-dialog .category-header iron-icon.open {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-library-dialog table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-library-dialog .library-spell td {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<template name="spellLibraryDialog">
|
||||||
|
<div class="fit spell-library-dialog layout vertical">
|
||||||
|
<app-toolbar class="app-grey white-text">
|
||||||
|
<paper-icon-button id="backButton"
|
||||||
|
icon="arrow-back">
|
||||||
|
</paper-icon-button>
|
||||||
|
<div main-title>Spells</div>
|
||||||
|
<paper-input label="Search" class="search-input">
|
||||||
|
<iron-icon icon="search" prefix></iron-icon>
|
||||||
|
</paper-input>
|
||||||
|
</app-toolbar>
|
||||||
|
<div class="flex scroll-y">
|
||||||
|
<div class="spells" style="padding:8px">
|
||||||
|
{{#if searchTerm}}
|
||||||
|
{{#if searchSpells.count}}
|
||||||
|
<table style="width: 100%">
|
||||||
|
<tbody>
|
||||||
|
{{#each spell in searchSpells}}
|
||||||
|
{{>librarySpell spell=spell selected=(isSelected spell)}}
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{else}}{{#if searchReady}}
|
||||||
|
No spells match "{{searchTerm}}"
|
||||||
|
{{/if}}{{/if}}
|
||||||
|
{{#unless searchReady}}
|
||||||
|
<div class="layout vertical center" style="width: 100%; padding: 16px;">
|
||||||
|
<paper-spinner active></paper-spinner>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
{{else}}
|
||||||
|
{{#each categories}}
|
||||||
|
<div class="paper-font-body2 category-header clickable">
|
||||||
|
<iron-icon icon="chevron-right" class="{{#if isOpen key}}open{{/if}}">
|
||||||
|
</iron-icon>
|
||||||
|
{{name}}
|
||||||
|
</div>
|
||||||
|
<iron-collapse opened={{isOpen key}}>
|
||||||
|
<table style="width: 100%">
|
||||||
|
<tbody>
|
||||||
|
{{#each spell in (spellsInCategory key)}}
|
||||||
|
{{>librarySpell spell=spell selected=(isSelected spell)}}
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{#unless ready key}}
|
||||||
|
<paper-spinner active></paper-spinner>
|
||||||
|
{{/unless}}
|
||||||
|
</iron-collapse>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layout horizontal end-justified">
|
||||||
|
<paper-button class="cancelButton">Cancel</paper-button>
|
||||||
|
<paper-button class="okButton">OK</paper-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="librarySpell">
|
||||||
|
<tr class="spell library-spell {{#if selected}}selected{{/if}}">
|
||||||
|
<td class="spellName">
|
||||||
|
{{spell.name}}
|
||||||
|
<paper-ripple></paper-ripple>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
const librarySubs = new SubsManager();
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{name: "Cantrips", key: 0},
|
||||||
|
{name: "Level 1", key: 1},
|
||||||
|
{name: "Level 2", key: 2},
|
||||||
|
{name: "Level 3", key: 3},
|
||||||
|
{name: "Level 4", key: 4},
|
||||||
|
{name: "Level 5", key: 5},
|
||||||
|
{name: "Level 6", key: 6},
|
||||||
|
{name: "Level 7", key: 7},
|
||||||
|
{name: "Level 8", key: 8},
|
||||||
|
{name: "Level 9", key: 9},
|
||||||
|
];
|
||||||
|
|
||||||
|
Template.spellLibraryDialog.onCreated(function(){
|
||||||
|
this.selectedSpell = new ReactiveVar();
|
||||||
|
this.searchTerm = new ReactiveVar();
|
||||||
|
this.categoriesOpen = new ReactiveVar([]);
|
||||||
|
this.readyDict = new ReactiveDict();
|
||||||
|
this.searchReady = new ReactiveVar();
|
||||||
|
librarySubs.subscribe("standardLibraries");
|
||||||
|
this.autorun(() => {
|
||||||
|
// Subscribe to all open categories
|
||||||
|
_.each(this.categoriesOpen.get(), (key) => {
|
||||||
|
var handle = librarySubs.subscribe("standardLibrarySpells", key);
|
||||||
|
this.autorun(() => {
|
||||||
|
this.readyDict.set(key, handle.ready());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.autorun(() => {
|
||||||
|
// If we are searching, subscibe to all categories
|
||||||
|
if (this.searchTerm.get()){
|
||||||
|
let handles = _.map(categories, category =>
|
||||||
|
librarySubs.subscribe("standardLibrarySpells", category.key)
|
||||||
|
);
|
||||||
|
// Ready when all handles are ready
|
||||||
|
this.autorun(() => {
|
||||||
|
this.searchReady.set(_.every(handles, h => h.ready()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.spellLibraryDialog.helpers({
|
||||||
|
ready(key){
|
||||||
|
return Template.instance().readyDict.get(key);
|
||||||
|
},
|
||||||
|
categories(){
|
||||||
|
return categories;
|
||||||
|
},
|
||||||
|
spellsInCategory(categoryKey){
|
||||||
|
return LibrarySpells.find({
|
||||||
|
library: "SRDLibraryGA3XWsd",
|
||||||
|
level: categoryKey,
|
||||||
|
}, {
|
||||||
|
sort: {name: 1},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isSelected(spell){
|
||||||
|
const selected = Template.instance().selectedSpell.get();
|
||||||
|
return selected && selected._id === spell._id;
|
||||||
|
},
|
||||||
|
isOpen(key){
|
||||||
|
const cats = Template.instance().categoriesOpen.get();
|
||||||
|
return _.contains(cats, key);
|
||||||
|
},
|
||||||
|
searchTerm(){
|
||||||
|
return Template.instance().searchTerm.get();
|
||||||
|
},
|
||||||
|
searchReady(){
|
||||||
|
return Template.instance().searchReady.get();
|
||||||
|
},
|
||||||
|
searchSpells(){
|
||||||
|
const searchTerm = Template.instance().searchTerm.get();
|
||||||
|
if (!searchTerm) return;
|
||||||
|
return LibrarySpells.find({
|
||||||
|
library: "SRDLibraryGA3XWsd",
|
||||||
|
name: {
|
||||||
|
$regex: new RegExp(".*" + searchTerm + ".*", "gi")
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.spellLibraryDialog.events({
|
||||||
|
"click .cancelButton": function(event, template){
|
||||||
|
popDialogStack();
|
||||||
|
},
|
||||||
|
"click .okButton": function(event, template){
|
||||||
|
popDialogStack(template.selectedSpell.get());
|
||||||
|
},
|
||||||
|
"click .library-spell": function(event, template){
|
||||||
|
template.selectedSpell.set(this.spell);
|
||||||
|
},
|
||||||
|
"click #backButton": function(event, template){
|
||||||
|
popDialogStack();
|
||||||
|
},
|
||||||
|
"click .category-header": function(event, template){
|
||||||
|
let cats = template.categoriesOpen.get();
|
||||||
|
const key = this.key;
|
||||||
|
// Toggle whether this key is in the array or not
|
||||||
|
if (_.contains(cats, key)){
|
||||||
|
cats = _.without(cats, key);
|
||||||
|
} else {
|
||||||
|
cats.push(key);
|
||||||
|
}
|
||||||
|
template.categoriesOpen.set(cats);
|
||||||
|
},
|
||||||
|
"input .search-input, change .search-input": function(event, template){
|
||||||
|
const value = event.currentTarget.value;
|
||||||
|
template.searchTerm.set(value);
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -174,7 +174,7 @@ const dialogCloseAnimation = ({element, returnElement, dialog, callback}) => {
|
|||||||
const stackCompensation = dialogs._array.length ? 16 : 0;
|
const stackCompensation = dialogs._array.length ? 16 : 0;
|
||||||
|
|
||||||
// Insert clone before its progenitor so it can inherit css correctly
|
// Insert clone before its progenitor so it can inherit css correctly
|
||||||
element.parentNode.insertBefore(clone, element);
|
element.parentNode && element.parentNode.insertBefore(clone, element);
|
||||||
|
|
||||||
// Polymer messes up fixed positioning, measure and compensate
|
// Polymer messes up fixed positioning, measure and compensate
|
||||||
startingRect = clone.getBoundingClientRect();
|
startingRect = clone.getBoundingClientRect();
|
||||||
|
|||||||
@@ -14,3 +14,12 @@ Meteor.publish("standardLibraryItems", function(categoryKey){
|
|||||||
sort: {name: 1},
|
sort: {name: 1},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Meteor.publish("standardLibrarySpells", function(level){
|
||||||
|
return LibrarySpells.find({
|
||||||
|
library: {$in: standardLibraryIds},
|
||||||
|
level,
|
||||||
|
}, {
|
||||||
|
sort: {name: 1},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user