|
@@ -1,4 +1,7 @@
|
|
|
const diceRegex = () => /\b(\d*)[dD](\d+)\b(?:\s?([+-])\s?(\d+))?/g
|
|
const diceRegex = () => /\b(\d*)[dD](\d+)\b(?:\s?([+-])\s?(\d+))?/g
|
|
|
|
|
+const rerollRegex = () => /\b(reroll|re-roll)\s+((?:(?:\S*|\d+s|\d+'s|\d+)\s*)+)/
|
|
|
|
|
+const numberRegex = () => /\b(one|two|three|four|five|six|seven|eight|nine|ten|ones|twos|threes|fours|fives|sixes|sevens|eights|nines|tens|one's|two's|three's|four's|five's|seven's|eight's|nine's|ten's|\d+)\b/gi
|
|
|
|
|
+const advRegex = () => /(disadvantage|advantage)/i
|
|
|
|
|
|
|
|
class Roll {
|
|
class Roll {
|
|
|
constructor(roll) {
|
|
constructor(roll) {
|
|
@@ -17,6 +20,11 @@ class Roll {
|
|
|
if (this.values.length > 1 || this.bonus) {
|
|
if (this.values.length > 1 || this.bonus) {
|
|
|
str += ` = ${this.value()}`
|
|
str += ` = ${this.value()}`
|
|
|
}
|
|
}
|
|
|
|
|
+ if (this.rerolls === 1) {
|
|
|
|
|
+ str += ` with 1 reroll`
|
|
|
|
|
+ } else if (this.rerolls > 1) {
|
|
|
|
|
+ str += ` with ${this.rerolls} rerolls`
|
|
|
|
|
+ }
|
|
|
return str
|
|
return str
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -30,6 +38,8 @@ class BadRoll extends Roll {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const random = n => Math.floor(Math.random() * n) + 1
|
|
|
|
|
+
|
|
|
class Dice {
|
|
class Dice {
|
|
|
constructor(dice) {
|
|
constructor(dice) {
|
|
|
if (dice) Object.assign(this, dice)
|
|
if (dice) Object.assign(this, dice)
|
|
@@ -44,16 +54,36 @@ class Dice {
|
|
|
|
|
|
|
|
let values = []
|
|
let values = []
|
|
|
for (let i = 0; i < this.count; i++) {
|
|
for (let i = 0; i < this.count; i++) {
|
|
|
- values.push(Math.floor(Math.random() * this.sides) + 1)
|
|
|
|
|
|
|
+ if (this.modifier === 'advantage') {
|
|
|
|
|
+ values.push(Math.max(random(this.sides), random(this.sides)))
|
|
|
|
|
+ } else if (this.modifier === 'disadvantage') {
|
|
|
|
|
+ values.push(Math.min(random(this.sides), random(this.sides)))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ values.push(random(this.sides))
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
let bonus = 0
|
|
let bonus = 0
|
|
|
switch (this.bonusSign) {
|
|
switch (this.bonusSign) {
|
|
|
case '-': bonus = -this.bonus; break
|
|
case '-': bonus = -this.bonus; break
|
|
|
case '+': bonus = this.bonus; break
|
|
case '+': bonus = this.bonus; break
|
|
|
}
|
|
}
|
|
|
|
|
+ let rerolls = 0
|
|
|
|
|
+ for (let i = 0; i < 10; i++) {
|
|
|
|
|
+ let foundAny = false
|
|
|
|
|
+ for (let d = 0; d < values.length; d++) {
|
|
|
|
|
+ const v = values[d]
|
|
|
|
|
+ if (this.rerollNumbers && this.rerollNumbers.includes(v)) {
|
|
|
|
|
+ values[d] = random(this.sides)
|
|
|
|
|
+ foundAny = true
|
|
|
|
|
+ rerolls++
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!foundAny) break
|
|
|
|
|
+ }
|
|
|
return new Roll({
|
|
return new Roll({
|
|
|
values,
|
|
values,
|
|
|
- bonus
|
|
|
|
|
|
|
+ bonus,
|
|
|
|
|
+ rerolls
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
toString() {
|
|
toString() {
|
|
@@ -61,11 +91,85 @@ class Dice {
|
|
|
if (this.bonusSign) {
|
|
if (this.bonusSign) {
|
|
|
str += this.bonusSign + this.bonus
|
|
str += this.bonusSign + this.bonus
|
|
|
}
|
|
}
|
|
|
|
|
+ if (this.modifier) {
|
|
|
|
|
+ str += ` with ${this.modifier}`
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.rerollNumbers && this.rerollNumbers.length) {
|
|
|
|
|
+ if (this.rerollNumbers.length === 1) {
|
|
|
|
|
+ str += ` and reroll ${this.rerollNumbers[0]}'s`
|
|
|
|
|
+ } else {
|
|
|
|
|
+ str += ` and reroll ${this.rerollNumbers.slice(0, this.rerollNumbers.length - 1).join(`'s, `)}'s, and ${this.rerollNumbers[this.rerollNumbers.length - 1]}'s`
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
return str
|
|
return str
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Dice.parse = str => {
|
|
Dice.parse = str => {
|
|
|
|
|
+ const rrRegex = rerollRegex()
|
|
|
|
|
+ const rerolls = []
|
|
|
|
|
+ const reroll = rrRegex.exec(str)
|
|
|
|
|
+ const rerollNumbers = []
|
|
|
|
|
+ if (reroll) {
|
|
|
|
|
+ const nRegex = numberRegex()
|
|
|
|
|
+ while (number = nRegex.exec(str)) {
|
|
|
|
|
+ switch (number[1]) {
|
|
|
|
|
+ case 'ones':
|
|
|
|
|
+ case 'one':
|
|
|
|
|
+ rerollNumbers.push(1)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'twos':
|
|
|
|
|
+ case 'two':
|
|
|
|
|
+ rerollNumbers.push(2)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'threes':
|
|
|
|
|
+ case 'three':
|
|
|
|
|
+ rerollNumbers.push(3)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'fours':
|
|
|
|
|
+ case 'four':
|
|
|
|
|
+ rerollNumbers.push(4)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'fives':
|
|
|
|
|
+ case 'five':
|
|
|
|
|
+ rerollNumbers.push(5)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'sixes':
|
|
|
|
|
+ case 'six':
|
|
|
|
|
+ rerollNumbers.push(6)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'sevens':
|
|
|
|
|
+ case 'seven':
|
|
|
|
|
+ rerollNumbers.push(7)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'eights':
|
|
|
|
|
+ case 'eight':
|
|
|
|
|
+ rerollNumbers.push(8)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'nines':
|
|
|
|
|
+ case 'nine':
|
|
|
|
|
+ rerollNumbers.push(9)
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'tens':
|
|
|
|
|
+ case 'ten':
|
|
|
|
|
+ rerollNumbers.push(10)
|
|
|
|
|
+ break
|
|
|
|
|
+ default:
|
|
|
|
|
+ const n = parseFloat(number)
|
|
|
|
|
+ if (!isNaN(n)) {
|
|
|
|
|
+ rerollNumbers.push(n)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const aRegex = advRegex()
|
|
|
|
|
+ const ad = aRegex.exec(str)
|
|
|
|
|
+
|
|
|
|
|
+ const modifier = ad ? (
|
|
|
|
|
+ ad[1].toLowerCase()[0] === 'a' ? 'advantage' : 'disadvantage'
|
|
|
|
|
+ ) : null
|
|
|
|
|
+
|
|
|
const regex = diceRegex()
|
|
const regex = diceRegex()
|
|
|
const ret = []
|
|
const ret = []
|
|
|
let dice
|
|
let dice
|
|
@@ -75,7 +179,9 @@ Dice.parse = str => {
|
|
|
count: dice[1] === '' ? 1 : parseFloat(dice[1]),
|
|
count: dice[1] === '' ? 1 : parseFloat(dice[1]),
|
|
|
sides: parseFloat(dice[2]),
|
|
sides: parseFloat(dice[2]),
|
|
|
bonusSign: dice[3] || null,
|
|
bonusSign: dice[3] || null,
|
|
|
- bonus: dice[4] === undefined ? null : parseFloat(dice[4])
|
|
|
|
|
|
|
+ bonus: dice[4] === undefined ? null : parseFloat(dice[4]),
|
|
|
|
|
+ rerollNumbers,
|
|
|
|
|
+ modifier
|
|
|
}))
|
|
}))
|
|
|
}
|
|
}
|
|
|
return ret
|
|
return ret
|
|
@@ -94,4 +200,10 @@ Dice.chat = chat => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-module.exports = {Dice, Roll}
|
|
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ Dice,
|
|
|
|
|
+ Roll,
|
|
|
|
|
+ diceRegex,
|
|
|
|
|
+ rerollRegex,
|
|
|
|
|
+ advRegex
|
|
|
|
|
+}
|