Computation writes variables available/computed to the creature document
This commit is contained in:
@@ -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 {};
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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}});
|
||||
}
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,32 +1,50 @@
|
||||
<template lang="html">
|
||||
<div class="effect-viewer">
|
||||
<property-name :value="model.name" v-if="model.name"/>
|
||||
<div class="layout row align-center wrap">
|
||||
<div class="headline">
|
||||
<code style="display: block;" class="my-1" v-for="stat in model.stats">{{stat}}</code>
|
||||
</div>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-icon v-on="on" class="mx-2" style="cursor: default;">{{effectIcon}}</v-icon>
|
||||
</template>
|
||||
<span>{{operation}}</span>
|
||||
</v-tooltip>
|
||||
<div v-if="showValue" class="headline">
|
||||
{{displayedValue}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="effect-viewer">
|
||||
<property-name
|
||||
v-if="model.name"
|
||||
:value="model.name"
|
||||
/>
|
||||
<div class="layout row align-center wrap">
|
||||
<div class="headline">
|
||||
<code
|
||||
v-for="stat in model.stats"
|
||||
:key="stat"
|
||||
style="display: block;"
|
||||
class="my-1"
|
||||
>{{ stat }}</code>
|
||||
</div>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-icon
|
||||
class="mx-2"
|
||||
style="cursor: default;"
|
||||
v-on="on"
|
||||
>
|
||||
{{ effectIcon }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>{{ operation }}</span>
|
||||
</v-tooltip>
|
||||
<div
|
||||
v-if="showValue"
|
||||
class="headline"
|
||||
>
|
||||
{{ displayedValue }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js';
|
||||
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
|
||||
import getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||
import { isFinite } from 'lodash';
|
||||
|
||||
export default {
|
||||
mixins: [propertyViewerMixin],
|
||||
computed: {
|
||||
resolvedValue(){
|
||||
return this.model.result !== undefined ? this.model.result : +this.model.calculation;
|
||||
return this.model.result !== undefined ? this.model.result : this.model.calculation;
|
||||
},
|
||||
effectIcon(){
|
||||
let value = this.resolvedValue;
|
||||
@@ -44,6 +62,7 @@
|
||||
case 'passiveAdd': return 'Passive bonus';
|
||||
case 'fail': return 'Always fail';
|
||||
case 'conditional': return 'Conditional benefit' ;
|
||||
default: return '';
|
||||
}
|
||||
},
|
||||
showValue(){
|
||||
@@ -58,21 +77,23 @@
|
||||
case 'passiveAdd': return true;
|
||||
case 'fail': return false;
|
||||
case 'conditional': return false;
|
||||
default: return false;
|
||||
}
|
||||
},
|
||||
displayedValue(){
|
||||
let value = this.resolvedValue;
|
||||
switch(this.model.operation) {
|
||||
case 'base': return value;
|
||||
case 'add': return Math.abs(value);
|
||||
case 'add': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'mul': return value;
|
||||
case 'min': return value;
|
||||
case 'max': return value;
|
||||
case 'advantage': return;
|
||||
case 'disadvantage': return;
|
||||
case 'passiveAdd': return Math.abs(value);
|
||||
case 'passiveAdd': return isFinite(value) ? Math.abs(value) : value;
|
||||
case 'fail': return;
|
||||
case 'conditional': return;
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user