|
@@ -259,6 +259,49 @@ class Asphodice extends D10 { |
|
|
* - dice: Array - final outcome |
|
|
* - dice: Array - final outcome |
|
|
* - balance: number - +/- of outcomes (successes/failures) |
|
|
* - balance: number - +/- of outcomes (successes/failures) |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Determines if a reroll is needed |
|
|
|
|
|
* |
|
|
|
|
|
* @remarks |
|
|
|
|
|
* |
|
|
|
|
|
* In some cases we don't reroll: |
|
|
|
|
|
* - reroll dice cancel each other out |
|
|
|
|
|
* - all are above cutoff (=> auto-success -- NB TODO crits) |
|
|
|
|
|
* - all below cutoff |
|
|
|
|
|
*/ |
|
|
|
|
|
rerollNeeded(resultDice: Array<number>): boolean{ |
|
|
|
|
|
// 1. if no re-rolls we can finish here |
|
|
|
|
|
if (!(resultDice.includes(this.passCrit) || resultDice.includes(this.failCrit))) { |
|
|
|
|
|
// results.total = results.dice.reduce((acc: number, curr: number) => acc + curr); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// count successes and fails |
|
|
|
|
|
let rerollGood = countOccurrencesOfNumber(resultDice, this.passCrit); |
|
|
|
|
|
let rerollBad = countOccurrencesOfNumber(resultDice, this.failCrit); |
|
|
|
|
|
|
|
|
|
|
|
// 2. only reroll if they don't cancel each other out |
|
|
|
|
|
if (rerollGood == rerollBad) { |
|
|
|
|
|
// console.log("Good = Bad, no need to reroll"); |
|
|
|
|
|
return false; |
|
|
|
|
|
// results.total = results.dice.reduce((acc: number, curr: number) => acc + curr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 3. If all dice are above/below cutoff we don't need to reroll |
|
|
|
|
|
if (this.allAboveCutOff(resultDice)) { |
|
|
|
|
|
console.log("All above cutoff, auto-success", resultDice); |
|
|
|
|
|
return false; |
|
|
|
|
|
} else if (this.allBelowCutOff(resultDice)) { |
|
|
|
|
|
console.log("All below cutoff, auto-fail", resultDice); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// We should re-roll |
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
roll (numToRoll: number): DiceResult { |
|
|
roll (numToRoll: number): DiceResult { |
|
|
let results: DiceResult = { total: 0, dice: [] }; |
|
|
let results: DiceResult = { total: 0, dice: [] }; |
|
|
|
|
|
|
|
@@ -266,48 +309,21 @@ class Asphodice extends D10 { |
|
|
for (let i = 0; i < numToRoll; i++) { |
|
|
for (let i = 0; i < numToRoll; i++) { |
|
|
results.dice.push(randIntMinOne(this.sides)); |
|
|
results.dice.push(randIntMinOne(this.sides)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Check for re-rolls |
|
|
|
|
|
// 1. if no re-rolls we can finish here |
|
|
|
|
|
if (!(results.dice.includes(this.passCrit) || results.dice.includes(this.failCrit))) { |
|
|
|
|
|
// results.total = results.dice.reduce((acc: number, curr: number) => acc + curr); |
|
|
|
|
|
results.reroll = false; |
|
|
|
|
|
} else { |
|
|
|
|
|
// count successes and fails |
|
|
|
|
|
let rerollGood = countOccurrencesOfNumber(results.dice, this.passCrit); |
|
|
|
|
|
let rerollBad = countOccurrencesOfNumber(results.dice, this.failCrit); |
|
|
|
|
|
|
|
|
|
|
|
// 2. only reroll if they don't cancel each other out |
|
|
|
|
|
if (rerollGood == rerollBad) { |
|
|
|
|
|
// console.log("Good = Bad, no need to reroll"); |
|
|
|
|
|
results.reroll = false; |
|
|
|
|
|
// results.total = results.dice.reduce((acc: number, curr: number) => acc + curr); |
|
|
|
|
|
} |
|
|
|
|
|
// If all dice are above/below cutoff we don't need to reroll |
|
|
|
|
|
// 3a. Above |
|
|
|
|
|
else if (this.allAboveCutOff(results.dice)) { |
|
|
|
|
|
console.log("All above cutoff, auto-success", results.dice); |
|
|
|
|
|
results.reroll = false; |
|
|
|
|
|
} |
|
|
|
|
|
// 3b. Below |
|
|
|
|
|
else if (this.allBelowCutOff(results.dice)) { |
|
|
|
|
|
console.log("All below cutoff, auto-fail", results.dice); |
|
|
|
|
|
results.reroll = false; |
|
|
|
|
|
} |
|
|
|
|
|
// Reroll |
|
|
|
|
|
else { |
|
|
|
|
|
// Reminder: arr1 = arr2 is a copy by reference! |
|
|
|
|
|
let olddice = results.dice.slice(); |
|
|
|
|
|
if (rerollGood > rerollBad) { |
|
|
|
|
|
// Re-roll low (<6) dice for chance of success |
|
|
|
|
|
results.dice = this.rerollLowDice(results.dice); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Re-roll high (>=6) dice for chance of failure |
|
|
|
|
|
results.dice = this.rerollHighDice(results.dice); |
|
|
|
|
|
} |
|
|
|
|
|
results.olddice = olddice; |
|
|
|
|
|
results.reroll = true; |
|
|
|
|
|
|
|
|
// Reroll? |
|
|
|
|
|
if (this.rerollNeeded(results.dice)) { |
|
|
|
|
|
// Reminder: arr1 = arr2 is a copy by reference! |
|
|
|
|
|
let olddice = results.dice.slice(); |
|
|
|
|
|
let rerollGood = countOccurrencesOfNumber(olddice, this.passCrit); |
|
|
|
|
|
let rerollBad = countOccurrencesOfNumber(olddice, this.failCrit); |
|
|
|
|
|
if (rerollGood > rerollBad) { |
|
|
|
|
|
// Re-roll low (<6) dice for chance of success |
|
|
|
|
|
results.dice = this.rerollLowDice(results.dice); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Re-roll high (>=6) dice for chance of failure |
|
|
|
|
|
results.dice = this.rerollHighDice(results.dice); |
|
|
} |
|
|
} |
|
|
|
|
|
results.olddice = olddice; |
|
|
|
|
|
results.reroll = true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
results.balance = this.countOutcomeBalance(results.dice); |
|
|
results.balance = this.countOutcomeBalance(results.dice); |
|
|