diff --git a/karma.conf.js b/karma.conf.js index 744a7ca..f2bbf72 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -23,8 +23,8 @@ module.exports = function (config) { ], customLaunchers: { chromeDebugging: { - base: 'Chrome', - flags: [ '--remote-debugging-port=9333' ] + base: "Chrome", + flags: [ "--remote-debugging-port=9333" ] }, chromeTravisCi: { base: "Chrome", diff --git a/package-lock.json b/package-lock.json index a2040d4..eb9f8cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dice-typescript", - "version": "1.4.1", + "version": "1.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1486,7 +1486,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.1.1", @@ -1561,6 +1562,7 @@ "version": "2.10.1", "bundled": true, "dev": true, + "optional": true, "requires": { "hoek": "2.16.3" } @@ -1730,6 +1732,7 @@ "version": "1.0.11", "bundled": true, "dev": true, + "optional": true, "requires": { "graceful-fs": "4.1.11", "inherits": "2.0.3", @@ -1797,7 +1800,8 @@ "graceful-fs": { "version": "4.1.11", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "har-schema": { "version": "1.0.5", @@ -1984,12 +1988,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "mkdirp": { "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2279,6 +2285,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "2.1.1" } @@ -4978,4 +4985,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 8e10833..211ba64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dice-typescript", - "version": "1.5.0", + "version": "1.6.0", "description": "A TypeScript library for parsing dice rolling expressions, most commonly used in tabletop RPGs.", "main": "./dist/index.js", "scripts": { diff --git a/spec/generator/dice-generator.generate.drop.spec.ts b/spec/generator/dice-generator.generate.drop.spec.ts index 28dba13..40988ef 100644 --- a/spec/generator/dice-generator.generate.drop.spec.ts +++ b/spec/generator/dice-generator.generate.drop.spec.ts @@ -29,5 +29,19 @@ describe('DiceGenerator', () => { const generator = new Generator.DiceGenerator(); expect(generator.generate(exp)).toBe('2d6dh'); }); + it('generates a drop with modifier (3d6dh2).', () => { + const exp = Ast.Factory.create(Ast.NodeType.Drop) + .setAttribute('type', 'highest'); + + const dice = Ast.Factory.create(Ast.NodeType.Dice); + dice.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 3)); + dice.addChild(Ast.Factory.create(Ast.NodeType.DiceSides).setAttribute('value', 6)); + + exp.addChild(dice); + exp.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 2)); + + const generator = new Generator.DiceGenerator(); + expect(generator.generate(exp)).toBe('3d6dh2'); + }); }); }); diff --git a/spec/generator/dice-generator.generate.keep.spec.ts b/spec/generator/dice-generator.generate.keep.spec.ts index 1de295b..b03f4d3 100644 --- a/spec/generator/dice-generator.generate.keep.spec.ts +++ b/spec/generator/dice-generator.generate.keep.spec.ts @@ -29,5 +29,19 @@ describe('DiceGenerator', () => { const generator = new Generator.DiceGenerator(); expect(generator.generate(exp)).toBe('2d6kl'); }); + it('generates a keep with modifier (3d6kl2).', () => { + const exp = Ast.Factory.create(Ast.NodeType.Keep) + .setAttribute('type', 'lowest'); + + const dice = Ast.Factory.create(Ast.NodeType.Dice); + dice.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 3)); + dice.addChild(Ast.Factory.create(Ast.NodeType.DiceSides).setAttribute('value', 6)); + + exp.addChild(dice); + exp.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 2)); + + const generator = new Generator.DiceGenerator(); + expect(generator.generate(exp)).toBe('3d6kl2'); + }); }); }); diff --git a/spec/interpreter/dice-interpreter.interpret.simple.ts b/spec/interpreter/dice-interpreter.interpret.simple.ts index 5513d05..7eac53d 100644 --- a/spec/interpreter/dice-interpreter.interpret.simple.ts +++ b/spec/interpreter/dice-interpreter.interpret.simple.ts @@ -24,5 +24,26 @@ describe('DiceInterpreter', () => { expect(res.renderedExpression).toBe('[1, 7, 4, 5] + 5', 'Expression rendered incorrectly'); expect(res.total).toBe(22, 'Total counted incorrectly'); }); + it('interprets a simple dice expression (4d6kh3).', () => { + const exp = Ast.Factory.create(Ast.NodeType.Keep) + .setAttribute('type', 'highest'); + + const dice = Ast.Factory.create(Ast.NodeType.Dice); + dice.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 4)); + dice.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 6)); + + exp.addChild(dice); + exp.addChild(Ast.Factory.create(Ast.NodeType.Number).setAttribute('value', 3)); + + const mockList = new MockListRandomProvider(); + mockList.numbers.push(6, 1, 4, 3); + + const interpreter = new Interpreter.DiceInterpreter(null, mockList); + const res = interpreter.interpret(exp); + + expect(res.errors.length).toBe(0, 'Unexpected errors found.'); + expect(res.renderedExpression).toBe('[6, 1, 4, 3]kh3', 'Expression rendered incorrectly'); + expect(res.total).toBe(13, 'Total counted incorrectly'); + }); }); }); diff --git a/src/generator/dice-generator.class.ts b/src/generator/dice-generator.class.ts index a172bbb..655f4f0 100644 --- a/src/generator/dice-generator.class.ts +++ b/src/generator/dice-generator.class.ts @@ -134,18 +134,22 @@ export class DiceGenerator implements Generator { generateKeep(expression: Ast.ExpressionNode): string { this.expectChildCount(expression, 1); - let keep = 'k'; - if (expression.getAttribute('type') === 'highest') { keep += 'h'; } - if (expression.getAttribute('type') === 'lowest') { keep += 'l'; } - return this.generate(expression.getChild(0)) + keep; + let exp = 'k'; + if (expression.getAttribute('type') === 'highest') { exp += 'h'; } + if (expression.getAttribute('type') === 'lowest') { exp += 'l'; } + + if (expression.getChildCount() > 1) { exp += this.generate(expression.getChild(1)); } + return this.generate(expression.getChild(0)) + exp; } generateDrop(expression: Ast.ExpressionNode): string { this.expectChildCount(expression, 1); - let drop = 'd'; - if (expression.getAttribute('type') === 'highest') { drop += 'h'; } - if (expression.getAttribute('type') === 'lowest') { drop += 'l'; } - return this.generate(expression.getChild(0)) + drop; + let exp = 'd'; + if (expression.getAttribute('type') === 'highest') { exp += 'h'; } + if (expression.getAttribute('type') === 'lowest') { exp += 'l'; } + + if (expression.getChildCount() > 1) { exp += this.generate(expression.getChild(1)); } + return this.generate(expression.getChild(0)) + exp; } generateCritical(expression: Ast.ExpressionNode): string {