Computation writes variables available/computed to the creature document
This commit is contained in:
@@ -78,7 +78,7 @@ export default class ComputationMemo {
|
|||||||
}
|
}
|
||||||
addProficiency(prop){
|
addProficiency(prop){
|
||||||
prop = this.registerProperty(prop);
|
prop = this.registerProperty(prop);
|
||||||
let targets = getProficiencyTargets(prop);
|
let targets = this.getProficiencyTargets(prop);
|
||||||
targets.forEach(target => {
|
targets.forEach(target => {
|
||||||
target.computationDetails.proficiencies.push(prop);
|
target.computationDetails.proficiencies.push(prop);
|
||||||
});
|
});
|
||||||
@@ -86,7 +86,7 @@ export default class ComputationMemo {
|
|||||||
getProficiencyTargets(prop){
|
getProficiencyTargets(prop){
|
||||||
let targets = new Set();
|
let targets = new Set();
|
||||||
if (!prop.stats) return targets;
|
if (!prop.stats) return targets;
|
||||||
proficiency.stats.forEach(statName => {
|
prop.stats.forEach(statName => {
|
||||||
let target = this.statsByVariableName[statName];
|
let target = this.statsByVariableName[statName];
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
targets.add(target);
|
targets.add(target);
|
||||||
@@ -146,4 +146,7 @@ const propDetailsByType = {
|
|||||||
computed: false,
|
computed: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
damageMultiplier(){
|
||||||
|
return {};
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import computedValueOfVariableName from '/imports/api/creature/computation/compu
|
|||||||
|
|
||||||
|
|
||||||
export default function combineStat(stat, aggregator, memo){
|
export default function combineStat(stat, aggregator, memo){
|
||||||
if (stat.type === "attribute"){
|
if (stat.type === 'attribute'){
|
||||||
combineAttribute(stat, aggregator);
|
combineAttribute(stat, aggregator);
|
||||||
} else if (stat.type === "skill"){
|
} else if (stat.type === 'skill'){
|
||||||
combineSkill(stat, aggregator, memo);
|
combineSkill(stat, aggregator, memo);
|
||||||
} else if (stat.type === "damageMultiplier"){
|
} else if (stat.type === 'damageMultiplier'){
|
||||||
combineDamageMultiplier(stat, memo);
|
combineDamageMultiplier(stat, memo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ function combineAttribute(stat, aggregator){
|
|||||||
if (result > aggregator.max) result = aggregator.max;
|
if (result > aggregator.max) result = aggregator.max;
|
||||||
if (!stat.decimal) result = Math.floor(result);
|
if (!stat.decimal) result = Math.floor(result);
|
||||||
stat.value = result;
|
stat.value = result;
|
||||||
if (stat.attributeType === "ability") {
|
if (stat.attributeType === 'ability') {
|
||||||
stat.mod = Math.floor((result - 10) / 2);
|
stat.mod = Math.floor((result - 10) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,7 @@ function combineSkill(stat, aggregator, memo){
|
|||||||
|
|
||||||
function combineDamageMultiplier(stat){
|
function combineDamageMultiplier(stat){
|
||||||
if (stat.immunityCount) return 0;
|
if (stat.immunityCount) return 0;
|
||||||
|
let result;
|
||||||
if (stat.ressistanceCount && !stat.vulnerabilityCount){
|
if (stat.ressistanceCount && !stat.vulnerabilityCount){
|
||||||
result = 0.5;
|
result = 0.5;
|
||||||
} else if (!stat.ressistanceCount && stat.vulnerabilityCount){
|
} else if (!stat.ressistanceCount && stat.vulnerabilityCount){
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
|
import { get } from 'lodash';
|
||||||
import computeStat from '/imports/api/creature/computation/computeStat.js';
|
import computeStat from '/imports/api/creature/computation/computeStat.js';
|
||||||
|
|
||||||
export default function computedValueOfVariableName(sub, memo){
|
export default function computedValueOfVariableName(name, memo){
|
||||||
const stat = memo.statsByVariableName[sub];
|
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) return null;
|
||||||
if (!stat.computationDetails.computed){
|
if (!stat.computationDetails.computed){
|
||||||
computeStat(stat, memo);
|
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 { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
|
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 computeMemo from '/imports/api/creature/computation/computeMemo.js';
|
||||||
import getCalculationProperties from '/imports/api/creature/computation/getCalculationProperties.js';
|
import getCalculationProperties from '/imports/api/creature/computation/getCalculationProperties.js';
|
||||||
import writeAlteredProperties from '/imports/api/creature/computation/writeAlteredProperties.js';
|
import writeAlteredProperties from '/imports/api/creature/computation/writeAlteredProperties.js';
|
||||||
|
import writeCreatureVariables from '/imports/api/creature/computation/writeCreatureVariables.js';
|
||||||
|
|
||||||
export const recomputeCreature = new ValidatedMethod({
|
export const recomputeCreature = new ValidatedMethod({
|
||||||
|
|
||||||
name: "Creatures.methods.recomputeCreature",
|
name: 'Creatures.methods.recomputeCreature',
|
||||||
|
|
||||||
validate: new SimpleSchema({
|
validate: new SimpleSchema({
|
||||||
charId: { type: String }
|
charId: { type: String }
|
||||||
@@ -65,5 +67,7 @@ export function recomputeCreatureById(creatureId){
|
|||||||
let computationMemo = new ComputationMemo(props);
|
let computationMemo = new ComputationMemo(props);
|
||||||
computeMemo(computationMemo);
|
computeMemo(computationMemo);
|
||||||
writeAlteredProperties(computationMemo);
|
writeAlteredProperties(computationMemo);
|
||||||
|
writeCreatureVariables(computationMemo, creatureId);
|
||||||
|
if(Meteor.isClient) console.log(computationMemo);
|
||||||
return computationMemo;
|
return computationMemo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor'
|
||||||
import { isEqual, forOwn } from 'lodash';
|
import { isEqual, forOwn } from 'lodash';
|
||||||
import { ComputedOnlySkillSchema } from '/imports/api/properties/Skills.js';
|
import { ComputedOnlySkillSchema } from '/imports/api/properties/Skills.js';
|
||||||
import { ComputedOnlyAttributeSchema } from '/imports/api/properties/Attributes.js';
|
import { ComputedOnlyAttributeSchema } from '/imports/api/properties/Attributes.js';
|
||||||
@@ -28,7 +29,10 @@ export default function writeAlteredProperties(memo){
|
|||||||
for (let key of schema.objectKeys()){
|
for (let key of schema.objectKeys()){
|
||||||
if (!isEqual(original[key], changed[key])){
|
if (!isEqual(original[key], changed[key])){
|
||||||
if (!op) op = newOperation(_id, changed.type);
|
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){
|
if (op){
|
||||||
@@ -42,14 +46,14 @@ function newOperation(_id, type){
|
|||||||
let newOp = {
|
let newOp = {
|
||||||
updateOne: {
|
updateOne: {
|
||||||
filter: {_id},
|
filter: {_id},
|
||||||
update: {$set: {}},
|
update: {'$set': {}},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (Meteor.isClient){
|
if (Meteor.isClient){
|
||||||
newOp.type = type;
|
newOp.type = type;
|
||||||
}
|
}
|
||||||
return newOp;
|
return newOp;
|
||||||
};
|
}
|
||||||
|
|
||||||
function bulkWriteProperties(bulkWriteOps){
|
function bulkWriteProperties(bulkWriteOps){
|
||||||
if (!bulkWriteOps.length) return;
|
if (!bulkWriteOps.length) return;
|
||||||
@@ -62,9 +66,13 @@ function bulkWriteProperties(bulkWriteOps){
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
_.each(bulkWriteOps, op => {
|
bulkWriteOps.forEach(op => {
|
||||||
CreatureProperties.update(op.updateOne.filter, op.updateOne.update, {
|
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({
|
let ComputedOnlyAttributeSchema = new SimpleSchema({
|
||||||
// The computed value of the attribute
|
// The computed value of the attribute
|
||||||
value: {
|
value: {
|
||||||
type: Number,
|
type: SimpleSchema.oneOf(Number, String, Boolean),
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
|
optional: true,
|
||||||
},
|
},
|
||||||
// The computed modifier, provided the attribute type is `ability`
|
// The computed modifier, provided the attribute type is `ability`
|
||||||
mod: {
|
mod: {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
|
import { Random } from 'meteor/random';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Effects are reason-value attached to skills and abilities
|
* Effects are reason-value attached to skills and abilities
|
||||||
@@ -54,7 +55,7 @@ const StoredEffectSchema = new SimpleSchema({
|
|||||||
const ComputedOnlyEffectSchema = new SimpleSchema({
|
const ComputedOnlyEffectSchema = new SimpleSchema({
|
||||||
// The computed result of the effect
|
// The computed result of the effect
|
||||||
result: {
|
result: {
|
||||||
type: SimpleSchema.oneOf(Number, String),
|
type: SimpleSchema.oneOf(Number, String, Boolean),
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,32 +1,50 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="effect-viewer">
|
<div class="effect-viewer">
|
||||||
<property-name :value="model.name" v-if="model.name"/>
|
<property-name
|
||||||
<div class="layout row align-center wrap">
|
v-if="model.name"
|
||||||
<div class="headline">
|
:value="model.name"
|
||||||
<code style="display: block;" class="my-1" v-for="stat in model.stats">{{stat}}</code>
|
/>
|
||||||
</div>
|
<div class="layout row align-center wrap">
|
||||||
<v-tooltip bottom>
|
<div class="headline">
|
||||||
<template v-slot:activator="{ on }">
|
<code
|
||||||
<v-icon v-on="on" class="mx-2" style="cursor: default;">{{effectIcon}}</v-icon>
|
v-for="stat in model.stats"
|
||||||
</template>
|
:key="stat"
|
||||||
<span>{{operation}}</span>
|
style="display: block;"
|
||||||
</v-tooltip>
|
class="my-1"
|
||||||
<div v-if="showValue" class="headline">
|
>{{ stat }}</code>
|
||||||
{{displayedValue}}
|
</div>
|
||||||
</div>
|
<v-tooltip bottom>
|
||||||
</div>
|
<template #activator="{ on }">
|
||||||
</div>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import propertyViewerMixin from '/imports/ui/properties/viewers/shared/propertyViewerMixin.js';
|
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 getEffectIcon from '/imports/ui/utility/getEffectIcon.js';
|
||||||
|
import { isFinite } from 'lodash';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [propertyViewerMixin],
|
mixins: [propertyViewerMixin],
|
||||||
computed: {
|
computed: {
|
||||||
resolvedValue(){
|
resolvedValue(){
|
||||||
return this.model.result !== undefined ? this.model.result : +this.model.calculation;
|
return this.model.result !== undefined ? this.model.result : this.model.calculation;
|
||||||
},
|
},
|
||||||
effectIcon(){
|
effectIcon(){
|
||||||
let value = this.resolvedValue;
|
let value = this.resolvedValue;
|
||||||
@@ -44,6 +62,7 @@
|
|||||||
case 'passiveAdd': return 'Passive bonus';
|
case 'passiveAdd': return 'Passive bonus';
|
||||||
case 'fail': return 'Always fail';
|
case 'fail': return 'Always fail';
|
||||||
case 'conditional': return 'Conditional benefit' ;
|
case 'conditional': return 'Conditional benefit' ;
|
||||||
|
default: return '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showValue(){
|
showValue(){
|
||||||
@@ -58,21 +77,23 @@
|
|||||||
case 'passiveAdd': return true;
|
case 'passiveAdd': return true;
|
||||||
case 'fail': return false;
|
case 'fail': return false;
|
||||||
case 'conditional': return false;
|
case 'conditional': return false;
|
||||||
|
default: return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
displayedValue(){
|
displayedValue(){
|
||||||
let value = this.resolvedValue;
|
let value = this.resolvedValue;
|
||||||
switch(this.model.operation) {
|
switch(this.model.operation) {
|
||||||
case 'base': return value;
|
case 'base': return value;
|
||||||
case 'add': return Math.abs(value);
|
case 'add': return isFinite(value) ? Math.abs(value) : value;
|
||||||
case 'mul': return value;
|
case 'mul': return value;
|
||||||
case 'min': return value;
|
case 'min': return value;
|
||||||
case 'max': return value;
|
case 'max': return value;
|
||||||
case 'advantage': return;
|
case 'advantage': return;
|
||||||
case 'disadvantage': return;
|
case 'disadvantage': return;
|
||||||
case 'passiveAdd': return Math.abs(value);
|
case 'passiveAdd': return isFinite(value) ? Math.abs(value) : value;
|
||||||
case 'fail': return;
|
case 'fail': return;
|
||||||
case 'conditional': return;
|
case 'conditional': return;
|
||||||
|
default: return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user