diff --git a/rpg-docs/Model/Character/Characters.js b/rpg-docs/Model/Character/Characters.js index 30003f7a..eeaebb40 100644 --- a/rpg-docs/Model/Character/Characters.js +++ b/rpg-docs/Model/Character/Characters.js @@ -2,17 +2,242 @@ Characters = new Meteor.Collection("characters"); Schemas.Character = new SimpleSchema({ - strings: { type: Schemas.Strings }, - attributes: { type: Schemas.Attributes }, - skills: { type: Schemas.Skills }, - proficiencies: { type: Schemas.Proficiencies }, + //strings + name: { type: String, defaultValue: "", optional: true }, + alignment: { type: String, defaultValue: "", optional: true }, + gender: { type: String, defaultValue: "", optional: true }, + race: { type: String, defaultValue: "", optional: true }, + description:{ type: String, defaultValue: "", optional: true }, + personality:{ type: String, defaultValue: "", optional: true }, + ideals: { type: String, defaultValue: "", optional: true }, + bonds: { type: String, defaultValue: "", optional: true }, + flaws: { type: String, defaultValue: "", optional: true }, + backstory: { type: String, defaultValue: "", optional: true }, + notes: { type: String, defaultValue: "", optional: true }, + + //attributes + //ability scores + strength: {type: Schemas.Attribute}, + dexterity: {type: Schemas.Attribute}, + constitution: {type: Schemas.Attribute}, + intelligence: {type: Schemas.Attribute}, + wisdom: {type: Schemas.Attribute}, + charisma: {type: Schemas.Attribute}, + + //stats + hitPoints: {type: Schemas.Attribute}, + "hitPoints.add": { + type: [Schemas.Effect], + defaultValue: [ + {name: "Constitution modifier for each level", calculation: "level * constitutionMod"} + ] + }, + experience: {type: Schemas.Attribute}, + proficiencyBonus: {type: Schemas.Attribute}, + speed: {type: Schemas.Attribute}, + weight: {type: Schemas.Attribute}, + weightCarried: {type: Schemas.Attribute}, + age: {type: Schemas.Attribute}, + ageRate: {type: Schemas.Attribute}, + armor: {type: Schemas.Attribute}, + "armor.add": { + type: [Schemas.Effect], + defaultValue: [ + {name: "Dexterity Modifier", calculation: "dexterityArmor"} + ] + }, + + //resources + level1SpellSlots: {type: Schemas.Attribute}, + level2SpellSlots: {type: Schemas.Attribute}, + level3SpellSlots: {type: Schemas.Attribute}, + level4SpellSlots: {type: Schemas.Attribute}, + level5SpellSlots: {type: Schemas.Attribute}, + level6SpellSlots: {type: Schemas.Attribute}, + level7SpellSlots: {type: Schemas.Attribute}, + level8SpellSlots: {type: Schemas.Attribute}, + level9SpellSlots: {type: Schemas.Attribute}, + ki: {type: Schemas.Attribute}, + sorceryPoints: {type: Schemas.Attribute}, + rages: {type: Schemas.Attribute}, + + + //hit dice + d6HitDice: {type: Schemas.Attribute}, + d8HitDice: {type: Schemas.Attribute}, + d10HitDice: {type: Schemas.Attribute}, + d12HitDice: {type: Schemas.Attribute}, + + //vulnerabilities + acidMultiplier: {type: Schemas.Vulnerability}, + bludgeoningMultiplier: {type: Schemas.Vulnerability}, + coldMultiplier: {type: Schemas.Vulnerability}, + fireMultiplier: {type: Schemas.Vulnerability}, + forceMultiplier: {type: Schemas.Vulnerability}, + lightningMultiplier: {type: Schemas.Vulnerability}, + necroticMultiplier: {type: Schemas.Vulnerability}, + piercingMultiplier: {type: Schemas.Vulnerability}, + poisonMultiplier: {type: Schemas.Vulnerability}, + psychicMultiplier: {type: Schemas.Vulnerability}, + radiantMultiplier: {type: Schemas.Vulnerability}, + slashingMultiplier: {type: Schemas.Vulnerability}, + thunderMultiplier: {type: Schemas.Vulnerability}, + + + //skills + //saves + strengthSave: {type: Schemas.Skill}, + "strengthSave.ability": { type: String, defaultValue: "strength" }, + + dexteritySave: {type: Schemas.Skill}, + "dexteritySave.ability": { type: String, defaultValue: "dexterity" }, + + constitutionSave:{type: Schemas.Skill}, + "constitutionSave.ability": { type: String, defaultValue: "constitution" }, + + intelligenceSave:{type: Schemas.Skill}, + "intelligenceSave.ability": { type: String, defaultValue: "intelligence" }, + + wisdomSave: {type: Schemas.Skill}, + "wisdomSave.ability": { type: String, defaultValue: "wisdom" }, + + charismaSave: {type: Schemas.Skill}, + "charismaSave.ability": { type: String, defaultValue: "charisma" }, + + + //skill skills + acrobatics: {type: Schemas.Skill}, + "acrobatics.ability": { type: String, defaultValue: "dexterity" }, + + animalHandling: {type: Schemas.Skill}, + "animalHandling.ability": { type: String, defaultValue: "wisdom" }, + + arcana: {type: Schemas.Skill}, + "arcana.ability": { type: String, defaultValue: "intelligence" }, + + athletics: {type: Schemas.Skill}, + "athletics.ability": { type: String, defaultValue: "strength" }, + + deception: {type: Schemas.Skill}, + "deception.ability": { type: String, defaultValue: "charisma" }, + + history: {type: Schemas.Skill}, + "history.ability": { type: String, defaultValue: "intelligence" }, + + insight: {type: Schemas.Skill}, + "insight.ability": { type: String, defaultValue: "wisdom" }, + + intimidation: {type: Schemas.Skill}, + "intimidation.ability": { type: String, defaultValue: "charisma" }, + + investigation: {type: Schemas.Skill}, + "investigation.ability": { type: String, defaultValue: "intelligence" }, + + medicine: {type: Schemas.Skill}, + "medicine.ability": { type: String, defaultValue: "wisdom" }, + + nature: {type: Schemas.Skill}, + "nature.ability": { type: String, defaultValue: "intelligence" }, + + perception: {type: Schemas.Skill}, + "perception.ability": { type: String, defaultValue: "wisdom" }, + + performance: {type: Schemas.Skill}, + "performance.ability": { type: String, defaultValue: "charisma" }, + + persuasion: {type: Schemas.Skill}, + "persuasion.ability": { type: String, defaultValue: "charisma" }, + + religion: {type: Schemas.Skill}, + "religion.ability": { type: String, defaultValue: "intelligence" }, + + sleightOfHand: {type: Schemas.Skill}, + "sleightOfHand.ability": { type: String, defaultValue: "dexterity" }, + + stealth: {type: Schemas.Skill}, + "stealth.ability": { type: String, defaultValue: "dexterity" }, + + survival: {type: Schemas.Skill}, + "survival.ability": { type: String, defaultValue: "wisdom" }, + + + //Mechanical Skills + initiative: {type: Schemas.Skill}, + "initiative.ability": { type: String, defaultValue: "dexterity" }, + + strengthAttack: {type: Schemas.Skill}, + "strengthAttack.ability": {type: String,defaultValue: "strength"}, + "strengthAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + dexterityAttack: {type: Schemas.Skill}, + "dexterityAttack.ability": { type: String, defaultValue: "dexterity" }, + "dexterityAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + constitutionAttack: {type: Schemas.Skill}, + "constitutionAttack.ability":{ type: String, defaultValue: "constitution" }, + "constitutionAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + intelligenceAttack: {type: Schemas.Skill}, + "intelligenceAttack.ability":{ type: String, defaultValue: "intelligence" }, + "intelligenceAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + wisdomAttack: {type: Schemas.Skill}, + "wisdomAttack.ability": { type: String, defaultValue: "wisdom" }, + "wisdomAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + charismaAttack: {type: Schemas.Skill}, + "charismaAttack.ability": { type: String, defaultValue: "charisma" }, + "charismaAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + rangedAttack: {type: Schemas.Skill}, + "rangedAttack.ability": { type: String, defaultValue: "dexterity" }, + "rangedAttack.proficiency": { + type: [Schemas.Effect], + defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] + }, + + dexterityArmor: {type: Schemas.Skill}, + "dexterityArmor.ability": { type: String, defaultValue: "dexterity" }, + + //proficiencies + weaponsProficiencies: { + type: [Schemas.Proficiency], + defaultValue: [] + }, + toolsProficiencies: { + type: [Schemas.Proficiency], + defaultValue: [] + }, + languages: { + type: [Schemas.Proficiency], + defaultValue: [] + }, + + //mechanics features: { type: [Schemas.Feature], defaultValue: []}, deathSave: { type: Schemas.DeathSave }, time: { type: Number, min: 0, decimal: true, defaultValue: 0}, initiativeOrder:{ type: Number, min: 0, max: 1, decimal: true, defaultValue: 0}, expirations: { type: [Schemas.Expiration], defaultValue: []} //TODO add permission stuff for owner, readers and writers - //TODO hit dice //TODO spells }); @@ -32,32 +257,69 @@ Characters.find({},{fields: {time: 1, expirations: 1}}).observe({ } }); -//functions and calculated values +//functions and calculated values. +//These functions can only rely on this._id since no other +//field is likely to be attached to all returned characters Characters.helpers({ + //returns the value stored in the field requested + //will set up dependencies on just that field + getField : function(fieldName){ + var fieldSelector = {}; + fieldSelector[fieldName] = 1; + var char = Characters.findOne(this._id, {fields: fieldSelector}); + var field = char[fieldName]; + if(field === undefined){ + throw "no such field "+fieldName+" exists"; + } + return field; + }, + //returns the value of a field + fieldValue : function(fieldName){ + if(!Schemas.Character.schema(fieldName)){ + console.log("Character's schema does not contain a field called: " + fieldName); + return; + } + var field = this.getField(fieldName); + //duck typing to get the right value function + //.proficiency implies skill + if (Schemas.Character.schema(fieldName + ".proficiency")){ + return this.skillMod(field); + } + //base without proficiency implies attribute + if (Schemas.Character.schema(fieldName + ".base")){ + return this.attributeValue(field); + } + //fall back to just returning the field itself + return field; + }, + attributeValue: function(attribute){ if (attribute === undefined) return; + var charId = this._id; + if (_.isString(attribute)){ + attribute = this.getField(attribute); + } //base value var value = attribute.base; - var char = this; //add all values in add array _.each(attribute.add, function(effect){ - value += evaluateEffect(char, effect); + value += evaluateEffect(charId, effect); }); //multiply all values in mul array _.each(attribute.mul, function(effect){ - value *= evaluateEffect(char, effect); + value *= evaluateEffect(charId, effect); }); //largest min _.each(attribute.min, function(effect){ - var min = evaluateEffect(char, effect); + var min = evaluateEffect(charId, effect); value = value > min? value : min; }); //smallest max _.each(attribute.max, function(effect){ - var max = evaluateEffect(char, effect); + var max = evaluateEffect(charId, effect); value = value < max? value : max; }); @@ -65,11 +327,14 @@ Characters.helpers({ }, proficiency: function(skill){ + if (_.isString(skill)){ + skill = this.getField(skill); + } + var charId = this._id; //return largest value in proficiency array - var char = this; var prof = 0; _.each(skill.proficiency, function(effect){ - var newProf = evaluateEffect(char, effect); + var newProf = evaluateEffect(charId, effect); if (newProf > prof){ prof = newProf; } @@ -82,9 +347,12 @@ Characters.helpers({ console.log("Cannot get skillMod of undefined"); return; } - var char = this; + var charId = this._id; + if (_.isString(skill)){ + skill = this.getField(skill); + } //get the final value of the ability score - var ability = this.attributeValue(this.attributes[skill.ability]); + var ability = this.attributeValue(skill.ability); //base modifier var mod = +getMod(ability) @@ -93,27 +361,27 @@ Characters.helpers({ var prof = this.proficiency(skill); //add multiplied proficiency bonus to modifier - mod += prof * this.attributeValue(this.attributes.proficiencyBonus); + mod += prof * this.attributeValue("proficiencyBonus"); //add all values in add array _.each(skill.add, function(effect){ - mod += evaluateEffect(char, effect); + mod += evaluateEffect(charId, effect); }); //multiply all values in mul array _.each(skill.mul, function(effect){ - mod *= evaluateEffect(char, effect); + mod *= evaluateEffect(charId, effect); }); //largest min _.each(skill.min, function(effect){ - var min = evaluateEffect(char, effect); + var min = evaluateEffect(charId, effect); mod = mod > min? mod : min; }); //smallest max _.each(skill.max, function(effect){ - var max = evaluateEffect(char, effect); + var max = evaluateEffect(charId, effect); mod = mod < max? mod : max; }); @@ -121,11 +389,14 @@ Characters.helpers({ }, passiveSkill: function(skill){ + if (_.isString(skill)){ + skill = this.getField(skill); + } + var charId = this._id var mod = +this.skillMod(skill); - var char = this; var value = 10 + mod; _.each(skill.passiveAdd, function(effect){ - value += evaluateEffect(char, effect); + value += evaluateEffect(charId, effect); }); return value; //TODO decide whether (dis)advantage gives (-)+5 to passive checks @@ -141,15 +412,16 @@ Characters.helpers({ }, level: function(){ - var xp = this.attributeValue(this.attributes.experience); + var xp = this.attributeValue("experience"); var xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000]; - _.each(xpTable, function(value, i){ - if(xp < value){ + for(var i = 0; i < 19; i++){ + if(xp < xpTable[i]){ return i; } - }); - return 20; + }; + if(xp > 355000) return 20; + return 0; } }); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Attribute.js b/rpg-docs/Model/Character/SubSchemas/Attribute.js new file mode 100644 index 00000000..79c5e92f --- /dev/null +++ b/rpg-docs/Model/Character/SubSchemas/Attribute.js @@ -0,0 +1,27 @@ +Schemas.Attribute = new SimpleSchema({ + //the unmodified value of the attribute + //should be zero for most attributes after a long rest + base: { + type: Number, + defaultValue: 0 + }, + //effect arrays + add: { type: [Schemas.Effect], defaultValue: [] }, + mul: { type: [Schemas.Effect], defaultValue: [] }, + min: { type: [Schemas.Effect], defaultValue: [] }, + max: { type: [Schemas.Effect], defaultValue: [] }, + conditional:{ type: [Schemas.Effect], defaultValue: [] } +}); + +//note that to make an invulnerability add a new max of zero value +Schemas.Vulnerability = new SimpleSchema({ + //same as attribute + base: { + type: Number, + defaultValue: 0 + }, + //effect arrays + mul: { type: [Schemas.Effect], defaultValue: [] }, + min: { type: [Schemas.Effect], defaultValue: [{name: "Resistance doesn't stack", value: 0.5}] }, + max: { type: [Schemas.Effect], defaultValue: [{name: "Vulnerability doesn't stack", value: 2}] }, +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Attributes.js b/rpg-docs/Model/Character/SubSchemas/Attributes.js deleted file mode 100644 index 5627ce6a..00000000 --- a/rpg-docs/Model/Character/SubSchemas/Attributes.js +++ /dev/null @@ -1,92 +0,0 @@ -Schemas.Attribute = new SimpleSchema({ - //the unmodified value of the attribute - //should be zero for most attributes after a long rest - base: { - type: Number, - defaultValue: 0 - }, - //effect arrays - add: { type: [Schemas.Effect], defaultValue: [] }, - mul: { type: [Schemas.Effect], defaultValue: [] }, - min: { type: [Schemas.Effect], defaultValue: [] }, - max: { type: [Schemas.Effect], defaultValue: [] }, - conditional:{ type: [Schemas.Effect], defaultValue: [] } -}); - -//note to make an invulnerability add a new max of zero value -Schemas.Vulnerability = new SimpleSchema({ - //same as attribute - base: { - type: Number, - defaultValue: 0 - }, - //effect arrays - add: { type: [Schemas.Effect], defaultValue: [] }, - mul: { type: [Schemas.Effect], defaultValue: [] }, - min: { type: [Schemas.Effect], defaultValue: [{name: "Resistance doesn't stack", value: 0.5}] }, - max: { type: [Schemas.Effect], defaultValue: [{name: "Vulnerability doesn't stack", value: 2}] }, - conditional:{ type: [Schemas.Effect], defaultValue: [] }, -}); - -Schemas.Attributes = new SimpleSchema({ - //ability scores - strength: {type: Schemas.Attribute}, - dexterity: {type: Schemas.Attribute}, - constitution: {type: Schemas.Attribute}, - intelligence: {type: Schemas.Attribute}, - wisdom: {type: Schemas.Attribute}, - charisma: {type: Schemas.Attribute}, - - //stats - hitPoints: {type: Schemas.Attribute}, - experience: {type: Schemas.Attribute}, - proficiencyBonus: {type: Schemas.Attribute}, - speed: {type: Schemas.Attribute}, - weight: {type: Schemas.Attribute}, - weightCarried: {type: Schemas.Attribute}, - age: {type: Schemas.Attribute}, - ageRate: {type: Schemas.Attribute}, - armor: {type: Schemas.Attribute}, - "armor.add": { - type: [Schemas.Effect], - defaultValue: [ - {name: "Dexterity Modifier", calculation: "dexterityArmor"} - ] - }, - - //resources - level1SpellSlots: {type: Schemas.Attribute}, - level2SpellSlots: {type: Schemas.Attribute}, - level3SpellSlots: {type: Schemas.Attribute}, - level4SpellSlots: {type: Schemas.Attribute}, - level5SpellSlots: {type: Schemas.Attribute}, - level6SpellSlots: {type: Schemas.Attribute}, - level7SpellSlots: {type: Schemas.Attribute}, - level8SpellSlots: {type: Schemas.Attribute}, - level9SpellSlots: {type: Schemas.Attribute}, - ki: {type: Schemas.Attribute}, - sorceryPoints: {type: Schemas.Attribute}, - rages: {type: Schemas.Attribute}, - - - //hit dice - d6HitDice: {type: Schemas.Attribute}, - d8HitDice: {type: Schemas.Attribute}, - d10HitDice: {type: Schemas.Attribute}, - d12HitDice: {type: Schemas.Attribute}, - - //vulnerabilities - acidMultiplier: {type: Schemas.Vulnerability}, - bludgeoningMultiplier: {type: Schemas.Vulnerability}, - coldMultiplier: {type: Schemas.Vulnerability}, - fireMultiplier: {type: Schemas.Vulnerability}, - forceMultiplier: {type: Schemas.Vulnerability}, - lightningMultiplier: {type: Schemas.Vulnerability}, - necroticMultiplier: {type: Schemas.Vulnerability}, - piercingMultiplier: {type: Schemas.Vulnerability}, - poisonMultiplier: {type: Schemas.Vulnerability}, - psychicMultiplier: {type: Schemas.Vulnerability}, - radiantMultiplier: {type: Schemas.Vulnerability}, - slashingMultiplier: {type: Schemas.Vulnerability}, - thunderMultiplier: {type: Schemas.Vulnerability}, -}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Features.js b/rpg-docs/Model/Character/SubSchemas/Feature.js similarity index 100% rename from rpg-docs/Model/Character/SubSchemas/Features.js rename to rpg-docs/Model/Character/SubSchemas/Feature.js diff --git a/rpg-docs/Model/Character/SubSchemas/Proficiencies.js b/rpg-docs/Model/Character/SubSchemas/Proficiencies.js deleted file mode 100644 index 9db2c493..00000000 --- a/rpg-docs/Model/Character/SubSchemas/Proficiencies.js +++ /dev/null @@ -1,19 +0,0 @@ -Schemas.Proficiency = new SimpleSchema({ - name: {type: String}, - source: {type: String} -}) - -Schemas.Proficiencies = new SimpleSchema({ - weapons: { - type: [Schemas.Proficiency], - defaultValue: [] - }, - tools: { - type: [Schemas.Proficiency], - defaultValue: [] - }, - languages: { - type: [Schemas.Proficiency], - defaultValue: [] - } -}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Proficiency.js b/rpg-docs/Model/Character/SubSchemas/Proficiency.js new file mode 100644 index 00000000..d8d54f44 --- /dev/null +++ b/rpg-docs/Model/Character/SubSchemas/Proficiency.js @@ -0,0 +1,4 @@ +Schemas.Proficiency = new SimpleSchema({ + name: {type: String}, + source: {type: String} +}) \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Skill.js b/rpg-docs/Model/Character/SubSchemas/Skill.js new file mode 100644 index 00000000..d429631f --- /dev/null +++ b/rpg-docs/Model/Character/SubSchemas/Skill.js @@ -0,0 +1,25 @@ +Schemas.Skill = new SimpleSchema({ + //attribute name that this skill used as base mod for roll + ability: { type: String, defaultValue: "" }, + //multiplied by profBonus and added to base mod + //only highest value proficiency is used + proficiency: { type: [Schemas.Effect], defaultValue: [] }, + //added to base mod + add: { type: [Schemas.Effect], defaultValue: [] }, + //multiplied by base + adds + mul: { type: [Schemas.Effect], defaultValue: [] }, + //lower bounds, highest used + min: { type: [Schemas.Effect], defaultValue: [] }, + //upper bounds, lowest used + max: { type: [Schemas.Effect], defaultValue: [] }, + //things giving advantage + advantage: { type: [Schemas.Effect], defaultValue: [] }, + //things giving disadvantage + disadvantage: { type: [Schemas.Effect], defaultValue: [] }, + //added to passive checks only + passiveAdd: { type: [Schemas.Effect], defaultValue: [] }, + //things causing all rolls to fail + fail: { type: [Schemas.Effect], defaultValue: [] }, + //things that only apply sometimes + conditional: { type: [Schemas.Effect], defaultValue: [] } +}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Skills.js b/rpg-docs/Model/Character/SubSchemas/Skills.js deleted file mode 100644 index 3377c047..00000000 --- a/rpg-docs/Model/Character/SubSchemas/Skills.js +++ /dev/null @@ -1,159 +0,0 @@ -Schemas.Skill = new SimpleSchema({ - //attribute name that this skill used as base mod for roll - ability: { type: String, defaultValue: "" }, - //multiplied by profBonus and added to base mod - //only highest value proficiency is used - proficiency: { type: [Schemas.Effect], defaultValue: [] }, - //added to base mod - add: { type: [Schemas.Effect], defaultValue: [] }, - //multiplied by base + adds - mul: { type: [Schemas.Effect], defaultValue: [] }, - //lower bounds, highest used - min: { type: [Schemas.Effect], defaultValue: [] }, - //upper bounds, lowest used - max: { type: [Schemas.Effect], defaultValue: [] }, - //things giving advantage - advantage: { type: [Schemas.Effect], defaultValue: [] }, - //things giving disadvantage - disadvantage: { type: [Schemas.Effect], defaultValue: [] }, - //added to passive checks only - passiveAdd: { type: [Schemas.Effect], defaultValue: [] }, - //things causing all rolls to fail - fail: { type: [Schemas.Effect], defaultValue: [] }, - //things that only apply sometimes - conditional: { type: [Schemas.Effect], defaultValue: [] } -}); - -Schemas.Skills = new SimpleSchema({ - //saves - strengthSave: {type: Schemas.Skill}, - "strengthSave.ability": { type: String, defaultValue: "strength" }, - - dexteritySave: {type: Schemas.Skill}, - "dexteritySave.ability": { type: String, defaultValue: "dexterity" }, - - constitutionSave:{type: Schemas.Skill}, - "constitutionSave.ability": { type: String, defaultValue: "constitution" }, - - intelligenceSave:{type: Schemas.Skill}, - "intelligenceSave.ability": { type: String, defaultValue: "intelligence" }, - - wisdomSave: {type: Schemas.Skill}, - "wisdomSave.ability": { type: String, defaultValue: "wisdom" }, - - charismaSave: {type: Schemas.Skill}, - "charismaSave.ability": { type: String, defaultValue: "charisma" }, - - - //skill skills - acrobatics: {type: Schemas.Skill}, - "acrobatics.ability": { type: String, defaultValue: "dexterity" }, - - animalHandling: {type: Schemas.Skill}, - "animalHandling.ability": { type: String, defaultValue: "wisdom" }, - - arcana: {type: Schemas.Skill}, - "arcana.ability": { type: String, defaultValue: "intelligence" }, - - athletics: {type: Schemas.Skill}, - "athletics.ability": { type: String, defaultValue: "strength" }, - - deception: {type: Schemas.Skill}, - "deception.ability": { type: String, defaultValue: "charisma" }, - - history: {type: Schemas.Skill}, - "history.ability": { type: String, defaultValue: "intelligence" }, - - insight: {type: Schemas.Skill}, - "insight.ability": { type: String, defaultValue: "wisdom" }, - - intimidation: {type: Schemas.Skill}, - "intimidation.ability": { type: String, defaultValue: "charisma" }, - - investigation: {type: Schemas.Skill}, - "investigation.ability": { type: String, defaultValue: "intelligence" }, - - medicine: {type: Schemas.Skill}, - "medicine.ability": { type: String, defaultValue: "wisdom" }, - - nature: {type: Schemas.Skill}, - "nature.ability": { type: String, defaultValue: "intelligence" }, - - perception: {type: Schemas.Skill}, - "perception.ability": { type: String, defaultValue: "wisdom" }, - - performance: {type: Schemas.Skill}, - "performance.ability": { type: String, defaultValue: "charisma" }, - - persuasion: {type: Schemas.Skill}, - "persuasion.ability": { type: String, defaultValue: "charisma" }, - - religion: {type: Schemas.Skill}, - "religion.ability": { type: String, defaultValue: "intelligence" }, - - sleightOfHand: {type: Schemas.Skill}, - "sleightOfHand.ability": { type: String, defaultValue: "dexterity" }, - - stealth: {type: Schemas.Skill}, - "stealth.ability": { type: String, defaultValue: "dexterity" }, - - survival: {type: Schemas.Skill}, - "survival.ability": { type: String, defaultValue: "wisdom" }, - - - //Mechanical Skills - initiative: {type: Schemas.Skill}, - "initiative.ability": { type: String, defaultValue: "dexterity" }, - - strengthAttack: {type: Schemas.Skill}, - "strengthAttack.ability": {type: String,defaultValue: "strength"}, - "strengthAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - dexterityAttack: {type: Schemas.Skill}, - "dexterityAttack.ability": { type: String, defaultValue: "dexterity" }, - "dexterityAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - constitutionAttack: {type: Schemas.Skill}, - "constitutionAttack.ability":{ type: String, defaultValue: "constitution" }, - "constitutionAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - intelligenceAttack: {type: Schemas.Skill}, - "intelligenceAttack.ability":{ type: String, defaultValue: "intelligence" }, - "intelligenceAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - wisdomAttack: {type: Schemas.Skill}, - "wisdomAttack.ability": { type: String, defaultValue: "wisdom" }, - "wisdomAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - charismaAttack: {type: Schemas.Skill}, - "charismaAttack.ability": { type: String, defaultValue: "charisma" }, - "charismaAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - rangedAttack: {type: Schemas.Skill}, - "rangedAttack.ability": { type: String, defaultValue: "dexterity" }, - "rangedAttack.proficiency": { - type: [Schemas.Effect], - defaultValue: [{_id: Random.id(),name: "Attack Proficiency",value: 1}] - }, - - dexterityArmor: {type: Schemas.Skill}, - "dexterityArmor.ability": { type: String, defaultValue: "dexterity" } -}); \ No newline at end of file diff --git a/rpg-docs/Model/Character/SubSchemas/Strings.js b/rpg-docs/Model/Character/SubSchemas/Strings.js deleted file mode 100644 index d62cfca0..00000000 --- a/rpg-docs/Model/Character/SubSchemas/Strings.js +++ /dev/null @@ -1,13 +0,0 @@ -Schemas.Strings = new SimpleSchema({ - name: { type: String, defaultValue: "", optional: true }, - alignment: { type: String, defaultValue: "", optional: true }, - gender: { type: String, defaultValue: "", optional: true }, - race: { type: String, defaultValue: "", optional: true }, - description:{ type: String, defaultValue: "", optional: true }, - personality:{ type: String, defaultValue: "", optional: true }, - ideals: { type: String, defaultValue: "", optional: true }, - bonds: { type: String, defaultValue: "", optional: true }, - flaws: { type: String, defaultValue: "", optional: true }, - backstory: { type: String, defaultValue: "", optional: true }, - notes: { type: String, defaultValue: "", optional: true }, -}); \ No newline at end of file diff --git a/rpg-docs/Routes/Routes.js b/rpg-docs/Routes/Routes.js index 4bbd07d1..fbce41f9 100644 --- a/rpg-docs/Routes/Routes.js +++ b/rpg-docs/Routes/Routes.js @@ -7,7 +7,7 @@ Router.map( function () { }, data: { characters: function(){ - return Characters.find() + return Characters.find({}, {fields: {_id: 1}}); } } }); @@ -19,7 +19,7 @@ Router.map( function () { return Meteor.subscribe("singleCharacter", this.params._id, Meteor.userId()); }, data: function() { - var data = Characters.findOne({_id: this.params._id}); + var data = Characters.findOne({_id: this.params._id}, {fields: {_id: 1}}); return data; } }); @@ -29,7 +29,7 @@ Router.map( function () { notFoundTemplate: 'characterNotFound', data: { containers: function() { - var containers = Containers.find({owner: data._id}); + var containers = Containers.find({owner: data._id}, {fields: {_id: 1}}); return containers; }, diff --git a/rpg-docs/client/main.js b/rpg-docs/client/main.js new file mode 100644 index 00000000..542bdd1e --- /dev/null +++ b/rpg-docs/client/main.js @@ -0,0 +1,8 @@ +_.each(Template, function (template, name) { + if(template){ + var counter = 0; + template.rendered = template.rendered || function () { + console.log(name, "render count: ", ++counter); + }; + } +}); \ No newline at end of file diff --git a/rpg-docs/client/views/character/bigAbilities/bigAbilities.html b/rpg-docs/client/views/character/bigAbilities/bigAbilities.html index 2095c40a..a142b929 100644 --- a/rpg-docs/client/views/character/bigAbilities/bigAbilities.html +++ b/rpg-docs/client/views/character/bigAbilities/bigAbilities.html @@ -4,10 +4,10 @@ Strength
- {{attributeValue attributes.strength}} + {{attributeValue "strength"}}
- {{abilityMod attributes.strength}} + {{abilityMod "strength"}}
@@ -15,10 +15,10 @@ Dexterity
- {{attributeValue attributes.dexterity}} + {{attributeValue "dexterity"}}
- {{abilityMod attributes.dexterity}} + {{abilityMod "dexterity"}}
@@ -26,10 +26,10 @@ Constitution
- {{attributeValue attributes.constitution}} + {{attributeValue "constitution"}}
- {{abilityMod attributes.constitution}} + {{abilityMod "constitution"}}
@@ -37,10 +37,10 @@ Intelligence
- {{attributeValue attributes.intelligence}} + {{attributeValue "intelligence"}}
- {{abilityMod attributes.intelligence}} + {{abilityMod "intelligence"}}
@@ -48,10 +48,10 @@ Wisdom
- {{attributeValue attributes.wisdom}} + {{attributeValue "wisdom"}}
- {{abilityMod attributes.wisdom}} + {{abilityMod "wisdom"}}
@@ -59,10 +59,10 @@ Charisma
- {{attributeValue attributes.charisma}} + {{attributeValue "charisma"}}
- {{abilityMod attributes.charisma}} + {{abilityMod "charisma"}}
\ No newline at end of file diff --git a/rpg-docs/client/views/character/healthBar/healthBar.html b/rpg-docs/client/views/character/healthBar/healthBar.html index 973a6307..a23eacda 100644 --- a/rpg-docs/client/views/character/healthBar/healthBar.html +++ b/rpg-docs/client/views/character/healthBar/healthBar.html @@ -26,7 +26,7 @@
- {{attributeValue attributes.hitPoints}}/{{maxHp}} + {{attributeValue "hitPoints"}}/{{maxHp}}
diff --git a/rpg-docs/client/views/character/healthBar/healthBar.js b/rpg-docs/client/views/character/healthBar/healthBar.js index dd723ae0..8ecaf172 100644 --- a/rpg-docs/client/views/character/healthBar/healthBar.js +++ b/rpg-docs/client/views/character/healthBar/healthBar.js @@ -1,14 +1,15 @@ Template.healthBar.helpers({ healthy: function(){ - var hp = this.attributeValue(this.attributes.hitPoints); + var hp = this.attributeValue("hitPoints"); return hp > 0; }, dead: function(){ - if(this.deathSave.canDeathSave){ - return this.deathSave.fail >= 3; + var deathSave = this.getField("deathSave"); + if(deathSave.canDeathSave){ + return deathSave.fail >= 3; } else{ //creatures that can't make death saves die at 0 HP - var hp = this.attributeValue(this.attributes.hitPoints); + var hp = this.attributeValue("hitPoints"); return hp <= 0; } } @@ -16,13 +17,13 @@ Template.healthBar.helpers({ Template.hitPointBars.helpers({ hpRed: function(){ - var currentHp = this.attributeValue(this.attributes.hitPoints); - var damage = this.attributes.hitPoints.base; + var currentHp = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; return 100*(currentHp/(currentHp - damage)); }, hpGreen: function(){ - var currentHp = this.attributeValue(this.attributes.hitPoints); - var damage = this.attributes.hitPoints.base; + var currentHp = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; var maxHp = currentHp - damage; var percent = 100*(currentHp/ maxHp); var change = 100 * Template.instance().deltaHp.get() / maxHp; @@ -33,8 +34,8 @@ Template.hitPointBars.helpers({ } }, hpYellow: function(){ - var currentHp = this.attributeValue(this.attributes.hitPoints); - var damage = this.attributes.hitPoints.base; + var currentHp = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; var maxHp = currentHp - damage; var percent = 100*(currentHp/ maxHp); var change = 100 * Template.instance().deltaHp.get() / maxHp; @@ -48,16 +49,16 @@ Template.hitPointBars.helpers({ if(!Template.instance().deltaHp){ Template.instance().deltaHp = new ReactiveVar(0); } - var currentHp = this.attributeValue(this.attributes.hitPoints); - var damage = this.attributes.hitPoints.base; + var currentHp = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; var maxHp = currentHp - damage; var percent = 100*(currentHp/ maxHp); var change = 100 * Template.instance().deltaHp.get() / maxHp; return percent + change; }, maxHp: function(){ - var currentHp = this.attributeValue(this.attributes.hitPoints); - var damage = this.attributes.hitPoints.base; + var currentHp = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; return currentHp - damage; }, deltaHp: function(){ @@ -81,8 +82,8 @@ Template.hitPointBars.events({ "drag": function(event, templateInstance, handler){ //the width of the bar, fetch dynamically if needed var healthBarWidth = 300; - var hpLeft = this.attributeValue(this.attributes.hitPoints) - var damage = this.attributes.hitPoints.base + var hpLeft = this.attributeValue("hitPoints"); + var damage = this.getField("hitPoints").base; var maxHp = hpLeft - damage; var dragMultiplier = maxHp / healthBarWidth; var newValue = dragMultiplier * handler.deltaX + Template.instance().startDrag.get(); @@ -98,7 +99,7 @@ Template.hitPointBars.events({ "click .healthBarPlus": function(event){ var newValue = Template.instance().deltaHp.get() + 1; //don't heal more than -damage - var damage = this.attributes.hitPoints.base + var damage = this.getField("hitPoints").base; newValue = newValue < -damage ? newValue : -damage; //set value Template.instance().deltaHp.set(newValue); @@ -106,13 +107,13 @@ Template.hitPointBars.events({ "click .healthBarMinus": function(event){ var newValue = Template.instance().deltaHp.get() - 1; //dont damage more than hit points left - var hpLeft = this.attributeValue(this.attributes.hitPoints) + var hpLeft = this.getField("hitPoints").base; newValue = newValue > -hpLeft ? newValue : -hpLeft; //set value Template.instance().deltaHp.set(newValue); }, "click #applyDelta": function(event){ - Characters.update(this._id, {$inc: {"attributes.hitPoints.base": Template.instance().deltaHp.get()}}) + Characters.update(this._id, {$inc: {"hitPoints.base": Template.instance().deltaHp.get()}}) Template.instance().deltaHp.set(0); } }); @@ -126,22 +127,26 @@ Template.deadBar.events({ Template.deathSaves.helpers({ deathFailGT: function(num){ - if(this.deathSave.fail > num) return "tickedDeathFail"; + var deathSave = this.getField("deathSave"); + if(deathSave.fail > num) return "tickedDeathFail"; else return "untickedDeathFail"; }, deathPassGT: function(num){ - if(this.deathSave.pass > num) return "tickedDeathPass"; + var deathSave = this.getField("deathSave"); + if(deathSave.pass > num) return "tickedDeathPass"; else return "untickedDeathPass"; }, stable: function(){ - if(this.deathSave.pass > 0 || this.deathSave.fail > 0){ + var deathSave = this.getField("deathSave"); + if(deathSave.pass > 0 || deathSave.fail > 0){ return "stability"; } else{ return "heal"; } }, stabilizeText: function(){ - if(this.deathSave.pass > 0 || this.deathSave.fail > 0){ + var deathSave = this.getField("deathSave"); + if(deathSave.pass > 0 || deathSave.fail > 0){ return "stabilize"; } else{ return "heal"; diff --git a/rpg-docs/client/views/character/skills/skills.js b/rpg-docs/client/views/character/skills/skills.js index 20b759d4..9b24a995 100644 --- a/rpg-docs/client/views/character/skills/skills.js +++ b/rpg-docs/client/views/character/skills/skills.js @@ -1,53 +1,55 @@ Template.skills.helpers({ saveList: function(){ - return [ - {name: "Strength", skill: this.skills.strengthSave}, - {name: "Dexterity", skill: this.skills.dexteritySave}, - {name: "Constitution", skill: this.skills.constitutionSave}, - {name: "Intelligence", skill: this.skills.intelligenceSave}, - {name: "Wisdom", skill: this.skills.wisdomSave}, - {name: "Charisma", skill: this.skills.charismaSave} + return [ + {name: "Strength", skill: "strengthSave"}, + {name: "Dexterity", skill: "dexteritySave"}, + {name: "Constitution", skill: "constitutionSave"}, + {name: "Intelligence", skill: "intelligenceSave"}, + {name: "Wisdom", skill: "wisdomSave"}, + {name: "Charisma", skill: "charismaSave"} ]; }, skillList: function(){ return [ - {name: "Acrobatics", skill: this.skills.acrobatics}, - {name: "Animal Handling", skill: this.skills.animalHandling}, - {name: "Arcana", skill: this.skills.arcana}, - {name: "Athletics", skill: this.skills.athletics}, - {name: "Deception", skill: this.skills.deception}, - {name: "History", skill: this.skills.history}, - {name: "Insight", skill: this.skills.insight}, - {name: "Intimidation", skill: this.skills.intimidation}, - {name: "Investigation", skill: this.skills.investigation}, - {name: "Medicine", skill: this.skills.medicine}, - {name: "Nature", skill: this.skills.nature}, - {name: "Perception", skill: this.skills.perception}, - {name: "Performance", skill: this.skills.performance}, - {name: "Persuasion", skill: this.skills.persuasion}, - {name: "Religion", skill: this.skills.religion}, - {name: "Sleight of Hand", skill: this.skills.sleightOfHand}, - {name: "Stealth", skill: this.skills.stealth}, - {name: "Survival", skill: this.skills.survival} + {name: "Acrobatics", skill: "acrobatics"}, + {name: "Animal Handling", skill: "animalHandling"}, + {name: "Arcana", skill: "arcana"}, + {name: "Athletics", skill: "athletics"}, + {name: "Deception", skill: "deception"}, + {name: "History", skill: "history"}, + {name: "Insight", skill: "insight"}, + {name: "Intimidation", skill: "intimidation"}, + {name: "Investigation", skill: "investigation"}, + {name: "Medicine", skill: "medicine"}, + {name: "Nature", skill: "nature"}, + {name: "Perception", skill: "perception"}, + {name: "Performance", skill: "performance"}, + {name: "Persuasion", skill: "persuasion"}, + {name: "Religion", skill: "religion"}, + {name: "Sleight of Hand", skill: "sleightOfHand"}, + {name: "Stealth", skill: "stealth"}, + {name: "Survival", skill: "survival"} ]; }, profIcon: function(skill){ - var prof = Template.parentData(1).proficiency(skill); + var prof = Template.parentData(1).proficiency(this.skill); if(prof > 0 && prof < 1) return "profHalf.png"; if(prof === 1) return "profSingle.png"; if(prof > 1) return "profDouble.png"; return "profNone.png"; }, failSkill: function(){ - return this.skill.fail.length > 0; + return Template.parentData(1).getField(this.skill).fail.length > 0; }, advantage: function(){ - var adv = this.skill.advantage.length; - var disadv = this.skill.disadvantage.length; + var adv = Template.parentData(1).getField(this.skill).advantage.length; + var disadv = Template.parentData(1).getField(this.skill).disadvantage.length; if(adv > 0 && disadv === 0) return "advantage"; if(disadv > 0 && adv === 0) return "disadvantage"; }, conditionals: function(){ - if(this.skill.conditional.length > 0) return "conditionals"; + if(Template.parentData(1).getField(this.skill).conditional.length > 0){ + return "conditionals"; + } } }); \ No newline at end of file diff --git a/rpg-docs/client/views/character/textField/textField.js b/rpg-docs/client/views/character/textField/textField.js index aa73b886..072d71fc 100644 --- a/rpg-docs/client/views/character/textField/textField.js +++ b/rpg-docs/client/views/character/textField/textField.js @@ -8,12 +8,12 @@ Template.textField.helpers({ return Template.instance().editing.get(); }, input: function(){ - var text = this.character.strings[this.field]; + var text = this.character.getField(this.field); if (_.isString(text)) return Spacebars.SafeString(text); return text; }, output: function(){ - var html = evaluateString(this.character, this.character.strings[this.field]); + var html = evaluateString(this.character._id, this.character.getField(this.field)); if (_.isString(html)) return Spacebars.SafeString(html); return html; }, @@ -33,7 +33,7 @@ Template.textField.events({ if(!_.isString(text)) text = ""; //TODO sanitise the html var setter = {}; - setter["strings."+this.field] = text; + setter[this.field] = text; Characters.update(this.character._id, {$set: setter}, function(error, result) { if(error) console.log(error); }); diff --git a/rpg-docs/client/views/home/home.html b/rpg-docs/client/views/home/home.html index 993e2488..64e5166a 100644 --- a/rpg-docs/client/views/home/home.html +++ b/rpg-docs/client/views/home/home.html @@ -2,7 +2,7 @@ {{>loginButtons}}
{{# each characters}} -
  • {{_id}}
  • +
  • {{_id}}
  • {{/each}}
    diff --git a/rpg-docs/client/views/home/home.js b/rpg-docs/client/views/home/home.js index 77bbe1ac..740d174a 100644 --- a/rpg-docs/client/views/home/home.js +++ b/rpg-docs/client/views/home/home.js @@ -2,7 +2,8 @@ Template.home.events({ "click #addCharacter": function (event, template) { Characters.insert({}); }, - "click .delete": function(event, template){ + "click #deleteChar": function(event, template){ + console.log("deleting", this); Characters.remove(this._id); } }); \ No newline at end of file diff --git a/rpg-docs/lib/functions/evaluateString.js b/rpg-docs/lib/functions/evaluate.js similarity index 56% rename from rpg-docs/lib/functions/evaluateString.js rename to rpg-docs/lib/functions/evaluate.js index e5d71af2..acc32bde 100644 --- a/rpg-docs/lib/functions/evaluateString.js +++ b/rpg-docs/lib/functions/evaluate.js @@ -1,22 +1,20 @@ -evaluate = function(character, string){ +//evaluates a calculation string +evaluate = function(charId, string){ if(!string) return string; - string = string.replace(/\b[a-z]+\b/g, function(sub){ - //skill mods - if(_.has(character.skills, sub)){ - return +character.skillMod(character.skills[sub]); - } - //attributes - if(_.has(character.attributes, sub)){ - return +character.attributeValue(character.attributes[sub]); + var char = Characters.findOne(charId, {fields: {_id: 1}}); + string = string.replace(/\b[a-zA-Z]+\b/g, function(sub){ + //fields + if(Schemas.Character.schema(sub)){ + return char.fieldValue(sub) } //ability modifiers var abilityMods = ["strengthMod", "dexterityMod", "constitutionMod", "intelligenceMod", "wisdomMod", "charismaMod"] if( _.contains(abilityMods, sub) ){ var slice = sub.slice(0, - 3); - return +character.abilityMod(character.attributes[slice]); + return char.abilityMod(slice); } if(sub === "level"){ - return +character.level(); + return char.level(); } return sub; }); @@ -29,7 +27,9 @@ evaluate = function(character, string){ } } -evaluateString = function(character, string){ +//takes a string with {calculations} and returns it with the results +//of the calculations returned in place +evaluateString = function(charId, string){ //define brackets as curly brackets around anything that isn't a curly bracket if(!string) return string; var brackets = /\{[^\{\}]*\}/g; @@ -37,7 +37,7 @@ evaluateString = function(character, string){ var exp = exp.replace(/(\{|\})/g, "") //remove brackets var span = jQuery('', { title: exp, - text: evaluate(character, exp), + text: evaluate(charId, exp), class: "calculatedValue" }); return span.prop('outerHTML'); @@ -46,11 +46,14 @@ evaluateString = function(character, string){ return result; } -evaluateEffect = function(character, effect){ +//returns the value of the effect if it exists, +//otherwise returns the result of the calculation if it exists, +//otherwise returns 0 +evaluateEffect = function(charId, effect){ if(_.isFinite(effect.value)){ return effect.value; } else if(_.isString(effect.calculation)){ - return +evaluate(character, effect.calculation); + return +evaluate(charId, effect.calculation); } else { return 0; }