diff --git a/app/imports/api/creature/computation/ComputationMemo.js b/app/imports/api/creature/computation/ComputationMemo.js index 795b5715..5595ca7c 100644 --- a/app/imports/api/creature/computation/ComputationMemo.js +++ b/app/imports/api/creature/computation/ComputationMemo.js @@ -78,7 +78,7 @@ export default class ComputationMemo { } addProficiency(prop){ prop = this.registerProperty(prop); - let targets = getProficiencyTargets(prop); + let targets = this.getProficiencyTargets(prop); targets.forEach(target => { target.computationDetails.proficiencies.push(prop); }); @@ -86,7 +86,7 @@ export default class ComputationMemo { getProficiencyTargets(prop){ let targets = new Set(); if (!prop.stats) return targets; - proficiency.stats.forEach(statName => { + prop.stats.forEach(statName => { let target = this.statsByVariableName[statName]; if (!target) return; targets.add(target); @@ -146,4 +146,7 @@ const propDetailsByType = { computed: false, }; }, + damageMultiplier(){ + return {}; + }, } diff --git a/app/imports/api/creature/computation/combineStat.js b/app/imports/api/creature/computation/combineStat.js index 8b99c93a..fb4ce6ce 100644 --- a/app/imports/api/creature/computation/combineStat.js +++ b/app/imports/api/creature/computation/combineStat.js @@ -3,11 +3,11 @@ import computedValueOfVariableName from '/imports/api/creature/computation/compu export default function combineStat(stat, aggregator, memo){ - if (stat.type === "attribute"){ + if (stat.type === 'attribute'){ combineAttribute(stat, aggregator); - } else if (stat.type === "skill"){ + } else if (stat.type === 'skill'){ combineSkill(stat, aggregator, memo); - } else if (stat.type === "damageMultiplier"){ + } else if (stat.type === 'damageMultiplier'){ combineDamageMultiplier(stat, memo); } } @@ -18,7 +18,7 @@ function combineAttribute(stat, aggregator){ if (result > aggregator.max) result = aggregator.max; if (!stat.decimal) result = Math.floor(result); stat.value = result; - if (stat.attributeType === "ability") { + if (stat.attributeType === 'ability') { stat.mod = Math.floor((result - 10) / 2); } } @@ -57,6 +57,7 @@ function combineSkill(stat, aggregator, memo){ function combineDamageMultiplier(stat){ if (stat.immunityCount) return 0; + let result; if (stat.ressistanceCount && !stat.vulnerabilityCount){ result = 0.5; } else if (!stat.ressistanceCount && stat.vulnerabilityCount){ diff --git a/app/imports/api/creature/computation/computedValueOfVariableName.js b/app/imports/api/creature/computation/computedValueOfVariableName.js index 4349af9f..dc805983 100644 --- a/app/imports/api/creature/computation/computedValueOfVariableName.js +++ b/app/imports/api/creature/computation/computedValueOfVariableName.js @@ -1,10 +1,14 @@ +import { get } from 'lodash'; import computeStat from '/imports/api/creature/computation/computeStat.js'; -export default function computedValueOfVariableName(sub, memo){ - const stat = memo.statsByVariableName[sub]; +export default function computedValueOfVariableName(name, memo){ + let path = name.split('.'); + let statName = path[0]; + let statPath = path.slice(1); + const stat = get(memo.statsByVariableName, statName); if (!stat) return null; if (!stat.computationDetails.computed){ computeStat(stat, memo); } - return stat.value; + return statPath.length ? get(stat, statPath) : stat.value; } diff --git a/app/imports/api/creature/computation/recomputeCreature.js b/app/imports/api/creature/computation/recomputeCreature.js index 9fc3af4a..690aed58 100644 --- a/app/imports/api/creature/computation/recomputeCreature.js +++ b/app/imports/api/creature/computation/recomputeCreature.js @@ -1,3 +1,4 @@ +import { Meteor } from 'meteor/meteor' import { ValidatedMethod } from 'meteor/mdg:validated-method'; import SimpleSchema from 'simpl-schema'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; @@ -5,10 +6,11 @@ import ComputationMemo from '/imports/api/creature/computation/ComputationMemo.j import computeMemo from '/imports/api/creature/computation/computeMemo.js'; import getCalculationProperties from '/imports/api/creature/computation/getCalculationProperties.js'; import writeAlteredProperties from '/imports/api/creature/computation/writeAlteredProperties.js'; +import writeCreatureVariables from '/imports/api/creature/computation/writeCreatureVariables.js'; export const recomputeCreature = new ValidatedMethod({ - name: "Creatures.methods.recomputeCreature", + name: 'Creatures.methods.recomputeCreature', validate: new SimpleSchema({ charId: { type: String } @@ -65,5 +67,7 @@ export function recomputeCreatureById(creatureId){ let computationMemo = new ComputationMemo(props); computeMemo(computationMemo); writeAlteredProperties(computationMemo); + writeCreatureVariables(computationMemo, creatureId); + if(Meteor.isClient) console.log(computationMemo); return computationMemo; } diff --git a/app/imports/api/creature/computation/writeAlteredProperties.js b/app/imports/api/creature/computation/writeAlteredProperties.js index 04926b9e..7c951be8 100644 --- a/app/imports/api/creature/computation/writeAlteredProperties.js +++ b/app/imports/api/creature/computation/writeAlteredProperties.js @@ -1,3 +1,4 @@ +import { Meteor } from 'meteor/meteor' import { isEqual, forOwn } from 'lodash'; import { ComputedOnlySkillSchema } from '/imports/api/properties/Skills.js'; import { ComputedOnlyAttributeSchema } from '/imports/api/properties/Attributes.js'; @@ -28,7 +29,10 @@ export default function writeAlteredProperties(memo){ for (let key of schema.objectKeys()){ if (!isEqual(original[key], changed[key])){ if (!op) op = newOperation(_id, changed.type); - op.updateOne.update.$set[key] = changed[key]; + let value = changed[key]; + // Use null instead of undefined because it works with the $set operator + if (value === undefined) value = null; + op.updateOne.update.$set[key] = value; } } if (op){ @@ -42,14 +46,14 @@ function newOperation(_id, type){ let newOp = { updateOne: { filter: {_id}, - update: {$set: {}}, + update: {'$set': {}}, } }; if (Meteor.isClient){ newOp.type = type; } return newOp; -}; +} function bulkWriteProperties(bulkWriteOps){ if (!bulkWriteOps.length) return; @@ -62,9 +66,13 @@ function bulkWriteProperties(bulkWriteOps){ } ); } else { - _.each(bulkWriteOps, op => { + bulkWriteOps.forEach(op => { CreatureProperties.update(op.updateOne.filter, op.updateOne.update, { - selector: {type: op.type} + // The server code is bypassing collection 2 validation, so do the same + // on the client + // include this if bypass is off: + // selector: {type: op.type} + bypassCollection2: true, }); }); } diff --git a/app/imports/api/creature/computation/writeCreatureVariables.js b/app/imports/api/creature/computation/writeCreatureVariables.js new file mode 100644 index 00000000..5a310531 --- /dev/null +++ b/app/imports/api/creature/computation/writeCreatureVariables.js @@ -0,0 +1,33 @@ +import { pick, forOwn } from 'lodash'; +import Creatures from '/imports/api/creature/Creatures.js'; + +export default function writeCreatureVariables(memo, creatureId) { + const fields = [ + 'name', + 'attributeType', + 'baseValue', + 'damage', + 'decimal', + 'reset', + 'resetMultiplier', + 'value', + 'mod', + 'ability', + 'skillType', + 'baseProficiency', + 'abilityMod', + 'advantage', + 'passiveBonus', + 'proficiency', + 'conditionalBenefits', + 'rollBonuses', + 'fail', + ]; + + memo.creatureVariables = {}; + forOwn(memo.statsByVariableName, (stat, variableName) => { + let condensedStat = pick(stat, fields); + memo.creatureVariables[variableName] = condensedStat; + }); + Creatures.update(creatureId, {$set: {variables: memo.creatureVariables}}); +} diff --git a/app/imports/api/properties/Attributes.js b/app/imports/api/properties/Attributes.js index dd58ede9..54a80d6e 100644 --- a/app/imports/api/properties/Attributes.js +++ b/app/imports/api/properties/Attributes.js @@ -70,8 +70,9 @@ let AttributeSchema = new SimpleSchema({ let ComputedOnlyAttributeSchema = new SimpleSchema({ // The computed value of the attribute value: { - type: Number, + type: SimpleSchema.oneOf(Number, String, Boolean), defaultValue: 0, + optional: true, }, // The computed modifier, provided the attribute type is `ability` mod: { diff --git a/app/imports/api/properties/Effects.js b/app/imports/api/properties/Effects.js index 76db387d..f71fde96 100644 --- a/app/imports/api/properties/Effects.js +++ b/app/imports/api/properties/Effects.js @@ -1,4 +1,5 @@ import SimpleSchema from 'simpl-schema'; +import { Random } from 'meteor/random'; /* * Effects are reason-value attached to skills and abilities @@ -54,7 +55,7 @@ const StoredEffectSchema = new SimpleSchema({ const ComputedOnlyEffectSchema = new SimpleSchema({ // The computed result of the effect result: { - type: SimpleSchema.oneOf(Number, String), + type: SimpleSchema.oneOf(Number, String, Boolean), optional: true, }, }) diff --git a/app/imports/ui/properties/viewers/EffectViewer.vue b/app/imports/ui/properties/viewers/EffectViewer.vue index 4f295f9f..d72405b0 100644 --- a/app/imports/ui/properties/viewers/EffectViewer.vue +++ b/app/imports/ui/properties/viewers/EffectViewer.vue @@ -1,32 +1,50 @@