From db1ae5db3da8ceef6961f4172a7a32eda3c5b2cb Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Fri, 5 Jun 2020 21:48:28 +0200 Subject: [PATCH] Iterated on XP system --- app/imports/api/creature/Creatures.js | 16 +-- .../creature/computation/ComputationMemo.js | 17 ++- .../creature/computation/recomputeCreature.js | 16 ++- .../api/creature/experience/Experiences.js | 35 ++++-- .../characterSheetTabs/PersonaTab.vue | 22 +++- .../experiences/ExperienceInsertDialog.vue | 17 +-- .../experiences/ExperienceListDialog.vue | 100 ++++++++++++++---- 7 files changed, 163 insertions(+), 60 deletions(-) diff --git a/app/imports/api/creature/Creatures.js b/app/imports/api/creature/Creatures.js index 45caaa1a..23cf5ceb 100644 --- a/app/imports/api/creature/Creatures.js +++ b/app/imports/api/creature/Creatures.js @@ -70,24 +70,26 @@ let CreatureSchema = new SimpleSchema({ type: deathSaveSchema, defaultValue: {}, }, + // Stats that are computed and denormalised outside of recomputation + denormalizedStats: { + type: Object, + defaultValue: {}, + }, // Sum of all XP gained by this character - xp: { + 'denormalizedStats.xp': { type: SimpleSchema.Integer, defaultValue: 0, }, // Sum of all levels granted by milestone XP - xpLevels: { + 'denormalizedStats.milestoneLevels': { type: SimpleSchema.Integer, defaultValue: 0, }, - weightCarried: { + // Sum of all weights of items and containers that are carried + 'denormalizedStats.weightCarried': { type: Number, defaultValue: 0, }, - level: { - type: SimpleSchema.Integer, - defaultValue: 0, - }, type: { type: String, defaultValue: 'pc', diff --git a/app/imports/api/creature/computation/ComputationMemo.js b/app/imports/api/creature/computation/ComputationMemo.js index 998a2765..fab2f978 100644 --- a/app/imports/api/creature/computation/ComputationMemo.js +++ b/app/imports/api/creature/computation/ComputationMemo.js @@ -3,7 +3,7 @@ import { includes, cloneDeep } from 'lodash'; // The computation memo is an in-memory data structure used only during the // computation process export default class ComputationMemo { - constructor(props){ + constructor(props, creature){ this.statsByVariableName = {}; this.extraStatsByVariableName = {}; this.statsById = {}; @@ -51,6 +51,15 @@ export default class ComputationMemo { this.addClassLevel(prop); } }); + for (let name in creature.denormalizedStats){ + if (!this.statsByVariableName[name]){ + this.statsByVariableName[name] = { + variableName: name, + value: creature.denormalizedStats[name], + computationDetails: propDetailsByType.denormalizedStat(), + } + } + } } registerProperty(prop){ this.originalPropsById[prop._id] = cloneDeep(prop); @@ -251,4 +260,10 @@ const propDetailsByType = { disabledByToggle: false, }; }, + denormalizedStat(){ + return { + toggleAncestors: [], + disabledByToggle: false, + }; + } } diff --git a/app/imports/api/creature/computation/recomputeCreature.js b/app/imports/api/creature/computation/recomputeCreature.js index 83ea1e36..a29c4808 100644 --- a/app/imports/api/creature/computation/recomputeCreature.js +++ b/app/imports/api/creature/computation/recomputeCreature.js @@ -6,7 +6,8 @@ import computeMemo from '/imports/api/creature/computation/computeMemo.js'; import getActiveProperties from '/imports/api/creature/getActiveProperties.js'; import writeAlteredProperties from '/imports/api/creature/computation/writeAlteredProperties.js'; import writeCreatureVariables from '/imports/api/creature/computation/writeCreatureVariables.js'; -import { recomputeDamageMultipliersById } from '/imports/api/creature/damageMultiplierDenormalise/recomputeDamageMultipliers.js' +import { recomputeDamageMultipliersById } from '/imports/api/creature/damageMultiplierDenormalise/recomputeDamageMultipliers.js'; +import Creatures from '/imports/api/creature/Creatures.js'; export const recomputeCreature = new ValidatedMethod({ @@ -17,8 +18,9 @@ export const recomputeCreature = new ValidatedMethod({ }).validator(), run({charId}) { + let creature = Creatures.findOne(charId); // Permission - assertEditPermission(charId, this.userId); + assertEditPermission(creature, this.userId); // Work, call this direcly if you are already in a method that has checked // for permission to edit a given character recomputeCreatureById(charId); @@ -35,6 +37,11 @@ const calculationPropertyTypes = [ 'toggle', ]; +export function recomputeCreatureById(creatureId){ + let creature = Creatures.findOne(creatureId); + recomputeCreatureByDoc(creature); +} + /** * This function is the heart of DiceCloud. It recomputes a creature's stats, * distilling down effects and proficiencies into the final stats that make up @@ -71,14 +78,15 @@ const calculationPropertyTypes = [ * - Mark the stat as computed * - Write the computed results back to the database */ -export function recomputeCreatureById(creatureId){ +function recomputeCreatureByDoc(creature){ + const creatureId = creature._id; let props = getActiveProperties({ ancestorId: creatureId, filter: {type: {$in: calculationPropertyTypes}}, includeUntoggled: true, // TODO filter out expensive fields, particularly icon field }); - let computationMemo = new ComputationMemo(props); + let computationMemo = new ComputationMemo(props, creature); computeMemo(computationMemo); writeAlteredProperties(computationMemo); writeCreatureVariables(computationMemo, creatureId); diff --git a/app/imports/api/creature/experience/Experiences.js b/app/imports/api/creature/experience/Experiences.js index bceb43b8..ba8c9aca 100644 --- a/app/imports/api/creature/experience/Experiences.js +++ b/app/imports/api/creature/experience/Experiences.js @@ -3,6 +3,7 @@ import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { getUserTier } from '/imports/api/users/patreon/tiers.js'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; import Creatures from '/imports/api/creature/Creatures.js'; +import { recomputeCreatureById } from '/imports/api/creature/computation/recomputeCreature.js'; let Experiences = new Mongo.Collection('experiences'); @@ -47,13 +48,19 @@ Experiences.attachSchema(ExperienceSchema); const insertExperienceForCreature = function({experience, creatureId, userId}){ assertEditPermission(creatureId, userId); if (experience.xp){ - Creatures.update(creatureId, {$inc: {xp: experience.xp}}); + Creatures.update(creatureId, {$inc: { + 'denormalizedStats.xp': experience.xp + }}); } if (experience.levels) { - Creatures.update(creatureId, {$inc: {xpLevels: experience.levels}}); + Creatures.update(creatureId, {$inc: { + 'denormalizedStats.milestoneLevels': experience.levels + }}); } experience.creatureId = creatureId; - return Experiences.insert(experience); + let id = Experiences.insert(experience); + recomputeCreatureById(creatureId); + return id; }; const insertExperience = new ValidatedMethod({ @@ -115,13 +122,19 @@ const removeExperience = new ValidatedMethod({ let creatureId = experience.creatureId assertEditPermission(creatureId, userId); if (experience.xp){ - Creatures.update(creatureId, {$inc: {xp: -experience.xp}}); + Creatures.update(creatureId, {$inc: { + 'denormalizedStats.xp': -experience.xp + }}); } if (experience.levels) { - Creatures.update(creatureId, {$inc: {xpLevels: -experience.levels}}); + Creatures.update(creatureId, {$inc: { + 'denormalizedStats.milestoneLevels': -experience.levels + }}); } experience.creatureId = creatureId; - return Experiences.remove(experienceId); + let numRemoved = Experiences.remove(experienceId); + recomputeCreatureById(creatureId); + return numRemoved; }, }); @@ -147,16 +160,20 @@ const recomputeExperiences = new ValidatedMethod({ assertEditPermission(creatureId, userId); let xp = 0; - let xpLevels = 0; + let milestoneLevels = 0; Experiences.find({ creatureId }, { fields: {xp: 1, levels: 1} }).forEach(experience => { xp += experience.xp || 0; - xpLevels += experience.levels || 0; + milestoneLevels += experience.levels || 0; }); - Creatures.update(creatureId, {$set: {xp, xpLevels}}); + Creatures.update(creatureId, {$set: { + 'denormalizedStats.xp': xp, + 'denormalizedStats.milestoneLevels': milestoneLevels + }}); + recomputeCreatureById(creatureId); }, }); diff --git a/app/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue b/app/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue index aa152899..80f0a424 100644 --- a/app/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue +++ b/app/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue @@ -28,14 +28,23 @@ > Level {{ creature.variables.level.value }} - + - - {{ creature.xpLevels }} Levels gained + + {{ creature.variables.milestoneLevels.value }} Milestone levels - {{ creature.xp }} XP + {{ + creature.variables.xp && + creature.variables.xp.value || + 0 + }} XP @@ -161,7 +170,8 @@ export default { elementId: 'experience-add-button', data: { creatureIds: [this.creatureId], - startAsMilestone: !!this.creature.xpLevels + startAsMilestone: this.creature.variables.milestoneLevels && + !!this.creature.variables.milestoneLevels.value, }, }); }, @@ -171,6 +181,8 @@ export default { elementId: 'experience-info-button', data: { creatureId: this.creatureId, + startAsMilestone: this.creature.variables.milestoneLevels && + !!this.creature.variables.milestoneLevels.value, }, }); }, diff --git a/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue b/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue index 17f6f7d4..edc1d628 100644 --- a/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue +++ b/app/imports/ui/creature/experiences/ExperienceInsertDialog.vue @@ -8,12 +8,6 @@ @push="push" @pull="pull" /> -

- {{ error }} -

Insert @@ -67,26 +60,20 @@ export default { schema: schema, validationContext: schema.newContext(), debounceTime: 0, - loading: false, - error: undefined, }; }, methods:{ insertExperience(){ - this.loading = true; let experience = this.schema.clean(this.model); - insertExperience.call({ + let id = insertExperience.call({ experience, creatureIds: this.creatureIds, }, (error) => { - this.loading = false; if (error){ - this.error = error.message || error; console.error(error); - } else { - this.$store.dispatch('popDialogStack'); } }); + this.$store.dispatch('popDialogStack', id); } } } diff --git a/app/imports/ui/creature/experiences/ExperienceListDialog.vue b/app/imports/ui/creature/experiences/ExperienceListDialog.vue index b0c08a81..96a86e41 100644 --- a/app/imports/ui/creature/experiences/ExperienceListDialog.vue +++ b/app/imports/ui/creature/experiences/ExperienceListDialog.vue @@ -5,6 +5,14 @@ Experiences + + add + - - - - {{ experience.name }} - - - - - delete - - - + + + + {{ formatDate(experience.date) }} + + + + + + + + + delete + + + +