Skip to content

Commit

Permalink
Allow specifying the maximum iterations on exploding dice
Browse files Browse the repository at this point in the history
  • Loading branch information
GreenImp committed Apr 22, 2021
1 parent 2008fd5 commit 7f8904e
Show file tree
Hide file tree
Showing 13 changed files with 453 additions and 76 deletions.
5 changes: 3 additions & 2 deletions src/modifiers/ComparisonModifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ class ComparisonModifier extends Modifier {
* Create a `ComparisonModifier` instance.
*
* @param {ComparePoint} [comparePoint] The comparison object
* @param {number|null} [limit=null] The maximum iteration limit per roll.
*
* @throws {TypeError} `comparePoint` must be an instance of `ComparePoint` or `undefined`
*/
constructor(comparePoint) {
super();
constructor(comparePoint, limit = null) {
super(limit);

if (comparePoint) {
this.comparePoint = comparePoint;
Expand Down
17 changes: 13 additions & 4 deletions src/modifiers/ExplodeModifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class ExplodeModifier extends ComparisonModifier {
* @param {ComparePoint} [comparePoint=null] The comparison object
* @param {boolean} [compound=false] Whether to compound or not
* @param {boolean} [penetrate=false] Whether to penetrate or not
* @param {number|null} [limit=null] The maximum iteration limit per roll.
*
* @throws {TypeError} comparePoint must be a `ComparePoint` object
*/
constructor(comparePoint = null, compound = false, penetrate = false) {
super(comparePoint);
constructor(comparePoint = null, compound = false, penetrate = false, limit = null) {
super(comparePoint, limit);

this[compoundSymbol] = !!compound;
this[penetrateSymbol] = !!penetrate;
Expand Down Expand Up @@ -58,7 +59,14 @@ class ExplodeModifier extends ComparisonModifier {
* @returns {string}
*/
get notation() {
return `!${this.compound ? '!' : ''}${this.penetrate ? 'p' : ''}${super.notation}`;
let notation = `!${this.compound ? '!' : ''}${this.penetrate ? 'p' : ''}`;

// if the max iterations has been changed, add it to the notation
if (this.maxIterations && (this.maxIterations !== this.constructor.defaultMaxIterations)) {
notation = `${notation}${this.maxIterations}`;
}

return `${notation}${super.notation}`;
}

/**
Expand Down Expand Up @@ -153,12 +161,13 @@ class ExplodeModifier extends ComparisonModifier {
* }}
*/
toJSON() {
const { compound, penetrate } = this;
const { compound, maxIterations, penetrate } = this;

return Object.assign(
super.toJSON(),
{
compound,
maxIterations,
penetrate,
},
);
Expand Down
1 change: 1 addition & 0 deletions src/modifiers/KeepModifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class KeepModifier extends Modifier {
if (value === Infinity) {
throw new RangeError('qty must be a finite number');
}

if (!isNumeric(value) || (value < 1)) {
throw new TypeError('qty must be a positive finite integer');
}
Expand Down
51 changes: 46 additions & 5 deletions src/modifiers/Modifier.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { isNumeric } from '../utilities/math.js';

const maxIterationsSymbol = Symbol('max-iterations');

/**
* A `Modifier` is the base modifier class that all others extend from.
*
Expand All @@ -10,8 +14,13 @@
class Modifier {
/**
* Create a `Modifier` instance.
*
* @param {number|null} [limit=null] The maximum iteration limit per roll.
*/
constructor() {
constructor(limit = null) {
// set the maximum iteration limit
this.maxIterations = limit;

// set the modifier's sort order
this.order = 999;
}
Expand All @@ -38,16 +47,48 @@ class Modifier {
}
/* eslint-enable class-methods-use-this */

/* eslint-disable class-methods-use-this */
/**
* The maximum number of iterations that the modifier can apply to a single die roll
* The maximum number of iterations that the modifier can apply to a single die roll.
*
* @returns {number} `1000`
* @returns {number}
*/
get maxIterations() {
return this[maxIterationsSymbol];
}

/**
* Set the maximum number of iterations that the modifier can apply to a single die roll.
*
* @param {number} value
*/
set maxIterations(value) {
const absoluteMax = this.constructor.defaultMaxIterations;

// if falsey, then set to the default max
if (!value && (value !== 0)) {
this[maxIterationsSymbol] = absoluteMax;
return;
}

if (!isNumeric(value)) {
throw new TypeError('maxIterations must be a number');
}

if ((value === Infinity) || (value < 1)) {
throw new RangeError(`maxIterations must be a number between 1 and ${absoluteMax}`);
}

this[maxIterationsSymbol] = Math.floor(Math.min(value, absoluteMax));
}

/**
* The default number of max iterations.
*
* @return {number}
*/
static get defaultMaxIterations() {
return 1000;
}
/* eslint-enable class-methods-use-this */

/* eslint-disable class-methods-use-this */
/**
Expand Down
6 changes: 4 additions & 2 deletions src/parser/grammars/grammar.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ Modifier

// Explode, Penetrate, Compound modifier
ExplodeModifier
= "!" compound:"!"? penetrate:"p"? comparePoint:ComparePoint? {
return new Modifiers.ExplodeModifier(comparePoint, !!compound, !!penetrate);
= "!" compound:"!"? penetrate:"p"? iterationLimit:IterationLimit? comparePoint:ComparePoint? {
return new Modifiers.ExplodeModifier(comparePoint, !!compound, !!penetrate, iterationLimit);
}

// Target / Success and Failure modifier
Expand Down Expand Up @@ -134,6 +134,8 @@ ComparePoint
CompareOperator
= "!=" / "<=" / ">=" / "=" / ">" / "<"

IterationLimit = IntegerNumber


/**
* Mathematical
Expand Down
8 changes: 4 additions & 4 deletions tests/RollGroup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,13 @@ describe('RollGroup', () => {

test('modifiers list always returns in correct order', () => {
// create modifiers and define their order
const mod1 = new Modifier('m1');
const mod1 = new Modifier();
mod1.order = 4;
const mod2 = new Modifier('m2');
const mod2 = new Modifier();
mod2.order = 3;
const mod3 = new Modifier('m3');
const mod3 = new Modifier();
mod3.order = 1;
const mod4 = new Modifier('m4');
const mod4 = new Modifier();
mod4.order = 2;

// create the dice instance
Expand Down
16 changes: 8 additions & 8 deletions tests/dice/FudgeDice.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ describe('FudgeDice', () => {
describe('Modifiers', () => {
test('setting modifiers in constructor calls setter', () => {
const spy = jest.spyOn(FudgeDice.prototype, 'modifiers', 'set');
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));

new FudgeDice(null, 1, modifiers);

Expand All @@ -182,7 +182,7 @@ describe('FudgeDice', () => {
});

test('can set modifiers with Map', () => {
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));
const die = new FudgeDice(null, 1);

die.modifiers = modifiers;
Expand All @@ -192,7 +192,7 @@ describe('FudgeDice', () => {
});

test('can set modifiers with Object', () => {
const modifier = new Modifier('m');
const modifier = new Modifier();
const die = new FudgeDice(null, 1);

die.modifiers = { foo: modifier };
Expand All @@ -202,7 +202,7 @@ describe('FudgeDice', () => {
});

test('can set modifiers with Array', () => {
const modifiers = [new Modifier('m')];
const modifiers = [new Modifier()];
const die = new FudgeDice(null, 1);

die.modifiers = modifiers;
Expand Down Expand Up @@ -238,13 +238,13 @@ describe('FudgeDice', () => {

test('modifiers list always returns in correct order', () => {
// create modifiers and define their order
const mod1 = new Modifier('m1');
const mod1 = new Modifier();
mod1.order = 4;
const mod2 = new Modifier('m2');
const mod2 = new Modifier();
mod2.order = 3;
const mod3 = new Modifier('m3');
const mod3 = new Modifier();
mod3.order = 1;
const mod4 = new Modifier('m4');
const mod4 = new Modifier();
mod4.order = 2;

// create the dice instance
Expand Down
16 changes: 8 additions & 8 deletions tests/dice/PercentileDice.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('PercentileDice', () => {
describe('Modifiers', () => {
test('setting modifiers in constructor calls setter', () => {
const spy = jest.spyOn(PercentileDice.prototype, 'modifiers', 'set');
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));

new PercentileDice(1, modifiers);

Expand All @@ -115,7 +115,7 @@ describe('PercentileDice', () => {
});

test('can set modifiers with Map', () => {
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));
const die = new PercentileDice();

die.modifiers = modifiers;
Expand All @@ -125,7 +125,7 @@ describe('PercentileDice', () => {
});

test('can set modifiers with Object', () => {
const modifier = new Modifier('m');
const modifier = new Modifier();
const die = new PercentileDice(1);

die.modifiers = { foo: modifier };
Expand All @@ -135,7 +135,7 @@ describe('PercentileDice', () => {
});

test('can set modifiers with Array', () => {
const modifiers = [new Modifier('m')];
const modifiers = [new Modifier()];
const die = new PercentileDice(1);

die.modifiers = modifiers;
Expand Down Expand Up @@ -171,13 +171,13 @@ describe('PercentileDice', () => {

test('modifiers list always returns in correct order', () => {
// create modifiers and define their order
const mod1 = new Modifier('m1');
const mod1 = new Modifier();
mod1.order = 4;
const mod2 = new Modifier('m2');
const mod2 = new Modifier();
mod2.order = 3;
const mod3 = new Modifier('m3');
const mod3 = new Modifier();
mod3.order = 1;
const mod4 = new Modifier('m4');
const mod4 = new Modifier();
mod4.order = 2;

// create the dice instance
Expand Down
16 changes: 8 additions & 8 deletions tests/dice/StandardDice.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ describe('StandardDice', () => {
describe('Modifiers', () => {
test('setting modifiers in constructor calls setter', () => {
const spy = jest.spyOn(StandardDice.prototype, 'modifiers', 'set');
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));

new StandardDice(6, 8, modifiers);

Expand All @@ -405,7 +405,7 @@ describe('StandardDice', () => {
});

test('can set modifiers with Map', () => {
const modifiers = new Map(Object.entries({ foo: new Modifier('m') }));
const modifiers = new Map(Object.entries({ foo: new Modifier() }));
const die = new StandardDice(6, 8);

die.modifiers = modifiers;
Expand All @@ -415,7 +415,7 @@ describe('StandardDice', () => {
});

test('can set modifiers with Object', () => {
const modifier = new Modifier('m');
const modifier = new Modifier();
const die = new StandardDice(6, 8);

die.modifiers = { foo: modifier };
Expand All @@ -425,7 +425,7 @@ describe('StandardDice', () => {
});

test('can set modifiers with Array', () => {
const modifiers = [new Modifier('m')];
const modifiers = [new Modifier()];
const die = new StandardDice(6, 8);

die.modifiers = modifiers;
Expand Down Expand Up @@ -461,13 +461,13 @@ describe('StandardDice', () => {

test('modifiers list always returns in correct order', () => {
// create modifiers and define their order
const mod1 = new Modifier('m1');
const mod1 = new Modifier();
mod1.order = 4;
const mod2 = new Modifier('m2');
const mod2 = new Modifier();
mod2.order = 3;
const mod3 = new Modifier('m3');
const mod3 = new Modifier();
mod3.order = 1;
const mod4 = new Modifier('m4');
const mod4 = new Modifier();
mod4.order = 2;

// create the dice instance
Expand Down
Loading

0 comments on commit 7f8904e

Please sign in to comment.