import resolve from '/imports/parser/resolve.js' import rollDice from '/imports/parser/rollDice.js'; export default { 'abs': { comment: 'Returns the absolute value of a number', examples: [ { input: 'abs(9)', result: '9' }, { input: 'abs(-3)', result: '3' }, ], arguments: ['number'], resultType: 'number', fn: Math.abs, }, 'sqrt': { comment: 'Returns the square root of a number', examples: [ { input: 'sqrt(16)', result: '4' }, { input: 'sqrt(10)', result: '3.1622776601683795' }, ], arguments: ['number'], resultType: 'number', fn: Math.sqrt, }, 'max': { comment: 'Returns the largest of the given numbers', examples: [{ input: 'max(12, 6, 3, 168)', result: '168' }], arguments: anyNumberOf('number'), resultType: 'number', fn: Math.max, }, 'min': { comment: 'Returns the smallest of the given numbers', examples: [{ input: 'min(12, 6, 3, 168)', result: '3' }], arguments: anyNumberOf('number'), resultType: 'number', fn: Math.min, }, 'round': { comment: 'Returns the value of a number rounded to the nearest integer', examples: [ { input: 'round(5.95)', result: '6' }, { input: 'round(5.5)', result: '6' }, { input: 'round(5.05)', result: '5' }, ], arguments: ['number'], resultType: 'number', fn: Math.round, }, 'floor': { comment: 'Rounds a number down to the next smallest integer', examples: [ { input: 'floor(5.95)', result: '5' }, { input: 'floor(5.05)', result: '5' }, { input: 'floor(5)', result: '5' }, { input: 'floor(-5.5)', result: '-6' }, ], arguments: ['number'], resultType: 'number', fn: Math.floor, }, 'ceil': { comment: 'Rounds a number up to the next largest integer', examples: [ { input: 'ceil(5.95)', result: '6' }, { input: 'ceil(5.05)', result: '6' }, { input: 'ceil(5)', result: '5' }, { input: 'ceil(-5.5)', result: '-5' }, ], arguments: ['number'], resultType: 'number', fn: Math.ceil, }, 'trunc': { comment: 'Returns the integer part of a number by removing any fractional digits', examples: [ { input: 'trunc(5.95)', result: '5' }, { input: 'trunc(5.05)', result: '5' }, { input: 'trunc(5)', result: '5' }, { input: 'trunc(-5.5)', result: '-5' }, ], arguments: ['number'], resultType: 'number', fn: Math.trunc, }, 'sign': { comment: 'Returns either a positive or negative 1, indicating the sign of a number, or zero', examples: [ { input: 'sign(-3)', result: '-1' }, { input: 'sign(3)', result: '1' }, { input: 'sign(0)', result: '0' }, ], arguments: ['number'], resultType: 'number', fn: Math.sign, }, 'tableLookup': { comment: 'Returns the index of the last value in the array that is less than the specified amount', examples: [ { input: 'tableLookup([100, 300, 900], 457)', result: '2' }, { input: 'tableLookup([100, 300, 900], 23)', result: '0' }, { input: 'tableLookup([100, 300, 900, 1200], 900)', result: '3' }, { input: 'tableLookup([100, 300], 594)', result: '2' }, ], arguments: ['array', 'number'], resultType: 'number', fn: function tableLookup(arrayNode, number) { for (let i in arrayNode.values) { let node = arrayNode.values[i]; if (node.value > number) return +i; } return arrayNode.values.length; } }, 'resolve': { comment: 'Forces the given calcultion to resolve into a number, even in calculations where it would usually keep the unknown values as is', examples: [ { input: 'resolve(someUndefinedVariable + 3 + 4)', result: '7' }, { input: 'resolve(1d6)', result: '4' }, ], arguments: ['parseNode'], fn: function resolveFn(node) { let { result } = resolve('reduce', node, this.scope, this.context); return result; } }, 'dropLowest': { comment: 'Removes one or more of the lowest values in a roll', examples: [ ], arguments: ['rollArray', 'number'], maxResolveLevels: ['roll', 'reduce'], minArguments: 1, maxArguments: 2, resultType: 'rollArray', fn: function dropLowestFn(rollArray, numberToDrop = 1) { // Create a new array where the values are sorted in ascending order const sortedArray = [...rollArray.values].sort(function (a, b) { return a.value - b.value; }); // mark the N smallest elements as dropped for (let i = 0; i < numberToDrop; i += 1) { console.log('dropped ' + sortedArray[i].value); sortedArray[i].disabled = true; sortedArray[i].disabledBy = 'dropLowest'; } return rollArray; }, }, 'dropHighest': { comment: 'Removes one or more of the highest values in a roll', examples: [ ], arguments: ['rollArray', 'number'], maxResolveLevels: ['roll', 'reduce'], minArguments: 1, maxArguments: 2, resultType: 'rollArray', fn: function dropHighestFn(rollArray, numberToDrop = 1) { // Create a new array where the values are sorted in ascending order const sortedArray = [...rollArray.values].sort(function (a, b) { return b.value - a.value; }); // mark the N smallest elements as dropped for (let i = 0; i < numberToDrop; i += 1) { sortedArray[i].disabled = true; sortedArray[i].disabledBy = 'dropHighest'; } return rollArray; }, }, 'reroll': { comment: 'Rerolls if a number is less than or equal to the given value', examples: [ ], arguments: ['rollArray', 'number', 'boolean'], maxResolveLevels: ['roll', 'reduce'], minArguments: 1, maxArguments: 3, resultType: 'rollArray', fn: function rerollFn(rollArray, numberToReroll = 1, keepNewRoll = false) { let rollValues = rollArray.values // Iterate through the roll values for (let i = 0; i < rollValues.length; i += 1) { // If the number is less than the reroll limit if (rollValues[i].value <= numberToReroll) { // Disable it rollValues[i].disabled = true; rollValues[i].disabledBy = 'reroll'; // Roll it again, insert the new roll into the list at the next index rollValues.splice(i + 1, 0, { value: rollDice(1, rollArray.diceSize)[0], }); // Skip iterating the inserted roll if we are forced to keep it if (keepNewRoll) { i += 1; } } if (i >= 100) { this.context.error('Can\'t roll more than 100 dice at once'); return rollArray; } } return rollArray; }, }, 'explode': { comment: 'Rerolls if a number is greater than or equal to the given value', examples: [ ], arguments: ['rollArray', 'number', 'number'], maxResolveLevels: ['roll', 'reduce', 'reduce'], minArguments: 1, maxArguments: 3, resultType: 'rollArray', fn: function explodeFn(rollArray, depth = 1, numberToReroll = rollArray.diceSize) { let overflowErrored = false; if (depth > 99) depth = 99; let rollValues = rollArray.values // Iterate through the roll values for (let i = 0; i < rollValues.length; i += 1) { // If the number is greater than or equal to the reroll limit // And there is space to reroll it if (rollValues[i].value >= numberToReroll) { rollValues[i].bold = true; let explodeDepth = 1; let explodeRoll; do { // Before inserting this roll, make sure the total dice in the roll // Doesn't exceed 100 if (rollValues.length >= 100) { if (!overflowErrored) { this.context.error('Can\'t roll more than 100 dice at once'); overflowErrored = true; } break; } explodeDepth += 1; explodeRoll = rollDice(1, rollArray.diceSize)[0]; const rollObj = { value: explodeRoll, italics: true, }; // Insert the roll rollValues.splice(i + 1, 0, rollObj); i += 1; } while (explodeDepth <= depth && explodeRoll >= numberToReroll) } } return rollArray; }, }, } function anyNumberOf(type) { let argumentArray = [type]; argumentArray.anyLength = true; return argumentArray; }