diff --git a/app/Routes/API.js b/app/Routes/API.js deleted file mode 100644 index abe340e5..00000000 --- a/app/Routes/API.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -Router.map(function() { - this.route("vmixCharacter", { - path: "/vmix-character/:_id/", - where: "server", - action: function() { - this.response.setHeader("Content-Type", "application/json"); - var query = this.params.query; - var key = query && query.key; - ifKeyValid(key, this.response, "vmixCharacter", () => - this.response.end(vMixCharacter(this.params._id)) - ); - }, - }); - this.route("vmixParty", { - path: "/vmix-party/:_id/", - where: "server", - action: function() { - this.response.setHeader("Content-Type", "application/json"); - var query = this.params.query; - var key = query && query.key; - ifKeyValid(key, this.response, "vmixParty", () => - this.response.end(vMixParty(this.params._id)) - ); - }, - }); - - this.route("jsonCharacterSheet", { - path: "/character/:_id/json", - where: "server", - action: function() { - this.response.setHeader("Content-Type", "application/json"); - var query = this.params.query; - var key = query && query.key; - ifKeyValid(key, this.response, "jsonCharacterSheet", () => { - if (canViewCharacter(this.params._id, userIdFromKey(key))){ - this.response.end(JSONExport(this.params._id)) - } else { - this.response.writeHead(403, "You do not have permission to view this character"); - this.response.end(); - } - } - ); - }, - }); -}); - -var ifKeyValid = function(apiKey, response, method, callback){ - if (!apiKey){ - response.writeHead(403, "You must use an api key to access this api"); - response.end(); - } else if (!isKeyValid(apiKey)){ - response.writeHead(403, "API key is invalid"); - response.end(); - } else if (isRateLimited(apiKey, method)){ - response.writeHead(429, "Too many requests"); - response.end(JSON.stringify({ - "timeToReset": rateLimiter.check({apiKey: apiKey, method: method}).timeToReset - })); - } else { - rateLimiter.increment({apiKey: apiKey, method: method}) - callback(); - } -}; - -var isKeyValid = function(apiKey){ - var user = Meteor.users.findOne({apiKey}); - if (!user) return false; - var blackListed = Blacklist.findOne({userId: user._id}); - return !blackListed; -}; - -var userIdFromKey = function(apiKey){ - var user = Meteor.users.findOne({apiKey}); // we know user exists from isKeyValid - return user._id; -} - -var rateLimiter = new RateLimiter(); -rateLimiter.addRule({apiKey: String}, 5, 5000); -rateLimiter.addRule({apiKey: String, method: "vmixCharacter"}, 2, 10000); -rateLimiter.addRule({apiKey: String, method: "vmixParty"}, 2, 10000); -rateLimiter.addRule({apiKey: String, method: "jsonCharacterSheet"}, 5, 5000); - -var isRateLimited = function(apiKey, method){ - const limited = !rateLimiter.check({apiKey: apiKey, method: method}).allowed - if (limited) { - console.log(`Rate limit hit by API key ${apiKey}`); - return true; - } else { - return false; - } -}; -*/ diff --git a/app/Routes/Routes.js b/app/Routes/Routes.js deleted file mode 100644 index 1172b971..00000000 --- a/app/Routes/Routes.js +++ /dev/null @@ -1,176 +0,0 @@ -/* -Router.configure({ - loadingTemplate: "loading", - layoutTemplate: "layout", - trackPageView: true, -}); - -Router.plugin("ensureSignedIn", { - only: [ - "profile", - "characterList", - ] -}); - -Router.plugin("dataNotFound", {notFoundTemplate: "notFound"}); - -var handleSubError = function(e){ - Session.set("error", {reason: e.reason, href: location.href}); - Router.go("/error"); -}; - -Router.map(function() { - this.route("/", { - name: "home", - onAfterAction: function() { - document.title = appName; - }, - }); - - this.route("characterList", { - path: "/characterList", - waitOn: function(){ - return subsManager.subscribe("characterList"); - }, - onAfterAction: function() { - document.title = appName + " - Characters"; - }, - fastRender: true, - }); - - this.route("characterSheetNaked", { - path: "/character/:_id/", - waitOn: function(){ - return [ - subsManager.subscribe( - "singleCharacter", this.params._id, {onError: handleSubError} - ), - ]; - }, - action: function(){ - var _id = this.params._id - var character = Characters.findOne(_id); - var urlName = character && character.urlName; - var path = `\/character\/${_id}\/${urlName || "-"}`; - Router.go(path,{},{replaceState:true}); - }, - }); - - this.route("characterSheet", { - path: "/character/:_id/:urlName", - waitOn: function(){ - return [ - subsManager.subscribe( - "singleCharacter", this.params._id, {onError: handleSubError} - ), - ]; - }, - data: function() { - var data = Characters.findOne( - {_id: this.params._id}, - {fields: {_id: 1, name: 1, color: 1, writers: 1, readers: 1}} - ); - return data; - }, - onAfterAction: function() { - var char = Characters.findOne({_id: this.params._id}, {fields: {name: 1}}); - var name = char && char.name; - if (name){ - document.title = name; - } - }, - //analytics - trackPageView: false, - onRun: function() { - window.ga && window.ga("send", "pageview", "/character"); - this.next(); - }, - fastRender: true, - }); - - this.route("printedCharacterSheet", { - path: "/character/:_id/:urlName/print", - waitOn: function(){ - return [ - subsManager.subscribe( - "singleCharacter", this.params._id, {onError: handleSubError} - ), - ]; - }, - data: function() { - var data = Characters.findOne( - {_id: this.params._id}, - {fields: {_id: 1, name: 1, color: 1, writers: 1, readers: 1}} - ); - return data; - }, - onAfterAction: function() { - var char = Characters.findOne({_id: this.params._id}, {fields: {name: 1}}); - var name = char && char.name; - if (name){ - document.title = name + " - Printing"; - } - }, - //analytics - trackPageView: false, - onRun: function() { - window.ga && window.ga("send", "pageview", "/print-character"); - this.next(); - }, - }); - - this.route("library", { - path: "/library", - waitOn: function(){ - return subsManager.subscribe("standardLibraries"); - }, - onAfterAction: function() { - document.title = appName + " - Library"; - }, - fastRender: true, - }); - - this.route("loading", { - path: "/loading" - }); - - this.route("profile", { - path: "/account", - onAfterAction: function() { - document.title = appName + " Account"; - }, - }); - - this.route("/changelog", { - name: "changeLog", - waitOn: function() { - return [ - subsManager.subscribe("changeLog"), - ] - }, - data: { - changeLogs: function() { - return ChangeLogs.find({}, {sort: {version: -1}}); - } - }, - onAfterAction: function() { - document.title = appName; - }, - fastRender: true, - }); - - this.route("/guide", { - name: "guide", - onAfterAction: function() { - document.title = appName; - }, - }); - - this.route("/error", { - name: "error", - onAfterAction: function() { - document.title = `${appName} - Error`; - }, - }); -}); -*/ diff --git a/app/imports/api/campaign/Instance.js b/app/imports/api/campaign/Instance.js index c47e2dd3..6065ab40 100644 --- a/app/imports/api/campaign/Instance.js +++ b/app/imports/api/campaign/Instance.js @@ -1,3 +1,5 @@ +import SimpleSchema from 'simpl-schema'; + let Instances = new Mongo.Collection("instances"); let instanceSchema = new SimpleSchema({ diff --git a/app/imports/api/campaign/Party.js b/app/imports/api/campaign/Party.js index 6c8c4ae8..92461adf 100644 --- a/app/imports/api/campaign/Party.js +++ b/app/imports/api/campaign/Party.js @@ -1,3 +1,5 @@ +import SimpleSchema from 'simpl-schema'; + let Parties = new Mongo.Collection("parties"); let partySchema = new SimpleSchema({ @@ -19,7 +21,7 @@ let partySchema = new SimpleSchema({ }, }); -Parties.attachSchema(Schemas.Party); +Parties.attachSchema(partySchema); Parties.allow({ insert: function(userId, doc) { diff --git a/app/imports/api/creature/Attributes.js b/app/imports/api/creature/Attributes.js index dcb1b492..597c56af 100644 --- a/app/imports/api/creature/Attributes.js +++ b/app/imports/api/creature/Attributes.js @@ -24,7 +24,7 @@ attributeSchema = new SimpleSchema({ }, // Attributes need to store their order to keep the sheet consistent order: { - type: Number, + type: SimpleSchema.Integer, index: 1, }, type: { @@ -42,20 +42,18 @@ attributeSchema = new SimpleSchema({ }, baseValue: { type: Number, - decimal: true, optional: true, }, value: { type: Number, - decimal: true, defaultValue: 0, }, mod: { - type: Number, + type: SimpleSchema.Integer, optional: true, }, adjustment: { - type: Number, + type: SimpleSchema.Integer, optional: true, }, // Can the value be decimal? diff --git a/app/imports/api/creature/Bundles.js b/app/imports/api/creature/Bundles.js new file mode 100644 index 00000000..876e21a2 --- /dev/null +++ b/app/imports/api/creature/Bundles.js @@ -0,0 +1,76 @@ +import SimpleSchema from "simpl-schema"; + +let Bundle = new Mongo.Collection("bundle"); + +let attributeSchema = new SimpleSchema({ + name: String, + variableName: String, + baseValue: String, + type: String, +}); + +let skillSchema = new SimpleSchema({ + name: String, + variableName: String, + ability: String, + type: String, +}); + +let damageMultiplierSchema = new SimpleSchema({ + name: String, + variableName: String, +}); + +let effectSchema = new SimpleSchema({ + name: String, + stat: String, + operation: {type: String}, + calculation: {type: String, optional: true}, + value: {type: Number, optional: true} +}); + +let itemSchema = new SimpleSchema({ + name: String, + plural: {type: String, optional: true,}, + description: {type: String, optional: true,}, + quantity: {type: SimpleSchema.Integer, min: 0,}, + weight: {type: Number, min: 0,}, + value: {type: Number, min: 0,}, + requiresAttunement: {type: Boolean, optional: true}, + settings: {type: Object, optional: true}, + "settings.showIncrement": {type: Boolean, optional: true}, +}); + +let containerSchema = new SimpleSchema({ + name: String, + isCarried: Boolean, + weight: {type: Number, min: 0}, + value: {type: Number, min: 0}, + description:{type: String, optional: true}, + items: Array, + "items.$": itemSchema, +}); + +let featureSchema = new SimpleSchema({ + name: String, + description: {type: String, optional: true}, + uses: {type: String, optional: true}, + alwaysEnabled: {type: Boolean, defaultValue: true}, + effects: Array, + "effects.$": effectSchema, +}); + +let bundleSchema = new SimpleSchema({ + attributes: Array, + "attributes.$": attributeSchema, + skills: Array, + "skills.$": skillSchema, + damageMultipliers: Array, + "damageMultipliers.$": damageMultiplierSchema, + effects: Array, + "effects.$": effectSchema, + containers: Array, + "containers.$": containerSchema, +}); + +export default Bundles; diff --git a/app/imports/api/creature/Classes.js b/app/imports/api/creature/Classes.js index 023aa51e..c86527c7 100644 --- a/app/imports/api/creature/Classes.js +++ b/app/imports/api/creature/Classes.js @@ -7,7 +7,7 @@ let Classes = new Mongo.Collection("classes"); classSchema= new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, name: {type: String, optional: true, trim: false}, - level: {type: Number}, + level: {type: SimpleSchema.Integer}, createdAt: { type: Date, autoValue: function() { diff --git a/app/imports/api/creature/CreatureDefaults.js b/app/imports/api/creature/CreatureDefaults.js new file mode 100644 index 00000000..9e00e12d --- /dev/null +++ b/app/imports/api/creature/CreatureDefaults.js @@ -0,0 +1,74 @@ +getDefaultCreatureDocs = function(charId, creatureType = "pc"){ + let docs = {attributes: [], skills: [], damageMultipliers: [], effects: []}; + if (creatureType === "pc"){ + const stats = DEFAULT_CHARACTER_STATS; + } else { + throw new Meteor.Error("Not implemented", + "Default stats for non-player characters aren't implemented yet"); + } + let order = 0; + const baseParent = { + collection: "Characters", + id: charId, + group: "default", + }; + let name, variableName, parent, attribute, skill, ability, dm, type, baseValue; + for (type in stats.attributes){ + for (let i in stats.attributes[type]){ + attribute = stats.attributes[type][i]; + if (_.isString(attribute)){ + name = attribute; + variableName = attribute.toLowerCase(); + } else { + name = attribute.name; + variableName = attribute.variableName; + } + baseValue = attribute.baseValue; + parent = _.clone(baseParent); + docs.attributes.push({ + _id: Random.id, + charId, name, variableName, order, type, parent, baseValue, + }); + order++; + } + } + order = 0; + for (type in stats.skills){ + for (let i in stats.skills[type]){ + skill = stats.skills[type][i]; + docs.skills.push({ + _id: Random.id, + charId, + type, + order, + name: skill.name, + variableName: skill.variableName, + ability: skill.ability, + parent: _.clone(baseParent), + }); + order++; + } + } + for (let i in stats.damageMultipliers){ + dm = stats.damageMultipliers[i]; + docs.damageMultipliers.push({ + _id: Random.id, + charId, + name: dm.name, + variableName: dm.variableName, + parent: _.clone(baseParent), + }); + } + for (let i in stats.effects){ + eff = stats.effects[i]; + docs.effects.push({ + _id: Random.id, + charId, + name: eff.name, + stat: eff.stat, + operation: eff.operation, + calculation:eff.calculation, + }); + } + return docs; +} diff --git a/app/imports/api/creature/Creatures.js b/app/imports/api/creature/Creatures.js index abd58787..648bb209 100644 --- a/app/imports/api/creature/Creatures.js +++ b/app/imports/api/creature/Creatures.js @@ -1,4 +1,5 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import SimpleSchema from 'simpl-schema'; import Effects from "/imports/api/creature/Effects.js" import deathSaveSchema from "/imports/api/creature/subSchemas/DeathSaves.js" import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js"; @@ -23,9 +24,9 @@ let creatureSchema = new SimpleSchema({ //mechanics deathSave: {type: deathSaveSchema}, - xp: {type: Number, defaultValue: 0}, + xp: {type: SimpleSchema.Integer, defaultValue: 0}, weightCarried: {type: Number, defaultValue: 0}, - level: {type: Number, defaultValue: 0}, + level: {type: SimpleSchema.Integer, defaultValue: 0}, type: {type: String, defaultValue: "pc", allowedValues: ["pc", "npc", "monster"]}, //permissions @@ -35,7 +36,7 @@ let creatureSchema = new SimpleSchema({ writers: {type: [String], regEx: SimpleSchema.RegEx.Id, defaultValue: [], index: 1}, //TODO add per-creature settings //how many experiences to load at a time in XP table - "settings.experiencesInc": {type: Number, defaultValue: 20}, + "settings.experiencesInc": {type: SimpleSchema.Integer, defaultValue: 20}, //slowed down by carrying too much? "settings.useVariantEncumbrance": {type: Boolean, defaultValue: false}, "settings.useStandardEncumbrance": {type: Boolean, defaultValue: true}, diff --git a/app/imports/api/creature/DamageMultipliers.js b/app/imports/api/creature/DamageMultipliers.js index 3b5515b9..e2027aaa 100644 --- a/app/imports/api/creature/DamageMultipliers.js +++ b/app/imports/api/creature/DamageMultipliers.js @@ -1,3 +1,5 @@ +import SimpleSchema from 'simpl-schema'; + DamageMultipliers = new Mongo.Collection("damageMultipliers"); /* @@ -19,7 +21,6 @@ Schemas.DamageMultiplier = new SimpleSchema({ }, value: { type: Number, - decimal: true, defaultValue: 1, }, enabled: { diff --git a/app/imports/api/creature/Effects.js b/app/imports/api/creature/Effects.js index 6b12ae25..ba186e8f 100644 --- a/app/imports/api/creature/Effects.js +++ b/app/imports/api/creature/Effects.js @@ -1,3 +1,4 @@ +import SimpleSchema from 'simpl-schema'; import {makeChild} from "/imports/api/parenting.js"; Effects = new Mongo.Collection("effects"); @@ -35,7 +36,6 @@ effectSchema = new SimpleSchema({ }, value: { type: Number, - decimal: true, optional: true, }, calculation: { @@ -56,7 +56,7 @@ effectSchema = new SimpleSchema({ Effects.attachSchema(effectSchema); -Effects.attachBehaviour("softRemovable"); +//Effects.attachBehaviour("softRemovable"); makeChild(Effects, ["enabled"]); //children of lots of things export default Effects; diff --git a/app/imports/api/creature/Experience.js b/app/imports/api/creature/Experiences.js similarity index 64% rename from app/imports/api/creature/Experience.js rename to app/imports/api/creature/Experiences.js index 4dc22b2a..f26de8c7 100644 --- a/app/imports/api/creature/Experience.js +++ b/app/imports/api/creature/Experiences.js @@ -1,10 +1,12 @@ +import SimpleSchema from 'simpl-schema'; + Experiences = new Mongo.Collection("experience"); -Schemas.Experience = new SimpleSchema({ +let experienceSchema = new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, name: {type: String, optional: true, trim: false, defaultValue: "New Experience"}, description: {type: String, optional: true, trim: false}, - value: {type: Number, defaultValue: 0}, + value: {type: SimpleSchema.Integer, defaultValue: 0}, dateAdded: { type: Date, autoValue: function() { @@ -19,9 +21,6 @@ Schemas.Experience = new SimpleSchema({ }, }); -Experiences.attachSchema(Schemas.Experience); +Experiences.attachSchema(experienceSchema); -Experiences.attachBehaviour("softRemovable"); - -Experiences.allow(CHARACTER_SUBSCHEMA_ALLOW); -Experiences.deny(CHARACTER_SUBSCHEMA_DENY); +//Experiences.attachBehaviour("softRemovable"); diff --git a/app/imports/api/creature/Features.js b/app/imports/api/creature/Features.js index dac786ea..5381bf9c 100644 --- a/app/imports/api/creature/Features.js +++ b/app/imports/api/creature/Features.js @@ -1,12 +1,15 @@ -Features = new Mongo.Collection("features"); +import SimpleSchema from 'simpl-schema'; import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js"; +import {makeParent} from "/imports/api/parenting.js"; -Schemas.Feature = new SimpleSchema({ +let Features = new Mongo.Collection("features"); + +let featureSchema = new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, name: {type: String, optional: true, trim: false}, description: {type: String, optional: true, trim: false}, uses: {type: String, optional: true, trim: false}, - used: {type: Number, defaultValue: 0}, + used: {type: SimpleSchema.Integer, defaultValue: 0}, reset: { type: String, allowedValues: ["manual", "longRest", "shortRest"], @@ -16,95 +19,10 @@ Schemas.Feature = new SimpleSchema({ alwaysEnabled:{type: Boolean, defaultValue: true}, }); -Features.attachSchema(Schemas.Feature); +Features.attachSchema(featureSchema); Features.attachSchema(ColorSchema); -Features.helpers({ - usesLeft: function(){ - return evaluate(this.charId, this.uses) - this.used; - }, - usesValue: function(){ - return evaluate(this.charId, this.uses); - }, -}); - //Features.attachBehaviour("softRemovable"); makeParent(Features, ["name", "enabled"]); //parents of effects and attacks -//give characters default feature of base ability scores of 10 -Characters.after.insert(function(userId, char) { - if (Meteor.isServer){ - var featureId = Features.insert({ - name: "Base Ability Scores", - charId: char._id, - enabled: true, - alwaysEnabled: true, - }); - Effects.insert({ - stat: "strength", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - Effects.insert({ - stat: "dexterity", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - Effects.insert({ - stat: "constitution", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - Effects.insert({ - stat: "intelligence", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - Effects.insert({ - stat: "wisdom", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - Effects.insert({ - stat: "charisma", - charId: char._id, - parent: { - id: featureId, - collection: "Features", - }, - operation: "base", - value: 10, - enabled: true, - }); - } -}); +export default Features; diff --git a/app/imports/api/creature/Notes.js b/app/imports/api/creature/Notes.js index c0df5e5e..1b66c215 100644 --- a/app/imports/api/creature/Notes.js +++ b/app/imports/api/creature/Notes.js @@ -1,16 +1,17 @@ -Notes = new Mongo.Collection("notes"); +import SimpleSchema from 'simpl-schema'; import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js"; -Schemas.Note = new SimpleSchema({ +let Notes = new Mongo.Collection("notes"); + +noteSchema = new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, name: {type: String, optional: true, trim: false}, description: {type: String, optional: true, trim: false}, }); -Notes.attachSchema(Schemas.Note); -Attributes.attachSchema(ColorSchema); +Notes.attachSchema(noteSchema); +Notes.attachSchema(ColorSchema); -Notes.attachBehaviour("softRemovable"); +//Notes.attachBehaviour("softRemovable"); -Notes.allow(CHARACTER_SUBSCHEMA_ALLOW); -Notes.deny(CHARACTER_SUBSCHEMA_DENY); +export default Notes; diff --git a/app/imports/api/creature/Proficiencies.js b/app/imports/api/creature/Proficiencies.js index 22c6851f..6595a726 100644 --- a/app/imports/api/creature/Proficiencies.js +++ b/app/imports/api/creature/Proficiencies.js @@ -1,6 +1,8 @@ +import SimpleSchema from 'simpl-schema'; + Proficiencies = new Mongo.Collection("proficiencies"); -Schemas.Proficiency = new SimpleSchema({ +proficiencySchema = new SimpleSchema({ charId: { type: String, regEx: SimpleSchema.RegEx.Id, @@ -15,7 +17,6 @@ Schemas.Proficiency = new SimpleSchema({ type: Number, allowedValues: [0, 0.5, 1, 2], defaultValue: 1, - decimal: true, }, type: { type: String, @@ -28,10 +29,7 @@ Schemas.Proficiency = new SimpleSchema({ }, }); -Proficiencies.attachSchema(Schemas.Proficiency); +Proficiencies.attachSchema(proficiencySchema); -Proficiencies.attachBehaviour("softRemovable"); +// Proficiencies.attachBehaviour("softRemovable"); makeChild(Proficiencies, ["enabled"]); - -Proficiencies.allow(CHARACTER_SUBSCHEMA_ALLOW); -Proficiencies.deny(CHARACTER_SUBSCHEMA_DENY); diff --git a/app/imports/api/creature/Skills.js b/app/imports/api/creature/Skills.js index 9f8829e5..1ce97d2d 100644 --- a/app/imports/api/creature/Skills.js +++ b/app/imports/api/creature/Skills.js @@ -1,12 +1,13 @@ +import SimpleSchema from 'simpl-schema'; import {makeChild} from "/imports/api/parenting.js"; -Skills = new Mongo.Collection("skills"); +let Skills = new Mongo.Collection("skills"); /* * Skills are anything that results in a modifier to be added to a D20 * Skills usually have an ability score modifier that they use as their basis */ -skillSchema = new SimpleSchema({ +let skillSchema = new SimpleSchema({ charId: { type: String, regEx: SimpleSchema.RegEx.Id, @@ -38,20 +39,18 @@ skillSchema = new SimpleSchema({ }, // Skills need to store their order to keep the sheet consistent order: { - type: Number, + type: SimpleSchema.Integer, }, baseValue: { type: Number, - decimal: true, optional: true, }, value: { type: Number, - decimal: true, defaultValue: 0, }, advantage: { - type: Number, + type: SimpleSchema.Integer, optional: true, allowedValues: [-1, 0, 1], }, @@ -62,14 +61,14 @@ skillSchema = new SimpleSchema({ proficiency: { type: Number, allowedValues: [0, 0.5, 1, 2], - defaultValue: 0, + defaultValue: 0, }, conditionalBenefits: { - type: Number, + type: SimpleSchema.Integer, optional: true, }, fail: { - type: Number, + type: SimpleSchema.Integer, optional: true, }, enabled: { @@ -80,7 +79,7 @@ skillSchema = new SimpleSchema({ Skills.attachSchema(skillSchema); -Skills.attachBehaviour("softRemovable"); +//Skills.attachBehaviour("softRemovable"); makeChild(Skills, ["enabled"]); //children of lots of things export default Skills; diff --git a/app/imports/api/creature/SpellLists.js b/app/imports/api/creature/SpellLists.js index 723ff916..2bfabd82 100644 --- a/app/imports/api/creature/SpellLists.js +++ b/app/imports/api/creature/SpellLists.js @@ -1,7 +1,9 @@ -SpellLists = new Mongo.Collection("spellLists"); +import SimpleSchema from 'simpl-schema'; import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js"; -Schemas.SpellLists = new SimpleSchema({ +let SpellLists = new Mongo.Collection("spellLists"); + +let spellListSchema = new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, name: {type: String, optional: true, trim: false}, description: {type: String, optional: true, trim: false}, @@ -11,7 +13,7 @@ Schemas.SpellLists = new SimpleSchema({ "settings.showUnprepared": {type: Boolean, defaultValue: true}, }); -SpellLists.attachSchema(Schemas.SpellLists); +SpellLists.attachSchema(spellListSchema); Attributes.attachSchema(ColorSchema); SpellLists.helpers({ @@ -27,8 +29,7 @@ SpellLists.helpers({ } }); -SpellLists.attachBehaviour("softRemovable"); +//SpellLists.attachBehaviour("softRemovable"); makeParent(SpellLists); //parents of spells -SpellLists.allow(CHARACTER_SUBSCHEMA_ALLOW); -SpellLists.deny(CHARACTER_SUBSCHEMA_DENY); +export default SpellLists; diff --git a/app/imports/api/creature/Spells.js b/app/imports/api/creature/Spells.js index 22cf664d..113fcfb6 100644 --- a/app/imports/api/creature/Spells.js +++ b/app/imports/api/creature/Spells.js @@ -1,7 +1,9 @@ -Spells = new Mongo.Collection("spells"); import ColorSchema from "/imports/api/creature/subSchemas/ColorSchema.js"; +import SimpleSchema from 'simpl-schema'; -Schemas.Spell = new SimpleSchema({ +let Spells = new Mongo.Collection("spells"); + +let spellSchema = new SimpleSchema({ charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, prepared: { type: String, @@ -45,7 +47,7 @@ Schemas.Spell = new SimpleSchema({ defaultValue: false, }, level: { - type: Number, + type: SimpleSchema.Integer, defaultValue: 1, }, school: { @@ -55,10 +57,10 @@ Schemas.Spell = new SimpleSchema({ }, }); -Spells.attachSchema(Schemas.Spell); +Spells.attachSchema(spellSchema); Attributes.attachSchema(ColorSchema); -Spells.attachBehaviour("softRemovable"); +//Spells.attachBehaviour("softRemovable"); makeChild(Spells); //children of spell lists makeParent(Spells, ["name", "enabled"]); //parents of attacks @@ -78,12 +80,6 @@ Spells.after.update(function (userId, spell, fieldNames) { } }); -Spells.allow(CHARACTER_SUBSCHEMA_ALLOW); -Spells.deny(CHARACTER_SUBSCHEMA_DENY); - - - - var checkMovePermission = function(spellId, parent, destinationOnly) { var spell = Spells.findOne(spellId); if (!spell) @@ -247,3 +243,5 @@ Meteor.methods({ copySpell(spellId, "Characters", charId); }, }); + +export default Spells; diff --git a/app/imports/api/creature/creatureDefaultStats.js b/app/imports/api/creature/creatureDefaultStats.js deleted file mode 100644 index a16ae04c..00000000 --- a/app/imports/api/creature/creatureDefaultStats.js +++ /dev/null @@ -1,177 +0,0 @@ -DEFAULT_CHARACTER_STATS = { - "attributes": { - "ability": [ - "Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma" - ], - "stat": [ - "Speed", - {"name": "Armor Class", "variableName": "armor", "baseValue": 10}, - ], - "hitDice": [ - {"name": "d6 Hit Dice", "variableName": "d6HitDice"}, - {"name": "d8 Hit Dice", "variableName": "d8HitDice"}, - {"name": "d10 Hit Dice", "variableName": "d10HitDice"}, - {"name": "d12 Hit Dice", "variableName": "d12HitDice"}, - ], - "healthBar": [ - {"name": "Hit Points", "variableName": "hitPoints"}, - {"name": "Temporary Hit Points", "variableName": "tempHitPoints"}, - ], - "resource": [ - "Ki", "Rages", - {"name": "Sourcery Points", "variableName": "sorceryPoints"}, - {"name": "Superiority Dice", "variableName": "superiorityDice"}, - {"name": "Expertise Dice", "variableName": "expertiseDice"}, - ], - "spellSlot": [ - {"name": "Level 1 Spell Slots", "variableName": "level1SpellSlots"}, - {"name": "Level 2 Spell Slots", "variableName": "level2SpellSlots"}, - {"name": "Level 3 Spell Slots", "variableName": "level3SpellSlots"}, - {"name": "Level 4 Spell Slots", "variableName": "level4SpellSlots"}, - {"name": "Level 5 Spell Slots", "variableName": "level5SpellSlots"}, - {"name": "Level 6 Spell Slots", "variableName": "level6SpellSlots"}, - {"name": "Level 7 Spell Slots", "variableName": "level7SpellSlots"}, - {"name": "Level 8 Spell Slots", "variableName": "level8SpellSlots"}, - {"name": "Level 9 Spell Slots", "variableName": "level9SpellSlots"}, - ], - "utility": [ - {"name": "Carry Capacity Multiplier", "variableName": "carryMultiplier", "baseValue": 1}, - {"name": "Rage Damage", "variableName": "rageDamage"}, - ], - }, - - "skills": { - "skill": [ - {"name": "Acrobatics", "variableName": "acrobatics", "ability": "dexterity"}, - {"name": "Animal Handling", "variableName": "animalHandling", "ability": "wisdom"}, - {"name": "Arcana", "variableName": "arcana", "ability": "intelligence"}, - {"name": "Athletics", "variableName": "athletics", "ability": "strength"}, - {"name": "Deception", "variableName": "deception", "ability": "charisma"}, - {"name": "History", "variableName": "history", "ability": "intelligence"}, - {"name": "Insight", "variableName": "insight", "ability": "wisdom"}, - {"name": "Intimidation", "variableName": "intimidation", "ability": "charisma"}, - {"name": "Investigation", "variableName": "investigation", "ability": "intelligence"}, - {"name": "Medicine", "variableName": "medicine", "ability": "wisdom"}, - {"name": "Nature", "variableName": "nature", "ability": "intelligence"}, - {"name": "Perception", "variableName": "perception", "ability": "wisdom"}, - {"name": "Performance", "variableName": "performance", "ability": "charisma"}, - {"name": "Persuasion", "variableName": "persuasion", "ability": "charisma"}, - {"name": "Religion", "variableName": "religion", "ability": "intelligence"}, - {"name": "Sleight of Hand", "variableName": "sleightOfHand", "ability": "dexterity"}, - {"name": "Stealth", "variableName": "stealth", "ability": "dexterity"}, - {"name": "Survival", "variableName": "survival", "ability": "wisdom"}, - ], - "save": [ - {"name": "Strength Save", "variableName": "strengthSave", "ability": "strength"}, - {"name": "Dexterity Save", "variableName": "dexteritySave", "ability": "dexterity"}, - {"name": "Constitution Save", "variableName": "constitutionSave", "ability": "constitution"}, - {"name": "Intelligence Save", "variableName": "intelligenceSave", "ability": "intelligence"}, - {"name": "Wisdom Save", "variableName": "wisdomSave", "ability": "wisdom"}, - {"name": "Charisma Save", "variableName": "charismaSave", "ability": "charisma"}, - ], - "stat": [ - {"name": "Proficiency Bonus", "variableName": "proficiencyBonus"}, - {"name": "initiative", "variableName": "initiative"}, - ], - }, - - "damageMultipliers": [ - {"name": "Acid Multiplier", "variableName":"acidMultiplier"}, - {"name": "Bludgeoning Multiplier", "variableName":"bludgeoningMultiplier"}, - {"name": "Cold Multiplier", "variableName":"coldMultiplier"}, - {"name": "Fire Multiplier", "variableName":"fireMultiplier"}, - {"name": "Force Multiplier", "variableName":"forceMultiplier"}, - {"name": "Lightning Multiplier", "variableName":"lightningMultiplier"}, - {"name": "Necrotic Multiplier", "variableName":"necroticMultiplier"}, - {"name": "Piercing Multiplier", "variableName":"piercingMultiplier"}, - {"name": "Poison Multiplier", "variableName":"poisonMultiplier"}, - {"name": "Psychic Multiplier", "variableName":"psychicMultiplier"}, - {"name": "Radiant Multiplier", "variableName":"radiantMultiplier"}, - {"name": "Slashing Multiplier", "variableName":"slashingMultiplier"}, - {"name": "Thunder Multiplier", "variableName":"thunderMultiplier"}, - ], - - "effects": [ - { - "name": "Proficiency bonus by level", - "stat": "proficiencyBonus", - "operation": "add", - "calculation": "floor(level / 4 + 1.75)", - }, - ] -} - -getDefaultCreatureDocs = function(charId, creatureType = "pc"){ - let docs = {attributes: [], skills: [], damageMultipliers: [], effects: []}; - if (creatureType === "pc"){ - const stats = DEFAULT_CHARACTER_STATS; - } else { - throw new Meteor.Error("Not implemented", - "Default stats for non-player characters aren't implemented yet"); - } - let order = 0; - const baseParent = { - collection: "Characters", - id: charId, - group: "default", - }; - let name, variableName, parent, attribute, skill, ability, dm, type, baseValue; - for (type in stats.attributes){ - for (let i in stats.attributes[type]){ - attribute = stats.attributes[type][i]; - if (_.isString(attribute)){ - name = attribute; - variableName = attribute.toLowerCase(); - } else { - name = attribute.name; - variableName = attribute.variableName; - } - baseValue = attribute.baseValue; - parent = _.clone(baseParent); - docs.attributes.push({ - _id: Random.id, - charId, name, variableName, order, type, parent, baseValue, - }); - order++; - } - } - order = 0; - for (type in stats.skills){ - for (let i in stats.skills[type]){ - skill = stats.skills[type][i]; - docs.skills.push({ - _id: Random.id, - charId, - type, - order, - name: skill.name, - variableName: skill.variableName, - ability: skill.ability, - parent: _.clone(baseParent), - }); - order++; - } - } - for (let i in stats.damageMultipliers){ - dm = stats.damageMultipliers[i]; - docs.damageMultipliers.push({ - _id: Random.id, - charId, - name: dm.name, - variableName: dm.variableName, - parent: _.clone(baseParent), - }); - } - for (let i in stats.effects){ - eff = stats.effects[i]; - docs.effects.push({ - _id: Random.id, - charId, - name: eff.name, - stat: eff.stat, - operation: eff.operation, - calculation:eff.calculation, - }); - } - return docs; -} diff --git a/app/imports/api/creature/subSchemas/ColorSchema.js b/app/imports/api/creature/subSchemas/ColorSchema.js index 7f447d92..77515bd9 100644 --- a/app/imports/api/creature/subSchemas/ColorSchema.js +++ b/app/imports/api/creature/subSchemas/ColorSchema.js @@ -1,4 +1,5 @@ import SimpleSchema from 'simpl-schema'; + const ColorSchema = new SimpleSchema({ color: { type: String, diff --git a/app/imports/api/creature/subSchemas/DeathSavesSchema.js b/app/imports/api/creature/subSchemas/DeathSavesSchema.js index dc51596a..ea7f2933 100644 --- a/app/imports/api/creature/subSchemas/DeathSavesSchema.js +++ b/app/imports/api/creature/subSchemas/DeathSavesSchema.js @@ -1,13 +1,14 @@ import SimpleSchema from 'simpl-schema'; + const DeathSavesSchema = new SimpleSchema({ pass: { - type: Number, + type: SimpleSchema.Integer, min: 0, max: 3, defaultValue: 0, }, fail: { - type: Number, + type: SimpleSchema.Integer, min: 0, max: 3, defaultValue: 0, diff --git a/app/imports/api/inventory/Containers.js b/app/imports/api/inventory/Containers.js index 2318c930..0b9e03f2 100644 --- a/app/imports/api/inventory/Containers.js +++ b/app/imports/api/inventory/Containers.js @@ -1,12 +1,15 @@ -//set up the collection for containers -Containers = new Mongo.Collection("containers"); +import SimpleSchema from 'simpl-schema'; +import {makeParent} from "/imports/api/parenting.js"; -Schemas.Container = new SimpleSchema({ +//set up the collection for containers +let Containers = new Mongo.Collection("containers"); + +let containerSchema = new SimpleSchema({ name: {type: String, optional: true, trim: false}, charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, isCarried: {type: Boolean}, - weight: {type: Number, min: 0, defaultValue: 0, decimal: true}, - value: {type: Number, min: 0, defaultValue: 0, decimal: true}, + weight: {type: Number, min: 0, defaultValue: 0}, + value: {type: Number, min: 0, defaultValue: 0}, description:{type: String, optional: true, trim: false}, color: { type: String, @@ -15,7 +18,7 @@ Schemas.Container = new SimpleSchema({ }, }); -Containers.attachSchema(Schemas.Container); +Containers.attachSchema(containerSchema); Containers.helpers({ contentsValue: function(){ @@ -50,7 +53,7 @@ Containers.helpers({ }, }); -Containers.attachBehaviour("softRemovable"); +// Containers.attachBehaviour("softRemovable"); makeParent(Containers); //parents of items -Containers.allow(CHARACTER_SUBSCHEMA_ALLOW); +export default Containers; diff --git a/app/imports/api/inventory/Items.js b/app/imports/api/inventory/Items.js index 6c5c00e1..79bbdc0e 100644 --- a/app/imports/api/inventory/Items.js +++ b/app/imports/api/inventory/Items.js @@ -1,3 +1,6 @@ +import SimpleSchema from 'simpl-schema'; +import {makeParent, makeChild} from "/imports/api/parenting.js"; + Items = new Mongo.Collection("items"); Schemas.Item = new SimpleSchema({ @@ -5,9 +8,9 @@ Schemas.Item = new SimpleSchema({ plural: {type: String, optional: true, trim: false}, description:{type: String, optional: true, trim: false}, charId: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, //id of owner - quantity: {type: Number, min: 0, defaultValue: 1}, - weight: {type: Number, min: 0, defaultValue: 0, decimal: true}, - value: {type: Number, min: 0, defaultValue: 0, decimal: true}, + quantity: {type: SimpleSchema.Integer, min: 0, defaultValue: 1}, + weight: {type: Number, min: 0, defaultValue: 0}, + value: {type: Number, min: 0, defaultValue: 0}, enabled: {type: Boolean, defaultValue: false}, requiresAttunement: {type: Boolean, defaultValue: false}, "settings.showIncrement": {type: Boolean, defaultValue: false}, @@ -200,11 +203,11 @@ Items.before.update(function(userId, doc, fieldNames, modifier, options){ } }); -Items.attachBehaviour("softRemovable"); +// Items.attachBehaviour("softRemovable"); makeChild(Items); //children of containers makeParent(Items, ["name", "enabled"]); //parents of effects and attacks -Items.allow(CHARACTER_SUBSCHEMA_ALLOW); +//Items.allow(CHARACTER_SUBSCHEMA_ALLOW); //give characters default items Characters.after.insert(function(userId, char) { diff --git a/app/imports/api/library/LibraryItems.js b/app/imports/api/library/LibraryItems.js index 569e1df9..20a02a94 100644 --- a/app/imports/api/library/LibraryItems.js +++ b/app/imports/api/library/LibraryItems.js @@ -5,9 +5,9 @@ Schemas.LibraryItems = new SimpleSchema({ name: {type: String, defaultValue: "New Item", trim: false}, plural: {type: String, optional: true, trim: false}, description:{type: String, optional: true, trim: false}, - quantity: {type: Number, min: 0, defaultValue: 1}, - weight: {type: Number, min: 0, defaultValue: 0, decimal: true}, - value: {type: Number, min: 0, defaultValue: 0, decimal: true}, + quantity: {type: SimpleSchema.Integer, min: 0, defaultValue: 1}, + weight: {type: Number, min: 0, defaultValue: 0}, + value: {type: Number, min: 0, defaultValue: 0}, requiresAttunement: {type: Boolean, defaultValue: false}, library: {type: String, regEx: SimpleSchema.RegEx.Id, index: 1}, diff --git a/app/imports/api/library/LibrarySpells.js b/app/imports/api/library/LibrarySpells.js index bdbb67de..e2a73a67 100644 --- a/app/imports/api/library/LibrarySpells.js +++ b/app/imports/api/library/LibrarySpells.js @@ -37,7 +37,7 @@ Schemas.LibrarySpells = new SimpleSchema({ defaultValue: false, }, level: { - type: Number, + type: SimpleSchema.Integer, defaultValue: 1, }, school: { diff --git a/app/imports/api/library/subSchemas/LibraryAttacks.js b/app/imports/api/library/subSchemas/LibraryAttacks.js index d606acd5..51088e88 100644 --- a/app/imports/api/library/subSchemas/LibraryAttacks.js +++ b/app/imports/api/library/subSchemas/LibraryAttacks.js @@ -1,4 +1,6 @@ -Schemas.LibraryAttacks = new SimpleSchema({ +import SimpleSchema from 'simpl-schema'; + +libraryAttacksSchema = new SimpleSchema({ name: { type: String, defaultValue: "New Attack", @@ -39,3 +41,5 @@ Schemas.LibraryAttacks = new SimpleSchema({ defaultValue: "slashing", }, }); + +export default libraryAttacksSchema; diff --git a/app/imports/api/library/subSchemas/LibraryEffects.js b/app/imports/api/library/subSchemas/LibraryEffects.js index 4abcb1ef..1921515d 100644 --- a/app/imports/api/library/subSchemas/LibraryEffects.js +++ b/app/imports/api/library/subSchemas/LibraryEffects.js @@ -1,4 +1,6 @@ -Schemas.LibraryEffects = new SimpleSchema({ +import SimpleSchema from 'simpl-schema'; + +libraryEffectsSchema = new SimpleSchema({ name: { type: String, optional: true, //TODO make necessary if there is no owner @@ -24,7 +26,6 @@ Schemas.LibraryEffects = new SimpleSchema({ // Effects either have a value OR a calculation value: { type: Number, - decimal: true, optional: true, }, calculation: { @@ -38,3 +39,5 @@ Schemas.LibraryEffects = new SimpleSchema({ optional: true, }, }); + +export default libraryEffectsSchema; diff --git a/app/imports/api/meta/Reports.js b/app/imports/api/meta/Reports.js index 21ac4fe7..940a12c2 100644 --- a/app/imports/api/meta/Reports.js +++ b/app/imports/api/meta/Reports.js @@ -22,7 +22,7 @@ Schemas.Report = new SimpleSchema({ }, //the immediate impact of doing this action (eg. -1 rages) severity: { - type: Number, + type: SimpleSchema.Integer, defaultValue: 5, min: 1, max: 10, diff --git a/app/server/main.js b/app/server/main.js new file mode 100644 index 00000000..e69de29b diff --git a/app/sharedMain.js b/app/sharedMain.js new file mode 100644 index 00000000..1bf2e900 --- /dev/null +++ b/app/sharedMain.js @@ -0,0 +1,5 @@ +import SimpleSchema from 'simpl-schema'; + +if (Meteor.isDevelopment){ + SimpleSchema.debug = true +} diff --git a/dataSources/rulesets/character5e.json b/dataSources/rulesets/character5e.json index 0df4e426..ca7ac964 100644 --- a/dataSources/rulesets/character5e.json +++ b/dataSources/rulesets/character5e.json @@ -1,96 +1,135 @@ { - "attributes": { - "ability": [ - "Strength", "Dexterity", "Constitution", "Intelligence", "Wisdom", "Charisma" - ], - "stat": [ - "Speed", - {"name": "Armor Class", "variableName": "armor"}, - ], - "hitDice": [ - {"name": "d6 Hit Dice", "variableName": "d6HitDice"}, - {"name": "d8 Hit Dice", "variableName": "d8HitDice"}, - {"name": "d10 Hit Dice", "variableName": "d10HitDice"}, - {"name": "d12 Hit Dice", "variableName": "d12HitDice"}, - ], - "healthBar": [ - {"name": "Hit Points", "variableName": "hitPoints"}, - {"name": "Temporary Hit Points", "variableName": "tempHitPoints"}, - ], - "resource": [ - "Ki", "Rages", - {"name": "Sourcery Points", "variableName": "sorceryPoints"}, - {"name": "Superiority Dice", "variableName": "superiorityDice"}, - {"name": "Expertise Dice", "variableName": "expertiseDice"}, - ], - "spellSlot": [ - {"name": "Level 1 Spell Slots", "variableName": "level1SpellSlots"}, - {"name": "Level 2 Spell Slots", "variableName": "level2SpellSlots"}, - {"name": "Level 3 Spell Slots", "variableName": "level3SpellSlots"}, - {"name": "Level 4 Spell Slots", "variableName": "level4SpellSlots"}, - {"name": "Level 5 Spell Slots", "variableName": "level5SpellSlots"}, - {"name": "Level 6 Spell Slots", "variableName": "level6SpellSlots"}, - {"name": "Level 7 Spell Slots", "variableName": "level7SpellSlots"}, - {"name": "Level 8 Spell Slots", "variableName": "level8SpellSlots"}, - {"name": "Level 9 Spell Slots", "variableName": "level9SpellSlots"}, - ], - "utility": [ - {"name": "Carry Capacity Multiplier", "variableName": "carryMultiplier"}, - {"name": "Rage Damage", "variableName": "rageDamage"}, - ], - }, + "attributes": [ + {"name": "Strength", "variableName": "strength", "baseValue": 10, "type": "ability"}, + {"name": "Dexterity", "variableName": "dexterity", "baseValue": 10, "type": "ability"}, + {"name": "Constitution", "variableName": "constitution", "baseValue": 10, "type": "ability"}, + {"name": "Intelligence", "variableName": "intelligence", "baseValue": 10, "type": "ability"}, + {"name": "Wisdom", "variableName": "wisdom", "baseValue": 10, "type": "ability"}, + {"name": "Charisma", "variableName": "charisma", "baseValue": 10, "type": "ability"}, - "skills": { - "skill": [ - {"name": "Acrobatics", "variableName": "acrobatics", "ability": "dexterity"}, - {"name": "Animal Handling", "variableName": "animalHandling", "ability": "wisdom"}, - {"name": "Arcana", "variableName": "arcana", "ability": "intelligence"}, - {"name": "Athletics", "variableName": "athletics", "ability": "strength"}, - {"name": "Deception", "variableName": "deception", "ability": "charisma"}, - {"name": "History", "variableName": "history", "ability": "intelligence"}, - {"name": "Insight", "variableName": "insight", "ability": "wisdom"}, - {"name": "Intimidation", "variableName": "intimidation", "ability": "charisma"}, - {"name": "Investigation", "variableName": "investigation", "ability": "intelligence"}, - {"name": "Medicine", "variableName": "medicine", "ability": "wisdom"}, - {"name": "Nature", "variableName": "nature", "ability": "intelligence"}, - {"name": "Perception", "variableName": "perception", "ability": "wisdom"}, - {"name": "Performance", "variableName": "performance", "ability": "charisma"}, - {"name": "Persuasion", "variableName": "persuasion", "ability": "charisma"}, - {"name": "Religion", "variableName": "religion", "ability": "intelligence"}, - {"name": "Sleight of Hand", "variableName": "sleightOfHand", "ability": "dexterity"}, - {"name": "Stealth", "variableName": "stealth", "ability": "dexterity"}, - {"name": "Survival", "variableName": "survival", "ability": "wisdom"}, - ], - "save": [ - {"name": "Strength Save", "variableName": "strengthSave", "ability": "strength"}, - {"name": "Dexterity Save", "variableName": "dexteritySave", "ability": "dexterity"}, - {"name": "Constitution Save", "variableName": "constitutionSave", "ability": "constitution"}, - {"name": "Intelligence Save", "variableName": "intelligenceSave", "ability": "intelligence"}, - {"name": "Wisdom Save", "variableName": "wisdomSave", "ability": "wisdom"}, - {"name": "Charisma Save", "variableName": "charismaSave", "ability": "charisma"}, - ], - "stat": [ - {"name": "Proficiency Bonus", "variableName": "proficiencyBonus"}, - {"name": "initiative", "variableName": "initiative"}, - ], - "utility": [ - {"name": "Dexterity Armor", "variableName": "dexterityArmor", "ability": "dexterity"}, - ], - }, + {"name": "Speed", "variableName": "speed", "baseValue": 30, "type": "stat"}, + {"name": "Armor Class", "variableName": "armor", "baseValue": 10, "type": "stat"}, + + {"name": "d6 Hit Dice", "variableName": "d6HitDice", "type": "hitDice"}, + {"name": "d8 Hit Dice", "variableName": "d8HitDice", "type": "hitDice"}, + {"name": "d10 Hit Dice", "variableName": "d10HitDice", "type": "hitDice"}, + {"name": "d12 Hit Dice", "variableName": "d12HitDice", "type": "hitDice"}, + + + {"name": "Hit Points", "variableName": "hitPoints", "type": "healthBar"}, + {"name": "Temporary Hit Points", "variableName": "tempHitPoints", "type": "healthBar"}, + + {"name": "Ki", "variableName": "ki", "type": "resource"}, + {"name": "Rages", "variableName": "rages", "type": "resource"}, + {"name": "Sourcery Points", "variableName": "sorceryPoints", "type": "resource"}, + {"name": "Superiority Dice", "variableName": "superiorityDice", "type": "resource"}, + {"name": "Expertise Dice", "variableName": "expertiseDice", "type": "resource"}, + + {"name": "Level 1 Spell Slots", "variableName": "level1SpellSlots", "type": "spellSlot"}, + {"name": "Level 2 Spell Slots", "variableName": "level2SpellSlots", "type": "spellSlot"}, + {"name": "Level 3 Spell Slots", "variableName": "level3SpellSlots", "type": "spellSlot"}, + {"name": "Level 4 Spell Slots", "variableName": "level4SpellSlots", "type": "spellSlot"}, + {"name": "Level 5 Spell Slots", "variableName": "level5SpellSlots", "type": "spellSlot"}, + {"name": "Level 6 Spell Slots", "variableName": "level6SpellSlots", "type": "spellSlot"}, + {"name": "Level 7 Spell Slots", "variableName": "level7SpellSlots", "type": "spellSlot"}, + {"name": "Level 8 Spell Slots", "variableName": "level8SpellSlots", "type": "spellSlot"}, + {"name": "Level 9 Spell Slots", "variableName": "level9SpellSlots", "type": "spellSlot"}, + + {"name": "Carry Capacity Multiplier", "variableName": "carryMultiplier", "type": "utility", "baseValue": 1}, + {"name": "Rage Damage", "variableName": "rageDamage", "type": "utility"}, + ], + + "skills": [ + {"name": "Acrobatics", "variableName": "acrobatics", "ability": "dexterity", "type":"skill"}, + {"name": "Animal Handling", "variableName": "animalHandling", "ability": "wisdom", "type":"skill"}, + {"name": "Arcana", "variableName": "arcana", "ability": "intelligence", "type":"skill"}, + {"name": "Athletics", "variableName": "athletics", "ability": "strength", "type":"skill"}, + {"name": "Deception", "variableName": "deception", "ability": "charisma", "type":"skill"}, + {"name": "History", "variableName": "history", "ability": "intelligence", "type":"skill"}, + {"name": "Insight", "variableName": "insight", "ability": "wisdom", "type":"skill"}, + {"name": "Intimidation", "variableName": "intimidation", "ability": "charisma", "type":"skill"}, + {"name": "Investigation", "variableName": "investigation", "ability": "intelligence", "type":"skill"}, + {"name": "Medicine", "variableName": "medicine", "ability": "wisdom", "type":"skill"}, + {"name": "Nature", "variableName": "nature", "ability": "intelligence", "type":"skill"}, + {"name": "Perception", "variableName": "perception", "ability": "wisdom", "type":"skill"}, + {"name": "Performance", "variableName": "performance", "ability": "charisma", "type":"skill"}, + {"name": "Persuasion", "variableName": "persuasion", "ability": "charisma", "type":"skill"}, + {"name": "Religion", "variableName": "religion", "ability": "intelligence", "type":"skill"}, + {"name": "Sleight of Hand", "variableName": "sleightOfHand", "ability": "dexterity", "type":"skill"}, + {"name": "Stealth", "variableName": "stealth", "ability": "dexterity", "type":"skill"}, + {"name": "Survival", "variableName": "survival", "ability": "wisdom", "type":"skill"}, + + {"name": "Strength Save", "variableName": "strengthSave", "ability": "strength", "type":"save"}, + {"name": "Dexterity Save", "variableName": "dexteritySave", "ability": "dexterity", "type":"save"}, + {"name": "Constitution Save", "variableName": "constitutionSave", "ability": "constitution", "type":"save"}, + {"name": "Intelligence Save", "variableName": "intelligenceSave", "ability": "intelligence", "type":"save"}, + {"name": "Wisdom Save", "variableName": "wisdomSave", "ability": "wisdom", "type":"save"}, + {"name": "Charisma Save", "variableName": "charismaSave", "ability": "charisma", "type":"save"}, + + {"name": "Proficiency Bonus", "variableName": "proficiencyBonus", "type": "stat"}, + {"name": "initiative", "variableName": "initiative", "type": "stat"}, + ], "damageMultipliers": [ - {"name": "Acid Multiplier", "variableName":"acidMultiplier"}, + {"name": "Acid Multiplier", "variableName":"acidMultiplier"}, {"name": "Bludgeoning Multiplier", "variableName":"bludgeoningMultiplier"}, - {"name": "Cold Multiplier", "variableName":"coldMultiplier"}, - {"name": "Fire Multiplier", "variableName":"fireMultiplier"}, - {"name": "Force Multiplier", "variableName":"forceMultiplier"}, - {"name": "Lightning Multiplier", "variableName":"lightningMultiplier"}, - {"name": "Necrotic Multiplier", "variableName":"necroticMultiplier"}, - {"name": "Piercing Multiplier", "variableName":"piercingMultiplier"}, - {"name": "Poison Multiplier", "variableName":"poisonMultiplier"}, - {"name": "Psychic Multiplier", "variableName":"psychicMultiplier"}, - {"name": "Radiant Multiplier", "variableName":"radiantMultiplier"}, - {"name": "Slashing Multiplier", "variableName":"slashingMultiplier"}, - {"name": "Thunder Multiplier", "variableName":"thunderMultiplier"}, - ] + {"name": "Cold Multiplier", "variableName":"coldMultiplier"}, + {"name": "Fire Multiplier", "variableName":"fireMultiplier"}, + {"name": "Force Multiplier", "variableName":"forceMultiplier"}, + {"name": "Lightning Multiplier", "variableName":"lightningMultiplier"}, + {"name": "Necrotic Multiplier", "variableName":"necroticMultiplier"}, + {"name": "Piercing Multiplier", "variableName":"piercingMultiplier"}, + {"name": "Poison Multiplier", "variableName":"poisonMultiplier"}, + {"name": "Psychic Multiplier", "variableName":"psychicMultiplier"}, + {"name": "Radiant Multiplier", "variableName":"radiantMultiplier"}, + {"name": "Slashing Multiplier", "variableName":"slashingMultiplier"}, + {"name": "Thunder Multiplier", "variableName":"thunderMultiplier"}, + ], + + "effects": [ + { + "name": "Proficiency bonus by level", + "stat": "proficiencyBonus", + "operation": "add", + "calculation": "floor(level / 4 + 1.75)", + }, + ], + + "containers": [ + { + "name": "Coin Pouch", + "isCarried": true, + "description": "A sturdy pouch for coins", + "items": [ + { + "name": "Gold piece", + "plural": "Gold pieces", + "quantity": 0, + "weight": 0.02, + "value": 1, + "settings": { + "showIncrement": true, + }, + }, { + "name": "Silver piece", + "plural": "Silver pieces", + "quantity": 0, + "weight": 0.02, + "value": 0.1, + "settings": { + "showIncrement": true, + }, + }, { + "name": "Copper piece", + "plural": "Copper pieces", + "quantity": 0, + "weight": 0.02, + "value": 0.01, + "settings": { + "showIncrement": true, + }, + }, + ], + }, + ], }