Computation writes variables available/computed to the creature document

This commit is contained in:
Thaum Rystra
2020-04-16 17:57:18 +02:00
parent 2164174218
commit 7416101a34
9 changed files with 114 additions and 38 deletions

View File

@@ -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 {};
},
}

View File

@@ -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){

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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,
});
});
}

View File

@@ -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}});
}

View File

@@ -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: {

View File

@@ -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,
},
})

View File

@@ -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;
}
}
},