Began implementing dice rolls in the maths parser
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import evaluateString from '/imports/api/creature/computation/afterComputation/evaluateString.js';
|
||||
import evaluateAndRollString from '/imports/api/creature/computation/afterComputation/evaluateAndRollString.js';
|
||||
|
||||
export default function applyDamage({
|
||||
prop,
|
||||
@@ -11,9 +11,9 @@ export default function applyDamage({
|
||||
...creature.variables,
|
||||
...actionContext,
|
||||
};
|
||||
let {result, errors} = evaluateString(prop.amount, scope);
|
||||
if (Meteor.isClient) errors.forEach(e => console.error(e));
|
||||
if (Number.isFinite(result)) {
|
||||
damageTargets.forEach()
|
||||
let {result, errors} = evaluateAndRollString(prop.amount, scope);
|
||||
if (Meteor.isClient){
|
||||
errors.forEach(e => console.error(e));
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import applyAction from '/imports/api/creature/actions/applyAction.js';
|
||||
//import applyDamage from '/imports/api/creature/actions/applyDamage.js';
|
||||
import applyDamage from '/imports/api/creature/actions/applyDamage.js';
|
||||
import applyBuff from '/imports/api/creature/actions/applyBuff.js';
|
||||
|
||||
function applyProperty(options){
|
||||
@@ -19,7 +19,7 @@ function applyProperty(options){
|
||||
applyAction(options);
|
||||
return true;
|
||||
case 'damage':
|
||||
// applyDamage(options);
|
||||
applyDamage(options);
|
||||
return true;
|
||||
case 'adjustment':
|
||||
// applyAdjustment(options);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import math from '/imports/math.js';
|
||||
import bareSymbolSubtitutor from '/imports/api/creature/computation/utility/bareSymbolSubtitutor.js';
|
||||
import substituteRollsWithFunctions from '/imports/api/creature/computation/afterComputation/substituteRollsWithFunctions.js'
|
||||
|
||||
export default function evaluateAndRollString(string, scope){
|
||||
let errors = [];
|
||||
if (!string){
|
||||
errors.push('No string provided');
|
||||
return {result: string, errors};
|
||||
}
|
||||
|
||||
if (!scope) errors.push('No scope provided');
|
||||
|
||||
// Parse the string using mathjs
|
||||
let calc;
|
||||
try {
|
||||
calc = math.parse(string);
|
||||
} catch (e) {
|
||||
errors.push(e);
|
||||
return {result: string, errors};
|
||||
}
|
||||
|
||||
// Replace all bare symbols with symbol.value
|
||||
let transformedCalc = calc.transform(bareSymbolSubtitutor(scope));
|
||||
// Replace all rolls with the function to call them
|
||||
transformedCalc = calc.transform(substituteRollsWithFunctions);
|
||||
|
||||
// Evaluate the expression to a number or return with substitutions
|
||||
try {
|
||||
let result = transformedCalc.evaluate(scope);
|
||||
return {result, errors};
|
||||
} catch (e1){
|
||||
errors.push(e1);
|
||||
try {
|
||||
let result = simplifyWithAccessors(transformedCalc, scope).toHTML();
|
||||
return {result, errors};
|
||||
} catch (e2){
|
||||
errors.push(e2);
|
||||
return {result: transformedCalc.toHTML(), errors};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function simplifyWithAccessors(calc, scope){
|
||||
let noAccessorCalc = calc.transform(substituteAccessors(scope));
|
||||
return math.simplify(noAccessorCalc);
|
||||
}
|
||||
|
||||
// returns a function to replace all accessors with either their resolved value
|
||||
// or a symbol to simplify with
|
||||
function substituteAccessors(scope){
|
||||
return function(node){
|
||||
if (node.isAccessorNode){
|
||||
try {
|
||||
return evaluateAccessor(node, scope);
|
||||
} catch (e) {
|
||||
return replaceAccessorWithSymbol(node);
|
||||
}
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throws error if symbol is undefined in scope
|
||||
function evaluateAccessor(node, scope){
|
||||
let value = node.evaluate(scope);
|
||||
if (value === undefined){
|
||||
throw 'Undefined symbol'
|
||||
}
|
||||
return new math.ConstantNode(value);
|
||||
}
|
||||
|
||||
function replaceAccessorWithSymbol(node){
|
||||
let symbolNode = new math.SymbolNode(node.toString());
|
||||
return symbolNode;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import math from '/imports/math.js';
|
||||
|
||||
const diceRegex = /d\d+/;
|
||||
|
||||
export default function substituteRollsWithFunctions(node){
|
||||
// TODO also replace dx as 1dx
|
||||
if (
|
||||
node.isOperatorNode &&
|
||||
node.fn === 'multiply' &&
|
||||
node.implicit &&
|
||||
node.args[1].isSymbolNode &&
|
||||
diceRegex.test(node.args[1].name)
|
||||
){
|
||||
let diceSize = node.args[1].name.slice(1);
|
||||
let diceSizeNode = new math.ConstantNode(diceSize);
|
||||
return new math.FunctionNode('roll', [node.args[0], diceSizeNode]);
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,20 @@
|
||||
import { create, all } from 'mathjs';
|
||||
import { Random } from 'meteor/random'
|
||||
|
||||
const math = create(all);
|
||||
math.import({
|
||||
'if': function(pred, a, b) {
|
||||
return pred ? a : b;
|
||||
},
|
||||
'roll': function(number, diceSize){
|
||||
if (number > 100) throw 'Can only roll 100 dice at a time';
|
||||
let rollTotal = 0;
|
||||
let i, roll;
|
||||
for (i = 0; i < number; i++){
|
||||
roll = ~~(Random.fraction() * diceSize) + 1
|
||||
rollTotal += roll;
|
||||
}
|
||||
return rollTotal;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user