From 5ddbecf97e2a70b1aa21a7ea3825e1c3652cdab4 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Fri, 5 May 2017 10:43:07 +0200 Subject: [PATCH] Added spells library --- rpg-docs/Model/Library/LibrarySpells.js | 66 ++++++++++ .../client/views/character/spells/spells.html | 9 ++ .../client/views/character/spells/spells.js | 55 ++++++++- .../spellLibraryDialog.css | 0 .../spellLibraryDialog.html | 68 +++++++++++ .../spellsLibraryDialog/spellLibraryDialog.js | 115 ++++++++++++++++++ rpg-docs/server/publications/library.js | 9 ++ 7 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 rpg-docs/Model/Library/LibrarySpells.js create mode 100644 rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.css create mode 100644 rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.html create mode 100644 rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.js diff --git a/rpg-docs/Model/Library/LibrarySpells.js b/rpg-docs/Model/Library/LibrarySpells.js new file mode 100644 index 00000000..bdbb67de --- /dev/null +++ b/rpg-docs/Model/Library/LibrarySpells.js @@ -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"], +}); diff --git a/rpg-docs/client/views/character/spells/spells.html b/rpg-docs/client/views/character/spells/spells.html index 35c0736e..7158c8c3 100644 --- a/rpg-docs/client/views/character/spells/spells.html +++ b/rpg-docs/client/views/character/spells/spells.html @@ -131,6 +131,15 @@ +
+ + Spell library + + + +
New spell diff --git a/rpg-docs/client/views/character/spells/spells.js b/rpg-docs/client/views/character/spells/spells.js index e7cf0ad7..85b010ba 100644 --- a/rpg-docs/client/views/character/spells/spells.js +++ b/rpg-docs/client/views/character/spells/spells.js @@ -211,8 +211,17 @@ Template.spells.events({ }); }, "click .addSpell": function(event, instance){ - var charId = this.charId; - var listId = SpellLists.findOne({charId: this._id})._id; + var charId = this._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({ name: "New Spell", charId: this._id, @@ -229,6 +238,48 @@ Template.spells.events({ 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.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){ event.stopPropagation(); }, diff --git a/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.css b/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.css new file mode 100644 index 00000000..e69de29b diff --git a/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.html b/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.html new file mode 100644 index 00000000..86972f17 --- /dev/null +++ b/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.html @@ -0,0 +1,68 @@ + + + diff --git a/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.js b/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.js new file mode 100644 index 00000000..7e37d184 --- /dev/null +++ b/rpg-docs/client/views/character/spells/spellsLibraryDialog/spellLibraryDialog.js @@ -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", + "settings.category": 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); + }, +}); diff --git a/rpg-docs/server/publications/library.js b/rpg-docs/server/publications/library.js index e113a531..e5d0c276 100644 --- a/rpg-docs/server/publications/library.js +++ b/rpg-docs/server/publications/library.js @@ -14,3 +14,12 @@ Meteor.publish("standardLibraryItems", function(categoryKey){ sort: {name: 1}, }); }); + +Meteor.publish("standardLibrarySpells", function(level){ + return LibraryItems.find({ + library: {$in: standardLibraryIds}, + level, + }, { + sort: {name: 1}, + }); +});